/* * Remove an existing empty directory and return 0 on success. * If the dir does not exist or still contains files, return -1. */ int sfs_rmdir(char *dirname) { sfs_dirblock_t currentDir, prevDir, nextDir; blkid bid, prevBlkid, nextBlkid; /* TODO: check if the dir exists */ bid = sfs_find_dir(dirname); if (bid != 0) { // Directory exists sfs_read_block((char*)¤tDir, bid); /* TODO: check if no files */ int i; for (i = 0; i < SFS_DB_NINODES; i++) { if (currentDir.inodes[i] != 0) { // directory is not empty printf("ERROR: inodes not empty = %d\n", currentDir.inodes[i]); return -1; } } /* TODO: go thru the linked list to delete the dir*/ // Need to change the next_dir pointer of the previous dir and dir to be deleted nextBlkid = sb.first_dir; if (nextBlkid == bid) { // Deleting the root directory sb.first_dir = 0; sfs_read_block((char*)¤tDir, nextBlkid); currentDir.next_dir = 0; memset(currentDir.dir_name, 0, sizeof(currentDir.dir_name)); return 0; } else { while (nextBlkid != bid) { prevBlkid = nextBlkid; sfs_read_block((char*)&prevDir, nextBlkid); nextBlkid = prevDir.next_dir; } nextBlkid = currentDir.next_dir; } // Remove the directory: update the linked list next_dir variable prevDir.next_dir = nextBlkid; currentDir.next_dir = 0; // Remove the dir_name of the dir to be deleted memset(currentDir.dir_name, 0, sizeof(currentDir.dir_name)); // Flush the removed directory and prevDir sfs_write_block((char*)¤tDir, bid); sfs_write_block((char*)&prevDir, prevBlkid); // Update the freemap so that deleted dir is empty sfs_free_block(bid); return 0; } return -1; }
/* * Print all directories. Return the number of directories. */ int sfs_lsdir() { /* TODO: go thru the linked list */ int num_dir = 0; char block_ptr[BLOCK_SIZE]; sfs_dirblock_t dir; sfs_read_block(&sb, 0); blkid dir_bid = sb.first_dir; printf("0: sb\t\t %d\n", dir_bid); if(dir_bid != 0){ do{ sfs_read_block(block_ptr, dir_bid); dir = *(sfs_dirblock_t*)block_ptr; printf("%d: %s", dir_bid, dir.dir_name); num_dir++; dir_bid = dir.next_dir; printf(" \t %d\n", dir_bid); } while(dir_bid != 0); } printf("Number of directories: %d\n", num_dir); return num_dir; }
/* * Get the bids of content blocks that hold the file content starting from cur * to cur+length. These bids are stored in the given array. * The caller of this function is supposed to allocate the memory for this * array. It is guaranteed that cur+length<size * * This function returns the number of bids being stored to the array. */ static u32 sfs_get_file_content(blkid *bids, int fd, u32 cur, u32 length) { u32 start; //Starting block of content u32 end; //Ending block of content sfs_inode_t inode; sfs_inode_frame_t frame; blkid frame_bid; char tmp[BLOCK_SIZE]; char frame_ptr[BLOCK_SIZE]; u32 num_bids = 0; //Counts the number of bids in the array //Get the bid of the desired frame fd_struct_t fd_struct = fdtable[fd]; sfs_read_block(tmp, fd_struct.inode_bid); inode = *(sfs_inode_t*)tmp; frame_bid = inode.first_frame; start = cur / BLOCK_SIZE; end = (cur + length) / BLOCK_SIZE; u32 numBlocks = end - start + 1; u32 blocks_remaining = numBlocks; u32 original_blocks = blocks_remaining; //Start searching at an offset determined by the start position u32 block_count = start % SFS_FRAME_COUNT; //This loop will iterate through the frames while(blocks_remaining > 0){ sfs_read_block(frame_ptr, frame_bid); frame = *(sfs_inode_frame_t*)frame_ptr; //Iterate through the content array of the frame while(block_count < SFS_FRAME_COUNT && blocks_remaining > 0){ //Allocate a content block if it is not yet set if(frame.content[block_count] == 0){ frame.content[block_count] = sfs_alloc_block(); } bids[num_bids] = frame.content[block_count]; num_bids++; block_count++; blocks_remaining--; } sfs_write_block(&frame, frame_bid); if(blocks_remaining != 0){ frame_bid = frame.next; block_count = 0; } } return num_bids; }
/* * Remove/delete an existing file * * This function returns zero on success. */ int sfs_remove(int fd) { blkid frame_bid, next_frame_bid; sfs_dirblock_t dir; sfs_inode_frame_t frame; int i, j; char *tmp; /* TODO: update dir */ sfs_read_block((char*)&dir, fdtable[fd].dir_bid); for (i = 0; i < SFS_DB_NINODES; i++) { if (dir.inodes[i] == fdtable[fd].inode_bid) { dir.inodes[i] = 0; } } // Write dir block to update inode values sfs_write_block((char*)&dir, fdtable[fd].dir_bid); /* TODO: free inode and all its frames */ frame_bid = fdtable[fd].inode.first_frame; while (frame_bid != 0) { sfs_read_block((char*)&frame, frame_bid); // Free all the content blocks for each frame for (j = 0; j < SFS_FRAME_COUNT; j++) { tmp = (char*)malloc(BLOCK_SIZE); memset(tmp, 0, BLOCK_SIZE); sfs_write_block(tmp, frame.content[j]); sfs_free_block(frame.content[j]); free(tmp); } next_frame_bid = frame.next; memset(&frame, 0, BLOCK_SIZE); sfs_write_block((char*)&frame, frame_bid); sfs_free_block(frame_bid); frame_bid = next_frame_bid; } // Free the inode memset((char*)&fdtable[fd].inode, 0, BLOCK_SIZE); sfs_write_block((char*)&fdtable[fd].inode, fdtable[fd].inode_bid); sfs_free_block(fdtable[fd].inode_bid); /* TODO: close the file */ sfs_close(fd); return 0; }
/* * Allocate a free block, mark it in the freemap and flush the freemap to disk */ static blkid sfs_alloc_block() { u32 size = sb.nfreemap_blocks * BLOCK_SIZE / sizeof(u32); // size = 1 * 512 / 4 = 128 four-byte sections = 4096 bits //Renaming variables i and j to be more specific u32 fm_blk, fm_byte; blkid free_block_id; //Search each freemap block for(fm_blk = 0; fm_blk < sb.nfreemap_blocks; fm_blk++){ //Read the freemap block located at the block ID int count; int freemap_id = fm_blk + 1; sfs_read_block(freemap, freemap_id); //Search each index of the freemap block for(fm_byte = 0; fm_byte < BLOCK_SIZE; fm_byte++){ u32 bitmap = freemap[fm_byte]; if((bitmap ^ 0xffffffff) != 0){ //There is a free bit at this index in the freemap u32 mask = 0x1; u32 result; count = 0; //Search each bit of the freemap block while(count < SFS_NBITS_IN_FREEMAP_ENTRY){ result = bitmap & mask; if(result == mask){ mask = mask << 1; count++; } else{ free_block_id = fm_byte * SFS_NBITS_IN_FREEMAP_ENTRY + count; //Set the bit and flush to disk u32 newBitmap = bitmap | mask; freemap[fm_byte] = newBitmap; sfs_flush_freemap(); //Clear the data stored in the block char empty_blk[BLOCK_SIZE]; memset(empty_blk, 0, BLOCK_SIZE); sfs_write_block(empty_blk, free_block_id); return free_block_id; } } } } } return 0; }
/* * Load the super block from disk and print the parameters inside */ sfs_superblock_t *sfs_print_info() { /* TODO: load the superblock from disk and print*/ sfs_read_block((char*)&sb, 0); printf("super block : nblocks = %d , nfreemap_blocks = %d , first_dir = %d\n", sb.nblocks, sb.nfreemap_blocks, sb.first_dir); return &sb; }
/* * Find the directory of the given name. * Return block id for the directory or zero if not found */ static blkid sfs_find_dir(char *dirname) { blkid dir_bid = 0; sfs_dirblock_t dir; //While the value of next_dir != 0, continue traversing the //list of directories until dirname is found dir_bid = sb.first_dir; char block_ptr[BLOCK_SIZE]; while(dir_bid != 0){ sfs_read_block(block_ptr, dir_bid); dir = *(sfs_dirblock_t*)block_ptr; if(strcmp(dirname,dir.dir_name) == 0){ return dir_bid; } else{ //Go to the next directory in the list dir_bid = dir.next_dir; } } return 0; }
/* * Create a new directory and return 0 on success. * If the dir already exists, return -1. */ int sfs_mkdir(char *dirname) { /* TODO: test if the dir exists */ /* TODO: insert a new dir to the linked list */ blkid nextBlkid; sfs_dirblock_t dir, new_dir; // Try finding the directory if it exists blkid bid = sfs_find_dir(dirname); if (bid == 0) { // Directory does not exists, create a new one bid = sfs_alloc_block(); // Add the new directory to the directory linked list nextBlkid = sb.first_dir; if (nextBlkid == 0) { sb.first_dir = bid; sfs_write_block((char*)&sb, 0); } else { sfs_read_block((char*)&dir, nextBlkid); while (dir.next_dir != 0) { nextBlkid = dir.next_dir; sfs_read_block((char*)&dir, nextBlkid); } dir.next_dir = bid; sfs_write_block((char*)&dir, nextBlkid); } // Create new directory with next_dir=0 and dir_name new_dir.next_dir = 0; memset(new_dir.dir_name, 0, sizeof(new_dir.dir_name)); // Empty dir_name memset(new_dir.inodes, 0, sizeof(new_dir.inodes)); // Empty inodes strcpy(new_dir.dir_name, dirname); // Copy new dir_name sfs_write_block((char*)&new_dir, bid); return 0; } // Directory already exists return -1; }
/* * Resize a file. * This file should be opened (in the file descriptor table). The new size * should be larger than the old one (not supposed to shrink a file) */ static void sfs_resize_file(int fd, u32 new_size) { /* the length of content that can be hold by a full frame (in bytes) */ int frame_size = BLOCK_SIZE * SFS_FRAME_COUNT; /* old file size */ int old_size = fdtable[fd].inode.size; /* how many frames are used before resizing */ int old_nframe = (old_size + frame_size -1) / frame_size; /* how many frames are required after resizing */ int new_nframe = (new_size + frame_size - 1) / frame_size; int i, j; blkid frame_bid = 0; sfs_inode_frame_t frame; blkid bid, content_bid; /* TODO: check if new frames are required */ if (new_nframe - old_nframe > 0) { /* TODO: allocate a full frame */ frame_bid = sfs_alloc_block(); for (j = 0; j < SFS_FRAME_COUNT; j++) { content_bid = sfs_alloc_block(); frame.content[j] = content_bid; // Empty content block char tmp[BLOCK_SIZE]; memset(tmp, 0, BLOCK_SIZE); sfs_write_block((char*)&tmp, content_bid); } /* TODO: add the new frame to the inode frame list Note that if the inode is changed, you need to write it to the disk */ bid = fdtable[fd].inode.first_frame; if (bid == 0) { fdtable[fd].inode.first_frame = frame_bid; sfs_write_block((char*)&fdtable[fd].inode, fdtable[fd].inode_bid); } else { for (i = 0; i < SFS_FRAME_COUNT; i++) { if (bid == 0) { frame.next = frame_bid; break; } sfs_read_block((char*)&frame, bid); bid = frame.next; } } // Write the new frame block sfs_write_block((char*)&frame, frame_bid); } }
/* This function returns 1 if it is EOF, otherwise 0. */ int sfs_eof(int fd) { char inode_ptr[BLOCK_SIZE]; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); sfs_inode_t inode = *(sfs_inode_t*)inode_ptr; if(fdtable[fd].cur > inode.size){ return 1; } return 0; }
/* * Read from an opend file. * Read can not enlarge file. So you should not read outside the size of * the file. If the read exceeds the file size, its result will be truncated. * * This function returns the number of bytes read. */ int sfs_read(int fd, void *buf, int length) { int remaining, to_copy, offset; blkid *bids; int i, n; char *p = (char *)buf; char tmp[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; /* TODO: check if we need to truncate */ if ((cur + length) > fdtable[fd].inode.size) { // Need to truncate, remove the last portion length = fdtable[fd].inode.size - length; } /* TODO: similar to the sfs_write() */ // Get the block ids of content bids = malloc(length/BLOCK_SIZE + 1); n = sfs_get_file_content(bids, fd, cur, length); // Read operation remaining = length; offset = cur % BLOCK_SIZE; if (BLOCK_SIZE - offset > remaining) { to_copy = remaining; } else { to_copy = BLOCK_SIZE - offset; } for (i = 0; i < n; i++) { sfs_read_block((char*)&tmp, bids[i]); memcpy(buf, tmp+offset, to_copy); remaining -= to_copy; offset = 0; if (remaining > BLOCK_SIZE) { to_copy = BLOCK_SIZE - offset; } else { to_copy = remaining; } } // Update variables fdtable[fd].cur += length; free(bids); return length; }
/* * List all the files in all directories. Return the number of files. */ int sfs_ls() { /* TODO: nested loop: traverse all dirs and all containing files */ int count = 0; int i, j, k; sfs_dirblock_t dir; sfs_inode_t inode; blkid bid; bid = sb.first_dir; while (bid != 0) { sfs_read_block((char*)&dir, bid); for (j = 0; j<sizeof(dir.dir_name); j++) { printf("%c", dir.dir_name[j]); } printf("\n"); for (i = 0; i < SFS_DB_NINODES; i++) { if (dir.inodes[i] != 0) { sfs_read_block((char*)&inode, dir.inodes[i]); printf("\t"); for (k = 0; k < sizeof(inode.file_name); k++) { printf("%c", inode.file_name[k]); } printf("\tsize = %d\n", inode.size); count++; } } bid = dir.next_dir; } printf("count = %d\n", count); return count; }
/* * List all the files in all directories. Return the number of files. */ int sfs_ls() { /* TODO: nested loop: traverse all dirs and all containing files*/ sfs_read_block(&sb, 0); blkid next_dir = sb.first_dir; char block_ptr[BLOCK_SIZE]; sfs_dirblock_t dir; int num_files = 0; //Traverse all directories while(next_dir != 0){ sfs_read_block(block_ptr, next_dir); dir = *(sfs_dirblock_t*)block_ptr; next_dir = dir.next_dir; //Traverse all files within the directory sfs_inode_t inode; int count = 0; printf("\n%s:\n", dir.dir_name); while(count < SFS_DB_NINODES){ if(dir.inodes[count] != 0){ sfs_read_block(block_ptr, dir.inodes[count]); inode = *(sfs_inode_t*)block_ptr; printf("%s\n", inode.file_name); num_files++; } count++; } } printf("\n"); return num_files; }
/* * Find the directory of the given name. * * Return block id for the directory or zero if not found */ static blkid sfs_find_dir(char *dirname) { blkid dir_bid = 0; sfs_dirblock_t dir; /* TODO: start from the sb.first_dir, treverse the linked list */ dir_bid = sb.first_dir; while (dir_bid != 0) { sfs_read_block((char*)&dir, dir_bid); // Check if the dirnames are equal if (!strncmp(dir.dir_name, dirname, sizeof(dirname))) { return dir_bid; } dir_bid = dir.next_dir; } return 0; }
/* * Free a block, unmark it in the freemap and flush */ static void sfs_free_block(blkid bid) { u32 fm_block; u32 bitmap; u32 newBitmap; u32 mask; //Find the freemap block and index where the block is fm_block = bid / (BLOCK_SIZE * 8); fm_block = fm_block + 1; //Freemap blocks start at BID 1 sfs_read_block(freemap, fm_block); bitmap = freemap[bid/32]; bitmap = bitmap & ~(1<<(bid%32)); freemap[bid/32] = bitmap; sfs_flush_freemap(); }
/* * Load the super block from disk and print the parameters inside */ sfs_superblock_t *sfs_print_info() { sfs_read_block(&sb, 0); printf("\nSFS_PRINT_INFO\n"); printf("Number of blocks: %d\n", sb.nblocks); printf("First dir: %d\n", sb.first_dir); printf("Num freemap blocks: %d\n\n", sb.nfreemap_blocks); //Print freeblock information /* printf("FREEBLOCK INFO\n"); sfs_read_block(freemap, 1); int i; for(i = 0; i < BLOCK_SIZE; i++){ if(freemap[i] != 0){ printf("freemap[%d] = %#x\n", i, freemap[i]); } } */ return &sb; }
/* * Seek inside the file. * Loc is the starting point of the seek, which can be: * - SFS_SEEK_SET represents the beginning of the file. * - SFS_SEEK_CUR represents the current cursor. * - SFS_SEEK_END represents the end of the file. * Relative tells whether to seek forwards (positive) or backwards (negative). * * This function returns 0 on success. */ int sfs_seek(int fd, int relative, int loc) { int new_cur; if(loc == SFS_SEEK_SET){ new_cur = relative; } else if(loc == SFS_SEEK_CUR){ new_cur = fdtable[fd].cur + relative; } else if(loc == SFS_SEEK_END){ char tmp[BLOCK_SIZE]; sfs_inode_t inode; sfs_read_block(tmp, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)tmp; new_cur = inode.size + relative; } if(new_cur < 0){ fdtable[fd].cur = 0; } else{ fdtable[fd].cur = new_cur; } return 0; }
/* * Get the bids of content blocks that hold the file content starting from cur * to cur+length. These bids are stored in the given array. * The caller of this function is supposed to allocate the memory for this * array. It is guaranteed that cur+length<size * * This function returns the number of bids being stored to the array. */ static u32 sfs_get_file_content(blkid *bids, int fd, u32 cur, u32 length) { /* the starting block of the content */ u32 start = cur / BLOCK_SIZE; /* the ending block of the content */ u32 end = (cur + length) / BLOCK_SIZE; u32 i; sfs_inode_frame_t frame; blkid bid; /* TODO: find blocks between start and end. Transverse the frame list if needed */ bid = fdtable[fd].inode.first_frame; sfs_read_block((char*)&frame, bid); for (i = start; i <= end; i++) { bids[i-start] = frame.content[i]; } return (end - start + 1); }
/* * Print all directories. Return the number of directories. */ int sfs_lsdir() { /* TODO: go thru the linked list */ int count = 0; int i; sfs_dirblock_t dir; blkid bid = sb.first_dir; while (bid != 0) { sfs_read_block((char*)&dir, bid); printf("\tdir_name = "); for (i = 0; i < sizeof(dir.dir_name); i++) { printf("%c", ((char *)dir.dir_name)[i]); } printf("\t\tdir_bid = %d\tnext_dir = %d", bid, dir.next_dir); printf("\n"); bid = dir.next_dir; count++; } return count; }
/* * Read from an opened file. * Read can not enlarge file. So you should not read outside the size of * the file. If the read exceeds the file size, its result will be truncated. * * This function returns the number of bytes read. */ int sfs_read(int fd, void *buf, int length) { int remaining, to_copy, offset; int frame_start, frame_end, content_blk, num_blocks; int i, n; char *p = (char *)buf; char inode_ptr[BLOCK_SIZE]; char tmp[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; sfs_inode_t inode; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)inode_ptr; remaining = length; num_blocks = (length / BLOCK_SIZE) + 1; blkid bids[num_blocks]; //Find frame holding the cursor frame_start = cur / (SFS_FRAME_COUNT * BLOCK_SIZE); //Find the frame that would be holding the last byte we want to read frame_end = (cur + length) / (SFS_FRAME_COUNT * BLOCK_SIZE); int num_frames = frame_start - frame_end + 1; content_blk = cur / BLOCK_SIZE; offset = cur % BLOCK_SIZE; //Traverse the frames and check if the length exceeds the //number of frames blkid frame_bid = inode.first_frame; sfs_inode_frame_t frame; int count = 0; int nonzero_block = 0; //Truncate file to the smallest BLOCK //The first and last blocks will have fewer bytes stored //Check frames to determine if all content blocks exist while(count < num_blocks){ //Read the next frame sfs_read_block(tmp, frame_bid); frame = *(sfs_inode_frame_t*)tmp; frame_bid = frame.next; //Count the number of nonzero indices in the content array while(content_blk < SFS_FRAME_COUNT && count < num_blocks){ if(frame.content[content_blk] != 0){ nonzero_block++; count++; content_blk++; } } //Reset index to zero content_blk = 0; if(frame_bid == 0 && count < num_frames){ printf("The specified length exceeds the file size.\n"); break; } } //The length exceeds the number of valid blocks, truncate read if(count < num_blocks){ //Add fewer bytes from first block remaining = BLOCK_SIZE - offset; num_blocks--; //Add the remaining blocks remaining = remaining + num_blocks * BLOCK_SIZE; } else{ remaining = length; } /* TODO: similar to the sfs_write() */ int num_content_blocks = sfs_get_file_content(bids, fd, cur, length); int bid_count = 0; char block_ptr[BLOCK_SIZE]; while(remaining > 0){ to_copy = 0; sfs_read_block(block_ptr, bids[bid_count]); //Case 1: Read block with offset if(offset != 0){ //Partially fill block if(remaining < (BLOCK_SIZE - offset)){ to_copy = remaining; } else{ //Fill entire block to_copy = BLOCK_SIZE - offset; } strncpy(buf, block_ptr+offset, to_copy); offset = 0; } else if(remaining > BLOCK_SIZE){ //Case 2: Write to a full block to_copy = BLOCK_SIZE; strncpy(buf, block_ptr, to_copy); } else{ //Case 3: Write a partial block to_copy = remaining; strncpy(buf, block_ptr, to_copy); } remaining = remaining - to_copy; cur = cur + to_copy; fdtable[fd].cur = cur; bid_count++; } return length - remaining; }
/* * Write to a file. This function can potentially enlarge the file if the * cur+length exceeds the size of file. Also you should be aware that the * cur may already be larger than the size (due to sfs_seek). In such * case, you will need to expand the file as well. * * This function returns number of bytes written. */ int sfs_write(int fd, void *buf, int length) { int remaining, offset, to_copy; char *p = (char *)buf; char tmp[BLOCK_SIZE]; char inode_ptr[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; u32 buf_offset = 0; sfs_inode_t inode; remaining = length; offset = cur % BLOCK_SIZE; int numBids = (length / BLOCK_SIZE) + 1; blkid bids[numBids]; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)inode_ptr; blkid frame_bid = inode.first_frame; /* TODO: check if we need to resize */ sfs_inode_frame_t frame; sfs_read_block(tmp, frame_bid); frame = *(sfs_inode_frame_t*)tmp; if( (length + cur) > inode.size){ u32 new_size = length + cur; fdtable[fd].inode = inode; sfs_resize_file(fd, new_size); } /* TODO: get the block ids of all contents (using sfs_get_file_content() */ int num_blocks = sfs_get_file_content(bids, fd, cur, length); /* TODO: main loop, go through every block, copy the necessary parts to the buffer, consult the hint in the document. Do not forget to flush to the disk. */ char block_ptr[BLOCK_SIZE]; int bid_count = 0; //The block numbers should already be known by this part while(remaining > 0){ to_copy = 0; sfs_read_block(block_ptr, bids[bid_count]); //Case 1: Write to block with offset if(offset != 0){ //Partially fill block if(remaining < (BLOCK_SIZE - offset)){ to_copy = remaining; } else{ //Fill entire block to_copy = BLOCK_SIZE - offset; } strncpy(block_ptr+offset, buf, to_copy); offset = 0; } else if(remaining > BLOCK_SIZE){ //Case 2: Write to a full block to_copy = BLOCK_SIZE; strncpy(block_ptr, buf, to_copy); } else{ //Case 3: Write a partial block to_copy = remaining; strncpy(block_ptr, buf, to_copy); } sfs_write_block(&block_ptr, bids[bid_count]); remaining = remaining - to_copy; cur = cur + to_copy; bid_count++; } fdtable[fd].cur = cur; return length - remaining; }
/* * Remove/delete an existing file * This function returns zero on success. */ int sfs_remove(int fd_num) { blkid frame_bid; sfs_dirblock_t dir; char block_ptr[BLOCK_SIZE]; int i; fd_struct_t fd = fdtable[fd_num]; //Set the index of the inode to zero blkid dir_bid = fd.dir_bid; blkid inode_bid = fd.inode_bid; //Remove the inode from the directory sfs_read_block(block_ptr, dir_bid); dir = *(sfs_dirblock_t*)block_ptr; //Find the index at which the inode is stored int count = 0; while(count < SFS_DB_NINODES){ if(dir.inodes[count] == inode_bid){ dir.inodes[count] = 0; break; } count++; } dir.inodes[inode_bid] = 0; sfs_write_block(&dir, dir_bid); /* TODO: free inode and all its frames */ sfs_inode_t inode; sfs_read_block(block_ptr, inode_bid); inode = *(sfs_inode_t*)block_ptr; char frame_ptr[BLOCK_SIZE]; sfs_inode_frame_t frame; blkid next_frame = inode.first_frame; //Iterate through each of the nonzero content blocks //sfs_free_block() on all of them while(next_frame != 0){ sfs_read_block(frame_ptr, next_frame); frame = *(sfs_inode_frame_t*)frame_ptr; //Check each of the entries of the frame and free nonzero blocks int i; for(i = 0; i < SFS_FRAME_COUNT; i++){ blkid content_blk = frame.content[i]; if(content_blk != 0){ sfs_free_block(content_blk); } } sfs_free_block(next_frame); next_frame = frame.next; } /* TODO: close the file */ sfs_free_block(inode_bid); //Reset the file description to default fd.valid = 0; memset(&fd.inode, 0, sizeof(sfs_inode_t)); fd.dir_bid = 0; fd.inode_bid = 0; return 0; }
/* * Open a file. If it does not exist, create a new one. * Allocate a file desriptor for the opened file and return the fd. */ int sfs_open(char *dirname, char *name) { blkid dir_bid = 0, inode_bid = 0; char inode_ptr[BLOCK_SIZE]; sfs_inode_t inode; sfs_dirblock_t dir; fd_struct_t *fd_ptr; fd_struct_t fd; //Finds a free file descriptor number int fd_num = 0; while(fd_num < SFS_MAX_OPENED_FILES){ fd = fdtable[fd_num]; if(fd.valid == 0){ fd.valid = 1; fd.cur = 0; break; } else if(fd_num == SFS_MAX_OPENED_FILES - 1){ printf("The maximum number of files are already in use\n"); return -1; } else{ fd_num++; } } //Find the directory in which the specified file is contained dir_bid = sfs_find_dir(dirname); sfs_read_block(&dir, dir_bid); fd.dir_bid = dir_bid; //Iterate through all the indices of the inodes to find the file int count = 0; int fd_set = 0; int free_inode = -1; char *file_name; while(count < SFS_DB_NINODES){ inode_bid = dir.inodes[count]; if(inode_bid == 0){ if(free_inode == -1){ free_inode = count; } count++; continue; } //Read the inode at the specified index sfs_read_block(inode_ptr, inode_bid); inode = *(sfs_inode_t*)inode_ptr; file_name = inode.file_name; if(strcmp(file_name, name) == 0){ fd.inode = inode; fd.inode_bid = inode_bid; fd_set = 1; break; } count++; } //Create a new file if(fd_set == 0){ //Allocate a block for the inode blkid new_inode_bid = sfs_alloc_block(); //Put the inode bid into the directory inode array dir.inodes[free_inode] = new_inode_bid; sfs_write_block(&dir, dir_bid); strcpy(inode.file_name, name); //Allocate a block for the first frame blkid new_frame_bid = sfs_alloc_block(); inode.first_frame = new_frame_bid; inode.size = 0; //Place the inode in the file descriptor array fd.inode = inode; fd.inode_bid = new_inode_bid; sfs_write_block(&inode, new_inode_bid); sfs_read_block(&inode, new_inode_bid); //Allocate a block for the first content block of the frame char tmp[BLOCK_SIZE]; sfs_read_block(tmp, new_frame_bid); sfs_inode_frame_t new_frame = *(sfs_inode_frame_t*)tmp; blkid new_content_bid = sfs_alloc_block(); new_frame.content[0] = new_content_bid; sfs_write_block(&new_frame, new_frame_bid); } //Set the file descriptor in the file descriptor table fdtable[fd_num] = fd; return fd_num; }
/* * Open a file. If it does not exist, create a new one. * Allocate a file desriptor for the opened file and return the fd. */ int sfs_open(char *dirname, char *name) { blkid dir_bid = 0, inode_bid = 0; sfs_inode_t *inode, new_inode; sfs_dirblock_t dir; int fd; int i; /* TODO: find a free fd number */ for (i = 0; i < SFS_MAX_OPENED_FILES; i++) { if (fdtable[i].valid == 0) { // Found a free fd fd = i; break; } } /* TODO: find the dir first */ dir_bid = sfs_find_dir(dirname); if (dir_bid == 0) { printf("ERROR: the directory does not exists\n"); return -1; } sfs_read_block((char*)&dir, dir_bid); /* TODO: traverse the inodes to see if the file exists. If it exists, load its inode. Otherwise, create a new file. */ for (i = 0; i < SFS_DB_NINODES; i++) { if (dir.inodes[i] != 0) { sfs_read_block((char*)&new_inode, dir.inodes[i]); if (strcmp(new_inode.file_name, name) == 0) { inode_bid = dir.inodes[i]; break; } } } if (inode_bid == 0) { // Allocate a block to store new inode inode_bid = sfs_alloc_block(); // Find empty space in dir.inodes[] and set inode_bid for (i=0; i<SFS_DB_NINODES; i++) { if (dir.inodes[i] == 0) { dir.inodes[i] = inode_bid; break; } } // Did not find the inode, create a new one new_inode.first_frame = 0; new_inode.size = 0; memset(new_inode.file_name, 0, sizeof(new_inode.file_name)); strcpy(new_inode.file_name, name); sfs_write_block((char*)&new_inode, inode_bid); sfs_write_block((char*)&dir, dir_bid); } /* TODO: create a new file */ fdtable[fd].dir_bid = dir_bid; fdtable[fd].inode_bid = inode_bid; fdtable[fd].inode = new_inode; fdtable[fd].cur = 0; fdtable[fd].valid = 1; return fd; }
/* sfs_i_read - * */ W sfs_i_read (struct inode *ip, W start, B *buf, W length, W *rlength) { #ifdef notdef B blockbuf[ip->i_fs->fs_private.sfs_fs.sfs_blocksize]; /* GCC の拡張機能を使っている */ #endif W copysize; W offset; B *bufp; ID fd; struct fs *fsp; W bn; W cn; B *cbuf; #ifdef FMDEBUG printk ("sfs_i_read: start. ip = 0x%x, start = %d, length = %d, buf = 0x%x\n", ip, start, length, buf); #endif fd = ip->i_device; fsp = ip->i_fs; if (start + length > ip->i_private.sfs_inode.sfs_i_size) { length = ip->i_private.sfs_inode.sfs_i_size - start; } if (length < 0) length = 0; *rlength = length; bufp = buf; while (length > 0) { #ifdef FMDEBUG printk ("read block: %d\n", sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize)); #endif bn = sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize); if (bn < 0) { return (EP_IO); } #ifdef notdef sfs_read_block (fd, bn, fsp->fs_blksize, blockbuf); #else sfs_get_cache(fd, bn, &cn, &cbuf); #endif offset = start % fsp->fs_blksize; if (fsp->fs_blksize - offset < length) { copysize = fsp->fs_blksize - offset; } else { copysize = length; } #ifdef notdef bcopy (&blockbuf[offset], buf, copysize); #else bcopy(&cbuf[offset], buf, copysize); sfs_put_cache(cn, 0); #endif buf += copysize; start += copysize; length -= copysize; } return (EP_OK); }
/* * Remove an existing empty directory and return 0 on success. * If the dir does not exist or still contains files, return -1. */ int sfs_rmdir(char *dirname) { /* TODO: check if the dir exists */ blkid dir_bid = sfs_find_dir(dirname); if(dir_bid == 0){ printf("ERROR sfs_rmdir: Specified directory does not exist\n"); return -1; } if(sb.first_dir == 0 || dir_bid == 0){ //The directory does not exist return -1; } else{ //Unset the corresponding bit in the freemap sfs_free_block(dir_bid); } //Find the directories that come before and after the //directory we want to delete blkid next_dir = sb.first_dir; //First block blkid current_dir; //Current block is sb blkid previous_dir = 0; //No previous blocks char block_ptr[BLOCK_SIZE]; sfs_dirblock_t dir; if(next_dir == dir_bid){ sfs_read_block(block_ptr, next_dir); dir = *(sfs_dirblock_t*)block_ptr; blkid block_to_copy = dir.next_dir; sfs_read_block(&sb, 0); sb.first_dir = block_to_copy; sfs_write_block(&sb, 0); } //General case while(next_dir != dir_bid){ previous_dir = current_dir; current_dir = next_dir; sfs_read_block(block_ptr, next_dir); dir = *(sfs_dirblock_t*)block_ptr; next_dir = dir.next_dir; //The next block is what we want to remove if(next_dir == dir_bid){ //Set the next dir of the current block to the next+1 block sfs_read_block(block_ptr, next_dir); dir = *(sfs_dirblock_t*)block_ptr; blkid block_to_copy = dir.next_dir; sfs_read_block(block_ptr, current_dir); dir = *(sfs_dirblock_t*)block_ptr; dir.next_dir = block_to_copy; sfs_write_block(&dir, current_dir); } } return 0; }
/* * Create a new directory and return 0 on success. * If the dir already exists, return -1. */ int sfs_mkdir(char *dirname) { //Check if the directory has a valid name if(sizeof(dirname) > 120){ printf("Dir name exceeds max allowed characters.\n"); return -1; } //Test if the dir exists if(sfs_find_dir(dirname) != 0){ return -1; } else{ //Initialize variables blkid next_dir_id; char block_ptr[BLOCK_SIZE]; sfs_dirblock_t dir; //Allocate space for a new block blkid new_bid = sfs_alloc_block(); //Set the next_dir in the last directory block next_dir_id = sb.first_dir; sfs_read_block(block_ptr, next_dir_id); dir = *(sfs_dirblock_t*)block_ptr; if(next_dir_id == 0){ sb.first_dir = new_bid; sfs_write_block(&sb, 0); } else{ while(next_dir_id != 0){ sfs_read_block(block_ptr, next_dir_id); dir = *(sfs_dirblock_t*)block_ptr; //Next dir is zero, set it to the next available block if(dir.next_dir == 0){ blkid modified_dir_id = next_dir_id; sfs_read_block(block_ptr, modified_dir_id); dir = *(sfs_dirblock_t*)block_ptr; dir.next_dir = new_bid; //A value was changed, so this must be flushed to disk sfs_write_block(&dir, modified_dir_id); next_dir_id = 0; } else{ next_dir_id = dir.next_dir; } } } //Create a temporary directory and initialize its members //Set the next dir, name, and set all its inodes to zero sfs_dirblock_t temp_dir; temp_dir.next_dir = 0; strcpy(temp_dir.dir_name, dirname); memset(&temp_dir.inodes[0], 0, SFS_DB_NINODES * sizeof(blkid)); //Write the temporary block into the disk sfs_write_block(&temp_dir, new_bid); } return 0; }
W sfs_i_write (struct inode *ip, W start, B *buf, W size, W *rsize) { #ifdef notdef B blockbuf[ip->i_fs->fs_private.sfs_fs.sfs_blocksize]; /* GCC の拡張機能を使っている */ #endif int copysize; int offset; int retsize; int filesize; ID fd; struct fs *fsp; W bn; W cn; B *cbuf; #ifdef FMDEBUG printk ("sfs_i_write:(start = %d, size = %d)\n", start, size); /* */ #endif *rsize = 0; retsize = size; filesize = start + retsize; fd = ip->i_device; fsp = ip->i_fs; #ifdef FMDEBUG printk ("sfs_i_write: size = %d\n", size); /* */ #endif while (size > 0) { #ifdef FMDEBUG printk ("%s\n", (sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize) <= 0) ? "allocate block" : "read block"); #endif if (sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize) <= 0) { /* ファイルサイズを越えて書き込む場合には、新しくブロックをアロケートする */ bn = sfs_set_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize, sfs_alloc_block (fd, fsp)); /* * ip->sfs_i_direct[start / fsp->fs_blksize] = alloc_block (fd, fsp); */ #ifdef notdef bzero (blockbuf, fsp->fs_blksize); #else if (bn < 0) { return (EP_IO); } sfs_get_cache(fd, bn, &cn, &cbuf); #endif } else { #ifdef FMDEBUG printk ("read block %d\n", sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize)); #endif bn = sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize); if (bn < 0) { return (EP_IO); } #ifdef notdef sfs_read_block (fd, bn, fsp->fs_blksize, blockbuf); #else sfs_get_cache(fd, bn, &cn, &cbuf); #endif } /* 読み込んだブロックの内容を更新する */ offset = start % fsp->fs_blksize; copysize = MIN (fsp->fs_blksize - offset, size); #ifdef FMDEBUG printk ("*** read block contents ***\n"); { int i; char tmpbuf[2]; tmpbuf[1] = '\0'; printk ("copy size: %d\n", copysize); for (i = 0; i < copysize; i++) { tmpbuf[0] = blockbuf[i]; printk ("%s", tmpbuf); } } #endif #ifdef notdef bcopy (buf, &blockbuf[offset], copysize); #else bcopy(buf, &cbuf[offset], copysize); #endif #ifdef notdef printk ("sfs write block: block number = %d\n", sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize)); /* */ #endif /* 更新したブロックを書き込む */ #ifdef notdef bn = sfs_get_block_num (fd, fsp, &(ip->i_private.sfs_inode), start / fsp->fs_blksize); if (bn < 0) { return (EP_IO); } sfs_write_block (fd, bn, fsp->fs_blksize, blockbuf); #else sfs_put_cache(cn, 1); #endif buf += copysize; start += copysize; size -= copysize; } /* cache の sync をここで行う必要はあるか? */ sfs_sync_cache(fd); /* もし、書き込みをおこなった後にファイルのサイズが増えていれば、 * サイズを更新して inode を書き込む。 */ if (filesize > ip->i_private.sfs_inode.sfs_i_size) { ip->i_size = filesize; ip->i_size_blk = ROUNDUP(filesize, fsp->fs_blksize)/fsp->fs_blksize; ip->i_dirty = 1; /* これは deallocate の中で処理するのが普通 */ sfs_i_sync(ip); } else if (filesize < ip->i_private.sfs_inode.sfs_i_size) { sfs_i_truncate (ip, filesize); } *rsize = retsize - size; #ifdef FMDEBUG printk ("write size: %d bytes\n", *rsize); #endif return (EP_OK); }
/* * Resize a file. * This file should be opened (in the file descriptor table). The new size * should be larger than the old one (not supposed to shrink a file) */ static void sfs_resize_file(int fd, u32 new_size) { /* the length of content that can be hold by a full frame (in bytes) */ int frame_size = BLOCK_SIZE * SFS_FRAME_COUNT; /* old file size */ int old_size = fdtable[fd].inode.size; /* how many frames are used before resizing */ int old_nframe = (old_size + frame_size -1) / frame_size; //Opening a file always results in at least one frame if(old_nframe == 0){ old_nframe++; } /* how many frames are required after resizing */ int new_nframe = (new_size + frame_size - 1) / frame_size; int i, j; char inode_ptr[BLOCK_SIZE]; char tmp[BLOCK_SIZE]; sfs_inode_t inode; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)inode_ptr; blkid frame_bid = inode.first_frame; sfs_inode_frame_t frame; /* TODO: check if new frames are required */ int count = old_nframe; while(count < new_nframe){ sfs_read_block(tmp, frame_bid); frame = *(sfs_inode_frame_t*)tmp; blkid new_frame_bid = sfs_alloc_block(); //Update the next frame bid for the current frame frame.next = new_frame_bid; sfs_write_block(&frame, frame_bid); //Read the new frame bid and add the content blocks sfs_read_block(tmp, new_frame_bid); frame = *(sfs_inode_frame_t*)tmp; for(i = 0; i < SFS_FRAME_COUNT; i++){ frame.content[i] = sfs_alloc_block(); } sfs_write_block(&frame, new_frame_bid); frame_bid = new_frame_bid; count++; } sfs_read_block(tmp, inode.first_frame); frame = *(sfs_inode_frame_t*)tmp; inode.size = new_size; sfs_write_block(&inode, fdtable[fd].inode_bid); sfs_read_block(tmp, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)tmp; }