feat: support per-process current working directory (cwd)
authorMinep <zelong56@gmail.com>
Wed, 10 Aug 2022 12:31:26 +0000 (13:31 +0100)
committerMinep <zelong56@gmail.com>
Wed, 10 Aug 2022 12:33:52 +0000 (13:33 +0100)
fix: typo in README

README.md
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/lunistd.h
lunaix-os/includes/lunaix/process.h
lunaix-os/includes/lunaix/status.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/demos/iotest.c
lunaix-os/kernel/fs/vfs.c

index b9a96dc024805176f5484de09b17c5aa369d8149..1c48cd452f518603ccc1a1035bb661befa2828c2 100644 (file)
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有
 运行该操作系统需要一个虚拟磁盘镜像,可以使用如下命令快速创建一个:
 
 ```bash
-qemu-img create -f vdi machine/disk1.vdi 128M
+qemu-img create -f vdi machine/disk0.vdi 128M
 ```
 
 如果你想要使用别的磁盘镜像,需要修改`configs/make-debug-tool`
@@ -182,11 +182,16 @@ qemu-img create -f vdi machine/disk1.vdi 128M
 2. `fsync(2)`
 2. `dup(2)`
 2. `dup2(2)`
+2. `symlink(2)`
+2. `chdir(2)`
+2. `fchdir(2)`
+2. `getcwd(2)`
 
 ### LunaixOS自有
 
 1. `yield`
 2. `geterrno`
+3. `realpathat`
 
 ## 附录2:编译gcc作为交叉编译器<a id="appendix2"></a>
 
index 0764a61c26af42b9562d97d13b4252b5699b17d7..fd09e965537d47b1519074c018815c9aabfeea46 100644 (file)
@@ -137,6 +137,7 @@ struct v_dnode
     struct llist_header children;
     struct llist_header siblings;
     struct v_superblock* super_block;
+    uint32_t ref_count;
     struct
     {
         void (*destruct)(struct v_dnode* dnode);
index 556f239c695c67f0dfd6b536a90b38cc5a924c53..cb5af35db5fb79efc01ac4727059fb23b1b4feb2 100644 (file)
@@ -49,4 +49,10 @@ __LXSYSCALL1(int, fsync, int, fildes)
 
 __LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
 
+__LXSYSCALL1(int, chdir, const char*, path)
+
+__LXSYSCALL1(int, fchdir, int, fd)
+
+__LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
+
 #endif /* __LUNAIX_UNISTD_H */
index 7c8c114a8c607ceb4c333ed7e6ee8e2db0e7ee3b..18cddb94f6d29e4ad947e495af8c329dd74972ab 100644 (file)
@@ -79,6 +79,7 @@ struct proc_info
     int flags;
     void* sig_handler[_SIG_NUM];
     struct v_fdtable* fdtable;
+    struct v_dnode* cwd;
     pid_t pgid;
 };
 
index 4007c315a36ca54e335be97cb057af48b19ca0da..9bb6b4bd45107008797e95e5482dd01b81d4c243 100644 (file)
@@ -26,5 +26,6 @@
 #define EXDEV -21
 #define ELOOP -22
 #define ENODEV -23
+#define ERANGE -24
 
 #endif /* __LUNAIX_CODE_H */
index 94d197af1657f18329e1bee9d65f29f41290546d..1e205c20ccc3b71923d8a662dd9bfa7d1574b79d 100644 (file)
@@ -43,6 +43,9 @@
 #define __SYSCALL_dup2 35
 #define __SYSCALL_realpathat 36
 #define __SYSCALL_symlink 37
+#define __SYSCALL_chdir 38
+#define __SYSCALL_fchdir 39
+#define __SYSCALL_getcwd 40
 
 #define __SYSCALL_MAX 0x100
 
index 328afbf924c11fd12ca0287261d116b5f696ea89..b35a217ca99f7aedce6f658651550fa31a9c6ccc 100644 (file)
@@ -45,6 +45,9 @@
         .long __lxsys_dup2
         .long __lxsys_realpathat
         .long __lxsys_symlink
