Compare commits

..

2 Commits

1 changed files with 108 additions and 141 deletions

249
src/fs.c
View File

@ -1002,33 +1002,45 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para
}
static int find_free_fd(void)
{
for (int i = 0; i < FS_MAX_OPEN_FD; i++)
if (!fs_file_descriptions[i].inode)
return i;
return -1;
}
int fs_open(void *d)
{
char *fname = *((char **) d);
char *path = *((char **) d);
// find file inode
struct fs_file_description fd;
{
int *r = find_filename_in_directory(fs_cwd_inode_ptr, fname);
if (!r) {
pr_err("no such file: '%s'\n", fname);
return 0;
}
struct resolved_path rp;
resolve_path(&rp, path, FOLLOW_LAST_SYMLINK);
fd.inode = read_inode_ptr(r[2]);
free(r);
if (rp.target_inode_ptr < 0) {
pr_err("no such file: '%s'\n", path);
return 0;
}
fd.rw_offset = 0;
// find free file descriptor
int free_fd;
for (free_fd = 0; (free_fd < FS_MAX_OPEN_FD) && (fs_file_descriptions[free_fd].inode); free_fd++);
if (free_fd == FS_MAX_OPEN_FD) {
int free_fd = find_free_fd();
if (free_fd < 0) {
pr_err("no free file descriptor found\n");
return 0;
}
memcpy(&(fs_file_descriptions[free_fd]), &fd, sizeof(struct fs_file_description));
{
struct fs_inode i;
read_block(read_inode_ptr(rp.target_inode_ptr), &i);
if (i.ftype == DIRECTORY) {
pr_err("can't open '%s': file is a directory\n", rp.target_fname);
return 0;
}
}
fs_file_descriptions[free_fd].inode = read_inode_ptr(rp.target_inode_ptr);
fs_file_descriptions[free_fd].rw_offset = 0;
pr_stdout("%d\n", free_fd);
@ -1332,7 +1344,7 @@ int fs_write(void *d)
int fs_truncate(void *d)
{
char *fname = *((char **) d);
char *path = *((char **) d);
int size = *((int *) ((char **) d+1));
if (size < 0) {
@ -1340,52 +1352,48 @@ int fs_truncate(void *d)
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;
}
struct resolved_path rp;
resolve_path(&rp, path, FOLLOW_LAST_SYMLINK);
file_inode_ptr = r[2];
free(r);
if (rp.target_inode_ptr < 0) {
pr_err("no such file: '%s'\n", path);
return 0;
}
struct fs_inode f;
read_block(read_inode_ptr(file_inode_ptr), (void *) &f);
struct fs_inode inode;
read_block(read_inode_ptr(rp.target_inode_ptr), &inode);
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);
if (size > inode.size) {
pr("Increasing file size of '%s': %d -> %d\n", rp.target_fname, inode.size, size);
inode.size = size;
write_block(read_inode_ptr(rp.target_inode_ptr), &inode);
} else {
pr("Decreasing file size of '%s': %d -> %d\n", fname, f.size, size);
f.size = size;
pr("Decreasing file size of '%s': %d -> %d\n", rp.target_fname, inode.size, size);
inode.size = size;
// cleanup
int new_block_amount = f.size / FS_BLOCK_SIZE;
if (f.size % FS_BLOCK_SIZE)
int new_block_amount = inode.size / FS_BLOCK_SIZE;
if (inode.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;
if ((blocks_seen >= new_block_amount) && (inode.blocks[i])) {
mark_free(inode.blocks[i]);
inode.blocks[i] = 0;
}
}
write_block(read_inode_ptr(file_inode_ptr), (void *) &f);
write_block(read_inode_ptr(rp.target_inode_ptr), &inode);
// look through inode extension blocks
struct fs_inode_extension ext;
unsigned int next_ext = f.next_extension;
unsigned int next_ext = inode.next_extension;
unsigned int curr_ext;
while (next_ext) {
read_block(next_ext, (void *) &ext);
read_block(next_ext, &ext);
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++, blocks_seen++) {
if ((blocks_seen >= new_block_amount) && (ext.blocks[i])) {
@ -1394,25 +1402,25 @@ int fs_truncate(void *d)
}
}
write_block(next_ext, (void *) &ext);
write_block(next_ext, &ext);
next_ext = ext.next_extension;
}
// look through inode extensions themselves
int required_blocks_after_base_inode = (int) f.size - (int) BLOCK_ADDRESSES_PER_INODE;
int required_blocks_after_base_inode = (int) inode.size - (int) BLOCK_ADDRESSES_PER_INODE;
int required_extensions = required_blocks_after_base_inode >= 0
? required_blocks_after_base_inode / BLOCK_ADDRESSES_PER_INODE_EXTENSION
: 0;
if ((f.size - BLOCK_ADDRESSES_PER_INODE) % BLOCK_ADDRESSES_PER_INODE_EXTENSION)
if ((inode.size - BLOCK_ADDRESSES_PER_INODE) % BLOCK_ADDRESSES_PER_INODE_EXTENSION)
required_extensions++;
next_ext = f.next_extension;
next_ext = inode.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);
inode.next_extension = 0;
write_block(read_inode_ptr(rp.target_inode_ptr), &inode);
} else {
// seek to last required extension
for (int i = 0; i < required_extensions; i++) {
@ -1420,19 +1428,19 @@ int fs_truncate(void *d)
return 0;
curr_ext = next_ext;
read_block(curr_ext, (void *) &ext);
read_block(curr_ext, &ext);
next_ext = ext.next_extension;
}
// remove next_extension ptr
ext.next_extension = 0;
write_block(curr_ext, (void *) &ext);
write_block(curr_ext, &ext);
}
// erase all remaining extensions
while (next_ext) {
mark_free(next_ext);
read_block(next_ext, (void *) &ext);
read_block(next_ext, &ext);
next_ext = ext.next_extension;
}
}
@ -1546,108 +1554,63 @@ int fs_create(void *d)
int fs_ln(void *d)
{
if (used_file_fd <= 0) {
pr_err("no storage device\n");
return 0;
}
char *existing_fname = ((char **) d)[0];
char *new_fname = ((char **)d)[1];
int new_fname_len = strlen(new_fname);
char *prev_path = ((char **) d)[0];
char *new_path = ((char **)d)[1];
char new_fname[FS_MAX_FNAME_LEN+1];
{
// 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);
int new_fname_len = extract_basename(new_path, new_fname);
if (new_fname_len > FS_MAX_FNAME_LEN) {
pr_err("new filename too long (%d > %d)\n", new_fname_len, FS_MAX_FNAME_LEN);
return 0;
}
}
struct resolved_path prev_rp, new_rp;
if (new_fname_len > FS_MAX_FNAME_LEN) {
pr_err("new filename too long (%d > %d)\n", new_fname_len, FS_MAX_FNAME_LEN);
resolve_path(&prev_rp, prev_path, 0);
if (prev_rp.target_inode_ptr < 0) {
pr_err("no such file: '%s'\n", prev_path);
return 0;
}
pr("Making hard link '%s' -> '%s'\n", new_fname, existing_fname);
{
struct fs_inode prev_i;
read_block(read_inode_ptr(prev_rp.target_inode_ptr), &prev_i);
// find original file name
unsigned int original_inode_ptr = 0;
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(existing_fname, recs[k].fname)) {
original_inode_ptr = recs[k].inode_no;
goto original_inode_ptr_found;
}
}
if (prev_i.ftype == DIRECTORY) {
pr_err("refusing to create hard link for directory\n");
return 0;
}
}
// 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 (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;
}
}
}
}
resolve_path(&new_rp, new_path, 1);
if (new_rp.parent_inode_ptr < 0) {
pr_err("failed to create hard link: no such directory: '%s'\n", new_path);
return 0;
} else if (new_rp.target_inode_ptr >= 0) {
pr_err("file already exists: '%s'\n", new_rp.target_fname);
return 0;
}
pr_err("no such file '%s'\n", existing_fname);
return 0;
pr("Making hard link '%s' -> '%s'\n", new_path, prev_path);
original_inode_ptr_found:
pr("Original inode_ptr found (%d)\n", original_inode_ptr);
// register new filename with the same inode_ptr
if (fs_add_fname_to_directory(fs_cwd_inode_ptr, original_inode_ptr, new_fname) < 0) {
pr_err("failed to register filename in directory '%s'\n", fs_cwd);
if (fs_add_fname_to_directory(new_rp.parent_inode_ptr, prev_rp.target_inode_ptr, new_fname) < 0) {
pr_err("failed to add filename to directory '%s' (inode_ptr=%d)\n",
new_rp.parent_fname, new_rp.parent_inode_ptr);
return 0;
} else {
pr("Registered new filename in directory '%s'\n", fs_cwd);
pr("Added new filename to directory '%s' (inode_ptr=%d)\n",
new_rp.parent_fname, new_rp.parent_inode_ptr);
}
// update ref_count in file inode
struct fs_inode f;
read_block(read_inode_ptr(original_inode_ptr), (void *) &f);
f.ref_count++;
write_block(read_inode_ptr(original_inode_ptr), (void *) &f);
struct fs_inode i;
read_block(read_inode_ptr(prev_rp.target_inode_ptr), &i);
i.ref_count++;
write_block(read_inode_ptr(prev_rp.target_inode_ptr), &i);
pr("Updated inode ref_count (%d -> %d)\n", f.ref_count-1, f.ref_count);
pr("Updated inode ref_count (%d -> %d)\n", i.ref_count-1, i.ref_count);
return 0;
}
@ -1677,7 +1640,9 @@ static int extract_basename(char *path, char *name)
return -1;
}
strcpy(name, &(path[lsp+1]));
// allow the usage of NULL ptr to discard basename string
if (name)
strcpy(name, &(path[lsp+1]));
return fname_len;
}
@ -2188,23 +2153,25 @@ int fs_la(void *d)
int fs_stat(void *d)
{
char *fname = *((char **) d);
char *path = *((char **) d);
int file_inode_ptr = find_fname_in_directory(fs_cwd_inode_ptr, fname);
if (file_inode_ptr < 0) {
pr_err("no such file: '%s'\n", fname);
struct resolved_path rp;
resolve_path(&rp, path, 0);
if (rp.target_inode_ptr < 0) {
pr_err("no such file: '%s'\n", path);
return 0;
}
struct fs_inode f;
read_block(read_inode_ptr(file_inode_ptr), (void *) &f);
struct fs_inode i;
read_block(read_inode_ptr(rp.target_inode_ptr), &i);
if (f.ftype == DIRECTORY) {
if (i.ftype == DIRECTORY) {
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=dir\n",
file_inode_ptr, read_inode_ptr(file_inode_ptr), f.ref_count, f.size);
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
} else {
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=reg\n",
file_inode_ptr, read_inode_ptr(file_inode_ptr), f.ref_count, f.size);
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
}
return 0;