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.hpp> |
7 | #include <mos/lib/structures/list.hpp> |
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 | MOS_ENUM_OPERATORS(lastseg_resolve_flags_t) |
55 | |
56 | /** |
57 | * @brief Check if a path is absolute |
58 | * |
59 | * @param path The path to check |
60 | * @return true if the path is absolute (starts with a '/'), false otherwise |
61 | */ |
62 | should_inline bool path_is_absolute(const char *path) |
63 | { |
64 | return path[0] == '/'; |
65 | } |
66 | |
67 | should_inline dentry_t *dentry_parent(const dentry_t &dentry) |
68 | { |
69 | return tree_parent(&dentry, dentry_t); |
70 | } |
71 | |
72 | /** |
73 | * @brief Check the reference count of a dentry |
74 | * |
75 | * @param dentry The dentry to check |
76 | */ |
77 | void dentry_check_refstat(const dentry_t *dentry); |
78 | typedef void(dump_refstat_receiver_t)(int depth, const dentry_t *dentry, bool mountroot, void *data); |
79 | void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t receiver, void *data); |
80 | |
81 | /** |
82 | * @brief Increment the reference count of a dentry |
83 | * |
84 | * @param dentry The dentry to increment the reference count of |
85 | * @return the dentry itself |
86 | */ |
87 | dentry_t *dentry_ref(dentry_t *dentry); |
88 | |
89 | /** |
90 | * @brief Increment the reference count of a dentry up to a given dentry |
91 | * |
92 | * @param dentry The dentry to increment the reference count of |
93 | * @param root The dentry to stop at |
94 | * @return dentry_t* The dentry itself |
95 | */ |
96 | dentry_t *dentry_ref_up_to(dentry_t *dentry, dentry_t *root); |
97 | |
98 | /** |
99 | * @brief Decrement the reference count of a dentry |
100 | * |
101 | * @param dentry The dentry to decrement the reference count of |
102 | */ |
103 | void dentry_unref(dentry_t *dentry); |
104 | __nodiscard bool dentry_unref_one_norelease(dentry_t *dentry); |
105 | void dentry_try_release(dentry_t *dentry); |
106 | |
107 | /** |
108 | * @brief Attach an inode to a dentry |
109 | * |
110 | * @param d The dentry to attach the inode to |
111 | * @param inode The inode to attach |
112 | */ |
113 | void dentry_attach(dentry_t *d, inode_t *inode); |
114 | |
115 | /** |
116 | * @brief Detach the inode from a dentry |
117 | * |
118 | * @param dentry The dentry to detach the inode from |
119 | */ |
120 | void dentry_detach(dentry_t *dentry); |
121 | |
122 | /** |
123 | * @brief Get the dentry from a file descriptor |
124 | * |
125 | * @param fd The file descriptor, there's a special case for AT_FDCWD, which corresponds to the process's current working directory |
126 | * |
127 | * @return The dentry associated with the file descriptor, or NULL if the file descriptor is invalid |
128 | */ |
129 | PtrResult<dentry_t> dentry_from_fd(fd_t fd); |
130 | |
131 | /** |
132 | * @brief Get a child dentry from a parent dentry |
133 | * |
134 | * @param parent The parent dentry |
135 | * @param name The name of the child dentry |
136 | * |
137 | * @return The child dentry, always non-NULL, even if the child dentry does not exist in the filesystem |
138 | * @note The returned dentry will have its reference count incremented, even if it does not exist. |
139 | */ |
140 | PtrResult<dentry_t> dentry_lookup_child(dentry_t *parent, const char *name); |
141 | |
142 | /** |
143 | * @brief Lookup a path in the filesystem |
144 | * |
145 | * @details If the path is absolute, the base is ignored and the path starts from the root_dir |
146 | * If the path is relative, the base is used as the starting points |
147 | * |
148 | * @param starting_dir The starting directory when resolving a [relative] path |
149 | * @param root_dir the root directory when resolving the path, the resolved path will not go above this directory |
150 | * @param path The path to resolve, can be absolute or relative |
151 | * @param flags Flags to control the behavior of the path resolution, see \ref lastseg_resolve_flags_t |
152 | * |
153 | * @return The parent directory (if such a parent exists) containing (or to contain) the last segment of the path, or |
154 | * NULL if any intermediate directory in the path does not exist. |
155 | * |
156 | */ |
157 | PtrResult<dentry_t> dentry_resolve(dentry_t *starting_dir, dentry_t *root_dir, const char *path, lastseg_resolve_flags_t flags); |
158 | |
159 | /** |
160 | * @brief Mount a filesystem at a mountpoint |
161 | * |
162 | * @param mountpoint The mountpoint |
163 | * @param root The root directory of the filesystem |
164 | * @param fs The filesystem to mount |
165 | * |
166 | * @return true if the filesystem was mounted successfully, false otherwise |
167 | */ |
168 | __nodiscard bool dentry_mount(dentry_t *mountpoint, dentry_t *root, filesystem_t *fs); |
169 | |
170 | /** |
171 | * @brief Unmount a filesystem at the mountpoint |
172 | * |
173 | * @return __nodiscard |
174 | */ |
175 | __nodiscard dentry_t *dentry_unmount(dentry_t *root); |
176 | |
177 | /** |
178 | * @brief List the contents of a directory |
179 | * |
180 | * @param dir The directory to list |
181 | * @param state The state of the directory iterator |
182 | */ |
183 | void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state); |
184 | |
185 | /** |
186 | * @brief Get the path of a dentry |
187 | * |
188 | * @param dentry The dentry to get the path of |
189 | * @param root The root directory, the path will not go above this directory |
190 | * @param buf The buffer to write the path to |
191 | * @param size The size of the buffer |
192 | * @return ssize_t |
193 | */ |
194 | ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size); |
195 | |
196 | /**@}*/ |
197 | |