diff options
-rw-r--r-- | sys/include/sys/vfs.h | 2 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 59 |
2 files changed, 56 insertions, 5 deletions
diff --git a/sys/include/sys/vfs.h b/sys/include/sys/vfs.h index a684c3f..c1bef53 100644 --- a/sys/include/sys/vfs.h +++ b/sys/include/sys/vfs.h @@ -42,7 +42,7 @@ void vfs_init(void); struct fs_info *vfs_byname(const char *name); int vfs_vget(struct vnode *parent, const char *name, struct vnode **vp); -struct vnode *vfs_path_to_node(const char *path); +int vfs_path_to_node(const char *path, struct vnode **vp); char *vfs_get_fname_at(const char *path, size_t idx); int vfs_rootname(const char *path, char **new_path); bool vfs_is_valid_path(const char *path); diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 7d20bd2..1398964 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -29,6 +29,8 @@ #include <sys/types.h> #include <sys/vfs.h> +#include <sys/mount.h> +#include <sys/errno.h> #include <vm/dynalloc.h> #include <string.h> @@ -115,9 +117,58 @@ vfs_get_fname_at(const char *path, size_t idx) return ret; } -struct vnode * -vfs_path_to_node(const char *path) +/* + * Fetches a vnode from a path. + * + * @path: Path to fetch vnode from. + * @vp: Output var for fetched vnode. + * + * Returns 0 on success. + */ +int +vfs_path_to_node(const char *path, struct vnode **vp) { - /* TODO */ - return NULL; + struct vnode *vnode = g_root_vnode; + struct fs_info *fs; + char *name; + int s = 0, fs_caps = 0; + + if (strcmp(path, "/") == 0 || !vfs_is_valid_path(path)) { + return -1; + } else if (*path != '/') { + return -1; + } + + /* Fetch filesystem capabilities if we can */ + if (vnode->fs != NULL) { + fs = vnode->fs; + fs_caps = fs->caps; + } + + /* + * If the filesystem requires full-path lookups, we can try + * throwing the full path at the filesystem to see if + * it'll give us a vnode. + */ + if (__TEST(fs_caps, FSCAP_FULLPATH)) { + s = vfs_vget(g_root_vnode, path, &vnode); + goto done; + } + + for (size_t i = 0;; ++i) { + name = vfs_get_fname_at(path, i); + if (name == NULL) break; + + s = vfs_vget(vnode, name, &vnode); + dynfree(name); + + if (s != 0) break; + } + +done: + if (vp != NULL && s == 0) { + *vp = vnode; + } + + return s; } |