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 | |
37 | typedef 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 | */ |
60 | should_inline bool path_is_absolute(const char *path) |
61 | { |
62 | return path[0] == '/'; |
63 | } |
64 | |
65 | should_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 | */ |
75 | void dentry_check_refstat(const dentry_t *dentry); |
76 | typedef void(dump_refstat_receiver_t)(int depth, const dentry_t *dentry, bool mountroot, void *data); |
77 | void 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 | */ |
85 | dentry_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 | */ |
94 | dentry_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 | */ |
101 | void dentry_unref(dentry_t *dentry); |
102 | __nodiscard bool dentry_unref_one_norelease(dentry_t *dentry); |
103 | void 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 | */ |
111 | void 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 | */ |
118 | void 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 | */ |
127 | dentry_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 | */ |
138 | dentry_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 | */ |
155 | dentry_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 | */ |
181 | void 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 | */ |
192 | ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size); |
193 | |
194 | /**@}*/ |
195 | |