diff --git a/headers/private/fs_shell/fssh_module.h b/headers/private/fs_shell/fssh_module.h index e475f61177..692c64491f 100644 --- a/headers/private/fs_shell/fssh_module.h +++ b/headers/private/fs_shell/fssh_module.h @@ -40,23 +40,16 @@ typedef struct fssh_module_dependency { } fssh_module_dependency; -#if 0 - #ifdef __cplusplus extern "C" { #endif -extern status_t get_module(const char *path, module_info **_info); -extern status_t put_module(const char *path); -extern status_t get_next_loaded_module_name(uint32 *cookie, char *buffer, size_t *_bufferSize); -extern void *open_module_list(const char *prefix); -extern status_t close_module_list(void *cookie); -extern status_t read_next_module_name(void *cookie, char *buffer, size_t *_bufferSize); +extern fssh_status_t fssh_get_module(const char *path, + fssh_module_info **_info); +extern fssh_status_t fssh_put_module(const char *path); #ifdef __cplusplus } #endif -#endif // 0 - #endif /* _FSSH_MODULE_H */ diff --git a/src/tools/fs_shell/Jamfile b/src/tools/fs_shell/Jamfile index f4d84734d3..289963ccc6 100644 --- a/src/tools/fs_shell/Jamfile +++ b/src/tools/fs_shell/Jamfile @@ -22,7 +22,9 @@ BuildPlatformStaticLibrary fs_shell.a : hash.cpp list.cpp lock.cpp + module.cpp node_monitor.cpp + rootfs.cpp sem.cpp stat.cpp stat_util.cpp diff --git a/src/tools/fs_shell/fd.cpp b/src/tools/fs_shell/fd.cpp index e91b9f4952..ac9e266d86 100644 --- a/src/tools/fs_shell/fd.cpp +++ b/src/tools/fs_shell/fd.cpp @@ -13,6 +13,7 @@ #include "fssh_kernel_priv.h" #include "fssh_string.h" #include "fssh_uio.h" +#include "syscalls.h" //#define TRACE_FD diff --git a/src/tools/fs_shell/fssh.cpp b/src/tools/fs_shell/fssh.cpp index 485c8b7670..e0ef0852ce 100644 --- a/src/tools/fs_shell/fssh.cpp +++ b/src/tools/fs_shell/fssh.cpp @@ -3,9 +3,115 @@ * Distributed under the terms of the MIT License. */ +#include + +#include +#include + +#include "fssh_errors.h" +#include "fssh_module.h" +#include "module.h" +#include "syscalls.h" +#include "vfs.h" + + +using namespace FSShell; + +namespace FSShell { + extern fssh_file_system_module_info gRootFileSystem; +} + +extern fssh_module_info *modules[]; + + +static fssh_status_t +init_kernel() +{ + fssh_status_t error; + + // init module subsystem + error = module_init(NULL); + if (error != FSSH_B_OK) { + fprintf(stderr, "module_init() failed: %s\n", strerror(error)); + return error; + } else + printf("module_init() succeeded!\n"); + + // register built-in modules, i.e. the rootfs and the client FS + register_builtin_module(&gRootFileSystem.info); + for (int i = 0; modules[i]; i++) + register_builtin_module(modules[i]); + + // init VFS + error = vfs_init(NULL); + if (error != FSSH_B_OK) { + fprintf(stderr, "initializing VFS failed: %s\n", strerror(error)); + return error; + } else + printf("VFS initialized successfully!\n"); + + // mount root FS + fssh_dev_t rootDev = _kern_mount("/", NULL, "rootfs", 0, NULL, 0); + if (rootDev < 0) { + fprintf(stderr, "mounting rootfs failed: %s\n", strerror(rootDev)); + return rootDev; + } else + printf("mounted rootfs successfully!\n"); + + // create mount point for the client FS + error = _kern_create_dir(-1, "/myfs", 0775); + if (error != FSSH_B_OK) { + fprintf(stderr, "creating mount point failed: %s\n", strerror(error)); + return error; + } else + printf("mount point created successfully!\n"); + + return FSSH_B_OK; +} + int -main() +main(int argc, const char* const* argv) { + if (argc != 2) { + fprintf(stderr, "Usage: ...\n"); + return 1; + } + + const char* device = argv[1]; + + // get FS module + if (!modules[0]) { + fprintf(stderr, "Couldn't find FS module!\n"); + return 1; + } + const char* fsName = modules[0]->name; + + fssh_status_t error; + + // init kernel + error = init_kernel(); + if (error != FSSH_B_OK) { + fprintf(stderr, "initializing kernel failed: %s\n", strerror(error)); + return error; + } else + printf("kernel initialized successfully!\n"); + + // mount FS + fssh_dev_t fsDev = _kern_mount("/myfs", device, fsName, 0, NULL, 0); + if (fsDev < 0) { + fprintf(stderr, "mounting FS failed: %s\n", strerror(fsDev)); + return 1; + } else + printf("mounted FS successfully!\n"); + + // unmount FS + error = _kern_unmount("/myfs", 0); + if (error != FSSH_B_OK) { + fprintf(stderr, "unmounting FS failed: %s\n", strerror(error)); + return error; + } else + printf("FS unmounted successfully!\n"); + return 0; } diff --git a/src/tools/fs_shell/module.cpp b/src/tools/fs_shell/module.cpp new file mode 100644 index 0000000000..9e94c6b6dc --- /dev/null +++ b/src/tools/fs_shell/module.cpp @@ -0,0 +1,406 @@ +/* + * Copyright 2002-2007, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Thomas Kurschel. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +/** Manages kernel add-ons and their exported modules. */ + +#include "module.h" + +#include + +#include "fssh_errors.h" +#include "fssh_kernel_export.h" +#include "fssh_module.h" +#include "fssh_string.h" +#include "hash.h" +#include "lock.h" + + +//#define TRACE_MODULE +#ifdef TRACE_MODULE +# define TRACE(x) fssh_dprintf x +#else +# define TRACE(x) ; +#endif +#define FATAL(x) fssh_dprintf x + + +namespace FSShell { + + +#define MODULE_HASH_SIZE 16 + +enum module_state { + MODULE_QUERIED = 0, + MODULE_LOADED, + MODULE_INIT, + MODULE_READY, + MODULE_UNINIT, + MODULE_ERROR +}; + + +/* Each known module will have this structure which is put in the + * gModulesHash, and looked up by name. + */ + +struct module { + struct module *next; + char *name; + char *file; + int32_t ref_count; + fssh_module_info *info; /* will only be valid if ref_count > 0 */ + int32_t offset; /* this is the offset in the headers */ + module_state state; /* state of module */ + uint32_t flags; +}; + +#define FSSH_B_BUILT_IN_MODULE 2 + + +/* locking scheme: there is a global lock only; having several locks + * makes trouble if dependent modules get loaded concurrently -> + * they have to wait for each other, i.e. we need one lock per module; + * also we must detect circular references during init and not dead-lock + */ +static recursive_lock sModulesLock; + +/* we store the loaded modules by directory path, and all known modules by module name + * in a hash table for quick access + */ +static hash_table *sModulesHash; + + +/** calculates hash for a module using its name */ + +static uint32_t +module_hash(void *_module, const void *_key, uint32_t range) +{ + module *module = (struct module *)_module; + const char *name = (const char *)_key; + + if (module != NULL) + return hash_hash_string(module->name) % range; + + if (name != NULL) + return hash_hash_string(name) % range; + + return 0; +} + + +/** compares a module to a given name */ + +static int +module_compare(void *_module, const void *_key) +{ + module *module = (struct module *)_module; + const char *name = (const char *)_key; + if (name == NULL) + return -1; + + return fssh_strcmp(module->name, name); +} + + +static inline void +inc_module_ref_count(struct module *module) +{ + module->ref_count++; +} + + +static inline void +dec_module_ref_count(struct module *module) +{ + module->ref_count--; +} + + +/** Extract the information from the module_info structure pointed at + * by "info" and create the entries required for access to it's details. + */ + +static fssh_status_t +create_module(fssh_module_info *info, const char *file, int offset, module **_module) +{ + module *module; + + TRACE(("create_module(info = %p, file = \"%s\", offset = %d, _module = %p)\n", + info, file, offset, _module)); + + if (!info->name) + return FSSH_B_BAD_VALUE; + + module = (struct module *)hash_lookup(sModulesHash, info->name); + if (module) { + FATAL(("Duplicate module name (%s) detected... ignoring new one\n", info->name)); + return FSSH_B_FILE_EXISTS; + } + + if ((module = (struct module *)malloc(sizeof(struct module))) == NULL) + return FSSH_B_NO_MEMORY; + + TRACE(("create_module: name = \"%s\", file = \"%s\"\n", info->name, file)); + + module->name = fssh_strdup(info->name); + if (module->name == NULL) { + free(module); + return FSSH_B_NO_MEMORY; + } + + module->file = fssh_strdup(file); + if (module->file == NULL) { + free(module->name); + free(module); + return FSSH_B_NO_MEMORY; + } + + module->state = MODULE_QUERIED; + module->info = info; + module->offset = offset; + // record where the module_info can be found in the module_info array + module->ref_count = 0; + module->flags = info->flags; + + recursive_lock_lock(&sModulesLock); + hash_insert(sModulesHash, module); + recursive_lock_unlock(&sModulesLock); + + if (_module) + *_module = module; + + return FSSH_B_OK; +} + + +/** Initializes a loaded module depending on its state */ + +static inline fssh_status_t +init_module(module *module) +{ + switch (module->state) { + case MODULE_QUERIED: + case MODULE_LOADED: + { + fssh_status_t status; + module->state = MODULE_INIT; + + // init module + + TRACE(("initializing module %s (at %p)... \n", module->name, module->info->std_ops)); + status = module->info->std_ops(FSSH_B_MODULE_INIT); + TRACE(("...done (%s)\n", strerror(status))); + + if (status >= FSSH_B_OK) + module->state = MODULE_READY; + else { + module->state = MODULE_LOADED; + } + + return status; + } + + case MODULE_READY: + return FSSH_B_OK; + + case MODULE_INIT: + FATAL(("circular reference to %s\n", module->name)); + return FSSH_B_ERROR; + + case MODULE_UNINIT: + FATAL(("tried to load module %s which is currently unloading\n", module->name)); + return FSSH_B_ERROR; + + case MODULE_ERROR: + FATAL(("cannot load module %s because its earlier unloading failed\n", module->name)); + return FSSH_B_ERROR; + + default: + return FSSH_B_ERROR; + } + // never trespasses here +} + + +/** Uninitializes a module depeding on its state */ + +static inline int +uninit_module(module *module) +{ + TRACE(("uninit_module(%s)\n", module->name)); + + switch (module->state) { + case MODULE_QUERIED: + case MODULE_LOADED: + return FSSH_B_NO_ERROR; + + case MODULE_INIT: + fssh_panic("Trying to unload module %s which is initializing\n", module->name); + return FSSH_B_ERROR; + + case MODULE_UNINIT: + fssh_panic("Trying to unload module %s which is un-initializing\n", module->name); + return FSSH_B_ERROR; + + case MODULE_READY: + { + fssh_status_t status; + + module->state = MODULE_UNINIT; + + TRACE(("uninitializing module %s...\n", module->name)); + status = module->info->std_ops(FSSH_B_MODULE_UNINIT); + TRACE(("...done (%s)\n", strerror(status))); + + if (status == FSSH_B_NO_ERROR) { + module->state = MODULE_LOADED; + return 0; + } + + FATAL(("Error unloading module %s (%s)\n", module->name, fssh_strerror(status))); + + module->state = MODULE_ERROR; + module->flags |= FSSH_B_KEEP_LOADED; + + return status; + } + default: + return FSSH_B_ERROR; + } + // never trespasses here +} + + +void +register_builtin_module(struct fssh_module_info *info) +{ + info->flags |= FSSH_B_BUILT_IN_MODULE; + // this is an internal flag, it doesn't have to be set by modules itself + + if (create_module(info, "", -1, NULL) != FSSH_B_OK) + fssh_dprintf("creation of built-in module \"%s\" failed!\n", info->name); +} + + +static int +dump_modules(int argc, char **argv) +{ + hash_iterator iterator; + struct module *module; + + hash_rewind(sModulesHash, &iterator); + fssh_dprintf("-- known modules:\n"); + + while ((module = (struct module *)hash_next(sModulesHash, &iterator)) != NULL) { + fssh_dprintf("%p: \"%s\", \"%s\" (%d), refcount = %d, state = %d\n", + module, module->name, module->file, (int)module->offset, (int)module->ref_count, + module->state); + } + + return 0; +} + + +// #pragma mark - +// Exported Kernel API (private part) + + +/** Setup the module structures and data for use - must be called + * before any other module call. + */ + +fssh_status_t +module_init(kernel_args *args) +{ + if (recursive_lock_init(&sModulesLock, "modules rlock") < FSSH_B_OK) + return FSSH_B_ERROR; + + sModulesHash = hash_init(MODULE_HASH_SIZE, 0, module_compare, module_hash); + if (sModulesHash == NULL) + return FSSH_B_NO_MEMORY; + + fssh_add_debugger_command("modules", &dump_modules, "list all known & loaded modules"); + + return FSSH_B_OK; +} + + +} // namespace FSShell + + +// #pragma mark - +// Exported Kernel API (public part) + + +using namespace FSShell; + + +fssh_status_t +fssh_get_module(const char *path, fssh_module_info **_info) +{ + module *module; + fssh_status_t status; + + TRACE(("get_module(%s)\n", path)); + + if (path == NULL) + return FSSH_B_BAD_VALUE; + + recursive_lock_lock(&sModulesLock); + + module = (struct module *)hash_lookup(sModulesHash, path); + if (module == NULL) + goto err; + + // The state will be adjusted by the call to init_module + // if we have just loaded the file + if (module->ref_count == 0) + status = init_module(module); + else + status = FSSH_B_OK; + + if (status == FSSH_B_OK) { + inc_module_ref_count(module); + *_info = module->info; + } + + recursive_lock_unlock(&sModulesLock); + return status; + +err: + recursive_lock_unlock(&sModulesLock); + return FSSH_B_ENTRY_NOT_FOUND; +} + + +fssh_status_t +fssh_put_module(const char *path) +{ + module *module; + + TRACE(("put_module(path = %s)\n", path)); + + recursive_lock_lock(&sModulesLock); + + module = (struct module *)hash_lookup(sModulesHash, path); + if (module == NULL) { + FATAL(("module: We don't seem to have a reference to module %s\n", path)); + recursive_lock_unlock(&sModulesLock); + return FSSH_B_BAD_VALUE; + } + + if ((module->flags & FSSH_B_KEEP_LOADED) == 0) { + dec_module_ref_count(module); + + if (module->ref_count == 0) + uninit_module(module); + } + + recursive_lock_unlock(&sModulesLock); + return FSSH_B_OK; +} diff --git a/src/tools/fs_shell/module.h b/src/tools/fs_shell/module.h new file mode 100644 index 0000000000..4bd3a9b687 --- /dev/null +++ b/src/tools/fs_shell/module.h @@ -0,0 +1,23 @@ +/* + * Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Distributed under the terms of the MIT License. + */ + +#ifndef _FSSH_MODULE_PRIVATE_H +#define _FSSH_MODULE_PRIVATE_H + +#include "fssh_defs.h" + +struct fssh_module_info; + +namespace FSShell { + +struct kernel_args; + +fssh_status_t module_init(kernel_args *args); +void register_builtin_module(struct fssh_module_info *info); + + +} // namespace FSShell + +#endif // _FSSH_MODULE_PRIVATE_H diff --git a/src/tools/fs_shell/rootfs.cpp b/src/tools/fs_shell/rootfs.cpp new file mode 100644 index 0000000000..2a29b244e9 --- /dev/null +++ b/src/tools/fs_shell/rootfs.cpp @@ -0,0 +1,1103 @@ +/* + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +#include + +#include "fssh_dirent.h" +#include "fssh_errors.h" +#include "fssh_fs_interface.h" +#include "fssh_kernel_export.h" +#include "fssh_node_monitor.h" +#include "fssh_stat.h" +#include "fssh_stdio.h" +#include "fssh_string.h" +#include "fssh_unistd.h" +#include "hash.h" +#include "list.h" +#include "lock.h" + + +//#define TRACE_ROOTFS +#ifdef TRACE_ROOTFS +# define TRACE(x) fssh_dprintf x +#else +# define TRACE(x) +#endif + + +namespace FSShell { + + +struct rootfs_stream { + fssh_mode_t type; + struct stream_dir { + struct rootfs_vnode *dir_head; + struct list cookies; + } dir; + struct stream_symlink { + char *path; + fssh_size_t length; + } symlink; +}; + +struct rootfs_vnode { + struct rootfs_vnode *all_next; + fssh_vnode_id id; + char *name; + fssh_time_t modification_time; + fssh_time_t creation_time; + fssh_uid_t uid; + fssh_gid_t gid; + struct rootfs_vnode *parent; + struct rootfs_vnode *dir_next; + struct rootfs_stream stream; +}; + +struct rootfs { + fssh_mount_id id; + mutex lock; + fssh_vnode_id next_vnode_id; + hash_table *vnode_list_hash; + struct rootfs_vnode *root_vnode; +}; + +// dircookie, dirs are only types of streams supported by rootfs +struct rootfs_dir_cookie { + struct list_link link; + struct rootfs_vnode *current; + int32_t state; // iteration state +}; + +// directory iteration states +enum { + ITERATION_STATE_DOT = 0, + ITERATION_STATE_DOT_DOT = 1, + ITERATION_STATE_OTHERS = 2, + ITERATION_STATE_BEGIN = ITERATION_STATE_DOT, +}; + +#define ROOTFS_HASH_SIZE 16 + + +static uint32_t +rootfs_vnode_hash_func(void *_v, const void *_key, uint32_t range) +{ + struct rootfs_vnode *vnode = (rootfs_vnode *)_v; + const fssh_vnode_id *key = (const fssh_vnode_id *)_key; + + if (vnode != NULL) + return vnode->id % range; + + return (uint64_t)*key % range; +} + + +static int +rootfs_vnode_compare_func(void *_v, const void *_key) +{ + struct rootfs_vnode *v = (rootfs_vnode *)_v; + const fssh_vnode_id *key = (const fssh_vnode_id *)_key; + + if (v->id == *key) + return 0; + + return -1; +} + + +static struct rootfs_vnode * +rootfs_create_vnode(struct rootfs *fs, struct rootfs_vnode *parent, + const char *name, int type) +{ + struct rootfs_vnode *vnode; + + vnode = (rootfs_vnode *)malloc(sizeof(struct rootfs_vnode)); + if (vnode == NULL) + return NULL; + + fssh_memset(vnode, 0, sizeof(struct rootfs_vnode)); + + vnode->name = fssh_strdup(name); + if (vnode->name == NULL) { + free(vnode); + return NULL; + } + + vnode->id = fs->next_vnode_id++; + vnode->stream.type = type; + vnode->creation_time = vnode->modification_time = fssh_time(NULL); + vnode->uid = fssh_geteuid(); + vnode->gid = parent ? parent->gid : fssh_getegid(); + // inherit group from parent if possible + + if (FSSH_S_ISDIR(type)) + list_init(&vnode->stream.dir.cookies); + + return vnode; +} + + +static fssh_status_t +rootfs_delete_vnode(struct rootfs *fs, struct rootfs_vnode *v, bool force_delete) +{ + // cant delete it if it's in a directory or is a directory + // and has children + if (!force_delete && (v->stream.dir.dir_head != NULL || v->dir_next != NULL)) + return FSSH_EPERM; + + // remove it from the global hash table + hash_remove(fs->vnode_list_hash, v); + + free(v->name); + free(v); + + return 0; +} + + +/* makes sure none of the dircookies point to the vnode passed in */ + +static void +update_dir_cookies(struct rootfs_vnode *dir, struct rootfs_vnode *vnode) +{ + struct rootfs_dir_cookie *cookie = NULL; + + while ((cookie = (rootfs_dir_cookie *)list_get_next_item(&dir->stream.dir.cookies, cookie)) != NULL) { + if (cookie->current == vnode) + cookie->current = vnode->dir_next; + } +} + + +static struct rootfs_vnode * +rootfs_find_in_dir(struct rootfs_vnode *dir, const char *path) +{ + struct rootfs_vnode *vnode; + + if (!fssh_strcmp(path, ".")) + return dir; + if (!fssh_strcmp(path, "..")) + return dir->parent; + + for (vnode = dir->stream.dir.dir_head; vnode; vnode = vnode->dir_next) { + if (fssh_strcmp(vnode->name, path) == 0) + return vnode; + } + return NULL; +} + + +static fssh_status_t +rootfs_insert_in_dir(struct rootfs *fs, struct rootfs_vnode *dir, + struct rootfs_vnode *vnode) +{ + // make sure the directory stays sorted alphabetically + + struct rootfs_vnode *node = dir->stream.dir.dir_head, *last = NULL; + while (node && fssh_strcmp(node->name, vnode->name) < 0) { + last = node; + node = node->dir_next; + } + if (last == NULL) { + // the new vnode is the first entry in the list + vnode->dir_next = dir->stream.dir.dir_head; + dir->stream.dir.dir_head = vnode; + } else { + // insert after that node + vnode->dir_next = last->dir_next; + last->dir_next = vnode; + } + + vnode->parent = dir; + dir->modification_time = fssh_time(NULL); + + fssh_notify_stat_changed(fs->id, dir->id, FSSH_B_STAT_MODIFICATION_TIME); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_remove_from_dir(struct rootfs *fs, struct rootfs_vnode *dir, + struct rootfs_vnode *findit) +{ + struct rootfs_vnode *v; + struct rootfs_vnode *last_v; + + for (v = dir->stream.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) { + if (v == findit) { + /* make sure all dircookies dont point to this vnode */ + update_dir_cookies(dir, v); + + if (last_v) + last_v->dir_next = v->dir_next; + else + dir->stream.dir.dir_head = v->dir_next; + v->dir_next = NULL; + + dir->modification_time = fssh_time(NULL); + fssh_notify_stat_changed(fs->id, dir->id, FSSH_B_STAT_MODIFICATION_TIME); + return FSSH_B_OK; + } + } + return FSSH_B_ENTRY_NOT_FOUND; +} + + +static bool +rootfs_is_dir_empty(struct rootfs_vnode *dir) +{ + return !dir->stream.dir.dir_head; +} + + +/** You must hold the FS lock when calling this function */ + +static fssh_status_t +remove_node(struct rootfs *fs, struct rootfs_vnode *directory, struct rootfs_vnode *vnode) +{ + // schedule this vnode to be removed when it's ref goes to zero + fssh_status_t status = fssh_remove_vnode(fs->id, vnode->id); + if (status < FSSH_B_OK) + return status; + + rootfs_remove_from_dir(fs, directory, vnode); + fssh_notify_entry_removed(fs->id, directory->id, vnode->name, vnode->id); + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_remove(struct rootfs *fs, struct rootfs_vnode *dir, const char *name, bool isDirectory) +{ + struct rootfs_vnode *vnode; + fssh_status_t status = FSSH_B_OK; + + mutex_lock(&fs->lock); + + vnode = rootfs_find_in_dir(dir, name); + if (!vnode) + status = FSSH_B_ENTRY_NOT_FOUND; + else if (isDirectory && !FSSH_S_ISDIR(vnode->stream.type)) + status = FSSH_B_NOT_A_DIRECTORY; + else if (!isDirectory && FSSH_S_ISDIR(vnode->stream.type)) + status = FSSH_B_IS_A_DIRECTORY; + else if (isDirectory && !rootfs_is_dir_empty(vnode)) + status = FSSH_B_DIRECTORY_NOT_EMPTY; + + if (status < FSSH_B_OK) + goto err; + + status = remove_node(fs, dir, vnode); + +err: + mutex_unlock(&fs->lock); + + return status; +} + + +// #pragma mark - + + +static fssh_status_t +rootfs_mount(fssh_mount_id id, const char *device, uint32_t flags, const char *args, + fssh_fs_volume *_fs, fssh_vnode_id *root_vnid) +{ + struct rootfs *fs; + struct rootfs_vnode *vnode; + fssh_status_t err; + + TRACE(("rootfs_mount: entry\n")); + + fs = (rootfs*)malloc(sizeof(struct rootfs)); + if (fs == NULL) + return FSSH_B_NO_MEMORY; + + fs->id = id; + fs->next_vnode_id = 1; + + err = mutex_init(&fs->lock, "rootfs_mutex"); + if (err < FSSH_B_OK) + goto err1; + + fs->vnode_list_hash = hash_init(ROOTFS_HASH_SIZE, (fssh_addr_t)&vnode->all_next - (fssh_addr_t)vnode, + &rootfs_vnode_compare_func, &rootfs_vnode_hash_func); + if (fs->vnode_list_hash == NULL) { + err = FSSH_B_NO_MEMORY; + goto err2; + } + + // create the root vnode + vnode = rootfs_create_vnode(fs, NULL, ".", FSSH_S_IFDIR | 0777); + if (vnode == NULL) { + err = FSSH_B_NO_MEMORY; + goto err3; + } + vnode->parent = vnode; + + fs->root_vnode = vnode; + hash_insert(fs->vnode_list_hash, vnode); + fssh_publish_vnode(id, vnode->id, vnode); + + *root_vnid = vnode->id; + *_fs = fs; + + return FSSH_B_OK; + +err3: + hash_uninit(fs->vnode_list_hash); +err2: + mutex_destroy(&fs->lock); +err1: + free(fs); + + return err; +} + + +static fssh_status_t +rootfs_unmount(fssh_fs_volume _fs) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *v; + struct hash_iterator i; + + TRACE(("rootfs_unmount: entry fs = %p\n", fs)); + + // release the reference to the root + fssh_put_vnode(fs->id, fs->root_vnode->id); + + // delete all of the vnodes + hash_open(fs->vnode_list_hash, &i); + while ((v = (struct rootfs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { + rootfs_delete_vnode(fs, v, true); + } + hash_close(fs->vnode_list_hash, &i, false); + + hash_uninit(fs->vnode_list_hash); + mutex_destroy(&fs->lock); + free(fs); + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_sync(fssh_fs_volume fs) +{ + TRACE(("rootfs_sync: entry\n")); + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_lookup(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name, fssh_vnode_id *_id, int *_type) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *dir = (struct rootfs_vnode *)_dir; + struct rootfs_vnode *vnode,*vdummy; + fssh_status_t status; + + TRACE(("rootfs_lookup: entry dir %p, name '%s'\n", dir, name)); + if (!FSSH_S_ISDIR(dir->stream.type)) + return FSSH_B_NOT_A_DIRECTORY; + + mutex_lock(&fs->lock); + + // look it up + vnode = rootfs_find_in_dir(dir, name); + if (!vnode) { + status = FSSH_B_ENTRY_NOT_FOUND; + goto err; + } + + status = fssh_get_vnode(fs->id, vnode->id, (fssh_fs_vnode *)&vdummy); + if (status < FSSH_B_OK) + goto err; + + *_id = vnode->id; + *_type = vnode->stream.type; + +err: + mutex_unlock(&fs->lock); + + return status; +} + + +static fssh_status_t +rootfs_get_vnode_name(fssh_fs_volume _fs, fssh_fs_vnode _vnode, char *buffer, fssh_size_t bufferSize) +{ + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode; + + TRACE(("rootfs_get_vnode_name: vnode = %p (name = %s)\n", vnode, vnode->name)); + + fssh_strlcpy(buffer, vnode->name, bufferSize); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_get_vnode(fssh_fs_volume _fs, fssh_vnode_id id, fssh_fs_vnode *_vnode, bool reenter) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *vnode; + + TRACE(("rootfs_getvnode: asking for vnode %Ld, r %d\n", id, reenter)); + + if (!reenter) + mutex_lock(&fs->lock); + + vnode = (rootfs_vnode *)hash_lookup(fs->vnode_list_hash, &id); + + if (!reenter) + mutex_unlock(&fs->lock); + + TRACE(("rootfs_getnvnode: looked it up at %p\n", *_vnode)); + + if (vnode == NULL) + return FSSH_B_ENTRY_NOT_FOUND; + + *_vnode = vnode; + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_put_vnode(fssh_fs_volume _fs, fssh_fs_vnode _vnode, bool reenter) +{ +#ifdef TRACE_ROOTFS + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode; + + TRACE(("rootfs_putvnode: entry on vnode 0x%Lx, r %d\n", vnode->id, reenter)); +#endif + return FSSH_B_OK; // whatever +} + + +static fssh_status_t +rootfs_remove_vnode(fssh_fs_volume _fs, fssh_fs_vnode _vnode, bool reenter) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode; + + TRACE(("rootfs_remove_vnode: remove %p (0x%Lx), r %d\n", vnode, vnode->id, reenter)); + + if (!reenter) + mutex_lock(&fs->lock); + + if (vnode->dir_next) { + // can't remove node if it's linked to the dir + fssh_panic("rootfs_remove_vnode: vnode %p asked to be removed is present in dir\n", vnode); + } + + rootfs_delete_vnode(fs, vnode, false); + + if (!reenter) + mutex_unlock(&fs->lock); + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_create(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name, int omode, int perms, fssh_fs_cookie *_cookie, fssh_vnode_id *new_vnid) +{ + return FSSH_B_BAD_VALUE; +} + + +static fssh_status_t +rootfs_open(fssh_fs_volume _fs, fssh_fs_vnode _v, int oflags, fssh_fs_cookie *_cookie) +{ + // allow to open the file, but it can't be done anything with it + + *_cookie = NULL; + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_close(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie _cookie) +{ +#ifdef TRACE_ROOTFS + struct rootfs_vnode *v = _v; + struct rootfs_cookie *cookie = _cookie; + + TRACE(("rootfs_close: entry vnode %p, cookie %p\n", v, cookie)); +#endif + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_free_cookie(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie _cookie) +{ + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_fsync(fssh_fs_volume _fs, fssh_fs_vnode _v) +{ + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_read(fssh_fs_volume _fs, fssh_fs_vnode _vnode, fssh_fs_cookie _cookie, + fssh_off_t pos, void *buffer, fssh_size_t *_length) +{ + return FSSH_EINVAL; +} + + +static fssh_status_t +rootfs_write(fssh_fs_volume fs, fssh_fs_vnode vnode, fssh_fs_cookie cookie, + fssh_off_t pos, const void *buffer, fssh_size_t *_length) +{ + TRACE(("rootfs_write: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", + vnode, cookie, pos, *_length)); + + return FSSH_EPERM; +} + + +static fssh_status_t +rootfs_create_dir(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name, int mode, fssh_vnode_id *_newID) +{ + struct rootfs *fs = (rootfs*)_fs; + struct rootfs_vnode *dir = (rootfs_vnode*)_dir; + struct rootfs_vnode *vnode; + fssh_status_t status = 0; + + TRACE(("rootfs_create_dir: dir %p, name = '%s', perms = %d, id = 0x%Lx pointer id = %p\n", + dir, name, mode,*_newID, _newID)); + + mutex_lock(&fs->lock); + + vnode = rootfs_find_in_dir(dir, name); + if (vnode != NULL) { + status = FSSH_B_FILE_EXISTS; + goto err; + } + + TRACE(("rootfs_create: creating new vnode\n")); + vnode = rootfs_create_vnode(fs, dir, name, FSSH_S_IFDIR | (mode & FSSH_S_IUMSK)); + if (vnode == NULL) { + status = FSSH_B_NO_MEMORY; + goto err; + } + + rootfs_insert_in_dir(fs, dir, vnode); + hash_insert(fs->vnode_list_hash, vnode); + + fssh_notify_entry_created(fs->id, dir->id, name, vnode->id); + + mutex_unlock(&fs->lock); + return FSSH_B_OK; + +err: + mutex_unlock(&fs->lock); + + return status; +} + + +static fssh_status_t +rootfs_remove_dir(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name) +{ + struct rootfs *fs = (rootfs*)_fs; + struct rootfs_vnode *dir = (rootfs_vnode*)_dir; + + TRACE(("rootfs_remove_dir: dir %p (0x%Lx), name '%s'\n", dir, dir->id, name)); + + return rootfs_remove(fs, dir, name, true); +} + + +static fssh_status_t +rootfs_open_dir(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie *_cookie) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_v; + struct rootfs_dir_cookie *cookie; + + TRACE(("rootfs_open: vnode %p\n", vnode)); + + if (!FSSH_S_ISDIR(vnode->stream.type)) + return FSSH_B_BAD_VALUE; + + cookie = (rootfs_dir_cookie*)malloc(sizeof(struct rootfs_dir_cookie)); + if (cookie == NULL) + return FSSH_B_NO_MEMORY; + + mutex_lock(&fs->lock); + + cookie->current = vnode->stream.dir.dir_head; + cookie->state = ITERATION_STATE_BEGIN; + + list_add_item(&vnode->stream.dir.cookies, cookie); + *_cookie = cookie; + + mutex_unlock(&fs->lock); + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_free_dir_cookie(fssh_fs_volume _fs, fssh_fs_vnode _vnode, fssh_fs_cookie _cookie) +{ + struct rootfs_dir_cookie *cookie = (rootfs_dir_cookie *)_cookie; + struct rootfs_vnode *vnode = (rootfs_vnode *)_vnode; + struct rootfs *fs = (rootfs *)_fs; + + mutex_lock(&fs->lock); + list_remove_item(&vnode->stream.dir.cookies, cookie); + mutex_unlock(&fs->lock); + + free(cookie); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_read_dir(fssh_fs_volume _fs, fssh_fs_vnode _vnode, fssh_fs_cookie _cookie, struct fssh_dirent *dirent, fssh_size_t bufferSize, uint32_t *_num) +{ + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode; + struct rootfs_dir_cookie *cookie = (rootfs_dir_cookie *)_cookie; + struct rootfs *fs = (rootfs *)_fs; + fssh_status_t status = FSSH_B_OK; + struct rootfs_vnode *childNode = NULL; + const char *name = NULL; + struct rootfs_vnode *nextChildNode = NULL; + int nextState = cookie->state; + + TRACE(("rootfs_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _vnode, cookie, dirent, bufferSize,_num)); + + mutex_lock(&fs->lock); + + switch (cookie->state) { + case ITERATION_STATE_DOT: + childNode = vnode; + name = "."; + nextChildNode = vnode->stream.dir.dir_head; + nextState = cookie->state + 1; + break; + case ITERATION_STATE_DOT_DOT: + childNode = vnode->parent; + name = ".."; + nextChildNode = vnode->stream.dir.dir_head; + nextState = cookie->state + 1; + break; + default: + childNode = cookie->current; + if (childNode) { + name = childNode->name; + nextChildNode = childNode->dir_next; + } + break; + } + + if (!childNode) { + // we're at the end of the directory + *_num = 0; + goto err; + } + + dirent->d_dev = fs->id; + dirent->d_ino = childNode->id; + dirent->d_reclen = fssh_strlen(name) + sizeof(struct fssh_dirent); + + if (dirent->d_reclen > bufferSize) { + status = FSSH_ENOBUFS; + goto err; + } + + status = fssh_strlcpy(dirent->d_name, name, + bufferSize - sizeof(struct fssh_dirent)); + if (status < FSSH_B_OK) + goto err; + + cookie->current = nextChildNode; + cookie->state = nextState; + status = FSSH_B_OK; + +err: + mutex_unlock(&fs->lock); + + return status; +} + + +static fssh_status_t +rootfs_rewind_dir(fssh_fs_volume _fs, fssh_fs_vnode _vnode, fssh_fs_cookie _cookie) +{ + struct rootfs_dir_cookie *cookie = (rootfs_dir_cookie *)_cookie; + struct rootfs_vnode *vnode = (rootfs_vnode *)_vnode; + struct rootfs *fs = (rootfs *)_fs; + + mutex_lock(&fs->lock); + + cookie->current = vnode->stream.dir.dir_head; + cookie->state = ITERATION_STATE_BEGIN; + + mutex_unlock(&fs->lock); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_ioctl(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie _cookie, fssh_ulong op, void *buf, fssh_size_t len) +{ + TRACE(("rootfs_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n", _v, _cookie, op, buf, len)); + + return FSSH_EINVAL; +} + + +static bool +rootfs_can_page(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie cookie) +{ + return false; +} + + +static fssh_status_t +rootfs_read_pages(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie cookie, fssh_off_t pos, + const fssh_iovec *vecs, fssh_size_t count, fssh_size_t *_numBytes, bool reenter) +{ + return FSSH_B_NOT_ALLOWED; +} + + +static fssh_status_t +rootfs_write_pages(fssh_fs_volume _fs, fssh_fs_vnode _v, fssh_fs_cookie cookie, fssh_off_t pos, + const fssh_iovec *vecs, fssh_size_t count, fssh_size_t *_numBytes, bool reenter) +{ + return FSSH_B_NOT_ALLOWED; +} + + +static fssh_status_t +rootfs_read_link(fssh_fs_volume _fs, fssh_fs_vnode _link, char *buffer, fssh_size_t *_bufferSize) +{ + struct rootfs_vnode *link = (rootfs_vnode *)_link; + fssh_size_t bufferSize = *_bufferSize; + + if (!FSSH_S_ISLNK(link->stream.type)) + return FSSH_B_BAD_VALUE; + + *_bufferSize = link->stream.symlink.length + 1; + // we always need to return the number of bytes we intend to write! + + if (bufferSize <= link->stream.symlink.length) + return FSSH_B_BUFFER_OVERFLOW; + + fssh_memcpy(buffer, link->stream.symlink.path, link->stream.symlink.length + 1); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_symlink(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name, const char *path, int mode) +{ + struct rootfs *fs = (rootfs *)_fs; + struct rootfs_vnode *dir = (rootfs_vnode *)_dir; + struct rootfs_vnode *vnode; + fssh_status_t status = FSSH_B_OK; + + TRACE(("rootfs_symlink: dir %p, name = '%s', path = %s\n", dir, name, path)); + + mutex_lock(&fs->lock); + + vnode = rootfs_find_in_dir(dir, name); + if (vnode != NULL) { + status = FSSH_B_FILE_EXISTS; + goto err; + } + + TRACE(("rootfs_create: creating new symlink\n")); + vnode = rootfs_create_vnode(fs, dir, name, FSSH_S_IFLNK | (mode & FSSH_S_IUMSK)); + if (vnode == NULL) { + status = FSSH_B_NO_MEMORY; + goto err; + } + + rootfs_insert_in_dir(fs, dir, vnode); + hash_insert(fs->vnode_list_hash, vnode); + + vnode->stream.symlink.path = fssh_strdup(path); + if (vnode->stream.symlink.path == NULL) { + status = FSSH_B_NO_MEMORY; + goto err1; + } + vnode->stream.symlink.length = fssh_strlen(path); + + fssh_notify_entry_created(fs->id, dir->id, name, vnode->id); + + mutex_unlock(&fs->lock); + return FSSH_B_OK; + +err1: + rootfs_delete_vnode(fs, vnode, false); +err: + mutex_unlock(&fs->lock); + return status; +} + + +static fssh_status_t +rootfs_unlink(fssh_fs_volume _fs, fssh_fs_vnode _dir, const char *name) +{ + struct rootfs *fs = (rootfs *)_fs; + struct rootfs_vnode *dir = (rootfs_vnode *)_dir; + + TRACE(("rootfs_unlink: dir %p (0x%Lx), name '%s'\n", dir, dir->id, name)); + + return rootfs_remove(fs, dir, name, false); +} + + +static fssh_status_t +rootfs_rename(fssh_fs_volume _fs, fssh_fs_vnode _fromDir, const char *fromName, fssh_fs_vnode _toDir, const char *toName) +{ + struct rootfs *fs = (rootfs *)_fs; + struct rootfs_vnode *fromDirectory = (rootfs_vnode *)_fromDir; + struct rootfs_vnode *toDirectory = (rootfs_vnode *)_toDir; + struct rootfs_vnode *vnode, *targetVnode, *parent; + fssh_status_t status; + char *nameBuffer = NULL; + + TRACE(("rootfs_rename: from %p (0x%Lx), fromName '%s', to %p (0x%Lx), toName '%s'\n", + fromDirectory, fromDirectory->id, fromName, toDirectory, toDirectory->id, toName)); + + mutex_lock(&fs->lock); + + vnode = rootfs_find_in_dir(fromDirectory, fromName); + if (vnode != NULL) { + status = FSSH_B_ENTRY_NOT_FOUND; + goto err; + } + + // make sure the target not a subdirectory of us + parent = toDirectory->parent; + while (parent != NULL) { + if (parent == vnode) { + status = FSSH_B_BAD_VALUE; + goto err; + } + + parent = parent->parent; + } + + // we'll reuse the name buffer if possible + if (fssh_strlen(fromName) >= fssh_strlen(toName)) { + nameBuffer = fssh_strdup(toName); + if (nameBuffer == NULL) { + status = FSSH_B_NO_MEMORY; + goto err; + } + } + + targetVnode = rootfs_find_in_dir(toDirectory, toName); + if (targetVnode != NULL) { + // target node exists, let's see if it is an empty directory + if (FSSH_S_ISDIR(targetVnode->stream.type) && !rootfs_is_dir_empty(targetVnode)) { + status = FSSH_B_NAME_IN_USE; + goto err; + } + + // so we can cleanly remove it + remove_node(fs, toDirectory, targetVnode); + } + + // change the name on this node + if (nameBuffer == NULL) { + // we can just copy it + fssh_strcpy(vnode->name, toName); + } else { + free(vnode->name); + vnode->name = nameBuffer; + } + + // remove it from the dir + rootfs_remove_from_dir(fs, fromDirectory, vnode); + + // Add it back to the dir with the new name. + // We need to do this even in the same directory, + // so that it keeps sorted correctly. + rootfs_insert_in_dir(fs, toDirectory, vnode); + + fssh_notify_entry_moved(fs->id, fromDirectory->id, fromName, toDirectory->id, toName, vnode->id); + status = FSSH_B_OK; + +err: + if (status != FSSH_B_OK) + free(nameBuffer); + + mutex_unlock(&fs->lock); + + return status; +} + + +static fssh_status_t +rootfs_read_stat(fssh_fs_volume _fs, fssh_fs_vnode _v, struct fssh_stat *stat) +{ + struct rootfs *fs = (rootfs *)_fs; + struct rootfs_vnode *vnode = (rootfs_vnode *)_v; + + TRACE(("rootfs_read_stat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id, stat)); + + // stream exists, but we know to return size 0, since we can only hold directories + stat->fssh_st_dev = fs->id; + stat->fssh_st_ino = vnode->id; + stat->fssh_st_size = 0; + stat->fssh_st_mode = vnode->stream.type; + + stat->fssh_st_nlink = 1; + stat->fssh_st_blksize = 65536; + + stat->fssh_st_uid = vnode->uid; + stat->fssh_st_gid = vnode->gid; + + stat->fssh_st_atime = fssh_time(NULL); + stat->fssh_st_mtime = stat->fssh_st_ctime = vnode->modification_time; + stat->fssh_st_crtime = vnode->creation_time; + + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_write_stat(fssh_fs_volume _fs, fssh_fs_vnode _vnode, const struct fssh_stat *stat, uint32_t statMask) +{ + struct rootfs *fs = (rootfs *)_fs; + struct rootfs_vnode *vnode = (rootfs_vnode *)_vnode; + + TRACE(("rootfs_write_stat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id, stat)); + + // we cannot change the size of anything + if (statMask & FSSH_B_STAT_SIZE) + return FSSH_B_BAD_VALUE; + + mutex_lock(&fs->lock); + + if (statMask & FSSH_B_STAT_MODE) + vnode->stream.type = (vnode->stream.type & ~FSSH_S_IUMSK) | (stat->fssh_st_mode & FSSH_S_IUMSK); + + if (statMask & FSSH_B_STAT_UID) + vnode->uid = stat->fssh_st_uid; + if (statMask & FSSH_B_STAT_GID) + vnode->gid = stat->fssh_st_gid; + + if (statMask & FSSH_B_STAT_MODIFICATION_TIME) + vnode->modification_time = stat->fssh_st_mtime; + if (statMask & FSSH_B_STAT_CREATION_TIME) + vnode->creation_time = stat->fssh_st_crtime; + + mutex_unlock(&fs->lock); + + fssh_notify_stat_changed(fs->id, vnode->id, statMask); + return FSSH_B_OK; +} + + +static fssh_status_t +rootfs_std_ops(int32_t op, ...) +{ + switch (op) { + case FSSH_B_MODULE_INIT: + return FSSH_B_OK; + + case FSSH_B_MODULE_UNINIT: + return FSSH_B_OK; + + default: + return FSSH_B_ERROR; + } +} + + +fssh_file_system_module_info gRootFileSystem = { + { + "file_systems/rootfs" FSSH_B_CURRENT_FS_API_VERSION, + 0, + rootfs_std_ops, + }, + + "Root File System", + + NULL, // identify_partition() + NULL, // scan_partition() + NULL, // free_identify_partition_cookie() + NULL, // free_partition_content_cookie() + + &rootfs_mount, + &rootfs_unmount, + NULL, + NULL, + &rootfs_sync, + + &rootfs_lookup, + &rootfs_get_vnode_name, + + &rootfs_get_vnode, + &rootfs_put_vnode, + &rootfs_remove_vnode, + + &rootfs_can_page, + &rootfs_read_pages, + &rootfs_write_pages, + + NULL, // get_file_map() + + /* common */ + &rootfs_ioctl, + NULL, // fs_set_flags() + NULL, // select + NULL, // deselect + &rootfs_fsync, + + &rootfs_read_link, + &rootfs_symlink, + NULL, // fs_link() + &rootfs_unlink, + &rootfs_rename, + + NULL, // fs_access() + &rootfs_read_stat, + &rootfs_write_stat, + + /* file */ + &rootfs_create, + &rootfs_open, + &rootfs_close, + &rootfs_free_cookie, + &rootfs_read, + &rootfs_write, + + /* directory */ + &rootfs_create_dir, + &rootfs_remove_dir, + &rootfs_open_dir, + &rootfs_close, // same as for files - it does nothing, anyway + &rootfs_free_dir_cookie, + &rootfs_read_dir, + &rootfs_rewind_dir, + + // the other operations are not supported (attributes, indices, queries) + NULL, +}; + + +} // namespace FSShell diff --git a/src/tools/fs_shell/syscalls.h b/src/tools/fs_shell/syscalls.h new file mode 100644 index 0000000000..18bdee0cce --- /dev/null +++ b/src/tools/fs_shell/syscalls.h @@ -0,0 +1,89 @@ +/* + * Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Distributed under the terms of the MIT License. + */ + +#ifndef _FSSH_SYSCALLS_H +#define _FSSH_SYSCALLS_H + +#include "fssh_defs.h" + + +struct fssh_iovec; + + +// defined in vfs.cpp +fssh_dev_t _kern_mount(const char *path, const char *device, + const char *fsName, uint32_t flags, const char *args, + fssh_size_t argsLength); +fssh_status_t _kern_unmount(const char *path, uint32_t flags); +fssh_status_t _kern_read_fs_info(fssh_dev_t device, + struct fssh_fs_info *info); +fssh_status_t _kern_write_fs_info(fssh_dev_t device, + const struct fssh_fs_info *info, int mask); +fssh_status_t _kern_sync(void); +fssh_dev_t _kern_next_device(int32_t *_cookie); +int _kern_open_entry_ref(fssh_dev_t device, fssh_ino_t inode, + const char *name, int openMode, int perms); +int _kern_open(int fd, const char *path, int openMode, int perms); +int _kern_open_dir_entry_ref(fssh_dev_t device, fssh_ino_t inode, + const char *name); +int _kern_open_dir(int fd, const char *path); +fssh_status_t _kern_fcntl(int fd, int op, uint32_t argument); +fssh_status_t _kern_fsync(int fd); +fssh_status_t _kern_lock_node(int fd); +fssh_status_t _kern_unlock_node(int fd); +fssh_status_t _kern_create_dir_entry_ref(fssh_dev_t device, fssh_ino_t inode, + const char *name, int perms); +fssh_status_t _kern_create_dir(int fd, const char *path, int perms); +fssh_status_t _kern_remove_dir(int fd, const char *path); +fssh_status_t _kern_read_link(int fd, const char *path, char *buffer, + fssh_size_t *_bufferSize); +fssh_status_t _kern_create_symlink(int fd, const char *path, + const char *toPath, int mode); +fssh_status_t _kern_create_link(const char *path, const char *toPath); +fssh_status_t _kern_unlink(int fd, const char *path); +fssh_status_t _kern_rename(int oldFD, const char *oldPath, int newFD, + const char *newPath); +fssh_status_t _kern_access(const char *path, int mode); +fssh_status_t _kern_read_stat(int fd, const char *path, bool traverseLeafLink, + struct fssh_stat *stat, fssh_size_t statSize); +fssh_status_t _kern_write_stat(int fd, const char *path, + bool traverseLeafLink, const struct fssh_stat *stat, + fssh_size_t statSize, int statMask); +int _kern_open_attr_dir(int fd, const char *path); +int _kern_create_attr(int fd, const char *name, uint32_t type, + int openMode); +int _kern_open_attr(int fd, const char *name, int openMode); +fssh_status_t _kern_remove_attr(int fd, const char *name); +fssh_status_t _kern_rename_attr(int fromFile, const char *fromName, + int toFile, const char *toName); +int _kern_open_index_dir(fssh_dev_t device); +fssh_status_t _kern_create_index(fssh_dev_t device, const char *name, + uint32_t type, uint32_t flags); +fssh_status_t _kern_read_index_stat(fssh_dev_t device, const char *name, + struct fssh_stat *stat); +fssh_status_t _kern_remove_index(fssh_dev_t device, const char *name); +fssh_status_t _kern_getcwd(char *buffer, fssh_size_t size); +fssh_status_t _kern_setcwd(int fd, const char *path); + +// defined in fd.cpp +fssh_ssize_t _kern_read(int fd, fssh_off_t pos, void *buffer, + fssh_size_t length); +fssh_ssize_t _kern_readv(int fd, fssh_off_t pos, const fssh_iovec *vecs, + fssh_size_t count); +fssh_ssize_t _kern_write(int fd, fssh_off_t pos, const void *buffer, + fssh_size_t length); +fssh_ssize_t _kern_writev(int fd, fssh_off_t pos, const fssh_iovec *vecs, + fssh_size_t count); +fssh_off_t _kern_seek(int fd, fssh_off_t pos, int seekType); +fssh_status_t _kern_ioctl(int fd, uint32_t op, void *buffer, + fssh_size_t length); +fssh_ssize_t _kern_read_dir(int fd, struct fssh_dirent *buffer, + fssh_size_t bufferSize, uint32_t maxCount); +fssh_status_t _kern_rewind_dir(int fd); +fssh_status_t _kern_close(int fd); +int _kern_dup(int fd); +int _kern_dup2(int ofd, int nfd); + +#endif // _FSSH_SYSCALLS_H diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp index fe6e098417..959217671c 100644 --- a/src/tools/fs_shell/vfs.cpp +++ b/src/tools/fs_shell/vfs.cpp @@ -20,11 +20,14 @@ #include "fssh_fs_info.h" #include "fssh_fs_volume.h" #include "fssh_kernel_export.h" +#include "fssh_module.h" #include "fssh_stat.h" +#include "fssh_stdio.h" #include "fssh_string.h" #include "fssh_unistd.h" #include "hash.h" #include "KPath.h" +#include "syscalls.h" //#define TRACE_VFS @@ -459,8 +462,7 @@ put_mount(struct fs_mount *mount) static fssh_status_t put_file_system(fssh_file_system_module_info *fs) { -// return put_module(fs->info.name); - return FSSH_B_ERROR; + return fssh_put_module(fs->info.name); } @@ -473,22 +475,19 @@ put_file_system(fssh_file_system_module_info *fs) static fssh_file_system_module_info * get_file_system(const char *fsName) { -#if 0 char name[FSSH_B_FILE_NAME_LENGTH]; - if (strncmp(fsName, "file_systems/", strlen("file_systems/"))) { + if (fssh_strncmp(fsName, "file_systems/", fssh_strlen("file_systems/"))) { // construct module name if we didn't get one // (we currently support only one API) - snprintf(name, sizeof(name), "file_systems/%s/v1", fsName); + fssh_snprintf(name, sizeof(name), "file_systems/%s/v1", fsName); fsName = NULL; } fssh_file_system_module_info *info; - if (get_module(fsName ? fsName : name, (module_info **)&info) != FSSH_B_OK) + if (fssh_get_module(fsName ? fsName : name, (fssh_module_info **)&info) != FSSH_B_OK) return NULL; return info; -#endif // 0 -return NULL; } @@ -4068,7 +4067,9 @@ fs_mount(char *path, const char *device, const char *fsName, uint32_t flags, if (!(flags & FSSH_B_MOUNT_VIRTUAL_DEVICE) && device) { // normalize the device path - status = normalizedDevice.SetTo(device, true); +// status = normalizedDevice.SetTo(device, true); +// NOTE: normalizing works only in our namespace. + status = normalizedDevice.SetTo(device, false); if (status != FSSH_B_OK) return status;