PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
path.c
Go to the documentation of this file.
1#include <_libstd/MAX_PATH.h>
2#include <kernel/fs/path.h>
3
4#include <kernel/fs/dentry.h>
6#include <kernel/fs/vfs.h>
7#include <kernel/log/log.h>
8#include <kernel/log/panic.h>
9#include <kernel/sync/mutex.h>
10
11#include <errno.h>
12#include <kernel/sync/rcu.h>
13#include <kernel/utils/map.h>
14#include <stdint.h>
15#include <stdlib.h>
16#include <string.h>
17
18typedef struct path_flag_short
19{
22
24 ['r'] = {.mode = MODE_READ},
25 ['w'] = {.mode = MODE_WRITE},
26 ['x'] = {.mode = MODE_EXECUTE},
27 ['n'] = {.mode = MODE_NONBLOCK},
28 ['a'] = {.mode = MODE_APPEND},
29 ['c'] = {.mode = MODE_CREATE},
30 ['e'] = {.mode = MODE_EXCLUSIVE},
31 ['p'] = {.mode = MODE_PARENTS},
32 ['t'] = {.mode = MODE_TRUNCATE},
33 ['d'] = {.mode = MODE_DIRECTORY},
34 ['R'] = {.mode = MODE_RECURSIVE},
35 ['l'] = {.mode = MODE_NOFOLLOW},
36 ['P'] = {.mode = MODE_PRIVATE},
37 ['g'] = {.mode = MODE_PROPAGATE},
38 ['L'] = {.mode = MODE_LOCKED},
39};
40
41typedef struct path_flag
42{
44 const char* name;
46
47static const path_flag_t flags[] = {
48 {.mode = MODE_READ, .name = "read"},
49 {.mode = MODE_WRITE, .name = "write"},
50 {.mode = MODE_EXECUTE, .name = "execute"},
51 {.mode = MODE_NONBLOCK, .name = "nonblock"},
52 {.mode = MODE_APPEND, .name = "append"},
53 {.mode = MODE_CREATE, .name = "create"},
54 {.mode = MODE_EXCLUSIVE, .name = "exclusive"},
55 {.mode = MODE_PARENTS, .name = "parents"},
56 {.mode = MODE_TRUNCATE, .name = "truncate"},
57 {.mode = MODE_DIRECTORY, .name = "directory"},
58 {.mode = MODE_RECURSIVE, .name = "recursive"},
59 {.mode = MODE_NOFOLLOW, .name = "nofollow"},
60 {.mode = MODE_PRIVATE, .name = "private"},
61 {.mode = MODE_PROPAGATE, .name = "propagate"},
62 {.mode = MODE_LOCKED, .name = "locked"},
63};
64
65static mode_t path_flag_to_mode(const char* flag, size_t length)
66{
67 if (flag == NULL || length == 0)
68 {
69 return MODE_NONE;
70 }
71
72 for (size_t i = 0; i < ARRAY_SIZE(flags); i++)
73 {
74 size_t len = strnlen_s(flags[i].name, MAX_NAME);
75 if (len == length && strncmp(flag, flags[i].name, length) == 0)
76 {
77 return flags[i].mode;
78 }
79 }
80
81 mode_t combinedMode = MODE_NONE;
82 for (size_t i = 0; i < length; i++)
83 {
84 if (flag[i] < 0 || (uint8_t)flag[i] >= INT8_MAX)
85 {
86 return MODE_NONE;
87 }
88 mode_t mode = shortFlags[(uint8_t)flag[i]].mode;
89 if (mode == MODE_NONE)
90 {
91 return MODE_NONE;
92 }
93 combinedMode |= mode;
94 }
95
96 return combinedMode;
97}
98
99static inline bool path_is_char_valid(char ch)
100{
101 static const bool forbidden[UINT8_MAX + 1] = {
102 [0 ... 31] = true,
103 ['<'] = true,
104 ['>'] = true,
105 [':'] = true,
106 ['\"'] = true,
107 ['/'] = true,
108 ['\\'] = true,
109 ['|'] = true,
110 ['?'] = true,
111 ['*'] = true,
112 };
113 return !forbidden[(uint8_t)ch];
114}
115
116uint64_t pathname_init(pathname_t* pathname, const char* string)
117{
118 if (pathname == NULL)
119 {
120 errno = EINVAL;
121 return ERR;
122 }
123
124 memset(pathname->string, 0, MAX_PATH);
125 pathname->mode = MODE_NONE;
126
127 if (string == NULL)
128 {
129 errno = EINVAL;
130 return ERR;
131 }
132
133 uint64_t length = strnlen_s(string, MAX_PATH);
134 if (length >= MAX_PATH)
135 {
137 return ERR;
138 }
139
140 uint64_t index = 0;
141 uint64_t currentNameLength = 0;
142 while (string[index] != '\0' && string[index] != ':')
143 {
144 if (string[index] == '/')
145 {
146 currentNameLength = 0;
147 }
148 else
149 {
150 if (!path_is_char_valid(string[index]))
151 {
152 errno = EINVAL;
153 return ERR;
154 }
155 currentNameLength++;
156 if (currentNameLength >= MAX_NAME)
157 {
159 return ERR;
160 }
161 }
162
163 pathname->string[index] = string[index];
164 index++;
165 }
166
167 pathname->string[index] = '\0';
168
169 if (string[index] != ':')
170 {
171 return 0;
172 }
173
174 index++; // Skip ':'.
175 const char* flags = &string[index];
176
177 while (true)
178 {
179 while (string[index] == ':')
180 {
181 index++;
182 }
183
184 if (string[index] == '\0')
185 {
186 break;
187 }
188
189 const char* token = &string[index];
190 while (string[index] != '\0' && string[index] != ':')
191 {
192 if (!isalnum(string[index]))
193 {
194 errno = EINVAL;
195 return ERR;
196 }
197 index++;
198 }
199
200 uint64_t tokenLength = &string[index] - token;
201 if (tokenLength >= MAX_NAME)
202 {
204 return ERR;
205 }
206
207 mode_t mode = path_flag_to_mode(token, tokenLength);
208 if (mode == MODE_NONE)
209 {
210 errno = EINVAL;
211 return ERR;
212 }
213
214 pathname->mode |= mode;
215 }
216
217 return 0;
218}
219
220static bool path_is_name_valid(const char* name)
221{
222 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
223 {
224 return false;
225 }
226
227 for (uint64_t i = 0; i < MAX_NAME - 1; i++)
228 {
229 if (name[i] == '\0')
230 {
231 return true;
232 }
233 if (!path_is_char_valid(name[i]))
234 {
235 return false;
236 }
237 }
238
239 return false;
240}
241
242void path_set(path_t* path, mount_t* mount, dentry_t* dentry)
243{
244 if (dentry != NULL)
245 {
246 REF(dentry);
247 }
248
249 if (mount != NULL)
250 {
251 REF(mount);
252 }
253
254 if (path->dentry != NULL)
255 {
256 UNREF(path->dentry);
257 }
258
259 if (path->mount != NULL)
260 {
261 UNREF(path->mount);
262 }
263
264 path->dentry = dentry;
265 path->mount = mount;
266}
267
268void path_copy(path_t* dest, const path_t* src)
269{
270 path_set(dest, src->mount, src->dentry);
271}
272
273void path_put(path_t* path)
274{
275 if (path->dentry != NULL)
276 {
277 UNREF(path->dentry);
278 path->dentry = NULL;
279 }
280
281 if (path->mount != NULL)
282 {
283 UNREF(path->mount);
284 path->mount = NULL;
285 }
286}
287
298
300
302{
303 if (REF_TRY(ctx->dentry) == NULL)
304 {
305 errno = ENOENT;
306 return ERR;
307 }
308 if (REF_TRY(ctx->mount) == NULL)
309 {
310 UNREF(ctx->dentry);
311 errno = ENOENT;
312 return ERR;
313 }
314
316 return 0;
317}
318
319static inline void path_walk_release(path_walk_ctx_t* ctx)
320{
322
323 UNREF(ctx->dentry);
324 UNREF(ctx->mount);
325}
326
327static inline void path_walk_set_lookup(path_walk_ctx_t* ctx, dentry_t* dentry)
328{
329 if (ctx->lookup != NULL)
330 {
331 UNREF(ctx->lookup);
332 }
333 ctx->lookup = dentry;
334}
335
336static inline void path_walk_cleanup(path_walk_ctx_t* ctx)
337{
338 if (ctx->lookup != NULL)
339 {
340 UNREF(ctx->lookup);
341 ctx->lookup = NULL;
342 }
343}
344
346{
347 if (ctx->mount != NULL && REF_TRY(ctx->mount) == NULL)
348 {
349 errno = ENONET;
350 return ERR;
351 }
352
353 if ((ctx->lookup == NULL || ctx->dentry != ctx->lookup) && ctx->dentry != NULL && REF_TRY(ctx->dentry) == NULL)
354 {
355 UNREF(ctx->mount);
356 errno = ENOENT;
357 return ERR;
358 }
359
360 UNREF(path->mount);
361 UNREF(path->dentry);
362 path->mount = ctx->mount;
363 path->dentry = ctx->dentry;
364
365 if (ctx->lookup != NULL && ctx->dentry != ctx->lookup)
366 {
367 UNREF(ctx->lookup);
368 }
369 ctx->lookup = NULL;
370
371 return 0;
372}
373
375{
376 if (path_walk_acquire(ctx) == ERR)
377 {
378 return ERR;
379 }
380
381 uint64_t result = 0;
382
383 uint64_t iter = 0;
384 while (ctx->dentry == ctx->mount->source)
385 {
386 if (ctx->mount->parent == NULL || ctx->mount->target == NULL)
387 {
388 break;
389 }
390
391 mount_t* nextMount = REF(ctx->mount->parent);
392 dentry_t* nextDentry = REF(ctx->mount->target);
393 UNREF(ctx->mount);
394 ctx->mount = nextMount;
395 UNREF(ctx->dentry);
396 ctx->dentry = nextDentry;
397
398 iter++;
399 if (iter >= PATH_MAX_DOTDOT)
400 {
401 errno = ELOOP;
402 result = ERR;
403 break;
404 }
405 }
406
407 dentry_t* parent = REF(ctx->dentry->parent);
408 UNREF(ctx->dentry);
409 ctx->dentry = parent;
410
412 return result;
413}
414
416{
417 if (ctx->symlinks >= PATH_MAX_SYMLINK)
418 {
419 errno = ELOOP;
420 return ERR;
421 }
422
423 if (REF_TRY(symlink) == NULL)
424 {
425 return ERR;
426 }
428
429 if (path_walk_acquire(ctx) == ERR)
430 {
431 return ERR;
432 }
433
434 char symlinkPath[MAX_PATH];
435 size_t readCount = vfs_readlink(symlink->vnode, symlinkPath, MAX_PATH - 1);
436
438
439 if (readCount == ERR)
440 {
441 return ERR;
442 }
443 symlinkPath[readCount] = '\0';
444
445 pathname_t pathname;
446 if (pathname_init(&pathname, symlinkPath) == ERR)
447 {
448 return ERR;
449 }
450
451 const pathname_t* oldPathname = ctx->pathname;
452
453 ctx->pathname = &pathname;
454 ctx->symlinks++;
455
456 uint64_t result = path_rcu_walk(ctx);
457
458 ctx->symlinks--;
459 ctx->pathname = oldPathname;
460
461 return result;
462}
463
464static uint64_t path_rcu_step(path_walk_ctx_t* ctx, const char* name, size_t length)
465{
466 if (length == 1 && name[0] == '.')
467 {
468 return 0;
469 }
470
471 if (length == 2 && name[0] == '.' && name[1] == '.')
472 {
473 return path_rcu_dotdot(ctx);
474 }
475
476 dentry_t* next = dentry_rcu_get(ctx->dentry, name, length);
477 if (next == NULL)
478 {
479 if (path_walk_acquire(ctx) == ERR)
480 {
481 return ERR;
482 }
483
484 next = dentry_lookup(ctx->dentry, name, length);
485
487
488 if (next == NULL)
489 {
490 return ERR;
491 }
492
494 }
495
496 if (DENTRY_IS_SYMLINK(next) && !(ctx->mode & MODE_NOFOLLOW))
497 {
498 if (path_rcu_symlink(ctx, next) == ERR)
499 {
500 return ERR;
501 }
502 }
503 else
504 {
505 ctx->dentry = next;
506 }
507
508 if (atomic_load(&next->mountCount) != 0)
509 {
510 namespace_rcu_traverse(ctx->ns, &ctx->mount, &ctx->dentry);
511 }
512
513 return 0;
514}
515
517{
518 const char* p = ctx->pathname->string;
519 if (ctx->pathname->string[0] == '/')
520 {
521 namespace_rcu_get_root(ctx->ns, &ctx->mount, &ctx->dentry);
522 p++;
523 }
524
525 while (true)
526 {
527 while (*p == '/')
528 {
529 p++;
530 }
531
532 if (*p == '\0')
533 {
534 break;
535 }
536
537 const char* component = p;
538 while (*p != '\0' && *p != '/')
539 {
540 p++;
541 }
542 size_t length = p - component;
543
544 if (path_rcu_step(ctx, component, length) == ERR)
545 {
546 return ERR;
547 }
548 }
549
550 return 0;
551}
552
553uint64_t path_step(path_t* path, mode_t mode, const char* name, namespace_t* ns)
554{
555 if (path == NULL || name == NULL || !path_is_name_valid(name) || ns == NULL)
556 {
557 errno = EINVAL;
558 return ERR;
559 }
560
562
563 path_walk_ctx_t ctx = {
564 .pathname = NULL,
565 .ns = ns,
566 .mode = mode,
567 .mount = path->mount,
568 .dentry = path->dentry,
569 .symlinks = 0,
570 .lookup = NULL,
571 };
572
573 if (path->dentry != NULL && atomic_load(&path->dentry->mountCount) != 0)
574 {
575 namespace_rcu_traverse(ctx.ns, &ctx.mount, &ctx.dentry);
576 }
577
578 if (path_rcu_step(&ctx, name, strlen(name)) == ERR)
579 {
580 path_walk_cleanup(&ctx);
581 return ERR;
582 }
583
584 if (path_walk_get_result(&ctx, path) == ERR)
585 {
586 path_walk_cleanup(&ctx);
587 return ERR;
588 }
589
590 return 0;
591}
592
593uint64_t path_walk(path_t* path, const pathname_t* pathname, namespace_t* ns)
594{
595 if (path == NULL || pathname == NULL || ns == NULL)
596 {
597 errno = EINVAL;
598 return ERR;
599 }
600
602
603 path_walk_ctx_t ctx = {
604 .pathname = pathname,
605 .ns = ns,
606 .mode = pathname->mode,
607 .mount = path->mount,
608 .dentry = path->dentry,
609 .symlinks = 0,
610 .lookup = NULL,
611 };
612
613 if (path->dentry != NULL && atomic_load(&path->dentry->mountCount) != 0)
614 {
615 namespace_rcu_traverse(ctx.ns, &ctx.mount, &ctx.dentry);
616 }
617
618 if (path_rcu_walk(&ctx) == ERR)
619 {
620 path_walk_cleanup(&ctx);
621 return ERR;
622 }
623
624 if (path_walk_get_result(&ctx, path) == ERR)
625 {
626 path_walk_cleanup(&ctx);
627 return ERR;
628 }
629
630 return 0;
631}
632
633uint64_t path_walk_parent(path_t* path, const pathname_t* pathname, char* outLastName, namespace_t* ns)
634{
635 if (path == NULL || pathname == NULL || outLastName == NULL || ns == NULL)
636 {
637 errno = EINVAL;
638 return ERR;
639 }
640
641 memset(outLastName, 0, MAX_NAME);
642
643 if (strcmp(pathname->string, "/") == 0)
644 {
645 errno = EINVAL;
646 return ERR;
647 }
648
649 char string[MAX_PATH];
650 strncpy(string, pathname->string, MAX_PATH - 1);
651 string[MAX_PATH - 1] = '\0';
652
653 uint64_t len = strnlen_s(string, MAX_PATH);
654 while (len > 1 && string[len - 1] == '/')
655 {
656 string[len - 1] = '\0';
657 len--;
658 }
659
660 char* lastSlash = strrchr(string, '/');
661 if (lastSlash == NULL)
662 {
663 strncpy(outLastName, string, MAX_NAME - 1);
664 outLastName[MAX_NAME - 1] = '\0';
665 return 0;
666 }
667
668 char* lastComponent = lastSlash + 1;
669 strncpy(outLastName, lastComponent, MAX_NAME - 1);
670 outLastName[MAX_NAME - 1] = '\0';
671
672 if (lastSlash == string)
673 {
674 string[1] = '\0';
675 }
676 else
677 {
678 *lastSlash = '\0';
679 }
680
681 pathname_t parentPathname;
682 if (pathname_init(&parentPathname, string) == ERR)
683 {
684 return ERR;
685 }
686
687 return path_walk(path, &parentPathname, ns);
688}
689
690uint64_t path_walk_parent_and_child(const path_t* from, path_t* outParent, path_t* outChild, const pathname_t* pathname,
691 namespace_t* ns)
692{
693 if (from == NULL || outParent == NULL || outChild == NULL || pathname == NULL || ns == NULL)
694 {
695 errno = EINVAL;
696 return ERR;
697 }
698
699 char lastName[MAX_NAME];
700 path_copy(outParent, from);
701 if (path_walk_parent(outParent, pathname, lastName, ns) == ERR)
702 {
703 return ERR;
704 }
705
706 path_copy(outChild, outParent);
707 if (path_step(outChild, pathname->mode, lastName, ns) == ERR)
708 {
709 return ERR;
710 }
711
712 return 0;
713}
714
715uint64_t path_to_name(const path_t* path, pathname_t* pathname)
716{
717 if (path == NULL || path->dentry == NULL || path->mount == NULL || pathname == NULL)
718 {
719 errno = EINVAL;
720 return ERR;
721 }
722
723 char* buffer = pathname->string;
724 char* ptr = buffer + MAX_PATH - 1;
725 *ptr = '\0';
726
727 dentry_t* dentry = path->dentry;
728 mount_t* mount = path->mount;
729
730 while (true)
731 {
732 if (dentry == mount->source)
733 {
734 if (mount->parent == NULL)
735 {
736 break;
737 }
738
739 dentry = mount->target;
740 mount = mount->parent;
741 continue;
742 }
743
744 if (dentry->parent == NULL)
745 {
746 errno = ENOENT;
747 return ERR;
748 }
749
750 size_t len = strnlen_s(dentry->name, MAX_NAME);
751 if ((size_t)(ptr - buffer) < len + 1)
752 {
754 return ERR;
755 }
756
757 ptr -= len;
758 memcpy(ptr, dentry->name, len);
759
760 ptr--;
761 *ptr = '/';
762
763 dentry = dentry->parent;
764 }
765
766 if (*ptr == '\0')
767 {
768 if (ptr == buffer)
769 {
771 return ERR;
772 }
773 ptr--;
774 *ptr = '/';
775 }
776
777 size_t totalLen = (buffer + MAX_PATH - 1) - ptr;
778 memmove(buffer, ptr, totalLen + 1);
779
780 pathname->mode = MODE_NONE;
781 return 0;
782}
783
784uint64_t mode_to_string(mode_t mode, char* out, uint64_t length)
785{
786 if (out == NULL || length == 0)
787 {
788 errno = EINVAL;
789 return ERR;
790 }
791
792 uint64_t index = 0;
793 for (uint64_t i = 0; i < ARRAY_SIZE(flags); i++)
794 {
795 if (mode & flags[i].mode)
796 {
797 uint64_t nameLength = strnlen_s(flags[i].name, MAX_NAME);
798 if (index + nameLength + 1 >= length)
799 {
801 return ERR;
802 }
803
804 out[index] = ':';
805 index++;
806
807 memcpy(&out[index], flags[i].name, nameLength);
808 index += nameLength;
809 }
810 }
811
812 out[index] = '\0';
813 return index;
814}
815
817{
818 if (mode == NULL)
819 {
820 errno = EINVAL;
821 return ERR;
822 }
823
824 if (((*mode & MODE_ALL_PERMS) & ~maxPerms) != MODE_NONE)
825 {
826 errno = EACCES;
827 return ERR;
828 }
829
830 if ((*mode & MODE_ALL_PERMS) == MODE_NONE)
831 {
832 *mode |= maxPerms & MODE_ALL_PERMS;
833 }
834
835 return 0;
836}
837
838#ifdef _TESTING_
839
840#include <kernel/utils/test.h>
841
842TEST_DEFINE(path)
843{
844 pathname_t pathname;
845
846 TEST_ASSERT(pathname_init(&pathname, "/usr/bin/init") == 0);
847 TEST_ASSERT(strcmp(pathname.string, "/usr/bin/init") == 0);
848 TEST_ASSERT(pathname.mode == MODE_NONE);
849
850 TEST_ASSERT(pathname_init(&pathname, "/dev/sda:read:write") == 0);
851 TEST_ASSERT(strcmp(pathname.string, "/dev/sda") == 0);
852 TEST_ASSERT((pathname.mode & (MODE_READ | MODE_WRITE)) == (MODE_READ | MODE_WRITE));
853
854 TEST_ASSERT(pathname_init(&pathname, "/tmp/file:c:w") == 0);
855 TEST_ASSERT(strcmp(pathname.string, "/tmp/file") == 0);
857
858 TEST_ASSERT(pathname_init(&pathname, "/var/log:append:c") == 0);
859 TEST_ASSERT(strcmp(pathname.string, "/var/log") == 0);
861
862 TEST_ASSERT(pathname_init(&pathname, "/file:rw") == 0);
863 TEST_ASSERT(strcmp(pathname.string, "/file") == 0);
864 TEST_ASSERT((pathname.mode & (MODE_READ | MODE_WRITE)) == (MODE_READ | MODE_WRITE));
865
866 TEST_ASSERT(pathname_init(&pathname, "/home/user/fi?le") == ERR);
868
869 TEST_ASSERT(pathname_init(&pathname, "/home:invalid") == ERR);
871
872 TEST_ASSERT(pathname_init(&pathname, "") == 0);
873 TEST_ASSERT(strcmp(pathname.string, "") == 0);
874
875 TEST_ASSERT(pathname_init(&pathname, ":read") == 0);
876 TEST_ASSERT(strcmp(pathname.string, "") == 0);
877 TEST_ASSERT(pathname.mode == MODE_READ);
878
879 return 0;
880}
881
882#endif
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
#define isalnum(c)
Definition ctype.h:12
#define DENTRY_IS_SYMLINK(dentry)
Check if the vnode associated with a dentry is a symbolic link.
Definition dentry.h:91
dentry_t * dentry_lookup(dentry_t *parent, const char *name, size_t length)
Lookup a dentry for the given name without traversing mountpoints.
Definition dentry.c:229
dentry_t * dentry_rcu_get(const dentry_t *parent, const char *name, size_t length)
Get a dentry from the dentry cache in an RCU read-side critical section without traversing mountpoint...
Definition dentry.c:188
void namespace_rcu_get_root(namespace_t *ns, mount_t **mount, dentry_t **dentry)
Get the root mount of a namespace in an RCU read critical section.
Definition namespace.c:490
bool namespace_rcu_traverse(namespace_t *ns, mount_t **mount, dentry_t **dentry)
If the given path is a mountpoint in the namespace, traverse to the mounted filesystem in an RCU read...
Definition namespace.c:352
#define PATH_MAX_DOTDOT
Maximum iterations to handle .. in a path.
Definition path.h:113
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
#define PATH_MAX_SYMLINK
Maximum iterations to handle symlinks in a path.
Definition path.h:120
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
static void rcu_read_unlock(void)
RCU read-side critical section end.
Definition rcu.h:86
#define RCU_READ_SCOPE()
RCU read-side critical section for the current scope.
Definition rcu.h:94
static void rcu_read_lock(void)
RCU read-side critical section begin.
Definition rcu.h:76
#define REF_TRY(ptr)
Increment reference count, but only if the current count is not zero.
Definition ref.h:95
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define REF(ptr)
Increment reference count.
Definition ref.h:82
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define TEST_DEFINE(_name)
Define a test function to be run by TEST_ALL().
Definition test.h:71
#define TEST_ASSERT(cond)
Assert a condition in a test.
Definition test.h:82
size_t vfs_readlink(vnode_t *symlink, char *buffer, size_t size)
Read the path in a symbolic link.
Definition vfs.c:1080
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ELOOP
Too many symbolic links encountered.
Definition errno.h:232
#define ENAMETOOLONG
File name too long.
Definition errno.h:212
#define ENONET
Machine is not on the network.
Definition errno.h:347
#define errno
Error number variable.
Definition errno.h:27
#define EACCES
Permission denied.
Definition errno.h:97
#define ARRAY_SIZE(x)
Get the number of elements in a static array.
Definition defs.h:111
uint64_t mount(const char *mountpoint, const char *fs, const char *options)
System call for mounting a filesystem.
Definition mount.c:5
uint64_t symlink(const char *target, const char *linkpath)
System call for creating a symbolic link.
Definition symlink.c:8
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
static uint64_t path_walk_acquire(path_walk_ctx_t *ctx)
Definition path.c:301
static uint64_t path_walk_get_result(path_walk_ctx_t *ctx, path_t *path)
Definition path.c:345
static void path_walk_release(path_walk_ctx_t *ctx)
Definition path.c:319
static const path_flag_t flags[]
Definition path.c:47
static void path_walk_set_lookup(path_walk_ctx_t *ctx, dentry_t *dentry)
Definition path.c:327
static bool path_is_char_valid(char ch)
Definition path.c:99
static uint64_t path_rcu_dotdot(path_walk_ctx_t *ctx)
Definition path.c:374
static bool path_is_name_valid(const char *name)
Definition path.c:220
static path_flag_short_t shortFlags[UINT8_MAX+1]
Definition path.c:23
static uint64_t path_rcu_symlink(path_walk_ctx_t *ctx, dentry_t *symlink)
Definition path.c:415
static mode_t path_flag_to_mode(const char *flag, size_t length)
Definition path.c:65
static uint64_t path_rcu_step(path_walk_ctx_t *ctx, const char *name, size_t length)
Definition path.c:464
static void path_walk_cleanup(path_walk_ctx_t *ctx)
Definition path.c:336
static uint64_t path_rcu_walk(path_walk_ctx_t *ctx)
Definition path.c:516
static atomic_long next
Definition main.c:12
#define atomic_load(object)
Definition stdatomic.h:288
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
#define INT8_MAX
Definition stdint.h:61
#define UINT8_MAX
Definition stdint.h:62
_PUBLIC void * memmove(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
_PUBLIC char * strncpy(char *_RESTRICT s1, const char *_RESTRICT s2, size_t n)
Definition strncpy.c:3
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
_PUBLIC int strncmp(const char *s1, const char *s2, size_t n)
Definition strncmp.c:3
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
_PUBLIC char * strrchr(const char *s, int c)
Definition strrchr.c:3
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
Directory entry structure.
Definition dentry.h:155
char name[MAX_NAME]
The name of the dentry, immutable after creation.
Definition dentry.h:158
dentry_t * parent
The parent dentry, will be itself if this is the root dentry, immutable after creation.
Definition dentry.h:160
Mount structure.
Definition mount.h:48
dentry_t * target
The dentry which the source is mounted to, can be NULL for the root filesystem.
Definition mount.h:53
mount_t * parent
The parent mount, can be NULL for the root filesystem.
Definition mount.h:55
dentry_t * source
The dentry to appear at target once mounted, usually the root dentry of the mounted filesystem.
Definition mount.h:52
Namespace structure.
Definition namespace.h:57
mode_t mode
Definition path.c:20
const char * name
Definition path.c:44
mode_t mode
Definition path.c:43
Path structure.
Definition path.h:127
mount_t * mount
Definition path.h:128
dentry_t * dentry
Definition path.h:129
mode_t mode
Definition path.c:292
mount_t * mount
Definition path.c:293
dentry_t * dentry
Definition path.c:294
namespace_t * ns
Definition path.c:291
const pathname_t * pathname
Definition path.c:290
dentry_t * lookup
Definition path.c:296
uint64_t symlinks
Definition path.c:295
Pathname structure.
Definition path.h:139
char string[MAX_PATH]
Definition path.h:140
mode_t mode
Definition path.h:141