X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/6f6da1abb22dff69dbb710bd2fd9d95f083f2b43..0fd474df7001837bde53da0e42e83081827c9641:/lunaix-os/kernel/fs/path_walk.c diff --git a/lunaix-os/kernel/fs/path_walk.c b/lunaix-os/kernel/fs/path_walk.c index d376c79..246e903 100644 --- a/lunaix-os/kernel/fs/path_walk.c +++ b/lunaix-os/kernel/fs/path_walk.c @@ -3,9 +3,12 @@ #include #include +#include + #include #define VFS_SYMLINK_DEPTH 16 +#define VFS_SYMLINK_MAXLEN 512 extern struct lru_zone *dnode_lru, *inode_lru; @@ -28,11 +31,16 @@ __vfs_walk(struct v_dnode* start, if (path[0] == VFS_PATH_DELIM || !start) { if ((walk_options & VFS_WALK_FSRELATIVE) && start) { start = start->super_block->root; - } else { + } + else if (unlikely(!__current)) { start = vfs_sysroot; - if (!vfs_sysroot->mnt) { - panick("vfs: no root"); - } + } + else { + start = __current->root ?: vfs_sysroot; + } + + if (unlikely(!start || !start->mnt)) { + fail("vfs: no root"); } if (path[0] == VFS_PATH_DELIM) { @@ -49,9 +57,12 @@ __vfs_walk(struct v_dnode* start, struct hstr name = HSTR(fname_buffer, 0); char current = path[i++], lookahead; - while (current) { + while (current) + { lookahead = path[i++]; - if (current != VFS_PATH_DELIM) { + + if (current != VFS_PATH_DELIM) + { if (j >= VFS_NAME_MAXLEN - 1) { return ENAMETOOLONG; } @@ -82,13 +93,21 @@ __vfs_walk(struct v_dnode* start, lock_dnode(current_level); + if (!check_allow_execute(current_inode)) { + errno = EACCESS; + unlock_dnode(current_level); + goto error; + } + dnode = vfs_dcache_lookup(current_level, &name); - if (!dnode) { + if (!dnode) + { dnode = vfs_d_alloc(current_level, &name); if (!dnode) { errno = ENOMEM; + unlock_dnode(current_level); goto error; } @@ -119,21 +138,29 @@ __vfs_walk(struct v_dnode* start, current_level = dnode; current_inode = current_level->inode; - if ((current_inode->itype & F_MSLNK) && - !(walk_options & VFS_WALK_NOFOLLOW)) { + 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 (!current_inode->ops->read_symlink) { + if (!iops->read_symlink) { errno = ENOTSUP; goto error; } lock_inode(current_inode); - if ((errno = - current_inode->ops->read_symlink(current_inode, &link))) { + + 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, @@ -161,6 +188,7 @@ __vfs_walk(struct v_dnode* start, cleanup: vfs_d_free(dnode); + error: *dentry = NULL; return errno; @@ -173,6 +201,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); @@ -191,4 +224,36 @@ vfs_walk_proc(const char* path, int options) { return vfs_walk(__current->cwd, path, dentry, component, options); +} + +int +vfs_walkat(int fd, const char* path, int at_opts, struct v_dnode** dnode_out) +{ + int errno, options = 0; + struct v_dnode *root_dnode; + struct v_fd* _fd; + + if ((at_opts & AT_FDCWD)) { + root_dnode = __current->cwd; + } + else + { + errno = vfs_getfd(fd, &_fd); + if (errno) { + return errno; + } + + root_dnode = _fd->file->dnode; + } + + if ((at_opts & AT_SYMLINK_NOFOLLOW)) { + options |= VFS_WALK_NOFOLLOW; + } + + errno = vfs_walk(root_dnode, path, dnode_out, NULL, options); + if (errno) { + return errno; + } + + return 0; } \ No newline at end of file