PatchworkOS  c9fea19
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/io.h>
10
11typedef struct path path_t;
12typedef struct mount mount_t;
13typedef struct dentry dentry_t;
14typedef struct namespace namespace_t;
15
16/**
17 * @brief Unique location in the filesystem.
18 * @defgroup kernel_fs_path Path
19 * @ingroup kernel_fs
20 *
21 * A path is a single unique location in the filesystem hierarchy. It consists of a mount and a dentry. The mount is the
22 * filesystem that the path is in and the dentry is the actual location in that filesystem.
23 *
24 * Note how just a dentry is not enough to uniquely identify a location in the filesystem, this is because of
25 * mountpoints. A dentry can exist in a filesystem that is mounted at multiple locations in the filesystem hierarchy,
26 * thus both a mountpoint and a dentry is needed to uniquely identify a location.
27 *
28 * ## Flags/Mode
29 *
30 * Paths can have flags appended at the end, these flags are parsed to determine the mode with which the path is opened.
31 *
32 * Each flag starts with `:` and multiple instances of the same flag are allowed, for example
33 * `/path/to/file:append:append:nonblock`.
34 *
35 * Included is a list of all available flags:
36 *
37 * | Flag | Short | Description |
38 * |------|-------|-------------|
39 * | `read` | `r` | Open with read permissions. |
40 * | `write` | `w` | Open with write permissions. |
41 * | `execute` | `x` | Open with execute permissions. |
42 * | `nonblock` | `n` | The file will not block on operations that would normally block. |
43 * | `append` | `a` | Any data written to the file will be appended to the end. |
44 * | `create` | `c` | Create the file if it does not exist. |
45 * | `exclusive` | `e` | Will cause the open to fail if the file already exists. |
46 * | `truncate` | `t` | Truncate the file to zero length if it already exists. |
47 * | `directory` | `d` | Allow opening directories. |
48 * | `recursive` | `R` | Behaviour differs, but allows for recursive operations, for example when used with `remove` it
49 * will remove directories and their children recursively. |
50 *
51 * For convenience, a single letter short form is also available as shown above, these single letter forms do not need
52 * to be separated by colons, for example `/path/to/file:rwcte` is equivalent to
53 * `/path/to/file:read:write:create:truncate:exclusive`.
54 *
55 * The parsed mode is the primary way to handle both the behaviour of opened paths and permissions through out the
56 * kernel. For example, a file opened from within a directory which was bound with only read permissions will also have
57 * read only permissions, even if the file itself would allow write permissions.
58 *
59 * If no permissions, i.e. read, write or execute, are specified, the default is to open with the maximum currently
60 * allowed permissions.
61 *
62 * @see kernel_fs_namespace for information on mode inheritance when binding paths.
63 *
64 * @{
65 */
66
67/**
68 * @brief Path flags and permissions.
69 * @enum mode_t
70 *
71 * We store both flags and permissions in the same enum but permissions are sometimes treated differently to flags.
72 */
73typedef enum mode
74{
76 MODE_READ = 1 << 0,
77 MODE_WRITE = 1 << 1,
78 MODE_EXECUTE = 1 << 2,
79 MODE_NONBLOCK = 1 << 3,
80 MODE_APPEND = 1 << 4,
81 MODE_CREATE = 1 << 5,
83 MODE_TRUNCATE = 1 << 7,
88} mode_t;
89
90/**
91 * @brief Defer path put.
92 *
93 * This macro will call `path_put()` on the given path when it goes out of scope.
94 *
95 * @param path The path to defer.
96 */
97#define PATH_DEFER(path) __attribute__((cleanup(path_defer_cleanup))) path_t* CONCAT(i, __COUNTER__) = (path)
98
99/**
100 * @brief Check if a char is valid.
101 *
102 * A valid char is one of the following `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.
103 * ()[]{}~!@#$%^&?',;=+`.
104 *
105 * @todo Replace with array lookup.
106 *
107 * @param ch The char to check.
108 * @return true if the char is valid, false otherwise.
109 */
110#define PATH_VALID_CHAR(ch) \
111 (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. ()[]{}~!@#$%^&?',;=+", (ch)))
112
113/**
114 * @brief Maximum iterations to handle `..` in a path.
115 *
116 * This is to prevent infinite loops in case of a corrupted filesystem.
117 */
118#define PATH_HANDLE_DOTDOT_MAX_ITER 1000
119
120/**
121 * @brief Path structure.
122 * @struct path_t
123 */
124typedef struct path
125{
128} path_t;
129
130/**
131 * @brief Pathname structure.
132 * @struct pathname_t
133 *
134 * A pathname is a string representation of a path.
135 */
136typedef struct pathname
137{
138 char string[MAX_PATH];
141} pathname_t;
142
143/**
144 * @brief Check if a pathname is valid.
145 *
146 * A valid pathname is not `NULL` and has its `isValid` flag set to true.
147 *
148 * This flag is set in `pathname_init()`.
149 *
150 * @param pathname The pathname to check.
151 * @return true if the pathname is valid, false otherwise.
152 */
153#define PATHNAME_IS_VALID(pathname) ((pathname) != NULL && (pathname)->isValid)
154
155/**
156 * @brief Helper to create a pathname.
157 *
158 * This macro will create a pathname on the stack and initialize it with the given string.
159 *
160 * This is also the reason we have the `isValid` flag in the `pathname_t` structure, to be able to check if this macro
161 * failed without having to return an error code, streamlining the code a bit.
162 *
163 * @param string The string to initialize the pathname with.
164 * @return The initialized pathname.
165 */
166#define PATHNAME(string) \
167 ({ \
168 pathname_t* pathname = alloca(sizeof(pathname_t)); \
169 pathname_init(pathname, string); \
170 pathname; \
171 })
172
173/**
174 * @brief Initialize a pathname.
175 *
176 * If the string is invalid, it will error and set pathname->isValid to false.
177 *
178 * @param pathname The pathname to initialize.
179 * @param string The string to initialize the pathname with.
180 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
181 * - `EINVAL`: Invalid parameters.
182 * - `ENAMETOOLONG`: The string is too long or a component name is too long.
183 */
184uint64_t pathname_init(pathname_t* pathname, const char* string);
185
186/**
187 * @brief Helper to create an empty path.
188 *
189 * Its important to always use this as some functions, for example `path_copy()`, will deref the existing mount and
190 * dentry in the path.
191 *
192 * @return An empty path.
193 */
194#define PATH_EMPTY \
195 (path_t) \
196 { \
197 .mount = NULL, .dentry = NULL \
198 }
199
200/**
201 * @brief Helper to create a path.
202 *
203 * @param inMount The mount of the path.
204 * @param inDentry The dentry of the path.
205 * @return The created path.
206 */
207#define PATH_CREATE(inMount, inDentry) \
208 (path_t) \
209 { \
210 .mount = REF(inMount), .dentry = REF(inDentry), \
211 }
212
213/**
214 * @brief Set a path.
215 *
216 * Will deref the existing mount and dentry in the path if they are not `NULL`.
217 *
218 * @param path The path to set.
219 * @param mount The mount to set.
220 * @param dentry The dentry to set.
221 */
222void path_set(path_t* path, mount_t* mount, dentry_t* dentry);
223
224/**
225 * @brief Copy a path.
226 *
227 * Will deref the existing mount and dentry in the destination path if they are not `NULL`.
228 *
229 * @param dest The destination path.
230 * @param src The source path.
231 */
232void path_copy(path_t* dest, const path_t* src);
233
234/**
235 * @brief Put a path.
236 *
237 * Will deref the mount and dentry in the path if they are not `NULL`.
238 *
239 * @param path The path to put.
240 */
241void path_put(path_t* path);
242
243/**
244 * @brief Walk a single step in a path.
245 *
246 * @param path The path to traverse, will be updated to the new path, may be negative.
247 * @param name The name of the child dentry.
248 * @param ns The namespace to access mountpoints.
249 * @return On success, `0`. On failure, `ERR` and `errno` is set.
250 */
251uint64_t path_step(path_t* path, const char* name, namespace_t* ns);
252
253/**
254 * @brief Walk a pathname to a path.
255 *
256 * @param path The path to start from, will be updated to the new path, may be negative.
257 * @param pathname The pathname to walk to.
258 * @param ns The namespace to access mountpoints.
259 * @return On success, `0`. On failure, `ERR` and `errno` is set.
260 */
261uint64_t path_walk(path_t* path, const pathname_t* pathname, namespace_t* ns);
262
263/**
264 * @brief Walk a pathname to its parent and get the name of the last component.
265 *
266 * Will not modify `outParent` and `outChild` on failure.
267
268 * @param path The path to start from, will be updated to the parent path.
269 * @param pathname The pathname to traverse.
270 * @param outLastName The output last component name, must be at least `MAX_NAME` bytes.
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(path_t* path, const pathname_t* pathname, char* outLastName, namespace_t* ns);
275
276/**
277 * @brief Traverse a pathname to its parent and child paths.
278 *
279 * Will not modify `outParent` and `outChild` on failure.
280 *
281 * @param from The path to start from.
282 * @param outParent The output parent path.
283 * @param outChild The output child path, may be negative.
284 * @param pathname The pathname to traverse.
285 * @param ns The namespace to access mountpoints.
286 * @return On success, `0`. On failure, `ERR` and `errno` is set.
287 */
288uint64_t path_walk_parent_and_child(const path_t* from, path_t* outParent, path_t* outChild, const pathname_t* pathname,
289 namespace_t* ns);
290
291/**
292 * @brief Convert a path to a pathname.
293 *
294 * The resulting pathname will be absolute.
295 *
296 * @param path The path to convert.
297 * @param pathname The output pathname.
298 * @return On success, `0`. On failure, `ERR` and `errno` is set.
299 */
300uint64_t path_to_name(const path_t* path, pathname_t* pathname);
301
302static inline void path_defer_cleanup(path_t** path)
303{
304 if (*path != NULL)
305 {
306 path_put(*path);
307 }
308}
309
310/** @} */
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
static void path_defer_cleanup(path_t **path)
Definition path.h:302
mode_t
Path flags and permissions.
Definition path.h:74
void path_put(path_t *path)
Put a path.
Definition path.c:246
uint64_t path_step(path_t *path, const char *name, namespace_t *ns)
Walk a single step in a path.
Definition path.c:323
void path_set(path_t *path, mount_t *mount, dentry_t *dentry)
Set a path.
Definition path.c:196
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:440
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:497
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:347
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:89
void path_copy(path_t *dest, const path_t *src)
Copy a path.
Definition path.c:221
uint64_t path_to_name(const path_t *path, pathname_t *pathname)
Convert a path to a pathname.
Definition path.c:522
@ MODE_ALL_PERMS
Definition path.h:87
@ MODE_AMOUNT
Definition path.h:86
@ MODE_CREATE
Definition path.h:81
@ MODE_NONE
Definition path.h:75
@ MODE_APPEND
Definition path.h:80
@ MODE_EXECUTE
Definition path.h:78
@ MODE_NONBLOCK
Definition path.h:79
@ MODE_TRUNCATE
Definition path.h:83
@ MODE_WRITE
Definition path.h:77
@ MODE_RECURSIVE
Definition path.h:85
@ MODE_READ
Definition path.h:76
@ MODE_EXCLUSIVE
Definition path.h:82
@ MODE_DIRECTORY
Definition path.h:84
#define NULL
Pointer error value.
Definition NULL.h:23
static mount_t * mount
Definition ramfs.c:28
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
Directory entry structure.
Definition dentry.h:84
Mount structure.
Definition mount.h:44
Namespace structure.
Path structure.
Definition path.h:125
mount_t * mount
Definition path.h:126
dentry_t * dentry
Definition path.h:127
Pathname structure.
Definition path.h:137
mode_t mode
Definition path.h:139
bool isValid
Definition path.h:140