diff --git a/src/fs.c b/src/fs.c index 4847a6c..6c886dd 100644 --- a/src/fs.c +++ b/src/fs.c @@ -532,9 +532,86 @@ static int *find_filename_in_directory(unsigned int dir_inode_ptr, char *fname) } } + // list entries from inode extensions + struct fs_inode_extension ext; + unsigned int next_ext = dir.next_extension; + + while (next_ext) { + read_block(next_ext, (void *) &ext); + next_ext = ext.next_extension; + + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { + struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; + + if (ext.blocks[i]) { + read_block(ext.blocks[i], (void *) &recs); + + for (int k = 0; k < DIRECTORY_RECORDS_PER_BLOCK; k++) { + if (!recs[k].inode_no) + continue; + + if (strcmp(fname, recs[k].fname)) + continue; + + // filename found + int *r = malloc(sizeof(int) * 3); + r[0] = i; + r[1] = k; + r[2] = recs[k].inode_no; + return r; + } + } + } + } + return NULL; } +static int inode_is_referenced(unsigned int inode) +{ + struct fs_inode f; + read_block(inode, (void *) &f); + + if (f.ref_count) + return 1; + + for (int i = 0; i < FS_MAX_OPEN_FD; i++) + if (fs_file_descriptions[i].inode == inode) + return 1; + + return 0; +} + +static void clean_inode(unsigned int inode) +{ + pr("Removing all data related to inode=%d\n", inode); + + struct fs_inode f; + read_block(inode, (void *) &f); + + // clear blocks referenced in base inode + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { + if (f.blocks[i]) + mark_free(f.blocks[i]); + } + mark_free(inode); + + // clear blocks referenced in inode extensions + struct fs_inode_extension ext; + unsigned int next_extension = f.next_extension; + + while (next_extension) { + mark_free(next_extension); + read_block(next_extension, (void *) &ext); + next_extension = ext.next_extension; + + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { + if (ext.blocks[i]) + mark_free(ext.blocks[i]); + } + } +} + static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int target_inode_ptr, char *fname) { { @@ -689,6 +766,45 @@ static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int ta return 0; } +static void fs_remove_fname_from_directory_removal(struct fs_directory_record *recs, unsigned int k, unsigned int dir_block_addr) +{ + unsigned int inode_ptr_cache = recs[k].inode_no; + unsigned int inode_location_cache = read_inode_ptr(recs[k].inode_no); + + // decrement ref_count + struct fs_inode f; + read_block(read_inode_ptr(recs[k].inode_no), (void *) &f); + f.ref_count--; + write_block(read_inode_ptr(recs[k].inode_no), (void *) &f); + + // clear directory record inode_ptr + recs[k].inode_no = 0; + write_block(dir_block_addr, (void *) recs); + + // if it drops to zero, nullify inode_ptr pointing to this inode + if (f.ref_count) + return; + + pr("ref_count=0, clearing inode_ptr\n"); + write_inode_ptr(inode_ptr_cache, 0); + + // if no fd reference this inode, clean it up altogether + int i; + for (i = 0; i < FS_MAX_OPEN_FD; i++) + if (fs_file_descriptions[i].inode == inode_location_cache) + break; + + if (i != FS_MAX_OPEN_FD) { + pr("Inode %d is still referenced by fd %d, not removing it\n", + inode_location_cache, i); + return; + } + + pr("No open fd reference inode %d, cleaning up\n", inode_location_cache); + + clean_inode(inode_location_cache); +} + static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fname) { // find directory record with this fname @@ -715,68 +831,50 @@ static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fnam pr("Directory record for '%s' found in block=%d, record=%d, removing\n", fname, i, k); - unsigned int inode_ptr_cache = recs[k].inode_no; - unsigned int inode_location_cache = read_inode_ptr(recs[k].inode_no); - - // decrement ref_count - struct fs_inode f; - read_block(read_inode_ptr(recs[k].inode_no), (void *) &f); - f.ref_count--; - write_block(read_inode_ptr(recs[k].inode_no), (void *) &f); - - // clear directory record inode_ptr - recs[k].inode_no = 0; - write_block(dir.blocks[i], (void *) &recs); - - // if it drops to zero, nullify inode_ptr pointing to this inode - if (f.ref_count) - goto fs_remove_fname_from_directory_finish; - - pr("ref_count=0, clearing inode_ptr\n"); - write_inode_ptr(inode_ptr_cache, 0); - - // if no fd reference this inode, clean it up altogether - int i; - for (i = 0; i < FS_MAX_OPEN_FD; i++) - if (fs_file_descriptions[i].inode == inode_location_cache) - break; - - if (i != FS_MAX_OPEN_FD) { - pr("Inode %d is still referenced by fd %d, not removing it\n", - inode_location_cache, i); - goto fs_remove_fname_from_directory_finish; - } - - pr("No open fd reference inode %d, cleaning up\n", inode_location_cache); - - // clear blocks referenced in base inode - for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { - if (f.blocks[i]) - mark_free(f.blocks[i]); - } - mark_free(inode_location_cache); - - // clear blocks referenced in inode extensions - struct fs_inode_extension ext; - unsigned int next_extension = f.next_extension; - - while (next_extension) { - mark_free(next_extension); - read_block(next_extension, (void *) &ext); - next_extension = ext.next_extension; - - for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { - if (ext.blocks[i]) - mark_free(ext.blocks[i]); - } - } + fs_remove_fname_from_directory_removal(recs, k, dir.blocks[i]); goto fs_remove_fname_from_directory_finish; } } // list entries from inode extension - // TODO + struct fs_inode_extension ext; + + unsigned int next_ext = dir.next_extension; + unsigned int curr_ext = 0; + + unsigned int ext_no = 0; + + while (next_ext) { + ext_no++; + curr_ext = next_ext; + read_block(curr_ext, (void *) &ext); + next_ext = ext.next_extension; + + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { + struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; + + if (!ext.blocks[i]) + continue; + + read_block(ext.blocks[i], (void *) &recs); + + for (int k = 0; k < DIRECTORY_RECORDS_PER_BLOCK; k++) { + if (!recs[k].inode_no) + continue; + + if (strcmp(fname, recs[k].fname)) + continue; + + pr("Directory record for '%s' found in ext=%d, block=%d, record=%d, removing\n", + fname, ext_no, i, k); + + fs_remove_fname_from_directory_removal(recs, k, ext.blocks[i]); + + goto fs_remove_fname_from_directory_finish; + } + } + } pr_err("no such file '%s'\n", fname); return -1; @@ -1235,42 +1333,12 @@ int fs_close(void *d) fs_file_descriptions[fd].inode = 0; pr("fd %d closed\n", fd); - // cleanup file data on disk if ref_count=0 - // and no other open descriptor references it's inode - - struct fs_inode f; - read_block(inode_location_cache, (void *) &f); - if (f.ref_count) + if (inode_is_referenced(inode_location_cache)) return 0; - for (int i = 0; i < FS_MAX_OPEN_FD; i++) - if (fs_file_descriptions[i].inode == inode_location_cache) - return 0; - - // if ended up here, the inode is not referenced anywhere pr("No open fd reference inode %d, cleaning up\n", inode_location_cache); - // clear blocks referenced in base inode - for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { - if (f.blocks[i]) - mark_free(f.blocks[i]); - } - mark_free(inode_location_cache); - - // clear blocks referenced in inode extensions - struct fs_inode_extension ext; - unsigned int next_extension = f.next_extension; - - while (next_extension) { - mark_free(next_extension); - read_block(next_extension, (void *) &ext); - next_extension = ext.next_extension; - - for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { - if (ext.blocks[i]) - mark_free(ext.blocks[i]); - } - } + clean_inode(inode_location_cache); } @@ -1401,7 +1469,31 @@ int fs_ln(void *d) } // list entries from inode extensions - // TODO + struct fs_inode_extension ext; + unsigned int next_ext = dir.next_extension; + + while (next_ext) { + read_block(next_ext, (void *) &ext); + next_ext = ext.next_extension; + + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) { + struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; + + if (dir.blocks[i]) { + read_block(ext.blocks[i], (void *) &recs); + + for (int k = 0; k < DIRECTORY_RECORDS_PER_BLOCK; k++) { + if (!recs[k].inode_no) + continue; + + if (!strcmp(existing_fname, recs[k].fname)) { + original_inode_ptr = recs[k].inode_no; + goto original_inode_ptr_found; + } + } + } + } + } pr_err("no such file '%s'\n", existing_fname); return 0;