Compare commits

..

2 Commits

1 changed files with 108 additions and 141 deletions

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