diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/include/vfs.h | 1 | ||||
-rw-r--r-- | src/kernel/user/nullfs.c | 166 | ||||
-rw-r--r-- | src/kernel/user/vfs.c | 14 |
3 files changed, 170 insertions, 11 deletions
diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h index 19f43db..af94b2a 100644 --- a/src/kernel/include/vfs.h +++ b/src/kernel/include/vfs.h @@ -61,6 +61,7 @@ typedef struct fs_handle { // is currently in use. (different from posix semantics !) // - the root node of a filesystem is created when the filesystem is created // - dispose() is not called on the root node when a filesystem is shutdown +// - delete() is not expected to delete recursively : it should fail on a non-empty directory typedef struct { bool (*open)(fs_node_ptr n, int mode, fs_handle_t *s); // open current node diff --git a/src/kernel/user/nullfs.c b/src/kernel/user/nullfs.c index 2f54137..c27f923 100644 --- a/src/kernel/user/nullfs.c +++ b/src/kernel/user/nullfs.c @@ -295,7 +295,46 @@ bool nullfs_d_walk(fs_node_ptr n, const char* file, struct fs_node *node_d) { } bool nullfs_d_delete(fs_node_ptr n, const char* file) { - return false; //TODO + nullfs_dir_t* d = (nullfs_dir_t*)n; + + if (!d->fs->can_delete) return false; + + nullfs_item_t *i = hashtbl_find(d->items_idx, file); + if (i == 0) return false; + + if (i->ops == &nullfs_d_ops) { + // if it is a subdirectory, check it is empty + nullfs_dir_t* sd = (nullfs_dir_t*)i->data; + if (sd->items_list != 0) return false; + + delete_hashtbl(sd->items_idx, 0); + free(sd); + } else if (i->ops == &nullfs_f_ops) { + nullfs_file_t* f = (nullfs_file_t*)i->data; + + if (f->own_data) free(f->data); + free(f); + } else { + return false; // special nodes (devices, ...) may not be deleted + } + + hashtbl_remove(d->items_idx, i->name); + + if (d->items_list == i) { + d->items_list = i->next; + } else { + for (nullfs_item_t* it = d->items_list; it != 0; it++) { + if (it->next == i) { + it->next = i->next; + break; + } + } + } + + free(i->name); + free(i); + + return true; } bool nullfs_d_move(fs_node_ptr n, const char* old_name, fs_node_t *new_parent, const char *new_name) { @@ -303,11 +342,82 @@ bool nullfs_d_move(fs_node_ptr n, const char* old_name, fs_node_t *new_parent, c } bool nullfs_d_create(fs_node_ptr n, const char* file, int type) { - return false; //TODO + nullfs_dir_t *d = (nullfs_dir_t*)n; + nullfs_item_t *i = 0; + + if (type == FT_REGULAR) { + nullfs_file_t *f = (nullfs_file_t*)malloc(sizeof(nullfs_file_t)); + if (f == 0) return false; + + f->ok_modes = FM_READ | FM_WRITE | FM_TRUNC | FM_APPEND; + f->data = 0; + f->size = 0; + f->own_data = false; + f->lock = MUTEX_UNLOCKED; + + i = (nullfs_item_t*)malloc(sizeof(nullfs_item_t)); + if (i == 0) goto f_error; + + i->name = strdup(file); + if (i->name == 0) goto f_error; + + i->ops = &nullfs_f_ops; + i->data = f; + + bool add_ok = hashtbl_add(d->items_idx, i->name, i); + if (!add_ok) goto f_error; + + i->next = d->items_list; + d->items_list = i; + + return true; + + f_error: + if (i != 0 && i->name != 0) free(i->name); + if (i != 0) free(i); + free(f); + return false; + } else if (type == FT_DIR) { + nullfs_dir_t *x = (nullfs_dir_t*)malloc(sizeof(nullfs_dir_t)); + if (x == 0) return false; + + x->items_idx = create_hashtbl(str_key_eq_fun, str_hash_fun, 0, 0); + if (x->items_idx == 0) goto d_error; + + x->items_list = 0; + x->lock = MUTEX_UNLOCKED; + x->fs = d->fs; + + i = (nullfs_item_t*)malloc(sizeof(nullfs_item_t)); + if (i == 0) goto d_error; + + i->name = strdup(file); + if (i->name == 0) goto d_error; + + i->ops = &nullfs_d_ops; + i->data = x; + + bool add_ok = hashtbl_add(d->items_idx, i->name, i); + if (!add_ok) goto d_error; + + i->next = d->items_list; + d->items_list = i; + + return true; + + d_error: + if (i != 0 && i->name != 0) free(i->name); + if (i != 0) free(i); + if (x->items_idx != 0) delete_hashtbl(x->items_idx, 0); + free(x); + return false; + } else { + return false; + } } void nullfs_d_dispose(fs_node_ptr n) { - //TODO + // nothing to do } @@ -349,6 +459,14 @@ bool nullfs_f_open(fs_node_ptr n, int mode, fs_handle_t *s) { if (mode & ~f->ok_modes) return false; mutex_lock(&f->lock); + + if (mode & FM_TRUNC) { + // truncate file + if (f->own_data) free(f->data); + f->size = 0; + f->own_data = false; + f->data = 0; + } s->mode = mode; s->data = f; @@ -358,21 +476,51 @@ bool nullfs_f_open(fs_node_ptr n, int mode, fs_handle_t *s) { } bool nullfs_f_stat(fs_node_ptr n, stat_t *st) { - return false; //TODO + nullfs_file_t *f = (nullfs_file_t*)n; + + st->type = FT_REGULAR; + st->access = f->ok_modes; + st->size = f->size; + + return true; } void nullfs_f_dispose(fs_node_ptr n) { - // TODO + // nothing to do } // -- File handle -- -static size_t nullfs_fh_read(fs_handle_ptr f, size_t offset, size_t len, char* buf) { - return 0; //TODO +static size_t nullfs_fh_read(fs_handle_ptr h, size_t offset, size_t len, char* buf) { + nullfs_file_t *f = (nullfs_file_t*)h; + + if (offset >= f->size) return 0; + if (offset + len > f->size) len = f->size - offset; + + memcpy(buf, f->data + offset, len); + return len; } -static size_t nullfs_fh_write(fs_handle_ptr f, size_t offset, size_t len, const char* buf) { - return 0; //TODO +static size_t nullfs_fh_write(fs_handle_ptr h, size_t offset, size_t len, const char* buf) { + nullfs_file_t *f = (nullfs_file_t*)h; + + if (offset + len > f->size) { + // resize buffer (zero out new portion) + void* new_buffer = malloc(offset + len); + if (new_buffer == 0) return 0; + + memcpy(new_buffer, f->data, f->size); + if (offset > f->size) + memset(new_buffer + f->size, 0, offset - f->size); + + if (f->own_data) free(f->data); + f->data = new_buffer; + f->own_data = true; + f->size = offset + len; + } + + memcpy(f->data + offset, buf, len); + return len; } static void nullfs_fh_close(fs_handle_ptr h) { diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c index 5ba2064..0624a38 100644 --- a/src/kernel/user/vfs.c +++ b/src/kernel/user/vfs.c @@ -95,6 +95,7 @@ void unref_fs_node(fs_node_t *n) { unref_fs_node(n->parent); unref_fs(n->fs); + if (n->children != 0) delete_hashtbl(n->children, 0); free(n->name); free(n); } @@ -304,8 +305,15 @@ int fs_ioctl(fs_t *fs, const char* file, int command, void* data) { fs_handle_t* fs_open(fs_t *fs, const char* file, int mode) { fs_node_t *n = fs_walk_path(&fs->root, file); + if (n == 0 && (mode & FM_CREATE)) { + if (fs_create(fs, file, FT_REGULAR)) { + n = fs_walk_path(&fs->root, file); + } + } if (n == 0) return false; + mode &= ~FM_CREATE; + fs_handle_t *h = (fs_handle_t*)malloc(sizeof(fs_handle_t)); if (h == 0) { unref_fs_node(n); @@ -346,14 +354,14 @@ int file_get_mode(fs_handle_t *f) { } size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf) { - if (!(f->mode && FM_READ)) return 0; + if (!(f->mode & FM_READ)) return 0; if (f->ops->read == 0) return 0; return f->ops->read(f->data, offset, len, buf); } size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf) { - if (!(f->mode && FM_WRITE)) return 0; + if (!(f->mode & FM_WRITE)) return 0; if (f->ops->write == 0) return 0; return f->ops->write(f->data, offset, len, buf); @@ -364,6 +372,8 @@ bool file_stat(fs_handle_t *f, stat_t *st) { } bool file_readdir(fs_handle_t *f, dirent_t *d) { + if (!(f->mode & FM_READDIR)) return 0; + return f->ops->readdir && f->ops->readdir(f->data, d); } |