feat: symlink(2) and realpathat syscall
authorMinep <zelong56@gmail.com>
Tue, 2 Aug 2022 14:21:36 +0000 (15:21 +0100)
committerMinep <zelong56@gmail.com>
Tue, 2 Aug 2022 14:21:36 +0000 (15:21 +0100)
feat: symbolic link following

lunaix-os/includes/lunaix/fctrl.h
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/lunistd.h
lunaix-os/includes/lunaix/spike.h
lunaix-os/includes/lunaix/status.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/includes/lunaix/types.h
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/demos/dir_read.c
lunaix-os/kernel/fs/vfs.c

index b8bb08ff3ba4c891eb348223a8192dcaab3562df..dc2887295792db8ab933a4535cb6113e4d23fa99 100644 (file)
@@ -7,10 +7,10 @@
 
 __LXSYSCALL2(int, open, const char*, path, int, options)
 
-__LXSYSCALL1(int, mkdir, const char*, path);
-__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname);
+__LXSYSCALL1(int, mkdir, const char*, path)
+__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
 
-__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent);
+__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
 
 __LXSYSCALL4(int,
              readlinkat,
@@ -21,6 +21,8 @@ __LXSYSCALL4(int,
              char*,
              buf,
              size_t,
-             size);
+             size)
+
+__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
 
 #endif /* __LUNAIX_FCTRL_H */
index 43a5cf4b68d1a3ab2153e37046ba1e02e0e89508..bc22fd537e371c13f1c7c32e39f9256726a3c26b 100644 (file)
@@ -27,6 +27,7 @@
 #define VFS_WALK_MKPARENT 0x1
 #define VFS_WALK_FSRELATIVE 0x2
 #define VFS_WALK_PARENT 0x4
+#define VFS_WALK_NOFOLLOW 0x4
 
 #define VFS_IOBUF_FDIRTY 0x1
 
@@ -124,6 +125,8 @@ struct v_inode
         int (*rmdir)(struct v_inode* this);
         int (*unlink)(struct v_inode* this);
         int (*link)(struct v_inode* this, struct v_dnode* new_name);
+        int (*read_symlink)(struct v_inode* this, const char** path_out);
+        int (*symlink)(struct v_inode* this, const char* target);
         int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
     } ops;
 };
index 472f638d8eac77c05417688b75f24c6fad173dae..556f239c695c67f0dfd6b536a90b38cc5a924c53 100644 (file)
@@ -47,4 +47,6 @@ __LXSYSCALL1(int, dup, int, oldfd)
 
 __LXSYSCALL1(int, fsync, int, fildes)
 
+__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
+
 #endif /* __LUNAIX_UNISTD_H */
index 4e17993266adbf0e96971a034c39f4517d723cad..4363b4123a89efa9be46cddd743353360b5ce019 100644 (file)
@@ -3,12 +3,12 @@
 
 // Some helper functions. As helpful as Spike the Dragon! :)
 
-// 除法向上取整
+// 除法 v/(2^k) 向上取整
 #define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k))
 
 #define ICEIL(x, y) ((x) / (y) + ((x) % (y) != 0))
 
-// 除法向下取整
+// 除法 v/(2^k) 向下取整
 #define FLOOR(v, k) ((v) >> (k))
 
 // 获取v最近的最大k倍数
index df1a1d8c3e0ff2f220af32ce2cacee2791a570ed..fe9224c8e89c6e3a30d4b62265c5be481437d136 100644 (file)
@@ -24,5 +24,6 @@
 #define EISDIR -19
 #define EBUSY -20
 #define EXDEV -21
+#define ELOOP -22
 
 #endif /* __LUNAIX_CODE_H */
index 30941f6f23e2dbf007982fb20ae8add832f49945..94d197af1657f18329e1bee9d65f29f41290546d 100644 (file)
@@ -41,6 +41,8 @@
 #define __SYSCALL_fsync 33
 #define __SYSCALL_dup 34
 #define __SYSCALL_dup2 35
+#define __SYSCALL_realpathat 36
+#define __SYSCALL_symlink 37
 
 #define __SYSCALL_MAX 0x100
 
index e91025ad920f8641346d0eae509f6cf5f906a52f..4a1f275d290037ce1732b2120eac36009ace6c13 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __LUNAIX_TYPES_H
 #define __LUNAIX_TYPES_H
 
+#include <stddef.h>
 #include <stdint.h>
 
 #define PEXITTERM 0x100
index ae631176bd3f48b825b775c7813be82b0a45af33..328afbf924c11fd12ca0287261d116b5f696ea89 100644 (file)
@@ -43,6 +43,8 @@
         .long __lxsys_fsync
         .long __lxsys_dup
         .long __lxsys_dup2
