X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/d57ee3ae693448387e3022fdd07bd741b2db818a..34f6af4f61e0eec9c96113e07f140b609b4113c8:/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 0ffbabb..84e04d0 100644 --- a/lunaix-os/kernel/fs/path_walk.c +++ b/lunaix-os/kernel/fs/path_walk.c @@ -1,10 +1,12 @@ #include #include +#include #include #include #define VFS_SYMLINK_DEPTH 16 +#define VFS_SYMLINK_MAXLEN 512 extern struct lru_zone *dnode_lru, *inode_lru; @@ -21,7 +23,7 @@ __vfs_walk(struct v_dnode* start, int i = 0, j = 0; if (depth >= VFS_SYMLINK_DEPTH) { - return ENAMETOOLONG; + return ELOOP; } if (path[0] == VFS_PATH_DELIM || !start) { @@ -30,20 +32,25 @@ __vfs_walk(struct v_dnode* start, } else { start = vfs_sysroot; if (!vfs_sysroot->mnt) { - panick("vfs: no root"); + fail("vfs: no root"); } } - i++; + + if (path[0] == VFS_PATH_DELIM) { + i++; + } } + 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 && current_level) { + while (current) { lookahead = path[i++]; if (current != VFS_PATH_DELIM) { if (j >= VFS_NAME_MAXLEN - 1) { @@ -69,45 +76,11 @@ __vfs_walk(struct v_dnode* start, if (!lookahead && (walk_options & VFS_WALK_PARENT)) { if (component) { - component->hash = name.hash; - component->len = j; - strcpy(component->value, fname_buffer); + hstrcpy(component, &name); } 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; - } - - // reposition the resolved subtree pointed by symlink - vfs_dcache_rehash(current_level->parent, dnode); - current_level = dnode; - current_inode = dnode->inode; - } - lock_dnode(current_level); dnode = vfs_dcache_lookup(current_level, &name); @@ -145,6 +118,48 @@ __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; }; @@ -166,6 +181,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);