+        .long __lxsys_chdir
+        .long __lxsys_fchdir
+        .long __lxsys_getcwd
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
index 5e17b02db766f66f56d4c2ac625c73e1bb47c8ed..0ebe696eb48c5e1cc79fcb5c018945a5a8f61683 100644 (file)
@@ -15,11 +15,25 @@ _iotest_main()
     char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
                            "There were two regal sisters who ruled together "
                            "and created harmony for all the land.";
+    char read_out[256];
+
+    // 切换工作目录至 /dev
+    int errno = chdir("/dev");
+    if (errno) {
+        write(STDOUT, "fail to chdir", 15);
+        return;
+    }
+
+    if (getcwd(read_out, sizeof(read_out))) {
+        write(STDOUT, "current working dir: ", 22);
+        write(STDOUT, read_out, 256);
+        write(STDOUT, "\n", 2);
+    }
 
     // sda 设备 - 硬盘
     //  sda设备属于容积设备(Volumetric Device),
     //  Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能)
-    int fd = open("/dev/sda", 0);
+    int fd = open("./sda", 0);
 
     if (fd < 0) {
         kprintf(KERROR "fail to open (%d)\n", geterrno());
@@ -38,7 +52,6 @@ _iotest_main()
     lseek(fd, 4 * 4096, FSEEK_SET);
     write(fd, test_sequence, sizeof(test_sequence));
 
-    char read_out[256];
     write(STDOUT, "input: ", 8);
     int size = read(STDIN, read_out, 256);
 
index 11896ec6730e4377a24d3d4d72b7644622663c51..e13b489226760544a232dacadaff09cda0387517 100644 (file)
@@ -263,7 +263,7 @@ vfs_mount(const char* target, const char* fs_name, bdev_t device)
     int errno;
     struct v_dnode* mnt;
 
-    if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+    if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
         errno = vfs_mount_at(fs_name, device, mnt);
     }
 
@@ -276,7 +276,7 @@ vfs_unmount(const char* target)
     int errno;
     struct v_dnode* mnt;
 
-    if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+    if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
         errno = vfs_unmount_at(mnt);
     }
 
@@ -336,7 +336,6 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
     vfile->inode = inode;
     vfile->ref_count = 1;
     vfile->ops = inode->default_fops;
-    inode->open_count++;
 
     if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
         struct pcache* pcache = vzalloc(sizeof(struct pcache));
@@ -348,8 +347,11 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
     if (errno) {
         cake_release(file_pile, vfile);
     } else {
+        dnode->ref_count++;
+        inode->open_count++;
         *file = vfile;
     }
+
     return errno;
 }
 