+        .long __lxsys_realpathat
+        .long __lxsys_symlink
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
index bc4e024fd6701ed5b7b4f0aef40f152d3fceb44e..caa88cc60be5c2b141441c6a2e4f0b937a2f0bb5 100644 (file)
@@ -16,7 +16,7 @@ _readdir_main()
     }
 
     char path[129];
-    int len = readlinkat(fd, ".", path, 128);
+    int len = realpathat(fd, path, 128);
     if (len < 0) {
         kprintf(KERROR "fail to read (%d)\n", geterrno());
     } else {
index 05741d846f15df903cca7e9b524acce835eb5112..fcceb7073243dbb66102d5d3eb5952fdf2b05dcf 100644 (file)
@@ -114,11 +114,11 @@ vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
 }
 
 int
-vfs_walk(struct v_dnode* start,
-         const char* path,
-         struct v_dnode** dentry,
-         struct hstr* component,
-         int walk_options)
+__vfs_walk(struct v_dnode* start,
+           const char* path,
+           struct v_dnode** dentry,
+           struct hstr* component,
+           int walk_options)
 {
     int errno = 0;
     int i = 0, j = 0;
@@ -218,6 +218,45 @@ error:
     return errno;
 }
 
+#define VFS_MAX_SYMLINK 16
+
+int
+vfs_walk(struct v_dnode* start,
+         const char* path,
+         struct v_dnode** dentry,
+         struct hstr* component,
+         int options)
+{
+    struct v_dnode* interim;
+    char* pathname = path;
+    int errno = __vfs_walk(start, path, &interim, component, options);
+    int counter = 0;
+
+    while (!errno) {
+        if (counter >= VFS_MAX_SYMLINK) {
+            errno = ELOOP;
+            continue;
+        }
+        if ((interim->inode->itype & VFS_INODE_TYPE_SYMLINK) &&
+            !(options & VFS_WALK_NOFOLLOW) &&
+            interim->inode->ops.read_symlink) {
+            errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
+            if (errno) {
+                break;
+            }
+        } else {
+            break;
+        }
+        errno =
+          __vfs_walk_internal(start, pathname, &interim, component, options);
+        counter++;
+    }
+
+    *dentry = errno ? 0 : interim;
+
+    return errno;
+}
+
 int
 vfs_mount(const char* target, const char* fs_name, bdev_t device)
 {
@@ -632,7 +671,7 @@ __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
 }
 
 int
-vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth)
+vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
 {
     if (!dnode) {
         return 0;
@@ -642,7 +681,7 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth)
         return ELOOP;
     }
 
-    size_t len = vfs_readlink(dnode->parent, buf, size, depth + 1);
+    size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
 
     if (len >= size) {
         return len;
@@ -659,12 +698,42 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth)
     return len;
 }
 
+int
+vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
+{
+    char* link;
+    if (dnode->inode->ops.read_symlink) {
+        int errno = dnode->inode->ops.read_symlink(dnode->inode, &link);
+        strncpy(buf, link, size);
+        return errno;
+    }
+    return 0;
+}
+
+__DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else {
+        struct v_dnode* dnode;
+        errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
+    }
+
+    if (errno >= 0) {
+        return errno;
+    }
+
+    return DO_STATUS(errno);
+}
+
 __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
 {
     int errno;
     struct v_dnode* dnode;
-    if (!(errno = vfs_walk(NULL, path, &dnode, NULL, 0))) {
-        errno = vfs_readlink(dnode, buf, size, 0);
+    if (!(errno = vfs_walk(NULL, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
+        errno = vfs_readlink(dnode, buf, size);
     }
 
     if (errno >= 0) {
@@ -691,8 +760,12 @@ __DEFINE_LXSYSCALL4(int,
         errno = EBADF;
     } else {
         struct v_dnode* dnode;
-        if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
-            errno = vfs_readlink(fd_s->file->dnode, buf, size, 0);
+        if (!(errno = vfs_walk(fd_s->file->dnode,
+                               pathname,
+                               &dnode,
+                               NULL,
+                               VFS_WALK_NOFOLLOW))) {
+            errno = vfs_readlink(fd_s->file->dnode, buf, size);
         }
     }
 
@@ -868,5 +941,32 @@ __DEFINE_LXSYSCALL1(int, dup, int, oldfd)
         return newfd;
     }
 
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int,
+                    symlink,
+                    const char*,
+                    pathname,
+                    const char*,
+                    link_target)
+{
+    int errno;
+    struct v_dnode* dnode;
+    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+        goto done;
+    }
+    if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+        errno = EROFS;
+        goto done;
+    }
+    if (!dnode->inode->ops.symlink) {
+        errno = ENOTSUP;
+        goto done;
+    }
+
+    errno = dnode->inode->ops.symlink(dnode->inode, link_target);
+
+done:
     return DO_STATUS(errno);
 }
\ No newline at end of file