diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/include/vfs.h | 30 | ||||
-rw-r--r-- | src/kernel/user/vfs.c | 158 |
2 files changed, 171 insertions, 17 deletions
diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h index 4efd0a2..ccb33f4 100644 --- a/src/kernel/include/vfs.h +++ b/src/kernel/include/vfs.h @@ -19,6 +19,11 @@ typedef void* fs_handle_ptr; typedef void* fs_node_ptr; typedef void* fs_ptr; +// usefull forward declarations +struct fs; +struct fs_node; +struct fs_handle; + // ------------------------------------------- // Structure defining a handle to an open file @@ -32,6 +37,7 @@ typedef struct { typedef struct fs_handle { // These two field are filled by the VFS's generic open() code struct fs *fs; + struct fs_node *n; int refs; // These fields are filled by the FS's specific open() code @@ -47,13 +53,17 @@ typedef struct fs_handle { // Remarks : // - fs_node_t not to be used in public interface // - nodes keep a reference to their parent +// - delete() is expected to delete the node (make it inaccessible), but not dispose +// of its data before dispos() is called !! +// - 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 -struct fs_node; typedef struct { bool (*open)(fs_node_ptr n, int mode, fs_handle_t *s); // open current node bool (*stat)(fs_node_ptr n, stat_t *st); bool (*walk)(fs_node_ptr n, const char* file, struct fs_node *node_d); bool (*delete)(fs_node_ptr n); + bool (*move)(fs_node_ptr n, struct fs_node *new_parent, const char *new_name); // TODO : not sure about this ? bool (*create)(fs_node_ptr n, const char* name, int type); // create sub-node in directory int (*ioctl)(fs_node_ptr n, int command, void* data); void (*dispose)(fs_node_ptr n); @@ -96,6 +106,20 @@ typedef struct { } fs_driver_ops_t; // ------------------------------------------- +// All functions that return a fs_node_t*, fs_t* or fs_handle_t* return an object +// that will have to be dereferenced when not used anymore. +// (on fs_handle_t*, dereferencing is like closing, only that the actual closing happens +// when refcount falls to zero) + +// Internals + +void ref_fs_node(fs_node_t *n); +void unref_fs_node(fs_node_t *n); + +fs_node_t* fs_walk_one(fs_node_t* from, const char *file); +fs_node_t* fs_walk_path(fs_node_t* from, const char *p); +fs_node_t* fs_walk_path_except_last(fs_node_t* from, const char *p, char* last_file_buf); + // Public functions void register_fs_driver(const char* name, fs_driver_ops_t *ops); @@ -105,9 +129,9 @@ bool fs_add_source(fs_t *fs, fs_handle_t *source); void ref_fs(fs_t *fs); void unref_fs(fs_t *fs); -bool fs_delete(fs_t *fs, const char* file); bool fs_create(fs_t *fs, const char* file, int type); -bool fs_rename(fs_t *fs, const char* from, const char* to); +bool fs_delete(fs_t *fs, const char* file); +bool fs_move(fs_t *fs, const char* from, const char* to); bool fs_stat(fs_t *fs, const char* file, stat_t *st); int fs_ioctl(fs_t *fs, const char* file, int command, void* data); diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c index 32fcb03..81325dd 100644 --- a/src/kernel/user/vfs.c +++ b/src/kernel/user/vfs.c @@ -16,7 +16,7 @@ fs_driver_t *drivers = 0; void register_fs_driver(const char* name, fs_driver_ops_t *ops) { fs_driver_t *d = (fs_driver_t*)malloc(sizeof(fs_driver_t)); - ASSERT(d != 0); // should we fail in a more graceful manner ? + ASSERT(d != 0); // should we fail in a more graceful manner ? TODO d->name = name; d->ops = ops; @@ -25,7 +25,7 @@ void register_fs_driver(const char* name, fs_driver_ops_t *ops) { } // ================================== // -// CREATING AND DELETINF FILE SYSTEMS // +// CREATING AND DELETING FILE SYSTEMS // // ================================== // fs_t *make_fs(const char* drv_name, fs_handle_t *source, char* opts) { @@ -36,13 +36,18 @@ fs_t *make_fs(const char* drv_name, fs_handle_t *source, char* opts) { if (drv_name == 0 && source != 0 && i->ops->detect && i->ops->detect(source)) d = i; if (d != 0) break; } + if (d == 0) return 0; // driver not found // Open file system fs_t *fs = (fs_t*)malloc(sizeof(fs_t)); if (fs == 0) return 0; + fs->refs = 1; + fs->root.refs = 1; // root node is never disposed of (done by fs->shutdown) + fs->root.fs = fs; + fs->root.parent = 0; + if (d->ops->make(source, opts, fs)) { - fs->refs = 1; return fs; } else { free(fs); @@ -61,27 +66,141 @@ void ref_fs(fs_t *fs) { void unref_fs(fs_t *fs) { fs->refs--; if (fs->refs == 0) { + // don't unref root node, don't call dispose on it + // (done by fs->shutdown) fs->ops->shutdown(fs->data); free(fs); } } +// ====================================================== // +// WALKING IN THE FILE SYSTEM CREATING AND DELETING NODES // + +void ref_fs_node(fs_node_t *n) { + n->refs++; +} + +void unref_fs_node(fs_node_t *n) { + n->refs--; + if (n->refs == 0) { + ASSERT(n != &n->fs->root); + ASSERT(n->parent != 0); + + n->ops->dispose(n->data); + unref_fs_node(n->parent); + unref_fs(n->fs); + free(n); + } +} + +fs_node_t* fs_walk_one(fs_node_t* from, const char* file) { + 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; + } +} + +fs_node_t* fs_walk_path(fs_node_t* from, const char* path) { + fs_node_t *n = from; + ref_fs_node(n); + + while (n && (*path)) { + const char* d = strchr(path, '/'); + if (d == path) { + path++; + } else if (d == 0) { + fs_node_t *n2 = fs_walk_one(n, path); + unref_fs_node(n); + + return n2; + } else { + size_t nlen = d - path; + if (nlen >= DIR_MAX - 1) { + unref_fs_node(n); + return 0; // sorry, path item too long + } + char name_buf[DIR_MAX]; + strncpy(name_buf, path, nlen); + name_buf[nlen] = 0; + + fs_node_t *n2 = fs_walk_one(n, name_buf); + unref_fs_node(n); + n = n2; + + path = d + 1; + } + } + return n; +} + +fs_node_t* fs_walk_path_except_last(fs_node_t* from, const char* path, char* last_file_buf) { + // TODO : parse path, walk + // This function does NOT walk into the last component of the path (it may not even exist), + // instead it isolates it in the buffer last_file + // This buffer is expected to be of size DIR_MAX (defined in fs.h) + return 0; +} + +// ========================== // // DOING THINGS IN FLESYSTEMS // +bool fs_create(fs_t *fs, const char* file, int type) { + char name[DIR_MAX]; + fs_node_t *n = fs_walk_path_except_last(&fs->root, file, name); + if (n == 0) return false; + + bool ret = n->ops->create && n->ops->create(n->data, name, type); + unref_fs_node(n); + return ret; +} + bool fs_delete(fs_t *fs, const char* file) { - return fs->ops->delete && fs->ops->delete(fs->data, file); + fs_node_t* n = fs_walk_path(&fs->root, file); + if (n == 0) return false; + + bool ret = n->ops->delete && n->ops->delete(n->data); + unref_fs_node(n); + return ret; } -bool fs_rename(fs_t *fs, const char* from, const char* to) { - return fs->ops->rename && fs->ops->rename(fs->data, from, to); +bool fs_move(fs_t *fs, const char* from, const char* to) { + fs_node_t *n = fs_walk_path(&fs->root, from); + if (n == 0) return false; + + char new_name[DIR_MAX]; + fs_node_t *new_parent = fs_walk_path_except_last(&fs->root, to, new_name); + if (new_parent == 0) return false; + + return n->ops->move && n->ops->move(n->data, new_parent, new_name); } -bool fs_stat(fs_t *fs, const char* name, stat_t *st) { - return fs->ops->stat && fs->ops->stat(fs->data, name, st); +bool fs_stat(fs_t *fs, const char* file, stat_t *st) { + fs_node_t* n = fs_walk_path(&fs->root, file); + if (n == 0) return false; + + bool ret = n->ops->stat && n->ops->stat(n->data, st); + unref_fs_node(n); + return ret; } int fs_ioctl(fs_t *fs, const char* file, int command, void* data) { - return fs->ops->ioctl && fs->ops->ioctl(fs->data, file, command, data); + fs_node_t* n = fs_walk_path(&fs->root, file); + if (n == 0) return false; + + int ret = (n->ops->ioctl ? n->ops->ioctl(n->data, command, data) : -1); + unref_fs_node(n); + return ret; } // =================== // @@ -89,15 +208,25 @@ 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) return false; + fs_handle_t *h = (fs_handle_t*)malloc(sizeof(fs_handle_t)); - if (h == 0) return 0; + if (h == 0) { + unref_fs_node(n); + return 0; + } + + h->refs = 1; + h->fs = fs; + h->n = n; - if (fs->ops->open(fs->data, file, mode, h)) { - h->refs = 1; - h->fs = fs; + if (n->ops->open(n->data, mode, h)) { + // our reference to node n is transferred to the file handle ref_fs(fs); return h; } else { + unref_fs_node(n); free(h); return 0; } @@ -110,8 +239,9 @@ void ref_file(fs_handle_t *file) { void unref_file(fs_handle_t *file) { file->refs--; if (file->refs == 0) { - unref_fs(file->fs); file->ops->close(file->data); + unref_fs_node(file->n); + unref_fs(file->fs); free(file); } } |