/** * @brief Write data on an opened file * * Help from FUSE * * Write should return exactly the number of bytes requested except on error. * * @param path file path * @param buf buffer where we have data to write * @param size quantity of bytes to write * @param offset offset over the writing * @param fi FUSE structure linked to the opened file * @return 0 on success and <0 on error **/ static int my_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { char buffer[BLOCK_SIZE_BYTES]; // 1 bloque de caracteres. int bytes2Write = size, totalWrite = 0; NodeStruct *node = myFileSystem.nodes[fi->fh]; // fh==File handle. May be filled in by filesystem in open(). fprintf(stderr, "--->>>my_write: path %s, size %zu, offset %jd, fh %"PRIu64"\n", path, size, (intmax_t)offset, fi->fh); // Increase the file size if it is needed if(resizeNode(fi->fh, size + offset) < 0) return -EIO; // Write data while(bytes2Write) { int i; int currentBlock, offBloque; currentBlock = node->blocks[offset / BLOCK_SIZE_BYTES]; offBloque = offset % BLOCK_SIZE_BYTES; // posicionas el cursor del archivo en el bloque + offset. // lees un bloque entero empezando en esa posición. SI alguno de los dos falla exit. if((lseek(myFileSystem.fdVirtualDisk, currentBlock * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (read(myFileSystem.fdVirtualDisk, &buffer, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/read in my_write"); return -EIO; } // Desde el punto inicial del offset, hasta el final del bloque, escribes la información // del buf (texto que nos pasan en la función) en el buffer. for(i = offBloque; (i < BLOCK_SIZE_BYTES) && (totalWrite < size); i++) { buffer[i] = buf[totalWrite++]; } // GUardas el buffer con la información modificada en el archivo indicado en el descriptor físico. if((lseek(myFileSystem.fdVirtualDisk, currentBlock * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (write(myFileSystem.fdVirtualDisk, &buffer, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/write in my_write"); return -EIO; } // Discont the written stuff bytes2Write -= (i - offBloque); offset += i; } sync(); node->modificationTime = time(NULL); updateSuperBlock(&myFileSystem); updateBitmap(&myFileSystem); updateNode(&myFileSystem, fi->fh, node); return size; }
int my_unlink(const char *filename) { // printDirectory(myFileSystem.directory); // DEBUG stuff only for debugging /***** Copiar filename sin '/' en una nueva variable para ***** poder pasarla a findFileByNAme (que no admite strings constantes) ****/ int i=0; char* fname=(char*)(filename+1); // Convert ffrom const char to char. Y también, quitar el primer character (/) sumando uno al puntero de filename (hace algoritimia de punteros.) /** 1. Buscar si el archivo está en nuestro directorio **/ /** Si está, liberar el archivo y poner el nombre a empty **/ /** OJO! NO hay que tocar nodeIdx... **/ int nodeIndexDir = findFileByName(&myFileSystem, fname); // NodeIDx índice que ocupa un nodo en el array de nodos if (nodeIndexDir == -1) { fprintf(stderr, "File wasn't found on the directory entry\n"); return -1; // File is not on the directory. } // FILE to erase is on the directory. Free the directory entry. myFileSystem.directory.numFiles -= 1; // Decrementar numero de archivos en el directorio. myFileSystem.directory.files[nodeIndexDir].freeFile = true; // Put the node in directory as free. updateDirectory(&myFileSystem); int nodeIdx = myFileSystem.directory.files[nodeIndexDir].nodeIdx; // Hacer una copia de nodoIDx del directorio que nos sirve para acceder al array de nodos. NodeStruct* inode=myFileSystem.nodes[nodeIdx]; /** 2. Borrar datos y liberar nodo usando el nodeIdx obtenido del directorio **/ myFileSystem.numFreeNodes += 1; // Increase the number of free nodes by 1 because e erased one. for (i=0;i<inode->numBlocks;i++) myFileSystem.bitMap[inode->blocks[i]] = 0; // Marcar bloques de datos en bitmap como libre myFileSystem.superBlock.numOfFreeBlocks+=inode->numBlocks; updateBitmap(&myFileSystem); updateSuperBlock(&myFileSystem); /********************************************** * Se podría poner unicamente a NULL? Es peor? **********************************************/ inode->numBlocks=0; inode->fileSize=0; inode->freeNode=true; // Delete the note from the node's array. updateNode(&myFileSystem,nodeIdx,inode); free(inode); myFileSystem.nodes[nodeIdx]=NULL; //printAllNodes(myFileSystem.nodes); //printDirectory(myFileSystem.directory); // DEBUG stuff only for debugging fprintf(stderr, "\n Congrats!!! %s file deleted \n", filename); return 0; }
/** * @brief Modifies the data size originally reserved by an inode, reserving or removing space if needed. * * @param idxNode inode number * @param newSize new size for the inode * @return int **/ int resizeNode(uint64_t idxNode, size_t newSize) { NodeStruct *node = myFileSystem.nodes[idxNode]; char block[BLOCK_SIZE_BYTES]; int i, diff = newSize - node->fileSize; if(!diff) return 0; memset(block, 0, sizeof(char)*BLOCK_SIZE_BYTES); /// File size increases if(diff > 0) { /// Delete the extra conent of the last block if it exists and is not full if(node->numBlocks && node->fileSize % BLOCK_SIZE_BYTES) { int currentBlock = node->blocks[node->numBlocks - 1]; if((lseek(myFileSystem.fdVirtualDisk, currentBlock * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (read(myFileSystem.fdVirtualDisk, &block, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/read in resizeNode"); return -EIO; } int offBlock = node->fileSize % BLOCK_SIZE_BYTES; int bytes2Write = (diff > (BLOCK_SIZE_BYTES - offBlock)) ? BLOCK_SIZE_BYTES - offBlock : diff; for(i = 0; i < bytes2Write; i++) { block[offBlock++] = 0; } if((lseek(myFileSystem.fdVirtualDisk, currentBlock * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (write(myFileSystem.fdVirtualDisk, &block, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/write in resizeNode"); return -EIO; } } /// File size in blocks after the increment int newBlocks = (newSize + BLOCK_SIZE_BYTES - 1) / BLOCK_SIZE_BYTES - node->numBlocks; if(newBlocks) { memset(block, 0, sizeof(char)*BLOCK_SIZE_BYTES); // We check that there is enough space if(newBlocks > myFileSystem.superBlock.numOfFreeBlocks) return -ENOSPC; myFileSystem.superBlock.numOfFreeBlocks -= newBlocks; int currentBlock = node->numBlocks; node->numBlocks += newBlocks; for(i = 0; currentBlock != node->numBlocks; i++) { if(myFileSystem.bitMap[i] == 0) { myFileSystem.bitMap[i] = 1; node->blocks[currentBlock] = i; currentBlock++; // Clean disk (necessary for truncate) if((lseek(myFileSystem.fdVirtualDisk, i * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (write(myFileSystem.fdVirtualDisk, &block, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/write in resizeNode"); return -EIO; } } } } node->fileSize += diff; } /// File decreases else { // File size in blocks after truncation int numBlocks = (newSize + BLOCK_SIZE_BYTES - 1) / BLOCK_SIZE_BYTES; myFileSystem.superBlock.numOfFreeBlocks += (node->numBlocks - numBlocks); for(i = node->numBlocks; i > numBlocks; i--) { int nBloque = node->blocks[i - 1]; myFileSystem.bitMap[nBloque] = 0; // Clean disk (it is not really necessary) if((lseek(myFileSystem.fdVirtualDisk, nBloque * BLOCK_SIZE_BYTES, SEEK_SET) == (off_t) - 1) || (write(myFileSystem.fdVirtualDisk, &block, BLOCK_SIZE_BYTES) == -1)) { perror("Failed lseek/write in resizeNode"); return -EIO; } } node->numBlocks = numBlocks; node->fileSize += diff; } node->modificationTime = time(NULL); sync(); /// Update all the information in the backup file updateSuperBlock(&myFileSystem); updateBitmap(&myFileSystem); updateNode(&myFileSystem, idxNode, node); return 0; }
int myMkfs(MyFileSystem *myFileSystem, int diskSize, char *backupFileName) { // We create the virtual disk: myFileSystem->fdVirtualDisk = open(backupFileName, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); // Some minimal checks: assert(sizeof(SuperBlockStruct) <= BLOCK_SIZE_BYTES); assert(sizeof(DirectoryStruct) <= BLOCK_SIZE_BYTES); int numBlocks = diskSize / BLOCK_SIZE_BYTES; int minNumBlocks = 3 + MAX_BLOCKS_WITH_NODES + 1; // 3 --> por el superbloque, el raiz y el mapa de bits. // 1 --> porque al menos tenemos un bloque para datos. int maxNumBlocks = NUM_BITS; if(numBlocks < minNumBlocks) { return -1; } if(numBlocks >= maxNumBlocks) { return -2; } /// BITMAP // Initialization int i; for(i = 0; i < NUM_BITS; i++) { myFileSystem->bitMap[i] = 0; } // First three blocks will be superblock, bitmap and directory myFileSystem->bitMap[BITMAP_IDX] = 1; myFileSystem->bitMap[SUPERBLOCK_IDX] = 1; myFileSystem->bitMap[DIRECTORY_IDX] = 1; // Next MAX_BLOCKS_WITH_NODES will contain inodes for(i = 3; i < 3 + MAX_BLOCKS_WITH_NODES; i++) { myFileSystem->bitMap[i] = 1; } updateBitmap(myFileSystem); /// DIRECTORY // Initialization myFileSystem->directory.numFiles = 0; for(i = 0; i < MAX_FILES_PER_DIRECTORY; i++) { myFileSystem->directory.files[i].freeFile = 1; } updateDirectory(myFileSystem); /// INODES NodeStruct currentNode; currentNode.freeNode = 1; for(i = 0; i < MAX_NODES; i++) { updateNode(myFileSystem, i, ¤tNode); } /// SUPERBLOCK initializeSuperBlock(myFileSystem, diskSize); updateSuperBlock(myFileSystem); sync(); // At the end we have at least one block assert(myQuota(myFileSystem) >= 1); if(initializeNodes(myFileSystem)){ myFree(myFileSystem); return -3; } printf("SF: %s, %d B (%d B/block), %d blocks\n", backupFileName, diskSize, BLOCK_SIZE_BYTES, numBlocks); printf("1 block for SUPERBLOCK (%u B)\n", (unsigned int)sizeof(SuperBlockStruct)); printf("1 block for BITMAP, covering %u blocks, %u B\n", (unsigned int)NUM_BITS, (unsigned int)(NUM_BITS * BLOCK_SIZE_BYTES)); printf("1 block for DIRECTORY (%u B)\n", (unsigned int)sizeof(DirectoryStruct)); printf("%d blocks for inodes (%u B/inode, %u inodes)\n", MAX_BLOCKS_WITH_NODES, (unsigned int)sizeof(NodeStruct), (unsigned int)MAX_NODES); printf("%d blocks for data (%d B)\n", myFileSystem->superBlock.numOfFreeBlocks, BLOCK_SIZE_BYTES * myFileSystem->superBlock.numOfFreeBlocks); printf("Formatting completed!\n"); return 0; }