@@ -374,9 +376,8 @@ vfs_close(struct v_file* file)
 {
     int errno = 0;
     if (!file->ops.close || !(errno = file->ops.close(file))) {
-        if (file->inode->open_count) {
-            file->inode->open_count--;
-        }
+        file->dnode->ref_count--;
+        file->inode->open_count--;
         pcache_commit_all(file);
         cake_release(file_pile, file);
     }
@@ -464,6 +465,17 @@ vfs_i_free(struct v_inode* inode)
 #define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
 #define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
 
+#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
+
+int
+__vfs_getfd(int fd, struct v_fd** fd_s)
+{
+    if (TEST_FD(fd) && (*fd_s = __current->fdtable->fds[fd])) {
+        return 0;
+    }
+    return EBADF;
+}
+
 int
 __vfs_try_locate_file(const char* path,
                       struct v_dnode** fdir,
@@ -473,7 +485,8 @@ __vfs_try_locate_file(const char* path,
     char name_str[VFS_NAME_MAXLEN];
     struct hstr name = HSTR(name_str, 0);
     int errno;
-    if ((errno = vfs_walk(NULL, path, fdir, &name, VFS_WALK_PARENT))) {
+    if ((errno =
+           vfs_walk(__current->cwd, path, fdir, &name, VFS_WALK_PARENT))) {
         return errno;
     }
 
@@ -495,12 +508,6 @@ __vfs_try_locate_file(const char* path,
     return errno;
 }
 
-int
-__file_cached_read(struct v_file* file, void* buf, size_t len, size_t fpos)
-{
-    return pcache_read(file, buf, len, fpos);
-}
-
 int
 vfs_do_open(const char* path, int options)
 {
@@ -543,15 +550,11 @@ __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
     return DO_STATUS_OR_RETURN(errno);
 }
 
-#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
-#define GET_FD(fd, fd_s) (TEST_FD(fd) && (fd_s = __current->fdtable->fds[fd]))
-
 __DEFINE_LXSYSCALL1(int, close, int, fd)
 {
     struct v_fd* fd_s;
     int errno = 0;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
         goto done_err;
     }
 
@@ -584,9 +587,12 @@ __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
 {
     struct v_fd* fd_s;
     int errno;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
-    } else if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
+
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
+        goto done;
+    }
+
+    if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
         errno = ENOTDIR;
     } else {
         struct dir_context dctx =
@@ -616,7 +622,8 @@ __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
 {
     struct v_dnode *parent, *dir;
     struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0);
-    int errno = vfs_walk(NULL, path, &parent, &component, VFS_WALK_PARENT);
+    int errno =
+      vfs_walk(__current->cwd, path, &parent, &component, VFS_WALK_PARENT);
     if (errno) {
         goto done;
     }
@@ -646,8 +653,7 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 {
     int errno = 0;
     struct v_fd* fd_s;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
         goto done;
     }
 
@@ -674,8 +680,7 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
 {
     int errno = 0;
     struct v_fd* fd_s;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
         goto done;
     }
 
@@ -702,27 +707,28 @@ __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
 {
     int errno = 0;
     struct v_fd* fd_s;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
-    } else {
-        struct v_file* file = fd_s->file;
-        size_t fpos = file->f_pos;
-        switch (options) {
-            case FSEEK_CUR:
-                fpos = (size_t)((int)file->f_pos + offset);
-                break;
-            case FSEEK_END:
-                fpos = (size_t)((int)file->inode->fsize + offset);
-                break;
-            case FSEEK_SET:
-                fpos = offset;
-                break;
-        }
-        if (!file->ops.seek || !(errno = file->ops.seek(file, fpos))) {
-            file->f_pos = fpos;
-        }
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
+        goto done;
     }
 
+    struct v_file* file = fd_s->file;
+    size_t fpos = file->f_pos;
+    switch (options) {
+        case FSEEK_CUR:
+            fpos = (size_t)((int)file->f_pos + offset);
+            break;
+        case FSEEK_END:
+            fpos = (size_t)((int)file->inode->fsize + offset);
+            break;
+        case FSEEK_SET:
+            fpos = offset;
+            break;
+    }
+    if (!file->ops.seek || !(errno = file->ops.seek(file, fpos))) {
+        file->f_pos = fpos;
+    }
+
+done:
     return DO_STATUS(errno);
 }
 
@@ -770,17 +776,18 @@ __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 = __vfs_getfd(fd, &fd_s))) {
+        goto done;
     }
 
