PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
path.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/utils/map.h>
4
5#include <alloca.h>
6#include <ctype.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <sys/fs.h>
10
11typedef struct path path_t;
12typedef struct mount mount_t;
13typedef struct dentry dentry_t;
14typedef struct namespace namespace_t;
15typedef struct file file_t;
16
17// clang-format off
18/**
19 * @brief Unique location in the filesystem.
20 * @defgroup kernel_fs_path Path
21 * @ingroup kernel_fs
22 *
23 * A path is a single unique location in the filesystem hierarchy. It consists of a mount and a dentry. The mount is the
24 * filesystem that the path is in and the dentry is the actual location in that filesystem.
25 *
26 * Note how just a dentry is not enough to uniquely identify a location in the filesystem, this is because of
27 * mountpoints. A dentry can exist in a filesystem that is mounted at multiple locations in the filesystem hierarchy,
28 * thus both a mountpoint and a dentry is needed to uniquely identify a location.
29 *
30 * ## Flags/Mode
31 *
32 * Paths can have flags appended at the end, these flags are parsed to determine the mode of the related operation.
33 *
34 * Each flag starts with `:` and multiple instances of the same flag are allowed, for example
35 * `/path/to/file:append:append:nonblock`.
36 *
37 * Included is a list of all available flags:
38 *
39 * | Flag | Short | Description |
40 * |------|-------|-------------|
41 * | `read` | `r` | Open with read permissions. |
42 * | `write` | `w` | Open with write permissions. |
43 * | `execute` | `x` | Open with execute permissions. |
44 * | `nonblock` | `n` | The file will not block on operations that would normally block. |
45 * | `append` | `a` | Any data written to the file will be appended to the end. |
46 * | `create` | `c` | Create the file or directory if it does not exist. |
47 * | `exclusive` | `e` | Will cause the open to fail if the file or directory already exists and `:create` is specified. |
48 * | `parents` | `p` | Create any parent directories if they do not exist when creating a file or directory. |
49 * | `truncate` | `t` | Truncate the file to zero length if it already exists. |
50 * | `directory` | `d` | Create or remove directories. All other operations will ignore this flag. |
51 * | `recursive` | `R` | If removing a directory, remove all its contents recursively. If using `getdents()`, list contents recursively. |
52 * | `nofollow` | `l` | Do not follow symbolic links. |
53 * | `private` | `P` | Any files with this flag will be closed before a process starts executing. Any mounts with this flag will not be copied to a child namespace. |
54 * | `propagate` | `g` | Propagate mounts and unmounts to child namespaces. |
55 * | `locked` | `L` | Forbid unmounting this mount, useful for hiding directories or files. |
56 *
57 * For convenience, a single letter short form is also available as shown above, these single letter forms do not need
58 * to be separated by colons, for example `/path/to/file:rwcte` is equivalent to
59 * `/path/to/file:read:write:create:truncate:exclusive`.
60 *
61 * The parsed mode is the primary way to handle both the behaviour of vfs operations and permissions in the
62 * kernel. For example, a file opened from within a directory which was bound with only read permissions will also have
63 * read only permissions, even if the file itself would allow write permissions.
64 *
65 * If no permissions, i.e. read, write or execute, are specified, the default is to open with the maximum currently
66 * allowed permissions.
67 *
68 * @{
69 */
70// clang-format on
71
72/**
73 * @brief Path flags and permissions.
74 * @enum mode_t
75 *
76 * We store both flags and permissions in the same enum but permissions are sometimes treated differently to flags.
77 */
78typedef enum mode
79{
81 MODE_READ = 1 << 0,
82 MODE_WRITE = 1 << 1,
83 MODE_EXECUTE = 1 << 2,
84 MODE_NONBLOCK = 1 << 3,
85 MODE_APPEND = 1 << 4,
86 MODE_CREATE = 1 << 5,
88 MODE_PARENTS = 1 << 7,
89 MODE_TRUNCATE = 1 << 8,
91 MODE_RECURSIVE = 1 << 10,
92 MODE_NOFOLLOW = 1 << 11,
93 MODE_PRIVATE = 1 << 12,
94 MODE_PROPAGATE = 1 << 13,
95 MODE_LOCKED = 1 << 14,
97} mode_t;
98
99/**
100 * @brief Defer path put.
101 *
102 * This macro will call `path_put()` on the given path when it goes out of scope.
103 *
104 * @param path The path to defer.
105 */
106#define PATH_DEFER(path) __attribute__((cleanup(path_defer_cleanup))) path_t* CONCAT(i, __COUNTER__) = (path)
107
108/**
109 * @brief Maximum iterations to handle `..` in a path.
110 *
111 * This is to prevent infinite loops.
112 */
113#define PATH_MAX_DOTDOT 1000
114
115/**
116 * @brief Maximum iterations to handle symlinks in a path.
117 *
118 * This is to prevent infinite loops.
119 */
120#define PATH_MAX_SYMLINK 40
121
122/**
123 * @brief Path structure.
124 * @struct path_t
125 */
126typedef struct path
127{
130} path_t;
131
132/**
133 * @brief Pathname structure.
134 * @struct pathname_t
135 *
136 * A pathname is a string representation of a path.
137 */
138typedef struct pathname
139{
140 char string[MAX_PATH];
142} pathname_t;
143
144/**
145 * @brief Initialize a pathname.
146 *
147 * @param pathname The pathname to initialize.
148 * @param string The string to initialize the pathname with.
149 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
150 * - `EINVAL`: Invalid parameters.
151 * - `ENAMETOOLONG`: The string is too long or a component name is too long.
152 */
153uint64_t pathname_init(pathname_t* pathname, const char* string);
154
155/**
156 * @brief Helper to create an empty path.
157 *
158 * Its important to always use this as some functions, for example `path_copy()`, will deref the existing mount and
159 * dentry in the path.
160 *
161 * @return An empty path.
162 */
163#define PATH_EMPTY \
164 (path_t) \
165 { \
166 .mount = NULL, .dentry = NULL \
167 }
168
169/**
170 * @brief Helper to create a path.
171 *
172 * @param inMount The mount of the path.
173 * @param inDentry The dentry of the path.
174 * @return The created path.
175 */
176#define PATH_CREATE(inMount, inDentry) \
177 (path_t) \
178 { \
179 .mount = REF(inMount), .dentry = REF(inDentry), \
180 }
181
182/**
183 * @brief Check if a path is empty.
184 *
185 * @param path The path to check.
186 * @return true if the path is empty, false otherwise.
187 */
188#define PATH_IS_EMPTY(path) ((path).mount == NULL && (path).dentry == NULL)
189
190/**
191 * @brief Check if a path is valid.
192 *
193 * @param path The path to check.
194 * @return true if the path is valid, false otherwise.
195 */
196#define PATH_IS_VALID(path) ((path) != NULL && (path)->mount != NULL && (path)->dentry != NULL)
197
198/**
199 * @brief Set a path.
200 *
201 * Will deref the existing mount and dentry in the path if they are not `NULL`.
202 *
203 * @param path The path to set.
204 * @param mount The mount to set.
205 * @param dentry The dentry to set.
206 */
207void path_set(path_t* path, mount_t* mount, dentry_t* dentry);
208
209/**
210 * @brief Copy a path.
211 *
212 * Will deref the existing mount and dentry in the destination path if they are not `NULL`.
213 *
214 * @param dest The destination path.
215 * @param src The source path.
216 */
217void path_copy(path_t* dest, const path_t* src);
218
219/**
220 * @brief Put a path.
221 *
222 * Will deref the mount and dentry in the path if they are not `NULL`.
223 *
224 * @param path The path to put.
225 */
226void path_put(path_t* path);
227
228/**
229 * @brief Walk a single path component.
230 *
231 * @param path The path to step from, will be updated to the new path, may be negative.
232 * @param mode The mode to open the new path with.
233 * @param name The name of the new path component.
234 * @param ns The namespace to access mountpoints.
235 * @return On success, `0`. On failure, `ERR` and `errno` is set.
236 */
237uint64_t path_step(path_t* path, mode_t mode, const char* name, namespace_t* ns);
238
239/**
240 * @brief Walk a pathname to a path.
241 *
242 * @param path The path to start from, will be updated to the new path, may be negative.
243 * @param pathname The pathname to walk to.
244 * @param ns The namespace to access mountpoints.
245 * @return On success, `0`. On failure, `ERR` and `errno` is set.
246 */
247uint64_t path_walk(path_t* path, const pathname_t* pathname, namespace_t* ns);
248
249/**
250 * @brief Walk a pathname to its parent and get the name of the last component.
251 *
252 * Will not modify `outParent` and `outChild` on failure.
253
254 * @param path The path to start from, will be updated to the parent path.
255 * @param pathname The pathname to traverse.
256 * @param outLastName The output last component name, must be at least `MAX_NAME` bytes.
257 * @param ns The namespace to access mountpoints.
258 * @return On success, `0`. On failure, `ERR` and `errno` is set.
259 */
260uint64_t path_walk_parent(path_t* path, const pathname_t* pathname, char* outLastName, namespace_t* ns);
261
262/**
263 * @brief Traverse a pathname to its parent and child paths.
264 *
265 * Will not modify `outParent` and `outChild` on failure.
266 *
267 * @param from The path to start from.
268 * @param outParent The output parent path.
269 * @param outChild The output child path, may be negative.
270 * @param pathname The pathname to traverse.
271 * @param ns The namespace to access mountpoints.
272 * @return On success, `0`. On failure, `ERR` and `errno` is set.
273 */
274uint64_t path_walk_parent_and_child(const path_t* from, path_t* outParent, path_t* outChild, const pathname_t* pathname,
275 namespace_t* ns);
276
277/**
278 * @brief Convert a path to a pathname.
279 *
280 * The resulting pathname will be absolute.
281 *
282 * @param path The path to convert.
283 * @param pathname The output pathname.
284 * @return On success, `0`. On failure, `ERR` and `errno` is set.
285 */
286uint64_t path_to_name(const path_t* path, pathname_t* pathname);
287
288/**
289 * @brief Convert a mode to a string representation.
290 *
291 * The resulting string will be null terminated.
292 *
293 * @param mode The mode to convert.
294 * @param out The output string buffer.
295 * @param length The length of the output string buffer.
296 * @return On success, the length of the resulting string, excluding the null terminator. On failure, `ERR` and `errno`
297 * is set to:
298 * - `EINVAL`: Invalid parameters.
299 * - `ENAMETOOLONG`: The output buffer is too small.
300 */
301uint64_t mode_to_string(mode_t mode, char* out, uint64_t length);
302
303/**
304 * @brief Check and adjust mode permissions.
305 *
306 * If no permissions are set in the mode, it will be adjusted to have the maximum allowed permissions.
307 *
308 * @param mode The mode to check and adjust.
309 * @param maxPerms The maximum allowed permissions.
310 * @return On success, the adjusted mode. On failure, `ERR` and `errno` is set to:
311 * - `EINVAL`: Invalid parameters.
312 * - `EACCES`: Requested permissions exceed maximum allowed permissions.
313 */
314uint64_t mode_check(mode_t* mode, mode_t maxPerms);
315
316static inline void path_defer_cleanup(path_t** path)
317{
318 if (*path != NULL)
319 {
320 path_put(*path);
321 }
322}
323
324/** @} */
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
static void path_defer_cleanup(path_t **path)
Definition path.h:316
mode_t
Path flags and permissions.
Definition path.h:79
void path_put(path_t *path)
Put a path.
Definition path.c:273
uint64_t mode_check(mode_t *mode, mode_t maxPerms)
Check and adjust mode permissions.
Definition path.c:816
uint64_t mode_to_string(mode_t mode, char *out, uint64_t length)
Convert a mode to a string representation.
Definition path.c:784
uint64_t path_step(path_t *path, mode_t mode, const char *name, namespace_t *ns)
Walk a single path component.
Definition path.c:553
void path_set(path_t *path, mount_t *mount, dentry_t *dentry)
Set a path.
Definition path.c:242
uint64_t path_walk_parent(path_t *path, const pathname_t *pathname, char *outLastName, namespace_t *ns)
Walk a pathname to its parent and get the name of the last component.
Definition path.c:633
uint64_t path_walk_parent_and_child(const path_t *from, path_t *outParent, path_t *outChild, const pathname_t *pathname, namespace_t *ns)
Traverse a pathname to its parent and child paths.
Definition path.c:690
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:593
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:116
void path_copy(path_t *dest, const path_t *src)
Copy a path.
Definition path.c:268
uint64_t path_to_name(const path_t *path, pathname_t *pathname)
Convert a path to a pathname.
Definition path.c:715
@ MODE_LOCKED
Definition path.h:95
@ MODE_ALL_PERMS
Definition path.h:96
@ MODE_CREATE
Definition path.h:86
@ MODE_NONE
Definition path.h:80
@ MODE_APPEND
Definition path.h:85
@ MODE_PRIVATE
Definition path.h:93
@ MODE_NOFOLLOW
Definition path.h:92
@ MODE_EXECUTE
Definition path.h:83
@ MODE_NONBLOCK
Definition path.h:84
@ MODE_TRUNCATE
Definition path.h:89
@ MODE_WRITE
Definition path.h:82
@ MODE_RECURSIVE
Definition path.h:91
@ MODE_READ
Definition path.h:81
@ MODE_EXCLUSIVE
Definition path.h:87
@ MODE_PROPAGATE
Definition path.h:94
@ MODE_PARENTS
Definition path.h:88
@ MODE_DIRECTORY
Definition path.h:90
uint64_t mount(const char *mountpoint, const char *fs, const char *options)
System call for mounting a filesystem.
Definition mount.c:5
#define NULL
Pointer error value.
Definition NULL.h:25
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
Directory entry structure.
Definition dentry.h:155
File structure.
Definition file.h:39
Mount structure.
Definition mount.h:48
Namespace structure.
Definition namespace.h:57
Path structure.
Definition path.h:127
mount_t * mount
Definition path.h:128
dentry_t * dentry
Definition path.h:129
Pathname structure.
Definition path.h:139
mode_t mode
Definition path.h:141