Merge branch 'vfs-dev'
[lunaix-os.git] / lunaix-os / kernel / fs / vfs.c
index 11896ec6730e4377a24d3d4d72b7644622663c51..68a8d5fbe2b7aa87b09b4442448f4bbcfc65e133 100644 (file)
@@ -229,7 +229,7 @@ vfs_walk(struct v_dnode* start,
          int options)
 {
     struct v_dnode* interim;
-    char* pathname = path;
+    const char* pathname = path;
     int errno = __vfs_walk(start, path, &interim, component, options);
     int counter = 0;
 
@@ -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,11 +336,11 @@ 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));
         pcache_init(pcache);
+        pcache->master = inode;
         inode->pg_cache = pcache;
     }
 
@@ -348,8 +348,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,10 +377,9 @@ 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--;
-        }
-        pcache_commit_all(file);
+        file->dnode->ref_count--;
+        file->inode->open_count--;
+        pcache_commit_all(file->inode);
         cake_release(file_pile, file);
     }
     return errno;
@@ -387,12 +389,9 @@ int
 vfs_fsync(struct v_file* file)
 {
     int errno = ENOTSUP;
-    pcache_commit_all(file);
+    pcache_commit_all(file->inode);
     if (file->ops.sync) {
-        errno = file->ops.sync(file);
-    }
-    if (!errno && file->inode->ops.sync) {
-        return file->inode->ops.sync(file->inode);
+        errno = file->ops.sync(file->inode);
     }
     return errno;
 }
@@ -464,6 +463,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 +483,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 +506,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 +548,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 +585,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 =
@@ -600,7 +604,7 @@ __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
             __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
         } else {
             dctx.index -= 2;
-            if ((errno = fd_s->file->ops.readdir(fd_s->file, &dctx))) {
+            if ((errno = fd_s->file->ops.readdir(fd_s->file->inode, &dctx))) {
                 goto done;
             }
         }
@@ -616,7 +620,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 +651,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;
     }
 
@@ -657,9 +661,8 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
         goto done;
     }
 
-    cpu_enable_interrupt();
-    errno = file->ops.read(file, buf, count, file->f_pos);
-    cpu_disable_interrupt();
+    __SYSCALL_INTERRUPTIBLE(
+      { errno = file->ops.read(file->inode, buf, count, file->f_pos); })
 
     if (errno > 0) {
         file->f_pos += errno;
@@ -674,8 +677,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;
     }
 
@@ -685,9 +687,8 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
         goto done;
     }
 
-    cpu_enable_interrupt();
-    errno = file->ops.write(file, buf, count, file->f_pos);
-    cpu_disable_interrupt();
+    __SYSCALL_INTERRUPTIBLE(
+      { errno = file->ops.write(file->inode, buf, count, file->f_pos); })
 
     if (errno > 0) {
         file->f_pos += errno;
@@ -702,27 +703,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->inode, fpos))) {
+        file->f_pos = fpos;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -757,7 +759,7 @@ vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
 int
 vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
 {
-    char* link;
+    const char* link;
     if (dnode->inode->ops.read_symlink) {
         int errno = dnode->inode->ops.read_symlink(dnode->inode, &link);
         strncpy(buf, link, size);
@@ -770,17 +772,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 +791,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 +816,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 +838,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 +884,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 +902,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 +937,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,12 +967,17 @@ 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))) {
+    if (newfd_s && (errno = vfs_close(newfd_s->file))) {
         goto done;
     }
 
@@ -994,14 +999,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 +1022,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 +1038,85 @@ __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;
+    }
+
+    size_t len = 0;
+
+    if (!__current->cwd) {
+        *buf = PATH_DELIM;
+        len = 1;
+    } else {
+        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