X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/8c6f505faaa66e18cdca108dca549d4ad806a077..a8e9a00d034efa9e6b483c4a3decddf9f9686db2:/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 cd0ac01..df0942b 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) { @@ -43,15 +51,18 @@ __vfs_walk(struct v_dnode* start, 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) { + while (current) + { lookahead = path[i++]; - if (current != VFS_PATH_DELIM) { + + if (current != VFS_PATH_DELIM) + { if (j >= VFS_NAME_MAXLEN - 1) { return ENAMETOOLONG; } @@ -80,47 +91,23 @@ __vfs_walk(struct v_dnode* start, 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; - } + lock_dnode(current_level); - // reposition the resolved subtree pointed by symlink - // vfs_dcache_rehash(current_level->parent, dnode); - current_level = dnode; - current_inode = dnode->inode; + if (!check_allow_execute(current_inode)) { + errno = EACCESS; + unlock_dnode(current_level); + goto error; } - lock_dnode(current_level); - 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; } @@ -149,6 +136,49 @@ __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; }; @@ -158,6 +188,7 @@ __vfs_walk(struct v_dnode* start, cleanup: vfs_d_free(dnode); + error: *dentry = NULL; return errno; @@ -170,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); @@ -188,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