PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
vfs.c
Go to the documentation of this file.
1#include <_libstd/MAX_PATH.h>
2#include <kernel/fs/vfs.h>
3
5#include <kernel/fs/cwd.h>
6#include <kernel/fs/dentry.h>
7#include <kernel/fs/devfs.h>
9#include <kernel/fs/key.h>
10#include <kernel/fs/mount.h>
11#include <kernel/fs/path.h>
12#include <kernel/fs/vnode.h>
13#include <kernel/log/log.h>
14#include <kernel/log/panic.h>
15#include <kernel/mem/vmm.h>
16#include <kernel/proc/process.h>
17#include <kernel/sched/clock.h>
18#include <kernel/sched/sched.h>
19#include <kernel/sched/timer.h>
20#include <kernel/sched/wait.h>
21#include <kernel/sync/mutex.h>
22#include <kernel/sync/rcu.h>
23#include <kernel/sync/rwlock.h>
24#include <kernel/utils/ref.h>
25
26#include <kernel/cpu/regs.h>
27
28#include <assert.h>
29#include <errno.h>
30#include <stdint.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/fs.h>
35#include <sys/list.h>
36
37static uint64_t vfs_create(path_t* path, const pathname_t* pathname, namespace_t* ns)
38{
39 path_t parent = PATH_EMPTY;
40 path_t target = PATH_EMPTY;
41 if (path_walk_parent_and_child(path, &parent, &target, pathname, ns) == ERR)
42 {
43 if (errno != ENOENT || !(pathname->mode & MODE_PARENTS))
44 {
45 return ERR;
46 }
47
48 char parentString[MAX_PATH];
49 strncpy(parentString, pathname->string, MAX_PATH);
50 parentString[MAX_PATH - 1] = '\0';
51
52 size_t len = strlen(parentString);
53 while (len > 1 && parentString[len - 1] == '/')
54 {
55 parentString[--len] = '\0';
56 }
57
58 char* lastSlash = strrchr(parentString, '/');
59 if (lastSlash == NULL)
60 {
61 return ERR;
62 }
63
64 if (lastSlash == parentString)
65 {
66 parentString[1] = '\0';
67 }
68 else
69 {
70 *lastSlash = '\0';
71 }
72
73 pathname_t parentPathname;
74 if (pathname_init(&parentPathname, parentString) == ERR)
75 {
76 return ERR;
77 }
78
79 parentPathname.mode = MODE_DIRECTORY | MODE_CREATE | MODE_PARENTS;
80
81 path_t recursiveStart = PATH_CREATE(path->mount, path->dentry);
82 PATH_DEFER(&recursiveStart);
83
84 if (vfs_create(&recursiveStart, &parentPathname, ns) == ERR)
85 {
86 return ERR;
87 }
88
89 if (path_walk_parent_and_child(path, &parent, &target, pathname, ns) == ERR)
90 {
91 return ERR;
92 }
93 }
94
95 PATH_DEFER(&parent);
96 PATH_DEFER(&target);
97
98 if (!DENTRY_IS_POSITIVE(parent.dentry))
99 {
100 errno = ENOENT;
101 return ERR;
102 }
103
104 vnode_t* dir = parent.dentry->vnode;
105 if (dir->ops == NULL || dir->ops->create == NULL)
106 {
107 errno = EPERM;
108 return ERR;
109 }
110
111 MUTEX_SCOPE(&dir->mutex);
112
113 if (DENTRY_IS_POSITIVE(target.dentry))
114 {
115 if (pathname->mode & MODE_EXCLUSIVE)
116 {
117 errno = EEXIST;
118 return ERR;
119 }
120
121 path_copy(path, &target);
122 return 0;
123 }
124
125 if (!(parent.mount->mode & MODE_WRITE))
126 {
127 errno = EACCES;
128 return ERR;
129 }
130
132 if (dir->ops->create(dir, target.dentry, pathname->mode) == ERR)
133 {
134 return ERR;
135 }
136
137 path_copy(path, &target);
138 return 0;
139}
140
141static uint64_t vfs_open_lookup(path_t* path, const pathname_t* pathname, namespace_t* namespace)
142{
143 if (pathname->mode & MODE_CREATE)
144 {
145 return vfs_create(path, pathname, namespace);
146 }
147
148 if (path_walk(path, pathname, namespace) == ERR)
149 {
150 return ERR;
151 }
152
153 return 0;
154}
155
156file_t* vfs_open(const pathname_t* pathname, process_t* process)
157{
158 if (pathname == NULL || process == NULL)
159 {
160 errno = EINVAL;
161 return NULL;
162 }
163
164 return vfs_openat(NULL, pathname, process);
165}
166
167uint64_t vfs_open2(const pathname_t* pathname, file_t* files[2], process_t* process)
168{
169 if (pathname == NULL || files == NULL || process == NULL)
170 {
171 errno = EINVAL;
172 return ERR;
173 }
174
175 namespace_t* ns = process_get_ns(process);
176 if (ns == NULL)
177 {
178 return ERR;
179 }
180 UNREF_DEFER(ns);
181
182 path_t path = cwd_get(&process->cwd, ns);
183 PATH_DEFER(&path);
184
185 if (vfs_open_lookup(&path, pathname, ns) == ERR)
186 {
187 return ERR;
188 }
189
190 files[0] = file_new(&path, pathname->mode);
191 if (files[0] == NULL)
192 {
193 return ERR;
194 }
195
196 files[1] = file_new(&path, pathname->mode);
197 if (files[1] == NULL)
198 {
199 UNREF(files[0]);
200 return ERR;
201 }
202
203 if (pathname->mode & MODE_TRUNCATE && files[0]->vnode->type == VREG)
204 {
205 vnode_truncate(files[0]->vnode);
206 }
207
208 if (files[0]->ops != NULL && files[0]->ops->open2 != NULL)
209 {
211 uint64_t result = files[0]->ops->open2(files);
212 if (result == ERR)
213 {
214 UNREF(files[0]);
215 UNREF(files[1]);
216 return ERR;
217 }
218 }
219
220 return 0;
221}
222
223file_t* vfs_openat(const path_t* from, const pathname_t* pathname, process_t* process)
224{
225 if (pathname == NULL || process == NULL)
226 {
227 errno = EINVAL;
228 return NULL;
229 }
230
231 namespace_t* ns = process_get_ns(process);
232 if (ns == NULL)
233 {
234 return NULL;
235 }
236 UNREF_DEFER(ns);
237
238 path_t path;
239 if (from != NULL)
240 {
241 path = PATH_CREATE(from->mount, from->dentry);
242 }
243 else
244 {
245 path = cwd_get(&process->cwd, ns);
246 }
247 PATH_DEFER(&path);
248
249 if (vfs_open_lookup(&path, pathname, ns) == ERR)
250 {
251 return NULL;
252 }
253
254 file_t* file = file_new(&path, pathname->mode);
255 if (file == NULL)
256 {
257 return NULL;
258 }
259
260 if (pathname->mode & MODE_TRUNCATE && file->vnode->type == VREG)
261 {
262 vnode_truncate(file->vnode);
263 }
264
265 if (file->ops != NULL && file->ops->open != NULL)
266 {
268 uint64_t result = file->ops->open(file);
269 if (result == ERR)
270 {
271 UNREF(file);
272 return NULL;
273 }
274 }
275
276 return file;
277}
278
279size_t vfs_read(file_t* file, void* buffer, size_t count)
280{
281 if (file == NULL || buffer == NULL)
282 {
283 errno = EINVAL;
284 return ERR;
285 }
286
287 if (file->vnode->type == VDIR)
288 {
289 errno = EISDIR;
290 return ERR;
291 }
292
293 if (file->ops == NULL || file->ops->read == NULL)
294 {
295 errno = EINVAL;
296 return ERR;
297 }
298
299 if (!(file->mode & MODE_READ))
300 {
301 errno = EBADF;
302 return ERR;
303 }
304
306 size_t offset = file->pos;
307 size_t result = file->ops->read(file, buffer, count, &offset);
308 file->pos = offset;
309
310 return result;
311}
312
313size_t vfs_write(file_t* file, const void* buffer, size_t count)
314{
315 if (file == NULL || buffer == NULL)
316 {
317 errno = EINVAL;
318 return ERR;
319 }
320
321 if (file->vnode->type == VDIR)
322 {
323 errno = EISDIR;
324 return ERR;
325 }
326
327 if (file->ops == NULL || file->ops->write == NULL)
328 {
329 errno = EINVAL;
330 return ERR;
331 }
332
333 if (file->mode & MODE_APPEND)
334 {
335 if (file->ops->seek != NULL && file->ops->seek(file, 0, SEEK_END) == ERR)
336 {
337 return ERR;
338 }
339 }
340
341 if (!(file->mode & MODE_WRITE))
342 {
343 errno = EBADF;
344 return ERR;
345 }
346
348 size_t offset = file->pos;
349 size_t result = file->ops->write(file, buffer, count, &offset);
350 file->pos = offset;
351
352 return result;
353}
354
356{
357 if (file == NULL)
358 {
359 errno = EINVAL;
360 return ERR;
361 }
362
363 if (file->ops != NULL && file->ops->seek != NULL)
364 {
366 return file->ops->seek(file, offset, origin);
367 }
368
369 errno = ESPIPE;
370 return ERR;
371}
372
373uint64_t vfs_ioctl(file_t* file, uint64_t request, void* argp, size_t size)
374{
375 if (file == NULL)
376 {
377 errno = EINVAL;
378 return ERR;
379 }
380
381 if (file->vnode->type == VDIR)
382 {
383 errno = EISDIR;
384 return ERR;
385 }
386
387 if (file->ops == NULL || file->ops->ioctl == NULL)
388 {
389 errno = ENOTTY;
390 return ERR;
391 }
392
394 return file->ops->ioctl(file, request, argp, size);
395}
396
397void* vfs_mmap(file_t* file, void* address, size_t length, pml_flags_t flags)
398{
399 if (file == NULL)
400 {
401 errno = EINVAL;
402 return NULL;
403 }
404
405 if (file->vnode->type == VDIR)
406 {
407 errno = EISDIR;
408 return NULL;
409 }
410
411 if (file->ops == NULL || file->ops->mmap == NULL)
412 {
413 errno = ENODEV;
414 return NULL;
415 }
416
418 size_t offset = file->pos;
419 void* result = file->ops->mmap(file, address, length, &offset, flags);
420 if (result != NULL)
421 {
422 file->pos = offset;
423 }
424 return result;
425}
426
433
435{
436 memset(ctx->queues, 0, sizeof(wait_queue_t*) * CONFIG_MAX_FD);
437 memset(ctx->lookupTable, 0, sizeof(uint16_t) * CONFIG_MAX_FD);
438 ctx->queueAmount = 0;
439
440 for (uint64_t i = 0; i < amount; i++)
441 {
442 files[i].revents = POLLNONE;
443 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &files[i].revents);
444 if (queue == NULL)
445 {
446 return ERR;
447 }
448
449 // Avoid duplicate queues.
450 bool found = false;
451 for (uint16_t j = 0; j < ctx->queueAmount; j++)
452 {
453 if (ctx->queues[j] == queue)
454 {
455 found = true;
456 ctx->lookupTable[i] = j;
457 break;
458 }
459 }
460
461 if (!found)
462 {
463 ctx->queues[ctx->queueAmount] = queue;
464 ctx->lookupTable[i] = ctx->queueAmount;
465 ctx->queueAmount++;
466 }
467 }
468
469 return 0;
470}
471
473{
474 size_t readyCount = 0;
475
476 for (uint64_t i = 0; i < amount; i++)
477 {
478 poll_events_t revents = POLLNONE;
479 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &revents);
480 if (queue == NULL)
481 {
482 return ERR;
483 }
484
485 files[i].revents = (revents & (files[i].events | POLL_SPECIAL));
486
487 // Make sure the queue hasn't changed, just for debugging.
488 if (queue != ctx->queues[ctx->lookupTable[i]])
489 {
490 errno = EIO;
491 return ERR;
492 }
493
494 if ((files[i].revents & (files[i].events | POLL_SPECIAL)) != 0)
495 {
496 readyCount++;
497 }
498 }
499
500 return readyCount;
501}
502
504{
505 if (files == NULL || amount == 0 || amount > CONFIG_MAX_FD)
506 {
507 errno = EINVAL;
508 return ERR;
509 }
510
511 for (uint64_t i = 0; i < amount; i++)
512 {
513 if (files[i].file == NULL)
514 {
515 errno = EINVAL;
516 return ERR;
517 }
518
519 if (files[i].file->vnode->type == VDIR)
520 {
521 errno = EISDIR;
522 return ERR;
523 }
524
525 if (files[i].file->ops == NULL || files[i].file->ops->poll == NULL)
526 {
527 errno = ENOSYS;
528 return ERR;
529 }
530 }
531
532 vfs_poll_ctx_t ctx;
533 if (vfs_poll_ctx_init(&ctx, files, amount) == ERR)
534 {
535 return ERR;
536 }
537
539 clock_t deadline = CLOCKS_DEADLINE(timeout, uptime);
540
541 size_t readyCount = 0;
542 while (true)
543 {
545 clock_t remaining = CLOCKS_REMAINING(deadline, uptime);
546
547 if (wait_block_prepare(ctx.queues, ctx.queueAmount, remaining) == ERR)
548 {
549 return ERR;
550 }
551
552 readyCount = vfs_poll_ctx_check_events(&ctx, files, amount);
553 if (readyCount == ERR)
554 {
556 return ERR;
557 }
558
559 if (readyCount > 0 || uptime >= deadline)
560 {
562 break;
563 }
564
565 if (wait_block_commit() == ERR)
566 {
567 if (errno == ETIMEDOUT)
568 {
569 break;
570 }
571 return ERR;
572 }
573 }
574
575 return readyCount;
576}
577
586
596
597static bool vfs_dir_emit(dir_ctx_t* ctx, const char* name, vtype_t type)
598{
599 vfs_dir_ctx_t* vctx = (vfs_dir_ctx_t*)ctx;
600 if (vctx->written + sizeof(dirent_t) > vctx->count)
601 {
602 return false;
603 }
604
606
608 mode_t mode = vctx->path.mount->mode;
609 dentry_t* child = dentry_rcu_get(vctx->path.dentry, name, strlen(name));
610 if (REF_COUNT(child) != 0)
611 {
612 mount_t* mount = vctx->path.mount;
613 dentry_t* dentry = child;
614 if (namespace_rcu_traverse(vctx->ns, &mount, &dentry))
615 {
616 type = dentry->vnode->type;
617 mode = mount->mode;
619 }
620 }
621
623
624 dirent_t* d = (dirent_t*)((uint8_t*)vctx->buffer + vctx->written);
625 d->type = type;
626 d->flags = flags;
627 strncpy(d->path, name, MAX_PATH - 1);
628 d->path[MAX_PATH - 1] = '\0';
629 mode_to_string(mode, d->mode, MAX_PATH);
630
631 vctx->written += sizeof(dirent_t);
632 vctx->ctx.pos++;
633 return true;
634}
635
637 const char* prefix, namespace_t* ns)
638{
639 uint64_t offset = 0;
640 uint64_t bufSize = 1024;
641 dirent_t* buf = malloc(bufSize);
642 if (buf == NULL)
643 {
644 errno = ENOMEM;
645 return ERR;
646 }
647
648 while (true)
649 {
650 vfs_dir_ctx_t vctx = {
651 .ctx = {.emit = vfs_dir_emit, .pos = offset},
652 .buffer = buf,
653 .count = bufSize,
654 .written = 0,
655 .path = *path,
656 .ns = ns,
657 };
658
659 path->dentry->ops->iterate(path->dentry, &vctx.ctx);
660 offset = vctx.ctx.pos;
661
662 if (vctx.written == 0)
663 {
664 break;
665 }
666
667 uint64_t pos = 0;
668 while (pos < vctx.written)
669 {
670 dirent_t* d = (dirent_t*)((uint8_t*)buf + pos);
671 pos += sizeof(dirent_t);
672
673 if (ctx->currentOffset >= ctx->skip)
674 {
675 if (ctx->pos + sizeof(dirent_t) > ctx->count)
676 {
677 return 0;
678 }
679
680 dirent_t* out = (dirent_t*)((uint8_t*)ctx->buffer + ctx->pos);
681 *out = *d;
682
683 if (prefix[0] != '\0')
684 {
685 if (strcmp(d->path, ".") != 0 && strcmp(d->path, "..") != 0)
686 {
687 char tmp[MAX_PATH];
688 strncpy(tmp, d->path, MAX_PATH);
689 snprintf(out->path, MAX_PATH, "%s/%s", prefix, tmp);
690 }
691 else
692 {
693 snprintf(out->path, MAX_PATH, "%s/%s", prefix, d->path);
694 }
695 }
696
697 ctx->pos += sizeof(dirent_t);
698 }
699 ctx->currentOffset += sizeof(dirent_t);
700
701 if ((d->type == VDIR || d->type == VSYMLINK) && strcmp(d->path, ".") != 0 && strcmp(d->path, "..") != 0)
702 {
703 path_t childPath = PATH_CREATE(path->mount, path->dentry);
704 PATH_DEFER(&childPath);
705
706 if (path_step(&childPath, mode, d->path, ns) == ERR)
707 {
708 free(buf);
709 return ERR;
710 }
711
712 if (!DENTRY_IS_DIR(childPath.dentry))
713 {
714 continue;
715 }
716
717 char newPrefix[MAX_PATH];
718 if (prefix[0] == '\0')
719 {
720 snprintf(newPrefix, MAX_PATH, "%s", d->path);
721 }
722 else
723 {
724 snprintf(newPrefix, MAX_PATH, "%s/%s", prefix, d->path);
725 }
726
727 if (vfs_getdents_recursive_step(&childPath, mode, ctx, newPrefix, ns) == ERR)
728 {
729 free(buf);
730 return ERR;
731 }
732 path_put(&childPath);
733 }
734 }
735 }
736
737 free(buf);
738 return 0;
739}
740
742{
743 if (DENTRY_IS_ROOT(path->dentry))
744 {
745 errno = EBUSY;
746 return ERR;
747 }
748
749 if (!DENTRY_IS_DIR(path->dentry))
750 {
751 vnode_t* dir = path->dentry->parent->vnode;
752 if (dir->ops->remove(dir, path->dentry) == ERR)
753 {
754 return ERR;
755 }
756 return 0;
757 }
758
759 getdents_recursive_ctx_t ctx = {.buffer = NULL, .count = 0, .pos = 0, .skip = 0, .currentOffset = 0};
760
761 uint64_t offset = 0;
762 uint64_t bufSize = 1024;
763 dirent_t* buf = malloc(bufSize);
764 if (buf == NULL)
765 {
766 errno = ENOMEM;
767 return ERR;
768 }
769
770 while (true)
771 {
772 vfs_dir_ctx_t vctx = {.ctx = {.emit = vfs_dir_emit, .pos = offset},
773 .buffer = buf,
774 .count = bufSize,
775 .written = 0,
776 .path = *path,
777 .ns = process_get_ns(process)};
778 UNREF_DEFER(vctx.ns);
779
780 path->dentry->ops->iterate(path->dentry, &vctx.ctx);
781 offset = vctx.ctx.pos;
782
783 if (vctx.written == 0)
784 {
785 break;
786 }
787
788 uint64_t pos = 0;
789 bool removed = false;
790 while (pos < vctx.written)
791 {
792 dirent_t* d = (dirent_t*)((uint8_t*)buf + pos);
793 pos += sizeof(dirent_t);
794
795 if (strcmp(d->path, ".") == 0 || strcmp(d->path, "..") == 0)
796 {
797 continue;
798 }
799
800 path_t childPath = PATH_CREATE(path->mount, path->dentry);
801 PATH_DEFER(&childPath);
802
803 if (path_step(&childPath, MODE_NONE, d->path, vctx.ns) == ERR)
804 {
805 free(buf);
806 return ERR;
807 }
808
809 if (vfs_remove_recursive(&childPath, process) == ERR)
810 {
811 free(buf);
812 return ERR;
813 }
814
815 removed = true;
816 break;
817 }
818
819 if (removed)
820 {
821 offset = 0;
822 continue;
823 }
824 }
825
826 free(buf);
827
828 vnode_t* dir = path->dentry->parent->vnode;
829 if (dir->ops == NULL || dir->ops->remove == NULL)
830 {
831 errno = EPERM;
832 return ERR;
833 }
834
836
837 if (dir->ops->remove(dir, path->dentry) == ERR)
838 {
839 return ERR;
840 }
841
842 return 0;
843}
844
845size_t vfs_getdents(file_t* file, dirent_t* buffer, size_t count)
846{
847 if (file == NULL || (buffer == NULL && count > 0))
848 {
849 errno = EINVAL;
850 return ERR;
851 }
852
853 if (file->vnode == NULL || file->vnode->type != VDIR)
854 {
855 errno = ENOTDIR;
856 return ERR;
857 }
858
859 if (file->path.dentry == NULL || file->path.dentry->parent == NULL)
860 {
861 errno = EINVAL;
862 return ERR;
863 }
864
865 if (file->path.dentry->ops == NULL || file->path.dentry->ops->iterate == NULL)
866 {
867 errno = ENOSYS;
868 return ERR;
869 }
870
871 if (!(file->mode & MODE_READ))
872 {
873 errno = EBADF;
874 return ERR;
875 }
876
877 process_t* process = process_current();
878 assert(process != NULL);
879
880 namespace_t* ns = process_get_ns(process);
881 if (ns == NULL)
882 {
883 return ERR;
884 }
885 UNREF_DEFER(ns);
886
887 MUTEX_SCOPE(&file->vnode->mutex);
888
889 if (file->mode & MODE_RECURSIVE)
890 {
892 .buffer = buffer,
893 .count = count,
894 .pos = 0,
895 .skip = file->pos,
896 .currentOffset = 0,
897 };
898 if (vfs_getdents_recursive_step(&file->path, file->mode, &ctx, "", ns) == ERR)
899 {
900 return ERR;
901 }
902 file->pos = ctx.skip + ctx.pos;
903 return ctx.pos;
904 }
905
907
908 vfs_dir_ctx_t ctx = {.ctx = {.emit = vfs_dir_emit, .pos = file->pos},
909 .buffer = buffer,
910 .count = count,
911 .written = 0,
912 .path = file->path,
913 .ns = ns};
914
915 size_t result = file->path.dentry->ops->iterate(file->path.dentry, &ctx.ctx);
916 file->pos = ctx.ctx.pos;
917
918 if (result != ERR)
919 {
920 return ctx.written;
921 }
922 return result;
923}
924
925uint64_t vfs_stat(const pathname_t* pathname, stat_t* buffer, process_t* process)
926{
927 if (pathname == NULL || buffer == NULL || process == NULL)
928 {
929 errno = EINVAL;
930 return ERR;
931 }
932
933 namespace_t* ns = process_get_ns(process);
934 if (ns == NULL)
935 {
936 return ERR;
937 }
938 UNREF_DEFER(ns);
939
940 path_t path = cwd_get(&process->cwd, ns);
941 PATH_DEFER(&path);
942
943 if (path_walk(&path, pathname, ns) == ERR)
944 {
945 return ERR;
946 }
947
948 if (!(path.mount->mode & MODE_READ))
949 {
950 errno = EACCES;
951 return ERR;
952 }
953
954 memset(buffer, 0, sizeof(stat_t));
955
956 if (!DENTRY_IS_POSITIVE(path.dentry))
957 {
958 errno = ENOENT;
959 return ERR;
960 }
961
962 /// @todo Reimplement this after the async system.
963 vnode_t* vnode = path.dentry->vnode;
964 mutex_acquire(&vnode->mutex);
965 buffer->number = 0;
966 buffer->type = vnode->type;
967 buffer->size = vnode->size;
968 buffer->blocks = 0;
969 buffer->linkAmount = atomic_load(&vnode->dentryCount);
970 buffer->accessTime = 0;
971 buffer->modifyTime = 0;
972 buffer->changeTime = 0;
973 buffer->createTime = 0;
974
975 char mode[MAX_PATH];
976 if (mode_to_string(path.mount->mode, mode, MAX_PATH) == ERR)
977 {
978 return ERR;
979 }
980
981 if (snprintf(buffer->name, sizeof(buffer->name), "%s%s", path.dentry->name, mode) < 0)
982 {
983 errno = EIO;
984 return ERR;
985 }
986
987 mutex_release(&vnode->mutex);
988 return 0;
989}
990
991uint64_t vfs_link(const pathname_t* oldPathname, const pathname_t* newPathname, process_t* process)
992{
993 if (oldPathname == NULL || newPathname == NULL || process == NULL)
994 {
995 errno = EINVAL;
996 return ERR;
997 }
998
999 namespace_t* ns = process_get_ns(process);
1000 if (ns == NULL)
1001 {
1002 return ERR;
1003 }
1004 UNREF_DEFER(ns);
1005
1006 path_t cwd = cwd_get(&process->cwd, ns);
1007 PATH_DEFER(&cwd);
1008
1009 path_t oldParent = PATH_EMPTY;
1010 path_t old = PATH_EMPTY;
1011 PATH_DEFER(&oldParent);
1012 PATH_DEFER(&old);
1013
1014 if (path_walk_parent_and_child(&cwd, &oldParent, &old, oldPathname, ns) == ERR)
1015 {
1016 return ERR;
1017 }
1018
1019 path_t newParent = PATH_EMPTY;
1020 path_t new = PATH_EMPTY;
1021 PATH_DEFER(&newParent);
1022 PATH_DEFER(&new);
1023
1024 if (path_walk_parent_and_child(&cwd, &newParent, &new, newPathname, ns) == ERR)
1025 {
1026 return ERR;
1027 }
1028
1029 if (oldParent.dentry->superblock != newParent.dentry->superblock)
1030 {
1031 errno = EXDEV;
1032 return ERR;
1033 }
1034
1035 if (!DENTRY_IS_POSITIVE(old.dentry))
1036 {
1037 errno = ENOENT;
1038 return ERR;
1039 }
1040
1041 if (DENTRY_IS_DIR(old.dentry))
1042 {
1043 errno = EISDIR;
1044 return ERR;
1045 }
1046
1047 if (!DENTRY_IS_POSITIVE(newParent.dentry))
1048 {
1049 errno = ENOENT;
1050 return ERR;
1051 }
1052
1053 if (newParent.dentry->vnode->ops == NULL || newParent.dentry->vnode->ops->link == NULL)
1054 {
1055 errno = EPERM;
1056 return ERR;
1057 }
1058
1059 if (!(old.mount->mode & MODE_READ))
1060 {
1061 errno = EACCES;
1062 return ERR;
1063 }
1064
1065 if (!(newParent.mount->mode & MODE_WRITE))
1066 {
1067 errno = EACCES;
1068 return ERR;
1069 }
1070
1072 if (newParent.dentry->vnode->ops->link(newParent.dentry->vnode, old.dentry, new.dentry) == ERR)
1073 {
1074 return ERR;
1075 }
1076
1077 return 0;
1078}
1079
1080size_t vfs_readlink(vnode_t* symlink, char* buffer, size_t count)
1081{
1082 if (symlink == NULL || buffer == NULL || count == 0)
1083 {
1084 errno = EINVAL;
1085 return ERR;
1086 }
1087
1088 if (symlink->type != VSYMLINK)
1089 {
1090 errno = EINVAL;
1091 return ERR;
1092 }
1093
1094 if (symlink->ops == NULL || symlink->ops->readlink == NULL)
1095 {
1096 errno = EINVAL;
1097 return ERR;
1098 }
1099
1101 return symlink->ops->readlink(symlink, buffer, count);
1102}
1103
1104uint64_t vfs_symlink(const pathname_t* oldPathname, const pathname_t* newPathname, process_t* process)
1105{
1106 if (oldPathname == NULL || newPathname == NULL || process == NULL)
1107 {
1108 errno = EINVAL;
1109 return ERR;
1110 }
1111
1112 namespace_t* ns = process_get_ns(process);
1113 if (ns == NULL)
1114 {
1115 return ERR;
1116 }
1117 UNREF_DEFER(ns);
1118
1119 path_t cwd = cwd_get(&process->cwd, ns);
1120 PATH_DEFER(&cwd);
1121
1122 path_t newParent = PATH_EMPTY;
1123 path_t new = PATH_EMPTY;
1124 PATH_DEFER(&newParent);
1125 PATH_DEFER(&new);
1126
1127 if (path_walk_parent_and_child(&cwd, &newParent, &new, newPathname, ns) == ERR)
1128 {
1129 return ERR;
1130 }
1131
1132 if (!DENTRY_IS_POSITIVE(newParent.dentry))
1133 {
1134 errno = ENOENT;
1135 return ERR;
1136 }
1137
1138 if (DENTRY_IS_POSITIVE(new.dentry))
1139 {
1140 errno = EEXIST;
1141 return ERR;
1142 }
1143
1144 if (newParent.dentry->vnode->ops == NULL || newParent.dentry->vnode->ops->symlink == NULL)
1145 {
1146 errno = EPERM;
1147 return ERR;
1148 }
1149
1150 if (!(newParent.mount->mode & MODE_WRITE))
1151 {
1152 errno = EACCES;
1153 return ERR;
1154 }
1155
1157 return newParent.dentry->vnode->ops->symlink(newParent.dentry->vnode, new.dentry, oldPathname->string);
1158}
1159
1160uint64_t vfs_remove(const pathname_t* pathname, process_t* process)
1161{
1162 if (pathname == NULL || process == NULL)
1163 {
1164 errno = EINVAL;
1165 return ERR;
1166 }
1167
1168 namespace_t* ns = process_get_ns(process);
1169 if (ns == NULL)
1170 {
1171 return ERR;
1172 }
1173 UNREF_DEFER(ns);
1174
1175 path_t cwd = cwd_get(&process->cwd, ns);
1176 PATH_DEFER(&cwd);
1177
1178 path_t parent = PATH_EMPTY;
1179 path_t target = PATH_EMPTY;
1180 if (path_walk_parent_and_child(&cwd, &parent, &target, pathname, ns) == ERR)
1181 {
1182 return ERR;
1183 }
1184 PATH_DEFER(&parent);
1185 PATH_DEFER(&target);
1186
1187 if (!DENTRY_IS_POSITIVE(target.dentry))
1188 {
1189 errno = ENOENT;
1190 return ERR;
1191 }
1192
1193 if (!(pathname->mode & MODE_RECURSIVE))
1194 {
1195 if (pathname->mode & MODE_DIRECTORY)
1196 {
1197 if (!DENTRY_IS_DIR(target.dentry))
1198 {
1199 errno = ENOTDIR;
1200 return ERR;
1201 }
1202 }
1203 else
1204 {
1205 if (DENTRY_IS_DIR(target.dentry))
1206 {
1207 errno = EISDIR;
1208 return ERR;
1209 }
1210 }
1211 }
1212
1213 if (!(target.mount->mode & MODE_WRITE))
1214 {
1215 errno = EACCES;
1216 return ERR;
1217 }
1218
1219 if (pathname->mode & MODE_RECURSIVE)
1220 {
1221 return vfs_remove_recursive(&target, process);
1222 }
1223
1224 vnode_t* dir = parent.dentry->vnode;
1225 if (dir->ops == NULL || dir->ops->remove == NULL)
1226 {
1227 errno = EPERM;
1228 return ERR;
1229 }
1230
1232
1233 return dir->ops->remove(dir, target.dentry);
1234}
1235
1237{
1238 static _Atomic(uint64_t) newVfsId = ATOMIC_VAR_INIT(0);
1239
1240 return atomic_fetch_add(&newVfsId, 1);
1241}
1242
1243SYSCALL_DEFINE(SYS_OPEN, fd_t, const char* pathString)
1244{
1245 thread_t* thread = thread_current();
1246 process_t* process = thread->process;
1247
1248 pathname_t pathname;
1249 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1250 {
1251 return ERR;
1252 }
1253
1254 file_t* file = vfs_open(&pathname, process);
1255 if (file == NULL)
1256 {
1257 return ERR;
1258 }
1259 UNREF_DEFER(file);
1260
1261 return file_table_open(&process->fileTable, file);
1262}
1263
1264SYSCALL_DEFINE(SYS_OPEN2, uint64_t, const char* pathString, fd_t fds[2])
1265{
1266 if (fds == NULL)
1267 {
1268 errno = EINVAL;
1269 return ERR;
1270 }
1271
1272 thread_t* thread = thread_current();
1273 process_t* process = thread->process;
1274
1275 pathname_t pathname;
1276 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1277 {
1278 return ERR;
1279 }
1280
1281 file_t* files[2];
1282 if (vfs_open2(&pathname, files, process) == ERR)
1283 {
1284 return ERR;
1285 }
1286 UNREF_DEFER(files[0]);
1287 UNREF_DEFER(files[1]);
1288
1289 fd_t fdsLocal[2];
1290 fdsLocal[0] = file_table_open(&process->fileTable, files[0]);
1291 if (fdsLocal[0] == ERR)
1292 {
1293 return ERR;
1294 }
1295 fdsLocal[1] = file_table_open(&process->fileTable, files[1]);
1296 if (fdsLocal[1] == ERR)
1297 {
1298 file_table_close(&process->fileTable, fdsLocal[0]);
1299 return ERR;
1300 }
1301
1302 if (thread_copy_to_user(thread, fds, fdsLocal, sizeof(fd_t) * 2) == ERR)
1303 {
1304 file_table_close(&process->fileTable, fdsLocal[0]);
1305 file_table_close(&process->fileTable, fdsLocal[1]);
1306 return ERR;
1307 }
1308
1309 return 0;
1310}
1311
1312SYSCALL_DEFINE(SYS_OPENAT, fd_t, fd_t from, const char* pathString)
1313{
1314 thread_t* thread = thread_current();
1315 process_t* process = thread->process;
1316
1317 path_t fromPath = PATH_EMPTY;
1318 if (from != FD_NONE)
1319 {
1320 file_t* fromFile = file_table_get(&process->fileTable, from);
1321 if (fromFile == NULL)
1322 {
1323 return ERR;
1324 }
1325 path_copy(&fromPath, &fromFile->path);
1326 UNREF(fromFile);
1327 }
1328 PATH_DEFER(&fromPath);
1329
1330 pathname_t pathname;
1331 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1332 {
1333 return ERR;
1334 }
1335
1336 file_t* file = vfs_openat(from != FD_NONE ? &fromPath : NULL, &pathname, process);
1337 if (file == NULL)
1338 {
1339 return ERR;
1340 }
1341 UNREF_DEFER(file);
1342
1343 return file_table_open(&process->fileTable, file);
1344}
1345
1347{
1348 thread_t* thread = thread_current();
1349 process_t* process = thread->process;
1350
1351 file_t* file = file_table_get(&process->fileTable, fd);
1352 if (file == NULL)
1353 {
1354 return ERR;
1355 }
1356 UNREF_DEFER(file);
1357
1358 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1359 {
1360 return ERR;
1361 }
1362 uint64_t result = vfs_read(file, buffer, count);
1363 space_unpin(&process->space, buffer, count);
1364 return result;
1365}
1366
1368{
1369 thread_t* thread = thread_current();
1370 process_t* process = thread->process;
1371
1372 file_t* file = file_table_get(&process->fileTable, fd);
1373 if (file == NULL)
1374 {
1375 return ERR;
1376 }
1377 UNREF_DEFER(file);
1378
1379 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1380 {
1381 return ERR;
1382 }
1383 uint64_t result = vfs_write(file, buffer, count);
1384 space_unpin(&process->space, buffer, count);
1385 return result;
1386}
1387
1389{
1390 process_t* process = process_current();
1391
1392 file_t* file = file_table_get(&process->fileTable, fd);
1393 if (file == NULL)
1394 {
1395 return ERR;
1396 }
1397 UNREF_DEFER(file);
1398
1399 return vfs_seek(file, offset, origin);
1400}
1401
1402SYSCALL_DEFINE(SYS_IOCTL, uint64_t, fd_t fd, uint64_t request, void* argp, size_t size)
1403{
1404 thread_t* thread = thread_current();
1405 process_t* process = thread->process;
1406
1407 file_t* file = file_table_get(&process->fileTable, fd);
1408 if (file == NULL)
1409 {
1410 return ERR;
1411 }
1412 UNREF_DEFER(file);
1413
1414 if (space_pin(&process->space, argp, size, &thread->userStack) == ERR)
1415 {
1416 return ERR;
1417 }
1418 uint64_t result = vfs_ioctl(file, request, argp, size);
1419 space_unpin(&process->space, argp, size);
1420 return result;
1421}
1422
1423SYSCALL_DEFINE(SYS_MMAP, void*, fd_t fd, void* address, size_t length, prot_t prot)
1424{
1425 process_t* process = process_current();
1426 space_t* space = &process->space;
1427
1428 if (address != NULL && space_check_access(space, address, length) == ERR)
1429 {
1430 return NULL;
1431 }
1432
1434 if (flags == PML_NONE)
1435 {
1436 errno = EINVAL;
1437 return NULL;
1438 }
1439
1440 file_t* file = file_table_get(&process->fileTable, fd);
1441 if (file == NULL)
1442 {
1443 return NULL;
1444 }
1445 UNREF_DEFER(file);
1446
1447 if ((!(file->mode & MODE_READ) && (prot & PROT_READ)) || (!(file->mode & MODE_WRITE) && (prot & PROT_WRITE)) ||
1448 (!(file->mode & MODE_EXECUTE) && (prot & PROT_EXECUTE)))
1449 {
1450 errno = EACCES;
1451 return NULL;
1452 }
1453
1454 return vfs_mmap(file, address, length, flags | PML_USER);
1455}
1456
1458{
1459 thread_t* thread = thread_current();
1460 process_t* process = thread->process;
1461
1462 if (amount == 0 || amount >= CONFIG_MAX_FD)
1463 {
1464 errno = EINVAL;
1465 return ERR;
1466 }
1467
1468 if (space_pin(&process->space, fds, sizeof(pollfd_t) * amount, &thread->userStack) == ERR)
1469 {
1470 errno = EFAULT;
1471 return ERR;
1472 }
1473
1475 for (uint64_t i = 0; i < amount; i++)
1476 {
1477 files[i].file = file_table_get(&process->fileTable, fds[i].fd);
1478 if (files[i].file == NULL)
1479 {
1480 for (uint64_t j = 0; j < i; j++)
1481 {
1482 UNREF(files[j].file);
1483 }
1484 if (errno == EBADF)
1485 {
1486 fds[i].revents = POLLNVAL;
1487 }
1488 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1489 return ERR;
1490 }
1491
1492 files[i].events = fds[i].events;
1493 files[i].revents = POLLNONE;
1494 }
1495
1496 uint64_t result = vfs_poll(files, amount, timeout);
1497 if (result != ERR)
1498 {
1499 for (uint64_t i = 0; i < amount; i++)
1500 {
1501 fds[i].revents = files[i].revents;
1502 }
1503 }
1504 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1505
1506 for (uint64_t i = 0; i < amount; i++)
1507 {
1508 UNREF(files[i].file);
1509 }
1510
1511 return result;
1512}
1513
1515{
1516 thread_t* thread = thread_current();
1517 process_t* process = thread->process;
1518
1519 file_t* file = file_table_get(&process->fileTable, fd);
1520 if (file == NULL)
1521 {
1522 return ERR;
1523 }
1524 UNREF_DEFER(file);
1525
1526 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1527 {
1528 return ERR;
1529 }
1530 uint64_t result = vfs_getdents(file, buffer, count);
1531 space_unpin(&process->space, buffer, count);
1532 return result;
1533}
1534
1535SYSCALL_DEFINE(SYS_STAT, uint64_t, const char* pathString, stat_t* buffer)
1536{
1537 thread_t* thread = thread_current();
1538 process_t* process = thread->process;
1539
1540 pathname_t pathname;
1541 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1542 {
1543 return ERR;
1544 }
1545
1546 if (space_pin(&process->space, buffer, sizeof(stat_t), &thread->userStack) == ERR)
1547 {
1548 return ERR;
1549 }
1550 uint64_t result = vfs_stat(&pathname, buffer, process);
1551 space_unpin(&process->space, buffer, sizeof(stat_t));
1552 return result;
1553}
1554
1555SYSCALL_DEFINE(SYS_LINK, uint64_t, const char* oldPathString, const char* newPathString)
1556{
1557 thread_t* thread = thread_current();
1558 process_t* process = thread->process;
1559
1560 pathname_t oldPathname;
1561 if (thread_copy_from_user_pathname(thread, &oldPathname, oldPathString) == ERR)
1562 {
1563 return ERR;
1564 }
1565
1566 pathname_t newPathname;
1567 if (thread_copy_from_user_pathname(thread, &newPathname, newPathString) == ERR)
1568 {
1569 return ERR;
1570 }
1571
1572 return vfs_link(&oldPathname, &newPathname, process);
1573}
1574
1575SYSCALL_DEFINE(SYS_READLINK, uint64_t, const char* pathString, char* buffer, uint64_t count)
1576{
1577 thread_t* thread = thread_current();
1578 process_t* process = thread->process;
1579
1580 pathname_t pathname;
1581 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1582 {
1583 return ERR;
1584 }
1585
1586 namespace_t* ns = process_get_ns(process);
1587 if (ns == NULL)
1588 {
1589 return ERR;
1590 }
1591 UNREF_DEFER(ns);
1592
1593 path_t path = cwd_get(&process->cwd, ns);
1594 PATH_DEFER(&path);
1595
1596 if (path_walk(&path, &pathname, ns) == ERR)
1597 {
1598 return ERR;
1599 }
1600
1601 if (!DENTRY_IS_POSITIVE(path.dentry))
1602 {
1603 errno = ENOENT;
1604 return ERR;
1605 }
1606
1607 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1608 {
1609 return ERR;
1610 }
1611 uint64_t result = vfs_readlink(path.dentry->vnode, buffer, count);
1612 space_unpin(&process->space, buffer, count);
1613 return result;
1614}
1615
1616SYSCALL_DEFINE(SYS_SYMLINK, uint64_t, const char* targetString, const char* linkpathString)
1617{
1618 thread_t* thread = thread_current();
1619 process_t* process = thread->process;
1620
1621 pathname_t target;
1622 if (thread_copy_from_user_pathname(thread, &target, targetString) == ERR)
1623 {
1624 return ERR;
1625 }
1626
1627 pathname_t linkpath;
1628 if (thread_copy_from_user_pathname(thread, &linkpath, linkpathString) == ERR)
1629 {
1630 return ERR;
1631 }
1632
1633 return vfs_symlink(&target, &linkpath, process);
1634}
1635
1636SYSCALL_DEFINE(SYS_REMOVE, uint64_t, const char* pathString)
1637{
1638 thread_t* thread = thread_current();
1639 process_t* process = thread->process;
1640
1641 pathname_t pathname;
1642 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1643 {
1644 return ERR;
1645 }
1646
1647 return vfs_remove(&pathname, process);
1648}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define SEEK_END
Definition SEEK.h:6
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static dentry_t * dir
Definition fb.c:16
#define CONFIG_MAX_FD
Maximum file descriptor configuration.
Definition config.h:51
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:172
@ SYS_MMAP
Definition syscall.h:83
@ SYS_STAT
Definition syscall.h:82
@ SYS_WRITE
Definition syscall.h:78
@ SYS_SYMLINK
Definition syscall.h:101
@ SYS_LINK
Definition syscall.h:93
@ SYS_READ
Definition syscall.h:77
@ SYS_OPEN2
Definition syscall.h:75
@ SYS_POLL
Definition syscall.h:81
@ SYS_OPEN
Definition syscall.h:74
@ SYS_IOCTL
Definition syscall.h:80
@ SYS_OPENAT
Definition syscall.h:97
@ SYS_GETDENTS
Definition syscall.h:86
@ SYS_READLINK
Definition syscall.h:100
@ SYS_REMOVE
Definition syscall.h:92
@ SYS_SEEK
Definition syscall.h:79
static fb_ops_t ops
Definition gop.c:80
static uintptr_t address
Mapped virtual address of the HPET registers.
Definition hpet.c:96
path_t cwd_get(cwd_t *cwd, namespace_t *ns)
Get the current working directory.
Definition cwd.c:19
#define DENTRY_IS_DIR(dentry)
Check if the vnode associated with a dentry is a directory.
Definition dentry.h:83
#define DENTRY_IS_POSITIVE(dentry)
Check if a dentry is positive.
Definition dentry.h:67
#define DENTRY_IS_ROOT(dentry)
Macro to check if a dentry is the root entry in its filesystem.
Definition dentry.h:59
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
uint64_t file_table_close(file_table_t *table, fd_t fd)
Free a file descriptor.
Definition file_table.c:74
file_t * file_table_get(file_table_t *table, fd_t fd)
Get a file from its file descriptor.
Definition file_table.c:33
fd_t file_table_open(file_table_t *table, file_t *file)
Allocate a new file descriptor for a file.
Definition file_table.c:52
file_t * file_new(const path_t *path, mode_t mode)
Create a new file structure.
Definition file.c:40
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
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_to_string(mode_t mode, char *out, uint64_t length)
Convert a mode to a string representation.
Definition path.c:784
#define PATH_CREATE(inMount, inDentry)
Helper to create a path.
Definition path.h:176
#define PATH_DEFER(path)
Defer path put.
Definition path.h:106
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
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
#define PATH_EMPTY
Helper to create an empty path.
Definition path.h:163
@ MODE_CREATE
Definition path.h:86
@ MODE_NONE
Definition path.h:80
@ MODE_APPEND
Definition path.h:85
@ MODE_EXECUTE
Definition path.h:83
@ 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_PARENTS
Definition path.h:88
@ MODE_DIRECTORY
Definition path.h:90
void vnode_truncate(vnode_t *vnode)
Truncate the vnode.
Definition vnode.c:75
@ PML_USER
@ PML_NONE
void space_unpin(space_t *space, const void *address, size_t length)
Unpins pages in a region previously pinned with space_pin() or space_pin_string().
Definition space.c:418
uint64_t space_pin(space_t *space, const void *address, size_t length, stack_pointer_t *userStack)
Pins pages within a region of the address space.
Definition space.c:281
uint64_t space_check_access(space_t *space, const void *addr, size_t length)
Checks if a virtual memory region is within the allowed address range of the space.
Definition space.c:444
pml_flags_t vmm_prot_to_flags(prot_t prot)
Converts the user space memory protection flags to page table entry flags.
Definition vmm.c:128
static process_t * process_current(void)
Retrieves the process of the currently running thread.
Definition process.h:131
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:206
clock_t clock_uptime(void)
Retrieve the time in nanoseconds since boot.
Definition clock.c:99
static thread_t * thread_current(void)
Retrieves the currently running thread.
Definition thread.h:126
uint64_t thread_copy_from_user_pathname(thread_t *thread, pathname_t *pathname, const char *userPath)
Safely copy a string from user space and use it to initialize a pathname.
Definition thread.c:300
uint64_t thread_copy_to_user(thread_t *thread, void *userDest, const void *src, uint64_t length)
Safely copy data to user space.
Definition thread.c:220
uint64_t wait_block_prepare(wait_queue_t **waitQueues, uint64_t amount, clock_t timeout)
Prepare to block the currently running thread.
Definition wait.c:111
uint64_t wait_block_commit(void)
Block the currently running thread.
Definition wait.c:207
void wait_block_cancel(void)
Cancels blocking of the currently running thread.
Definition wait.c:186
void mutex_release(mutex_t *mtx)
Releases a mutex.
Definition mutex.c:105
void mutex_acquire(mutex_t *mtx)
Acquires a mutex, blocking until it is available.
Definition mutex.c:28
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
static void rcu_read_unlock(void)
RCU read-side critical section end.
Definition rcu.h:86
static void rcu_read_lock(void)
RCU read-side critical section begin.
Definition rcu.h:76
#define REF_COUNT(ptr)
Get current reference count.
Definition ref.h:71
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
size_t vfs_seek(file_t *file, ssize_t offset, seek_origin_t origin)
Seek in a file.
Definition vfs.c:355
uint64_t vfs_poll(poll_file_t *files, uint64_t amount, clock_t timeout)
Poll multiple files.
Definition vfs.c:503
size_t vfs_write(file_t *file, const void *buffer, size_t count)
Write to a file.
Definition vfs.c:313
size_t vfs_read(file_t *file, void *buffer, size_t count)
Read from a file.
Definition vfs.c:279
file_t * vfs_open(const pathname_t *pathname, process_t *process)
Open a file.
Definition vfs.c:156
size_t vfs_readlink(vnode_t *symlink, char *buffer, size_t count)
Read the path in a symbolic link.
Definition vfs.c:1080
uint64_t vfs_symlink(const pathname_t *oldPathname, const pathname_t *newPathname, process_t *process)
Create a symbolic link.
Definition vfs.c:1104
size_t vfs_getdents(file_t *file, dirent_t *buffer, size_t count)
Get directory entries from a directory file.
Definition vfs.c:845
uint64_t vfs_remove(const pathname_t *pathname, process_t *process)
Remove a file or directory.
Definition vfs.c:1160
uint64_t vfs_stat(const pathname_t *pathname, stat_t *buffer, process_t *process)
Get file information.
Definition vfs.c:925
file_t * vfs_openat(const path_t *from, const pathname_t *pathname, process_t *process)
Open a file relative to another path.
Definition vfs.c:223
void * vfs_mmap(file_t *file, void *address, size_t length, pml_flags_t flags)
Memory map a file.
Definition vfs.c:397
uint64_t vfs_link(const pathname_t *oldPathname, const pathname_t *newPathname, process_t *process)
Make the same file appear twice in the filesystem.
Definition vfs.c:991
uint64_t vfs_open2(const pathname_t *pathname, file_t *files[2], process_t *process)
Open one file, returning two file handles.
Definition vfs.c:167
uint64_t vfs_ioctl(file_t *file, uint64_t request, void *argp, size_t size)
Perform an ioctl operation on a file.
Definition vfs.c:373
uint64_t vfs_id_get(void)
Generates a new unique ID, to be used for any VFS object.
Definition vfs.c:1236
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EEXIST
File exists.
Definition errno.h:117
#define ESPIPE
Illegal seek.
Definition errno.h:177
#define EINVAL
Invalid argument.
Definition errno.h:142
#define EXDEV
Cross-device link.
Definition errno.h:122
#define EFAULT
Bad address.
Definition errno.h:102
#define ENOSYS
Function not implemented.
Definition errno.h:222
#define ETIMEDOUT
Connection timed out.
Definition errno.h:577
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EIO
I/O error.
Definition errno.h:57
#define EBUSY
Device or resource busy.
Definition errno.h:112
#define ENOTDIR
Not a directory.
Definition errno.h:132
#define errno
Error number variable.
Definition errno.h:27
#define ENODEV
No such device.
Definition errno.h:127
#define EACCES
Permission denied.
Definition errno.h:97
#define ENOTTY
Not a typewriter.
Definition errno.h:157
#define EBADF
Bad file number.
Definition errno.h:77
#define EPERM
Operation not permitted.
Definition errno.h:37
#define EISDIR
Is a directory.
Definition errno.h:137
vtype_t
Vnode type enum.
Definition fs.h:342
dirent_flags_t
Directory entry flags.
Definition fs.h:445
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
uint8_t seek_origin_t
Type for the seek() origin argument.
Definition fs.h:260
poll_events_t
Poll events type.
Definition fs.h:286
#define POLL_SPECIAL
Poll event values that will always be checked and included even if not specified.
Definition fs.h:298
@ VSYMLINK
Is a symbolic link.
Definition fs.h:345
@ VREG
Is a regular file.
Definition fs.h:343
@ VDIR
Is a directory.
Definition fs.h:344
@ DIRENT_MOUNTED
The directory entry is a mountpoint.
Definition fs.h:447
@ DIRENT_NONE
Definition fs.h:446
@ POLLNONE
None.
Definition fs.h:287
@ POLLNVAL
Invalid file descriptor.
Definition fs.h:292
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
prot_t
Memory protection flags.
Definition proc.h:122
@ PROT_READ
Readable memory.
Definition proc.h:124
@ PROT_EXECUTE
Executable memory.
Definition proc.h:126
@ PROT_WRITE
Writable memory.
Definition proc.h:125
#define NULL
Pointer error value.
Definition NULL.h:25
__INT64_TYPE__ ssize_t
Signed size type.
Definition ssize_t.h:11
#define FD_NONE
No file descriptor.
Definition fd_t.h:12
#define ERR
Integer error value.
Definition ERR.h:17
#define CLOCKS_REMAINING(deadline, uptime)
Safely calculate remaining time until deadline.
Definition clock_t.h:30
__UINT64_TYPE__ fd_t
File descriptor type.
Definition fd_t.h:10
#define CLOCKS_DEADLINE(timeout, uptime)
Safely calculate deadline from timeout.
Definition clock_t.h:47
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static uint64_t pos
Definition interactive.c:21
static uint64_t offset
Definition screen.c:19
static list_t files
Definition file.c:9
static const path_flag_t flags[]
Definition path.c:47
static atomic_long count
Definition main.c:11
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:34
static uint64_t rflags_read(void)
Definition regs.h:80
#define _Atomic(T)
Definition stdatomic.h:59
#define atomic_load(object)
Definition stdatomic.h:288
#define ATOMIC_VAR_INIT(value)
Definition stdatomic.h:74
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strncpy(char *_RESTRICT s1, const char *_RESTRICT s2, size_t n)
Definition strncpy.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
uint64_t(* iterate)(dentry_t *dentry, dir_ctx_t *ctx)
Iterate over the entries in a directory dentry.
Definition dentry.h:138
Directory entry structure.
Definition dentry.h:155
char name[MAX_NAME]
The name of the dentry, immutable after creation.
Definition dentry.h:158
const dentry_ops_t * ops
Definition dentry.h:164
dentry_t * parent
The parent dentry, will be itself if this is the root dentry, immutable after creation.
Definition dentry.h:160
vnode_t * vnode
Will be NULL if the dentry is negative, once positive it will never be modified.
Definition dentry.h:159
superblock_t * superblock
Definition dentry.h:163
Directory context used to iterate over directory entries.
Definition dentry.h:97
size_t pos
The current position in the directory, can be used to skip entries.
Definition dentry.h:112
bool(* emit)(dir_ctx_t *ctx, const char *name, vtype_t type)
Emit function.
Definition dentry.h:111
Directory entry struct.
Definition fs.h:455
char path[MAX_PATH]
The relative path of the entry.
Definition fs.h:458
dirent_flags_t flags
Definition fs.h:457
char mode[MAX_PATH]
The flags of the paths mount.
Definition fs.h:459
vtype_t type
Definition fs.h:456
size_t(* seek)(file_t *file, ssize_t offset, seek_origin_t origin)
Definition file.h:60
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
void *(* mmap)(file_t *file, void *address, size_t length, size_t *offset, pml_flags_t flags)
Definition file.h:63
size_t(* write)(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition file.h:59
uint64_t(* ioctl)(file_t *file, uint64_t request, void *argp, size_t size)
Definition file.h:61
uint64_t(* open)(file_t *file)
Definition file.h:55
File structure.
Definition file.h:39
const file_ops_t * ops
Definition file.h:45
mode_t mode
Definition file.h:42
vnode_t * vnode
Definition file.h:43
size_t pos
Definition file.h:41
path_t path
Definition file.h:44
dirent_t * buffer
Definition vfs.c:580
uint64_t currentOffset
Definition vfs.c:584
Mount structure.
Definition mount.h:48
mode_t mode
Specifies the maximum permissions for this mount and if it is a directory or a file.
Definition mount.h:56
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
char string[MAX_PATH]
Definition path.h:140
mode_t mode
Definition path.h:141
A entry in a page table without a specified address or callback ID.
Structure for polling multiple files.
Definition file.h:71
Poll file descriptor structure.
Definition fs.h:305
poll_events_t revents
The events that occurred.
Definition fs.h:308
poll_events_t events
The events to wait for.
Definition fs.h:307
fd_t fd
The file descriptor to poll.
Definition fs.h:306
Process structure.
Definition process.h:76
file_table_t fileTable
Definition process.h:88
space_t space
Definition process.h:84
cwd_t cwd
Definition process.h:87
Virtual address space structure.
Definition space.h:78
Stat type.
Definition fs.h:378
Thread of execution structure.
Definition thread.h:61
process_t * process
The parent process that the thread executes within.
Definition thread.h:62
stack_pointer_t userStack
The user stack of the thread.
Definition thread.h:74
dir_ctx_t ctx
Definition vfs.c:589
uint64_t written
Definition vfs.c:592
namespace_t * ns
Definition vfs.c:594
dirent_t * buffer
Definition vfs.c:590
uint64_t count
Definition vfs.c:591
path_t path
Definition vfs.c:593
uint16_t lookupTable[CONFIG_MAX_FD]
Definition vfs.c:430
wait_queue_t * queues[CONFIG_MAX_FD]
Definition vfs.c:429
uint16_t queueAmount
Definition vfs.c:431
uint64_t(* link)(vnode_t *dir, dentry_t *old, dentry_t *new)
Make the same file vnode appear twice in the filesystem.
Definition vnode.h:106
uint64_t(* symlink)(vnode_t *dir, dentry_t *target, const char *dest)
Create a symbolic link.
Definition vnode.h:124
vnode structure.
Definition vnode.h:48
mutex_t mutex
Definition vnode.h:59
uint64_t size
Used for convenience by certain filesystems, does not represent the file size.
Definition vnode.h:53
vtype_t type
Definition vnode.h:50
const vnode_ops_t * ops
Definition vnode.h:55
The primitive that threads block on.
Definition wait.h:185
static uint64_t vfs_open_lookup(path_t *path, const pathname_t *pathname, namespace_t *namespace)
Definition vfs.c:141
static uint64_t vfs_create(path_t *path, const pathname_t *pathname, namespace_t *ns)
Definition vfs.c:37
static uint64_t vfs_poll_ctx_check_events(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:472
static bool vfs_dir_emit(dir_ctx_t *ctx, const char *name, vtype_t type)
Definition vfs.c:597
static uint64_t vfs_poll_ctx_init(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:434
static uint64_t vfs_remove_recursive(path_t *path, process_t *process)
Definition vfs.c:741
static uint64_t vfs_getdents_recursive_step(path_t *path, mode_t mode, getdents_recursive_ctx_t *ctx, const char *prefix, namespace_t *ns)
Definition vfs.c:636