From 3ee64e5b5dc5ca2f3b37df02523baae0dbf7993b Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 26 Apr 2025 22:12:26 +0300 Subject: [PATCH] add truncate --- inc/fs.h | 1 + src/cli.c | 2 +- src/fs.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/inc/fs.h b/inc/fs.h index 6abd122..74fa310 100644 --- a/inc/fs.h +++ b/inc/fs.h @@ -60,5 +60,6 @@ int fs_seek(void *d); int fs_read(void *d); int fs_write(void *d); int fs_close(void *d); +int fs_truncate(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 d17fa36..5f98a5a 100644 --- a/src/cli.c +++ b/src/cli.c @@ -19,7 +19,7 @@ static const struct CliCommandEntry cmd[] = { {"ls", 0, NULL, fs_ls}, {"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln}, {"rm", 1, (enum CliArgType[]) {STR}, fs_rm}, - //{"truncate", 2, (enum CliArgType[]) {STR, INT}, fs_truncate}, + {"truncate", 2, (enum CliArgType[]) {STR, INT}, fs_truncate}, {"open", 1, (enum CliArgType[]) {STR}, fs_open}, {"seek", 2, (enum CliArgType[]) {INT, INT}, fs_seek}, {"read", 2, (enum CliArgType[]) {INT, INT}, fs_read}, diff --git a/src/fs.c b/src/fs.c index 21abef2..0960f5c 100644 --- a/src/fs.c +++ b/src/fs.c @@ -902,6 +902,112 @@ int fs_write(void *d) return 0; } +int fs_truncate(void *d) +{ + char *fname = *((char **) d); + int size = *((int *) ((char **) d+1)); + + if (size < 0) { + pr_err("file size can not be negative\n"); + return 0; + } + + int file_inode_ptr; + { + int *r = find_filename_in_directory(fs_cwd_inode_ptr, fname); + if (r == NULL) { + pr_err("no such file: '%s'\n", fname); + return 0; + } + + file_inode_ptr = r[2]; + free(r); + } + + struct fs_inode f; + read_block(read_inode_ptr(file_inode_ptr), (void *) &f); + + if (size > f.size) { + pr("Increasing file size of '%s': %d -> %d\n", fname, f.size, size); + f.size = size; + write_block(read_inode_ptr(file_inode_ptr), (void *) &f); + } else { + pr("Decreasing file size of '%s': %d -> %d\n", fname, f.size, size); + f.size = size; + + // cleanup + int new_block_amount = f.size / FS_BLOCK_SIZE; + if (f.size % FS_BLOCK_SIZE) + new_block_amount++; + + int blocks_seen = 0; + + // look through base inode blocks + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++, blocks_seen++) { + if ((blocks_seen > new_block_amount) && (f.blocks[i])) { + mark_free(f.blocks[i]); + f.blocks[i] = 0; + } + } + write_block(read_inode_ptr(file_inode_ptr), (void *) &f); + + // look through inode extension blocks + struct fs_inode_extension ext; + unsigned int next_ext = f.next_extension; + unsigned int curr_ext; + + while (next_ext) { + read_block(next_ext, (void *) &ext); + + for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++, blocks_seen++) { + if ((blocks_seen > new_block_amount) && (ext.blocks[i])) { + mark_free(ext.blocks[i]); + ext.blocks[i] = 0; + } + } + + write_block(next_ext, (void *) &ext); + next_ext = ext.next_extension; + } + + // look through inode extensions themselves + int required_extensions = (f.size - BLOCK_ADDRESSES_PER_INODE) / BLOCK_ADDRESSES_PER_INODE_EXTENSION; + if ((f.size - BLOCK_ADDRESSES_PER_INODE) % BLOCK_ADDRESSES_PER_INODE_EXTENSION) + required_extensions++; + + next_ext = f.next_extension; + + if (!required_extensions) { + // zero base inode next_extension ptr + f.next_extension = 0; + write_block(read_inode_ptr(file_inode_ptr), (void *) &f); + } + + // seek to last required extension + for (int i = 0; i < required_extensions; i++) { + if (!next_ext) + return 0; + + curr_ext = next_ext; + read_block(next_ext, (void *) &ext); + next_ext = ext.next_extension; + } + + // remove next_extension ptr + ext.next_extension = 0; + write_block(curr_ext, (void *) &ext); + + // erase all extensions after this one + while (next_ext) { + mark_free(next_ext); + read_block(next_ext, (void *) &ext); + next_ext = ext.next_extension; + } + } + + return 0; +} + int fs_close(void *d) { int fd = *((int *) d);