+    struct v_dnode* dnode;
+    errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
+
     if (errno >= 0) {
         return errno;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -788,7 +795,8 @@ __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, VFS_WALK_NOFOLLOW))) {
+    if (!(errno =
+            vfs_walk(__current->cwd, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
         errno = vfs_readlink(dnode, buf, size);
     }
 
@@ -812,23 +820,21 @@ __DEFINE_LXSYSCALL4(int,
 {
     int errno;
     struct v_fd* fd_s;
-    if (!GET_FD(dirfd, fd_s)) {
-        errno = EBADF;
-    } else {
-        struct v_dnode* dnode;
-        if (!(errno = vfs_walk(fd_s->file->dnode,
-                               pathname,
-                               &dnode,
-                               NULL,
-                               VFS_WALK_NOFOLLOW))) {
-            errno = vfs_readlink(fd_s->file->dnode, buf, size);
-        }
+    if ((errno = __vfs_getfd(dirfd, &fd_s))) {
+        goto done;
+    }
+
+    struct v_dnode* dnode;
+    if (!(errno = vfs_walk(
+            fd_s->file->dnode, pathname, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
+        errno = vfs_readlink(fd_s->file->dnode, buf, size);
     }
 
     if (errno >= 0) {
         return errno;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -836,7 +842,7 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
 {
     int errno;
     struct v_dnode* dnode;
-    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+    if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
         goto done;
     }
     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
@@ -882,7 +888,7 @@ __DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
 {
     int errno;
     struct v_dnode* dnode;
-    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+    if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
         goto done;
     }
     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
@@ -900,13 +906,13 @@ __DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
 {
     int errno;
     struct v_fd* fd_s;
-    if (!GET_FD(fd, fd_s)) {
-        errno = EBADF;
-    } else {
-        struct v_dnode* dnode;
-        if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
-            errno = __vfs_do_unlink(dnode->inode);
-        }
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
+        goto done;
+    }
+
+    struct v_dnode* dnode;
+    if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
+        errno = __vfs_do_unlink(dnode->inode);
     }
 
 done:
@@ -935,9 +941,7 @@ __DEFINE_LXSYSCALL1(int, fsync, int, fildes)
 {
     int errno;
     struct v_fd* fd_s;
-    if (!GET_FD(fildes, fd_s)) {
-        errno = EBADF;
-    } else {
+    if (!(errno = __vfs_getfd(fildes, &fd_s))) {
         errno = vfs_fsync(fd_s->file);
     }
 
@@ -967,10 +971,15 @@ vfs_dup2(int oldfd, int newfd)
 
     int errno;
     struct v_fd *oldfd_s, *newfd_s;
-    if (!GET_FD(oldfd, oldfd_s) || !TEST_FD(newfd)) {
+    if ((errno = __vfs_getfd(oldfd, &oldfd_s))) {
+        goto done;
+    }
+
+    if (!TEST_FD(newfd)) {
         errno = EBADF;
         goto done;
     }
+
     newfd_s = __current->fdtable->fds[newfd];
     if (newfd_s && (errno = vfs_close(newfd_s))) {
         goto done;
@@ -994,14 +1003,17 @@ __DEFINE_LXSYSCALL1(int, dup, int, oldfd)
 {
     int errno, newfd;
     struct v_fd *oldfd_s, *newfd_s;
-    if (!GET_FD(oldfd, oldfd_s)) {
-        errno = EBADF;
-    } else if (!(errno = vfs_alloc_fdslot(&newfd)) &&
-               !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+    if ((errno = __vfs_getfd(oldfd, &oldfd_s))) {
+        goto done;
+    }
+
+    if (!(errno = vfs_alloc_fdslot(&newfd)) &&
+        !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
         __current->fdtable->fds[newfd] = newfd_s;
         return newfd;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -1014,7 +1026,7 @@ __DEFINE_LXSYSCALL2(int,
 {
     int errno;
     struct v_dnode* dnode;
-    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+    if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
         goto done;
     }
     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
@@ -1030,4 +1042,83 @@ __DEFINE_LXSYSCALL2(int,
 
 done:
     return DO_STATUS(errno);
+}
+
+int
+__vfs_do_chdir(struct v_dnode* dnode)
+{
+    int errno = 0;
+    if (!(dnode->inode->itype & VFS_IFDIR)) {
+        errno = ENOTDIR;
+        goto done;
+    }
+
+    if (__current->cwd) {
+        __current->cwd->ref_count--;
+    }
+
+    dnode->ref_count++;
+    __current->cwd = dnode;
+
+done:
+    return errno;
+}
+
+__DEFINE_LXSYSCALL1(int, chdir, const char*, path)
+{
+    struct v_dnode* dnode;
+    int errno = 0;
+
+    if ((errno = vfs_walk(__current->cwd, path, &dnode, NULL, 0))) {
+        goto done;
+    }
+
+    errno = __vfs_do_chdir(dnode);
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, fchdir, int, fd)
+{
+    struct v_fd* fd_s;
+    int errno = 0;
+
+    if ((errno = __vfs_getfd(fd, &fd_s))) {
+        goto done;
+    }
+
+    errno = __vfs_do_chdir(fd_s->file->dnode);
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
+{
+    int errno = 0;
+    char* ret_ptr = 0;
+    if (size < 2) {
+        errno = ERANGE;
+        goto done;
+    }
+
+    if (!__current->cwd) {
+        *buf = PATH_DELIM;
+        goto done;
+    }
+
+    size_t len = vfs_get_path(__current->cwd, buf, size, 0);
+    if (len == size) {
+        errno = ERANGE;
+        goto done;
+    }
+
+    buf[len + 1] = '\0';
+
+    ret_ptr = buf;
+
+done:
+    __current->k_status = errno;
+    return ret_ptr;
 }
\ No newline at end of file