Boot framework rework (#45)
[lunaix-os.git] / lunaix-os / kernel / fs / path_walk.c
index 0ffbabb84bb36fe1b763a6a2a23d6a69f9fffc41..783d9b40fc062b5a0d2c124b97e8c445fdbbdeb3 100644 (file)
@@ -1,10 +1,12 @@
 #include <lunaix/fs.h>
 #include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
 #include <lunaix/spike.h>
 
 #include <klibc/string.h>
 
 #define VFS_SYMLINK_DEPTH 16
+#define VFS_SYMLINK_MAXLEN 512
 
 extern struct lru_zone *dnode_lru, *inode_lru;
 
@@ -21,7 +23,7 @@ __vfs_walk(struct v_dnode* start,
     int i = 0, j = 0;
 
     if (depth >= VFS_SYMLINK_DEPTH) {
-        return ENAMETOOLONG;
+        return ELOOP;
     }
 
     if (path[0] == VFS_PATH_DELIM || !start) {
@@ -33,17 +35,22 @@ __vfs_walk(struct v_dnode* start,
                 panick("vfs: no root");
             }
         }
-        i++;
+
+        if (path[0] == VFS_PATH_DELIM) {
+            i++;
+        }
     }
 
+    assert(start);
+
     struct v_dnode* dnode;
-    struct v_inode* current_inode;
     struct v_dnode* current_level = start;
+    struct v_inode* current_inode = current_level->inode;
 
     struct hstr name = HSTR(fname_buffer, 0);
 
     char current = path[i++], lookahead;
-    while (current && current_level) {
+    while (current) {
         lookahead = path[i++];
         if (current != VFS_PATH_DELIM) {
             if (j >= VFS_NAME_MAXLEN - 1) {
@@ -69,45 +76,11 @@ __vfs_walk(struct v_dnode* start,
 
         if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
             if (component) {
-                component->hash = name.hash;
-                component->len = j;
-                strcpy(component->value, fname_buffer);
+                hstrcpy(component, &name);
             }
             break;
         }
 
-        current_inode = current_level->inode;
-
-        if ((current_inode->itype & VFS_IFSYMLINK) &&
-            !(walk_options & VFS_WALK_NOFOLLOW)) {
-            const char* link;
-
-            lock_inode(current_inode);
-            if ((errno =
-                   current_inode->ops->read_symlink(current_inode, &link))) {
-                unlock_inode(current_inode);
-                goto error;
-            }
-            unlock_inode(current_inode);
-
-            errno = __vfs_walk(current_level->parent,
-                               link,
-                               &dnode,
-                               NULL,
-                               0,
-                               depth + 1,
-                               fname_buffer + name.len + 1);
-
-            if (errno) {
-                goto error;
-            }
-
-            // reposition the resolved subtree pointed by symlink
-            vfs_dcache_rehash(current_level->parent, dnode);
-            current_level = dnode;
-            current_inode = dnode->inode;
-        }
-
         lock_dnode(current_level);
 
         dnode = vfs_dcache_lookup(current_level, &name);
@@ -145,6 +118,48 @@ __vfs_walk(struct v_dnode* start,
 
         j = 0;
         current_level = dnode;
+        current_inode = current_level->inode;
+
+        assert(current_inode);
+        
+        if (check_symlink_node(current_inode) &&
+            !(walk_options & VFS_WALK_NOFOLLOW)) {
+            const char* link;
+            struct v_inode_ops* iops;
+
+            iops = current_inode->ops;
+
+            if (!iops->read_symlink) {
+                errno = ENOTSUP;
+                goto error;
+            }
+
+            lock_inode(current_inode);
+
+            errno = iops->read_symlink(current_inode, &link);
+            if ((errno < 0)) {
+                unlock_inode(current_inode);
+                goto error;
+            }
+
+            unlock_inode(current_inode);
+
+            errno = __vfs_walk(current_level->parent,
+                               link,
+                               &dnode,
+                               NULL,
+                               0,
+                               depth + 1,
+                               fname_buffer + name.len + 1);
+
+            if (errno) {
+                goto error;
+            }
+
+            current_level = dnode;
+            current_inode = dnode->inode;
+        }
+
     cont:
         current = lookahead;
     };
@@ -166,6 +181,11 @@ vfs_walk(struct v_dnode* start,
          struct hstr* component,
          int options)
 {
+    if (!path) {
+        *dentry = NULL;
+        return 0;
+    }
+
     // allocate a file name stack for path walking and recursion to resolve
     // symlink
     char* name_buffer = valloc(2048);