aboutsummaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/include/vfs.h1
-rw-r--r--src/kernel/user/nullfs.c166
-rw-r--r--src/kernel/user/vfs.c14
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);
}