1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#pragma once
4
5#include <mos/filesystem/fs_types.h>
6#include <mos/filesystem/vfs_types.h>
7#include <mos/lib/structures/list.h>
8#include <mos/mos_global.h>
9
10/**
11 * @defgroup dentry Directory Entry
12 * @brief Directory entry
13 * @ingroup vfs
14 *
15 * @details
16 * A dentry is a directory entry, it is a reference to an inode.
17 *
18 * dentry cache policy: The function who references the dentry should be
19 * responsible for unrefing it.
20 *
21 * All existing files' dentries have a reference count of 0 at the start.
22 * When a file is opened, the dentry will be referenced, and the reference
23 * count will be incremented by 1.
24 *
25 * For all directories, the initial reference count is also 0, but when
26 * a directory is opened, the reference count will be incremented by 1.
27 *
28 * When mounting a filesystem, the root dentry of the filesystem is
29 * inserted into the dentry cache, and will have a reference count of 1.
30 * The mountpoint itself will have its reference count incremented by 1.
31 *
32 * For the root dentry ("/"), the reference count is 2, one for the mountpoint,
33 * and one for the dentry cache.
34 * @{
35 */
36
37typedef enum
38{
39 // bit 0, 1: the operation only succeeds if the inode is a...
40 RESOLVE_EXPECT_FILE = 1 << 0,
41 RESOLVE_EXPECT_DIR = 1 << 1,
42 RESOLVE_EXPECT_ANY_TYPE = RESOLVE_EXPECT_FILE | RESOLVE_EXPECT_DIR,
43
44 // bit 2: follow symlinks?
45 // only for the last segment, (if it is a symlink)
46 RESOLVE_SYMLINK_NOFOLLOW = 1 << 2,
47
48 // bit 3, 4: the operation only succeeds if...
49 RESOLVE_EXPECT_EXIST = 1 << 3,
50 RESOLVE_EXPECT_NONEXIST = 1 << 4,
51 RESOLVE_EXPECT_ANY_EXIST = RESOLVE_EXPECT_EXIST | RESOLVE_EXPECT_NONEXIST,
52} lastseg_resolve_flags_t;
53
54/**
55 * @brief Check if a path is absolute
56 *
57 * @param path The path to check
58 * @return true if the path is absolute (starts with a '/'), false otherwise
59 */
60should_inline bool path_is_absolute(const char *path)
61{
62 return path[0] == '/';
63}
64
65should_inline dentry_t *dentry_parent(const dentry_t *dentry)
66{
67 return tree_parent(dentry, dentry_t);
68}
69
70/**
71 * @brief Check the reference count of a dentry
72 *
73 * @param dentry The dentry to check
74 */
75void dentry_check_refstat(const dentry_t *dentry);
76typedef void(dump_refstat_receiver_t)(int depth, const dentry_t *dentry, bool mountroot, void *data);
77void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t receiver, void *data);
78
79/**
80 * @brief Increment the reference count of a dentry
81 *
82 * @param dentry The dentry to increment the reference count of
83 * @return the dentry itself
84 */
85dentry_t *dentry_ref(dentry_t *dentry);
86
87/**
88 * @brief Increment the reference count of a dentry up to a given dentry
89 *
90 * @param dentry The dentry to increment the reference count of
91 * @param root The dentry to stop at
92 * @return dentry_t* The dentry itself
93 */
94dentry_t *dentry_ref_up_to(dentry_t *dentry, dentry_t *root);
95
96/**
97 * @brief Decrement the reference count of a dentry
98 *
99 * @param dentry The dentry to decrement the reference count of
100 */
101void dentry_unref(dentry_t *dentry);
102__nodiscard bool dentry_unref_one_norelease(dentry_t *dentry);
103void dentry_try_release(dentry_t *dentry);
104
105/**
106 * @brief Attach an inode to a dentry
107 *
108 * @param d The dentry to attach the inode to
109 * @param inode The inode to attach
110 */
111void dentry_attach(dentry_t *d, inode_t *inode);
112
113/**
114 * @brief Detach the inode from a dentry
115 *
116 * @param dentry The dentry to detach the inode from
117 */
118void dentry_detach(dentry_t *dentry);
119
120/**
121 * @brief Get the dentry from a file descriptor
122 *
123 * @param fd The file descriptor, there's a special case for AT_FDCWD, which corresponds to the process's current working directory
124 *
125 * @return The dentry associated with the file descriptor, or NULL if the file descriptor is invalid
126 */
127dentry_t *dentry_from_fd(fd_t fd);
128
129/**
130 * @brief Get a child dentry from a parent dentry
131 *
132 * @param parent The parent dentry
133 * @param name The name of the child dentry
134 *
135 * @return The child dentry, always non-NULL, even if the child dentry does not exist in the filesystem
136 * @note The returned dentry will have its reference count incremented, even if it does not exist.
137 */
138dentry_t *dentry_lookup_child(dentry_t *parent, const char *name);
139
140/**
141 * @brief Lookup a path in the filesystem
142 *
143 * @details If the path is absolute, the base is ignored and the path starts from the root_dir
144 * If the path is relative, the base is used as the starting points
145 *
146 * @param starting_dir The starting directory when resolving a [relative] path
147 * @param root_dir the root directory when resolving the path, the resolved path will not go above this directory
148 * @param path The path to resolve, can be absolute or relative
149 * @param flags Flags to control the behavior of the path resolution, see \ref lastseg_resolve_flags_t
150 *
151 * @return The parent directory (if such a parent exists) containing (or to contain) the last segment of the path, or
152 * NULL if any intermediate directory in the path does not exist.
153 *
154 */
155dentry_t *dentry_resolve(dentry_t *starting_dir, dentry_t *root_dir, const char *path, lastseg_resolve_flags_t flags);
156
157/**
158 * @brief Mount a filesystem at a mountpoint
159 *
160 * @param mountpoint The mountpoint
161 * @param root The root directory of the filesystem
162 * @param fs The filesystem to mount
163 *
164 * @return true if the filesystem was mounted successfully, false otherwise
165 */
166__nodiscard bool dentry_mount(dentry_t *mountpoint, dentry_t *root, filesystem_t *fs);
167
168/**
169 * @brief Unmount a filesystem at the mountpoint
170 *
171 * @return __nodiscard
172 */
173__nodiscard dentry_t *dentry_unmount(dentry_t *root);
174
175/**
176 * @brief List the contents of a directory
177 *
178 * @param dir The directory to list
179 * @param state The state of the directory iterator
180 */
181void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state);
182
183/**
184 * @brief Get the path of a dentry
185 *
186 * @param dentry The dentry to get the path of
187 * @param root The root directory, the path will not go above this directory
188 * @param buf The buffer to write the path to
189 * @param size The size of the buffer
190 * @return ssize_t
191 */
192ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size);
193
194/**@}*/
195