aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/user/vfs.c
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 15:17:10 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-13 15:17:10 +0100
commit15fd57adeaca5ad62fba20aa01c851a3ed01ee29 (patch)
treecaae830ee6433955eacd91a7450e0cb4a3aca768 /src/kernel/user/vfs.c
parent9004213b4422e7a43c8ec8aac99d4ecc92553f20 (diff)
downloadkogata-15fd57adeaca5ad62fba20aa01c851a3ed01ee29.tar.gz
kogata-15fd57adeaca5ad62fba20aa01c851a3ed01ee29.zip
Change semantics of VFS :
- nodes can be loaded in ram only once (nodes identified by their path) - unlink() can only be called if the node to be deleted is not used (not in ram)
Diffstat (limited to 'src/kernel/user/vfs.c')
-rw-r--r--src/kernel/user/vfs.c58
1 files changed, 48 insertions, 10 deletions
diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c
index 67b335c..995bfbc 100644
--- a/src/kernel/user/vfs.c
+++ b/src/kernel/user/vfs.c
@@ -46,6 +46,7 @@ fs_t *make_fs(const char* drv_name, fs_handle_t *source, char* opts) {
fs->root.refs = 1; // root node is never disposed of (done by fs->shutdown)
fs->root.fs = fs;
fs->root.parent = 0;
+ fs->root.children = 0;
if (d->ops->make(source, opts, fs)) {
return fs;
@@ -85,30 +86,62 @@ void unref_fs_node(fs_node_t *n) {
if (n->refs == 0) {
ASSERT(n != &n->fs->root);
ASSERT(n->parent != 0);
+ ASSERT(n->name != 0);
+
+ hashtbl_remove(n->parent->children, n->name);
if (n->ops->dispose) n->ops->dispose(n->data);
+
unref_fs_node(n->parent);
unref_fs(n->fs);
+
+ free(n->name);
free(n);
}
}
fs_node_t* fs_walk_one(fs_node_t* from, const char* file) {
+ if (from->children != 0) {
+ fs_node_t *n = (fs_node_t*)hashtbl_find(from->children, file);
+ if (n != 0) {
+ ref_fs_node(n);
+ return n;
+ }
+ }
+
+ bool walk_ok = false, add_ok = false;
+
fs_node_t *n = (fs_node_t*)malloc(sizeof(fs_node_t));
if (n == 0) return 0;
n->fs = from->fs;
n->refs = 1;
n->parent = from;
-
- if (from->ops->walk && from->ops->walk(from->data, file, n)) {
- ref_fs_node(n->parent);
- ref_fs(n->fs);
- return n;
- } else {
- free(n);
- return 0;
+ n->children = 0;
+ n->name = strdup(file);
+ if (n->name == 0) goto error;
+
+ walk_ok = from->ops->walk && from->ops->walk(from->data, file, n);
+ if (!walk_ok) goto error;
+
+ if (from->children == 0) {
+ from->children = create_hashtbl(str_key_eq_fun, str_hash_fun, 0, 0);
+ if (from->children == 0) goto error;
}
+
+ add_ok = hashtbl_add(from->children, n->name, n);
+ if (!add_ok) goto error;
+
+ ref_fs_node(n->parent);
+ ref_fs(n->fs);
+
+ return n;
+
+error:
+ if (walk_ok) n->ops->dispose(n->data);
+ if (n->name != 0) free(n->name);
+ free(n);
+ return 0;
}
fs_node_t* fs_walk_path(fs_node_t* from, const char* path) {
@@ -199,8 +232,8 @@ fs_node_t* fs_walk_path_except_last(fs_node_t* from, const char* path, char* las
return n;
}
-// ========================== //
-// DOING THINGS IN FLESYSTEMS //
+// =========================== //
+// DOING THINGS IN FILESYSTEMS //
bool fs_create(fs_t *fs, const char* file, int type) {
char name[DIR_MAX];
@@ -218,6 +251,11 @@ bool fs_unlink(fs_t *fs, const char* file) {
fs_node_t* n = fs_walk_path_except_last(&fs->root, file, name);
if (n == 0) return false;
+ if (n->children != 0) {
+ fs_node_t* x = (fs_node_t*)hashtbl_find(n->children, name);
+ if (x != 0) return false;
+ }
+
bool ret = n->ops->unlink && n->ops->unlink(n->data, name);
unref_fs_node(n);
return ret;