#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
#include <lunaix/spike.h>
+#include <usr/lunaix/fcntl_defs.h>
+
#include <klibc/string.h>
#define VFS_SYMLINK_DEPTH 16
+#define VFS_SYMLINK_MAXLEN 512
extern struct lru_zone *dnode_lru, *inode_lru;
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) {
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;
}
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;
+ 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) {
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;
};
cleanup:
vfs_d_free(dnode);
+
error:
*dentry = NULL;
return errno;
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);
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