49 pr_dinfo2(dcache,
"lookup parent of '%s'", original_path);
50 MOS_ASSERT_X(base_dir && root_dir && original_path,
"Invalid VFS lookup parameters");
51 if (last_seg_out !=
NULL)
63 char *path =
strdup(original_path);
70 if (last_seg_out !=
NULL)
77 pr_dinfo2(dcache,
"lookup parent: current segment '%s'", current_seg);
84 if (IS_ERR(parent_real_ref))
85 return ERR_PTR(-ENOENT);
86 parent_ref = parent_real_ref;
92 if (last_seg_out !=
NULL)
94 const bool ends_with_slash = original_path[
strlen(original_path) - 1] ==
PATH_DELIM;
95 char *tmp = kmalloc(
strlen(current_seg) + 2);
106 if (
strncmp(current_seg,
".", 2) == 0 ||
strcmp(current_seg,
"./") == 0)
112 if (
strncmp(current_seg,
"..", 3) == 0 ||
strcmp(current_seg,
"../") == 0)
114 if (parent_ref == root_dir)
140 *last_seg_out =
NULL;
144 return ERR_PTR(-ENOENT);
149 pr_dinfo2(dcache,
"jumping to mountpoint %s", child_ref->
name);
157 parent_ref = child_ref;
172 mos_panic(
"inode does not support readlink (symlink) operation, but it's a symlink!");
179 return ERR_PTR(-ENOENT);
185 return ERR_PTR(-ENAMETOOLONG);
190 pr_dinfo2(dcache,
"symlink target: %s", target);
192 char *last_segment =
NULL;
195 if (IS_ERR(parent_ref))
199 bool is_symlink =
false;
204 if (IS_ERR(child_ref) || is_symlink)
215 pr_dinfo2(dcache,
"resolving last segment: '%s'", leaf);
218 leaf[
strlen(leaf) - 1] =
'\0';
222 mos_warn(
"RESOLVE_EXPECT_DIR isn't set, but the provided path ends with a slash");
223 return ERR_PTR(-EINVAL);
228 else if (
strncmp(leaf,
"..", 3) == 0 ||
strcmp(leaf,
"../") == 0)
240 return parent_parent;
254 pr_dinfo2(dcache,
"file does not exist");
256 return ERR_PTR(-ENOENT);
264 return ERR_PTR(-EEXIST);
271 pr_dinfo2(dcache,
"resolving symlink for '%s'", leaf);
275 *is_symlink = symlink_target_ref !=
NULL;
276 return symlink_target_ref;
279 pr_dinfo2(dcache,
"not following symlink");
286 return ERR_PTR(-EISDIR);
298 return ERR_PTR(-ENOTDIR);
311 for (atomic_t i = 0; i < d->
refcount; i++)
345 return ERR_PTR(-EBADF);
348 return ERR_PTR(-EBADF);
377 pr_dinfo2(dcache,
"filesystem doesn't support lookup");
387 pr_dinfo2(dcache,
"dentry '%s' found in the filesystem",
name);
392 pr_dinfo2(dcache,
"dentry '%s' not found in the filesystem",
name);
400 return ERR_PTR(-ENOENT);
403 pr_dinfo2(dcache,
"resolving path '%s'", path);
405 if (IS_ERR(parent_ref))
407 pr_dinfo2(dcache,
"failed to resolve parent of '%s', file not found", path);
411 if (last_segment ==
NULL)
414 pr_dinfo2(dcache,
"path '%s' is a single '/' or is empty", path);
419 return ERR_PTR(-EISDIR);
425 bool symlink =
false;
428 if (IS_ERR(child_ref) || symlink)
#define MOS_ASSERT_X(cond, msg,...)
#define MOS_UNREACHABLE()
#define mos_warn(fmt,...)
#define MOS_PATH_MAX_LENGTH
static dentry_t * dentry_resolve_follow_symlink(dentry_t *dentry, lastseg_resolve_flags_t flags)
static dentry_t * dentry_resolve_to_parent(dentry_t *base_dir, dentry_t *root_dir, const char *original_path, char **last_seg_out)
Lookup the parent directory of a given path, and return the last segment of the path in last_seg_out.
static dentry_t * dentry_resolve_lastseg(dentry_t *parent, char *leaf, lastseg_resolve_flags_t flags, bool *symlink_resolved)
static void dirter_add(vfs_listdir_state_t *state, u64 ino, const char *name, size_t name_len, file_type_t type)
void dentry_attach(dentry_t *d, inode_t *inode)
Attach an inode to a dentry.
dentry_t * dentry_from_fd(fd_t fd)
Get the dentry from a file descriptor.
dentry_t * dentry_ref_up_to(dentry_t *dentry, dentry_t *root)
Increment the reference count of a dentry up to a given dentry.
should_inline bool path_is_absolute(const char *path)
Check if a path is absolute.
void dentry_detach(dentry_t *d)
Detach the inode from a dentry.
void dentry_try_release(dentry_t *dentry)
void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state)
List the contents of a directory.
dentry_t * dentry_ref(dentry_t *dentry)
Increment the reference count of a dentry.
should_inline dentry_t * dentry_parent(const dentry_t *dentry)
dentry_t * dentry_resolve(dentry_t *starting_dir, dentry_t *root_dir, const char *path, lastseg_resolve_flags_t flags)
Lookup a path in the filesystem.
dentry_t * dentry_lookup_child(dentry_t *parent, const char *name)
Get a child dentry from a parent dentry.
void dentry_unref(dentry_t *dentry)
Decrement the reference count of a dentry.
__nodiscard bool dentry_unref_one_norelease(dentry_t *dentry)
Decrease the refcount of ONE SINGLE dentry, including (if it's a mountpoint) the mountpoint dentry.
@ RESOLVE_SYMLINK_NOFOLLOW
@ RESOLVE_EXPECT_NONEXIST
MOSAPI char * strcat(char *__restrict dest, const char *__restrict src)
MOSAPI char * strcpy(char *__restrict dest, const char *__restrict src)
MOSAPI char * strdup(const char *src)
MOSAPI s32 strncmp(const char *str1, const char *str2, size_t n)
MOSAPI char * strtok_r(char *str, const char *delim, char **saveptr)
MOSAPI s32 strcmp(const char *str1, const char *str2)
MOSAPI char * strndup(const char *src, size_t n)
MOSAPI void(1, 2) fatal_abort(const char *fmt
MOSAPI void linked_list_init(list_node_t *head_node)
Initialise a circular double linked list.
MOSAPI void list_node_append(list_node_t *head, list_node_t *item)
#define list_node(element)
Get the ‘list_node’ of a list element. This is exactly the reverse of ‘list_entry’ above.
void inode_ref(inode_t *inode)
bool inode_unref(inode_t *inode)
#define statement_expr(type,...)
#define container_of(ptr, type, member)
dentry_t * dentry_root_get_mountpoint(dentry_t *dentry)
Given a mounted root dentry, return the mountpoint dentry that points to it.
mount_t * dentry_get_mount(const dentry_t *dentry)
#define mos_panic(fmt,...)
static size_t strlen(const char *s)
#define pr_dinfo2(feat, fmt,...)
io_t * process_get_fd(process_t *process, fd_t fd)
#define spinlock_acquire(lock)
#define spinlock_release(lock)
superblock_t * superblock
size_t(* readlink)(dentry_t *dentry, char *buffer, size_t buflen)
read the contents of a symbolic link
bool(* lookup)(inode_t *dir, dentry_t *dentry)
lookup a file in a directory, if it's unset for a directory, the VFS will use the default lookup
void(* iterate_dir)(dentry_t *dentry, vfs_listdir_state_t *iterator_state, dentry_iterator_op op)
iterate over the contents of a directory
size_t n_count
number of entries in the list
#define dentry_name(dentry)
void vfs_generic_iterate_dir(const dentry_t *dir, vfs_listdir_state_t *state, dentry_iterator_op add_record)
dentry_t * dentry_get_from_parent(superblock_t *sb, dentry_t *parent, const char *name)
Create a new dentry with the given name and parent.