aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/include/sys/vfs.h2
-rw-r--r--sys/kern/vfs_lookup.c59
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;
}