2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/process.h>
4 #include <lunaix/spike.h>
6 #include <usr/lunaix/fcntl.h>
8 #include <klibc/string.h>
10 #define VFS_SYMLINK_DEPTH 16
11 #define VFS_SYMLINK_MAXLEN 512
13 extern struct lru_zone *dnode_lru, *inode_lru;
16 __vfs_walk(struct v_dnode* start,
18 struct v_dnode** dentry,
19 struct hstr* component,
27 if (depth >= VFS_SYMLINK_DEPTH) {
31 if (path[0] == VFS_PATH_DELIM || !start) {
32 if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
33 start = start->super_block->root;
35 else if (unlikely(!__current)) {
39 start = __current->root ?: vfs_sysroot;
42 if (unlikely(!start || !start->mnt)) {
46 if (path[0] == VFS_PATH_DELIM) {
53 struct v_dnode* dnode;
54 struct v_dnode* current_level = start;
55 struct v_inode* current_inode = current_level->inode;
57 struct hstr name = HSTR(fname_buffer, 0);
59 char current = path[i++], lookahead;
62 lookahead = path[i++];
64 if (current != VFS_PATH_DELIM)
66 if (j >= VFS_NAME_MAXLEN - 1) {
69 if (!VFS_VALID_CHAR(current)) {
72 fname_buffer[j++] = current;
78 // handling cases like /^.*(\/+).*$/
79 if (lookahead == VFS_PATH_DELIM) {
85 hstr_rehash(&name, HSTR_FULL_HASH);
87 if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
89 hstrcpy(component, &name);
94 lock_dnode(current_level);
96 if (!check_allow_execute(current_inode)) {
98 unlock_dnode(current_level);
102 dnode = vfs_dcache_lookup(current_level, &name);
106 dnode = vfs_d_alloc(current_level, &name);
110 unlock_dnode(current_level);
114 lock_inode(current_inode);
116 errno = current_inode->ops->dir_lookup(current_inode, dnode);
118 if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
119 if (!current_inode->ops->mkdir) {
122 errno = current_inode->ops->mkdir(current_inode, dnode);
126 vfs_dcache_add(current_level, dnode);
127 unlock_inode(current_inode);
130 unlock_dnode(current_level);
135 unlock_dnode(current_level);
138 current_level = dnode;
139 current_inode = current_level->inode;
141 assert(current_inode);
143 if (check_symlink_node(current_inode) &&
144 !(walk_options & VFS_WALK_NOFOLLOW))
147 struct v_inode_ops* iops;
149 iops = current_inode->ops;
151 if (!iops->read_symlink) {
156 lock_inode(current_inode);
158 errno = iops->read_symlink(current_inode, &link);
160 unlock_inode(current_inode);
164 unlock_inode(current_inode);
166 errno = __vfs_walk(current_level->parent,
172 fname_buffer + name.len + 1);
178 current_level = dnode;
179 current_inode = dnode->inode;
186 *dentry = current_level;
198 vfs_walk(struct v_dnode* start,
200 struct v_dnode** dentry,
201 struct hstr* component,
209 // allocate a file name stack for path walking and recursion to resolve
211 char* name_buffer = valloc(2048);
214 __vfs_walk(start, path, dentry, component, options, 0, name_buffer);
221 vfs_walk_proc(const char* path,
222 struct v_dnode** dentry,
223 struct hstr* component,
226 return vfs_walk(__current->cwd, path, dentry, component, options);
230 vfs_walkat(int fd, const char* path, int at_opts, struct v_dnode** dnode_out)
232 int errno, options = 0;
233 struct v_dnode *root_dnode;
236 if ((at_opts & AT_FDCWD)) {
237 root_dnode = __current->cwd;
241 errno = vfs_getfd(fd, &_fd);
246 root_dnode = _fd->file->dnode;
249 if ((at_opts & AT_SYMLINK_NOFOLLOW)) {
250 options |= VFS_WALK_NOFOLLOW;
253 errno = vfs_walk(root_dnode, path, dnode_out, NULL, options);