diff --git a/inc/fs.h b/inc/fs.h index 941f486..a854ebe 100644 --- a/inc/fs.h +++ b/inc/fs.h @@ -49,5 +49,6 @@ int fs_use(void *d); int fs_mkfs(void *d); int fs_ls(void *d); int fs_la(void *d); +int fs_rm(void *d); int fs_allow_write(void *d); int fs_prohibit_write(void *d); diff --git a/src/cli.c b/src/cli.c index 6fc0f08..dd14a1e 100644 --- a/src/cli.c +++ b/src/cli.c @@ -17,6 +17,7 @@ static const struct CliCommandEntry cmd[] = { {"create", 1, (enum CliArgType[]) {STR}, fs_create}, {"ls", 0, NULL, fs_ls}, {"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln}, + {"rm", 1, (enum CliArgType[]) {STR}, fs_rm}, // custom commands {"use", 1, (enum CliArgType[]) {STR}, fs_use}, diff --git a/src/fs.c b/src/fs.c index 72caa38..894653f 100644 --- a/src/fs.c +++ b/src/fs.c @@ -36,6 +36,11 @@ static int read_block(unsigned int block_no, void *data) static int write_block(unsigned int block_no, void *data) { + if (!write_permitted) { + pr_err("write operations are prohibited\n"); + return -1; + } + if (lseek(used_file_fd, block_no * FS_BLOCK_SIZE, SEEK_SET) < 0) { pr_err("failed to seek to block %d (bs=%d) on device '%s'\n", block_no, FS_BLOCK_SIZE, used_file_path); return -1; @@ -332,8 +337,51 @@ static int fs_find_free_directory_record(unsigned int dir_inode_ptr) return -1; } +static int *find_filename_in_directory(unsigned int dir_inode_ptr, char *fname) +{ + int dir_inode = read_inode_ptr(fs_cwd_inode_ptr); + + struct fs_inode dir; + read_block(dir_inode, (void *) &dir); + + // list entries from base inode + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { + struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; + + if (dir.blocks[i]) { + read_block(dir.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) * 2); + r[0] = i; + r[1] = k; + return r; + } + } + } + + return NULL; +} + static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int target_inode_ptr, char *fname) { + { + // check if duplicate filename exists in specified directory + int *r = find_filename_in_directory(dir_inode_ptr, fname); + if (r) { + free(r); + pr_err("filename '%s' already exists\n", fname); + return 0; + } + } + int new_directory_record_index = fs_find_free_directory_record(dir_inode_ptr); if (new_directory_record_index < 0) { pr_err("no free inode pointer found\n"); @@ -356,7 +404,7 @@ static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int ta return -1; } else { pr("Allocated new physical block %d for inode_ptr=%d (inode=%d, inner_block_no=%d)\n", - new_block, read_inode_ptr(dir_inode_ptr), block_no); + new_block, dir_inode_ptr, read_inode_ptr(dir_inode_ptr), block_no); } char zero_data[FS_BLOCK_SIZE] = {}; @@ -382,7 +430,7 @@ static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int ta write_block(dir_inode.blocks[block_no], (void *) &recs); - pr("Written new directory record #%d for file '%s' (-> %d) in inode_ptr=%d\n", + pr("Written new directory record #%d for file '%s' (-> inode_ptr=%d) in inode_ptr=%d\n", new_directory_record_index, fname, target_inode_ptr, dir_inode_ptr); return 0; @@ -390,18 +438,83 @@ static int fs_add_fname_to_directory(unsigned int dir_inode_ptr, unsigned int ta // record is located in inode extension // TODO } +} - // I don't remember what was this, but this function shouldn't need it +static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fname) +{ + // find directory record with this fname + int dir_inode = read_inode_ptr(fs_cwd_inode_ptr); - // write new record - //unsigned int inode_block_no = read_inode_ptr(fs_inode_ptr); + struct fs_inode dir; + read_block(dir_inode, (void *) &dir); + + // list entries from base inode + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { + struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; + + if (dir.blocks[i]) { + read_block(dir.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)) { + pr("Directory record for '%s' found in block=%d, record=%d, removing\n", fname, i, k); + + // 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); + + // if it drops to zero, nullify inode_ptr pointing to this inode + if (!f.ref_count) { + pr("ref_count=0, clearing inode_ptr\n"); + write_inode_ptr(recs[k].inode_no, 0); + } + + // clear directory record inode_ptr + recs[k].inode_no = 0; + write_block(dir.blocks[i], (void *) &recs); + + goto fs_remove_fname_from_directory_finish; + } + } + } + } + + // list entries from inode extension + // TODO + + pr_err("no such file '%s'\n", fname); + return -1; + +fs_remove_fname_from_directory_finish: + pr("Removed fname from directory record successfully\n"); + return 0; } int fs_create(void *d) { + if (!write_permitted) { + pr_err("write operations are prohibited\n"); + return 0; + } + char *fname = *((char **) d); int fname_len = strlen(fname); + { + // check if duplicate filename exists in current directory + int *r = find_filename_in_directory(fs_cwd_inode_ptr, fname); + if (r) { + free(r); + pr_err("filename '%s' already exists\n", fname); + return 0; + } + } + if (fname_len > 59) { pr_err("filename too long (%d > %d)\n", fname_len, 59); return 0; @@ -452,7 +565,8 @@ int fs_create(void *d) return 0; } -int fs_ln(void *d) { +int fs_ln(void *d) +{ if (used_file_fd <= 0) { pr_err("no storage device\n"); return 0; @@ -462,6 +576,17 @@ int fs_ln(void *d) { char *new_fname = ((char **)d)[1]; int new_fname_len = strlen(new_fname); + { + // check if duplicate filename exists in current directory + int *r = find_filename_in_directory(fs_cwd_inode_ptr, new_fname); + if (r) { + free(r); + pr_err("filename '%s' already exists\n", new_fname); + return 0; + } + } + + if (new_fname_len > 59) { pr_err("new filename too long (%d > 59)\n", new_fname_len); return 0; @@ -496,6 +621,9 @@ int fs_ln(void *d) { } } + // list entries from inode extensions + // TODO + pr_err("no such file '%d'\n", existing_fname); return 0; @@ -519,7 +647,26 @@ original_inode_ptr_found: pr("Updated inode ref_count (%d -> %d)\n", f.ref_count-1, f.ref_count); } -int fs_ls(void *d) { +int fs_rm(void *d) +{ + if (!write_permitted) { + pr_err("device '%s' is write-protected\n", used_file_path); + return 0; + } + + char *fname = *((char **) d); + + if (fs_remove_fname_from_directory(fs_cwd_inode_ptr, fname) < 0) { + pr_err("failed to unlink '%s'\n", fname); + } else { + pr("Unlinked '%s'\n", fname); + } + + return 0; +} + +int fs_ls(void *d) +{ if (used_file_fd <= 0) { pr_err("no storage device\n"); return 0; @@ -552,7 +699,8 @@ int fs_ls(void *d) { return 0; } -int fs_la(void *d) { +int fs_la(void *d) +{ if (used_file_fd <= 0) { pr_err("no storage device\n"); return 0;