PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
vfs.c
Go to the documentation of this file.
1#include <kernel/fs/vfs.h>
2
4#include <kernel/fs/cwd.h>
5#include <kernel/fs/dentry.h>
7#include <kernel/fs/inode.h>
8#include <kernel/fs/key.h>
9#include <kernel/fs/mount.h>
10#include <kernel/fs/path.h>
11#include <kernel/fs/sysfs.h>
12#include <kernel/log/log.h>
13#include <kernel/log/panic.h>
14#include <kernel/mem/vmm.h>
15#include <kernel/proc/process.h>
16#include <kernel/sched/sched.h>
17#include <kernel/sched/clock.h>
18#include <kernel/sched/timer.h>
19#include <kernel/sched/wait.h>
20#include <kernel/sync/mutex.h>
21#include <kernel/sync/rwlock.h>
22#include <kernel/utils/ref.h>
23
24#include <kernel/cpu/regs.h>
25
26#include <assert.h>
27#include <errno.h>
28#include <stdint.h>
29#include <string.h>
30#include <sys/io.h>
31#include <sys/list.h>
32
33static uint64_t vfs_create(path_t* path, const pathname_t* pathname, namespace_t* ns)
34{
35 path_t parent = PATH_EMPTY;
36 path_t target = PATH_EMPTY;
37 if (path_walk_parent_and_child(path, &parent, &target, pathname, ns) == ERR)
38 {
39 return ERR;
40 }
41 PATH_DEFER(&parent);
42 PATH_DEFER(&target);
43
44 if (!dentry_is_positive(parent.dentry))
45 {
46 errno = ENOENT;
47 return ERR;
48 }
49
50 inode_t* dir = parent.dentry->inode;
51 if (dir->ops == NULL || dir->ops->create == NULL)
52 {
53 errno = ENOSYS;
54 return ERR;
55 }
56
57 if (dentry_is_positive(target.dentry))
58 {
59 if (pathname->mode & MODE_EXCLUSIVE)
60 {
61 errno = EEXIST;
62 return ERR;
63 }
64
65 path_copy(path, &target);
66 return 0;
67 }
68
70 if (dir->ops->create(dir, target.dentry, pathname->mode) == ERR)
71 {
72 return ERR;
73 }
74
75 path_copy(path, &target);
76 return 0;
77}
78
79static uint64_t vfs_open_lookup(path_t* path, const pathname_t* pathname, namespace_t* namespace)
80{
81 if (pathname->mode & MODE_CREATE)
82 {
83 return vfs_create(path, pathname, namespace);
84 }
85
86 if (path_walk(path, pathname, namespace) == ERR)
87 {
88 return ERR;
89 }
90
91 return 0;
92}
93
94file_t* vfs_open(const pathname_t* pathname, process_t* process)
95{
96 if (!PATHNAME_IS_VALID(pathname) || process == NULL)
97 {
98 errno = EINVAL;
99 return NULL;
100 }
101
102 path_t cwd = cwd_get(&process->cwd);
103 PATH_DEFER(&cwd);
104
105 return vfs_openat(&cwd, pathname, process);
106}
107
108uint64_t vfs_open2(const pathname_t* pathname, file_t* files[2], process_t* process)
109{
110 if (!PATHNAME_IS_VALID(pathname) || files == NULL || process == NULL)
111 {
112 errno = EINVAL;
113 return ERR;
114 }
115
116 path_t path = cwd_get(&process->cwd);
117 PATH_DEFER(&path);
118
119 if (vfs_open_lookup(&path, pathname, &process->ns) == ERR)
120 {
121 return ERR;
122 }
123
124 files[0] = file_new(&path, pathname->mode);
125 if (files[0] == NULL)
126 {
127 return ERR;
128 }
129
130 files[1] = file_new(&path, pathname->mode);
131 if (files[1] == NULL)
132 {
133 UNREF(files[0]);
134 return ERR;
135 }
136
137 if (pathname->mode & MODE_TRUNCATE && files[0]->inode->type == INODE_FILE)
138 {
139 inode_truncate(files[0]->inode);
140 }
141
142 if (files[0]->ops != NULL && files[0]->ops->open2 != NULL)
143 {
145 uint64_t result = files[0]->ops->open2(files);
146 if (result == ERR)
147 {
148 UNREF(files[0]);
149 UNREF(files[1]);
150 return ERR;
151 }
152 }
153
154 inode_notify_access(files[0]->inode);
155 return 0;
156}
157
158file_t* vfs_openat(const path_t* from, const pathname_t* pathname, process_t* process)
159{
160 if (!PATHNAME_IS_VALID(pathname) || process == NULL)
161 {
162 errno = EINVAL;
163 return NULL;
164 }
165
166 path_t path = PATH_CREATE(from->mount, from->dentry);
167 PATH_DEFER(&path);
168
169 if (vfs_open_lookup(&path, pathname, &process->ns) == ERR)
170 {
171 return NULL;
172 }
173
174 file_t* file = file_new(&path, pathname->mode);
175 if (file == NULL)
176 {
177 return NULL;
178 }
179
180 if (pathname->mode & MODE_TRUNCATE && file->inode->type == INODE_FILE)
181 {
183 }
184
185 if (file->ops != NULL && file->ops->open != NULL)
186 {
188 uint64_t result = file->ops->open(file);
189 if (result == ERR)
190 {
191 UNREF(file);
192 return NULL;
193 }
194 }
195
197 return file;
198}
199
201{
202 if (file == NULL || buffer == NULL)
203 {
204 errno = EINVAL;
205 return ERR;
206 }
207
208 if (file->inode->type == INODE_DIR)
209 {
210 errno = EISDIR;
211 return ERR;
212 }
213
214 if (file->ops == NULL || file->ops->read == NULL)
215 {
216 errno = ENOSYS;
217 return ERR;
218 }
219
220 if ((file->mode & MODE_APPEND) || !(file->mode & MODE_READ))
221 {
222 errno = EBADF;
223 return ERR;
224 }
225
227 uint64_t offset = file->pos;
228 uint64_t result = file->ops->read(file, buffer, count, &offset);
229 file->pos = offset;
230
231 if (result != ERR)
232 {
234 }
235
236 return result;
237}
238
240{
241 if (file == NULL || buffer == NULL)
242 {
243 errno = EINVAL;
244 return ERR;
245 }
246
247 if (file->inode->type == INODE_DIR)
248 {
249 errno = EISDIR;
250 return ERR;
251 }
252
253 if (file->ops == NULL || file->ops->write == NULL)
254 {
255 errno = ENOSYS;
256 return ERR;
257 }
258
259 if (file->mode & MODE_APPEND)
260 {
261 if (file->ops->seek != NULL && file->ops->seek(file, 0, SEEK_END) == ERR)
262 {
263 return ERR;
264 }
265 }
266
267 if (!(file->mode & MODE_WRITE))
268 {
269 errno = EBADF;
270 return ERR;
271 }
272
274 uint64_t offset = file->pos;
275 uint64_t result = file->ops->write(file, buffer, count, &offset);
276 file->pos = offset;
277
278 if (result != ERR)
279 {
281 }
282
283 return result;
284}
285
287{
288 if (file == NULL)
289 {
290 errno = EINVAL;
291 return ERR;
292 }
293
294 if (file->ops != NULL && file->ops->seek != NULL)
295 {
297 return file->ops->seek(file, offset, origin);
298 }
299
300 errno = ESPIPE;
301 return ERR;
302}
303
304uint64_t vfs_ioctl(file_t* file, uint64_t request, void* argp, uint64_t size)
305{
306 if (file == NULL)
307 {
308 errno = EINVAL;
309 return ERR;
310 }
311
312 if (file->inode->type == INODE_DIR)
313 {
314 errno = EISDIR;
315 return ERR;
316 }
317
318 if (file->ops == NULL || file->ops->ioctl == NULL)
319 {
320 errno = ENOTTY;
321 return ERR;
322 }
323
325 uint64_t result = file->ops->ioctl(file, request, argp, size);
326 if (result != ERR)
327 {
329 }
330 return result;
331}
332
334{
335 if (file == NULL)
336 {
337 errno = EINVAL;
338 return NULL;
339 }
340
341 if (file->inode->type == INODE_DIR)
342 {
343 errno = EISDIR;
344 return NULL;
345 }
346
347 if (file->ops == NULL || file->ops->mmap == NULL)
348 {
349 errno = ENOSYS;
350 return NULL;
351 }
352
354 uint64_t offset = file->pos;
355 void* result = file->ops->mmap(file, address, length, &offset, flags);
356 if (result != NULL)
357 {
359 file->pos = offset;
360 }
361 return result;
362}
363
370
372{
373 memset(ctx->queues, 0, sizeof(wait_queue_t*) * CONFIG_MAX_FD);
374 memset(ctx->lookupTable, 0, sizeof(uint16_t) * CONFIG_MAX_FD);
375 ctx->queueAmount = 0;
376
377 for (uint64_t i = 0; i < amount; i++)
378 {
379 files[i].revents = POLLNONE;
380 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &files[i].revents);
381 if (queue == NULL)
382 {
383 return ERR;
384 }
385
386 // Avoid duplicate queues.
387 bool found = false;
388 for (uint16_t j = 0; j < ctx->queueAmount; j++)
389 {
390 if (ctx->queues[j] == queue)
391 {
392 found = true;
393 ctx->lookupTable[i] = j;
394 break;
395 }
396 }
397
398 if (!found)
399 {
400 ctx->queues[ctx->queueAmount] = queue;
401 ctx->lookupTable[i] = ctx->queueAmount;
402 ctx->queueAmount++;
403 }
404 }
405
406 return 0;
407}
408
410{
411 uint64_t readyCount = 0;
412
413 for (uint64_t i = 0; i < amount; i++)
414 {
415 poll_events_t revents = POLLNONE;
416 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &revents);
417 if (queue == NULL)
418 {
419 return ERR;
420 }
421
422 files[i].revents = (revents & (files[i].events | POLL_SPECIAL));
423
424 // Make sure the queue hasn't changed, just for debugging.
425 if (queue != ctx->queues[ctx->lookupTable[i]])
426 {
427 errno = EIO;
428 return ERR;
429 }
430
431 if ((files[i].revents & (files[i].events | POLL_SPECIAL)) != 0)
432 {
433 readyCount++;
434 }
435 }
436
437 return readyCount;
438}
439
441{
442 if (files == NULL || amount == 0 || amount > CONFIG_MAX_FD)
443 {
444 errno = EINVAL;
445 return ERR;
446 }
447
448 for (uint64_t i = 0; i < amount; i++)
449 {
450 if (files[i].file == NULL)
451 {
452 errno = EINVAL;
453 return ERR;
454 }
455
456 if (files[i].file->inode->type == INODE_DIR)
457 {
458 errno = EISDIR;
459 return ERR;
460 }
461
462 if (files[i].file->ops == NULL || files[i].file->ops->poll == NULL)
463 {
464 errno = ENOSYS;
465 return ERR;
466 }
467 }
468
469 vfs_poll_ctx_t ctx;
470 if (vfs_poll_ctx_init(&ctx, files, amount) == ERR)
471 {
472 return ERR;
473 }
474
476 clock_t deadline = CLOCKS_DEADLINE(timeout, uptime);
477
478 uint64_t readyCount = 0;
479 while (true)
480 {
482 clock_t remaining = CLOCKS_REMAINING(deadline, uptime);
483
484 if (wait_block_prepare(ctx.queues, ctx.queueAmount, remaining) == ERR)
485 {
486 return ERR;
487 }
488
489 readyCount = vfs_poll_ctx_check_events(&ctx, files, amount);
490 if (readyCount == ERR)
491 {
493 return ERR;
494 }
495
496 if (readyCount > 0 || uptime >= deadline)
497 {
499 break;
500 }
501
502 if (wait_block_commit() == ERR)
503 {
504 if (errno == ETIMEDOUT)
505 {
506 break;
507 }
508 return ERR;
509 }
510 }
511
512 return readyCount;
513}
514
516{
517 if (file == NULL || (buffer == NULL && count > 0))
518 {
519 errno = EINVAL;
520 return ERR;
521 }
522
523 if (file->inode == NULL || file->inode->type != INODE_DIR)
524 {
525 errno = ENOTDIR;
526 return ERR;
527 }
528
529 if (file->path.dentry == NULL || file->path.dentry->parent == NULL)
530 {
531 errno = EINVAL;
532 return ERR;
533 }
534
535 if (file->path.dentry->ops == NULL || file->path.dentry->ops->getdents == NULL)
536 {
537 errno = ENOSYS;
538 return ERR;
539 }
540
541 if (!(file->mode & MODE_READ))
542 {
543 errno = EBADF;
544 return ERR;
545 }
546
548 uint64_t result = file->path.dentry->ops->getdents(file->path.dentry, buffer, count, &file->pos, file->mode);
549 if (result != ERR)
550 {
552 }
553 return result;
554}
555
556uint64_t vfs_stat(const pathname_t* pathname, stat_t* buffer, process_t* process)
557{
558 if (!PATHNAME_IS_VALID(pathname) || buffer == NULL || process == NULL)
559 {
560 errno = EINVAL;
561 return ERR;
562 }
563
564 if (pathname->mode != MODE_NONE)
565 {
566 errno = EINVAL;
567 return ERR;
568 }
569
570 path_t path = cwd_get(&process->cwd);
571 PATH_DEFER(&path);
572
573 if (path_walk(&path, pathname, &process->ns) == ERR)
574 {
575 return ERR;
576 }
577
578 if (!(path.mount->mode & MODE_READ))
579 {
580 errno = EACCES;
581 return ERR;
582 }
583
584 memset(buffer, 0, sizeof(stat_t));
585
586 if (!dentry_is_positive(path.dentry))
587 {
588 errno = ENOENT;
589 return ERR;
590 }
591
592 inode_t* inode = path.dentry->inode;
593 mutex_acquire(&inode->mutex);
594 buffer->number = inode->number;
595 buffer->type = inode->type;
596 buffer->size = inode->size;
597 buffer->blocks = inode->blocks;
598 buffer->linkAmount = atomic_load(&inode->dentryCount);
599 buffer->accessTime = inode->accessTime;
600 buffer->modifyTime = inode->modifyTime;
601 buffer->changeTime = inode->changeTime;
602 buffer->createTime = inode->createTime;
603 strncpy(buffer->name, path.dentry->name, MAX_NAME - 1);
604 buffer->name[MAX_NAME - 1] = '\0';
605 mutex_release(&inode->mutex);
606 return 0;
607}
608
609uint64_t vfs_link(const pathname_t* oldPathname, const pathname_t* newPathname, process_t* process)
610{
611 if (!PATHNAME_IS_VALID(oldPathname) || !PATHNAME_IS_VALID(newPathname) || process == NULL)
612 {
613 errno = EINVAL;
614 return ERR;
615 }
616
617 if (oldPathname->mode != MODE_NONE || newPathname->mode != MODE_NONE)
618 {
619 errno = EINVAL;
620 return ERR;
621 }
622
623 path_t cwd = cwd_get(&process->cwd);
624 PATH_DEFER(&cwd);
625
626 path_t oldParent = PATH_EMPTY;
627 path_t old = PATH_EMPTY;
628 if (path_walk_parent_and_child(&cwd, &oldParent, &old, oldPathname, &process->ns) == ERR)
629 {
630 return ERR;
631 }
632 PATH_DEFER(&oldParent);
633 PATH_DEFER(&old);
634
635 path_t newParent = PATH_EMPTY;
636 path_t new = PATH_EMPTY;
637 if (path_walk_parent_and_child(&cwd, &newParent, &new, newPathname, &process->ns) == ERR)
638 {
639 return ERR;
640 }
641 PATH_DEFER(&newParent);
642 PATH_DEFER(&new);
643
644 if (oldParent.dentry->superblock->id != newParent.dentry->superblock->id)
645 {
646 errno = EXDEV;
647 return ERR;
648 }
649
650 if (!dentry_is_positive(old.dentry))
651 {
652 errno = ENOENT;
653 return ERR;
654 }
655
656 if (dentry_is_dir(old.dentry))
657 {
658 errno = EISDIR;
659 return ERR;
660 }
661
662 if (!dentry_is_positive(newParent.dentry))
663 {
664 errno = ENOENT;
665 return ERR;
666 }
667
668 if (newParent.dentry->inode->ops == NULL || newParent.dentry->inode->ops->link == NULL)
669 {
670 errno = ENOSYS;
671 return ERR;
672 }
673
674 if (!(old.mount->mode & MODE_READ))
675 {
676 errno = EACCES;
677 return ERR;
678 }
679
680 if (!(newParent.mount->mode & MODE_WRITE))
681 {
682 errno = EACCES;
683 return ERR;
684 }
685
687 if (newParent.dentry->inode->ops->link(newParent.dentry->inode, old.dentry, new.dentry) == ERR)
688 {
689 return ERR;
690 }
691
692 inode_notify_modify(newParent.dentry->inode);
694
695 return 0;
696}
697
698uint64_t vfs_remove(const pathname_t* pathname, process_t* process)
699{
700 if (!PATHNAME_IS_VALID(pathname) || process == NULL)
701 {
702 errno = EINVAL;
703 return ERR;
704 }
705
706 path_t cwd = cwd_get(&process->cwd);
707 PATH_DEFER(&cwd);
708
709 path_t parent = PATH_EMPTY;
710 path_t target = PATH_EMPTY;
711 if (path_walk_parent_and_child(&cwd, &parent, &target, pathname, &process->ns) == ERR)
712 {
713 return ERR;
714 }
715 PATH_DEFER(&parent);
716 PATH_DEFER(&target);
717
718 if (!dentry_is_positive(target.dentry))
719 {
720 errno = ENOENT;
721 return ERR;
722 }
723
724 if (pathname->mode & MODE_DIRECTORY)
725 {
726 if (dentry_is_file(target.dentry))
727 {
728 errno = ENOTDIR;
729 return ERR;
730 }
731 }
732 else
733 {
734 if (dentry_is_dir(target.dentry))
735 {
736 errno = EISDIR;
737 return ERR;
738 }
739 }
740
741 if (!(target.mount->mode & MODE_WRITE))
742 {
743 errno = EACCES;
744 return ERR;
745 }
746
747 inode_t* dir = parent.dentry->inode;
748 if (dir->ops == NULL || dir->ops->remove == NULL)
749 {
750 errno = ENOSYS;
751 return ERR;
752 }
753
755
756 if (dir->ops->remove(dir, target.dentry, pathname->mode) == ERR)
757 {
758 return ERR;
759 }
760
762 return 0;
763}
764
766{
767 static _Atomic(uint64_t) newVfsId = ATOMIC_VAR_INIT(0);
768
769 return atomic_fetch_add(&newVfsId, 1);
770}
771
772SYSCALL_DEFINE(SYS_OPEN, fd_t, const char* pathString)
773{
774 thread_t* thread = sched_thread();
775 process_t* process = thread->process;
776
777 pathname_t pathname;
778 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
779 {
780 return ERR;
781 }
782
783 file_t* file = vfs_open(&pathname, process);
784 if (file == NULL)
785 {
786 return ERR;
787 }
789
790 return file_table_alloc(&process->fileTable, file);
791}
792
793SYSCALL_DEFINE(SYS_OPEN2, uint64_t, const char* pathString, fd_t fds[2])
794{
795 if (fds == NULL)
796 {
797 errno = EINVAL;
798 return ERR;
799 }
800
801 thread_t* thread = sched_thread();
802 process_t* process = thread->process;
803
804 pathname_t pathname;
805 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
806 {
807 return ERR;
808 }
809
810 file_t* files[2];
811 if (vfs_open2(&pathname, files, process) == ERR)
812 {
813 return ERR;
814 }
815 UNREF_DEFER(files[0]);
816 UNREF_DEFER(files[1]);
817
818 fd_t fdsLocal[2];
819 fdsLocal[0] = file_table_alloc(&process->fileTable, files[0]);
820 if (fdsLocal[0] == ERR)
821 {
822 return ERR;
823 }
824 fdsLocal[1] = file_table_alloc(&process->fileTable, files[1]);
825 if (fdsLocal[1] == ERR)
826 {
827 file_table_free(&process->fileTable, fdsLocal[0]);
828 return ERR;
829 }
830
831 if (thread_copy_to_user(thread, fds, fdsLocal, sizeof(fd_t) * 2) == ERR)
832 {
833 file_table_free(&process->fileTable, fdsLocal[0]);
834 file_table_free(&process->fileTable, fdsLocal[1]);
835 return ERR;
836 }
837
838 return 0;
839}
840
841SYSCALL_DEFINE(SYS_OPENAT, fd_t, fd_t from, const char* pathString)
842{
843 thread_t* thread = sched_thread();
844 process_t* process = thread->process;
845
846 path_t fromPath = PATH_EMPTY;
847 if (from == FD_NONE)
848 {
849 path_t cwd = cwd_get(&process->cwd);
850 path_copy(&fromPath, &cwd);
851 path_put(&cwd);
852 }
853 else
854 {
855 file_t* fromFile = file_table_get(&process->fileTable, from);
856 if (fromFile == NULL)
857 {
858 return ERR;
859 }
860 path_copy(&fromPath, &fromFile->path);
861 UNREF(fromFile);
862 }
863 PATH_DEFER(&fromPath);
864
865 pathname_t pathname;
866 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
867 {
868 return ERR;
869 }
870
871 file_t* file = vfs_openat(&fromPath, &pathname, process);
872 if (file == NULL)
873 {
874 return ERR;
875 }
877
878 return file_table_alloc(&process->fileTable, file);
879}
880
882{
883 thread_t* thread = sched_thread();
884 process_t* process = thread->process;
885
886 file_t* file = file_table_get(&process->fileTable, fd);
887 if (file == NULL)
888 {
889 return ERR;
890 }
892
893 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
894 {
895 return ERR;
896 }
897 uint64_t result = vfs_read(file, buffer, count);
898 space_unpin(&process->space, buffer, count);
899 return result;
900}
901
903{
904 thread_t* thread = sched_thread();
905 process_t* process = thread->process;
906
907 file_t* file = file_table_get(&process->fileTable, fd);
908 if (file == NULL)
909 {
910 return ERR;
911 }
913
914 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
915 {
916 return ERR;
917 }
918 uint64_t result = vfs_write(file, buffer, count);
919 space_unpin(&process->space, buffer, count);
920 return result;
921}
922
924{
925 process_t* process = sched_process();
926
927 file_t* file = file_table_get(&process->fileTable, fd);
928 if (file == NULL)
929 {
930 return ERR;
931 }
933
934 return vfs_seek(file, offset, origin);
935}
936
937SYSCALL_DEFINE(SYS_IOCTL, uint64_t, fd_t fd, uint64_t request, void* argp, uint64_t size)
938{
939 thread_t* thread = sched_thread();
940 process_t* process = thread->process;
941
942 file_t* file = file_table_get(&process->fileTable, fd);
943 if (file == NULL)
944 {
945 return ERR;
946 }
948
949 if (space_pin(&process->space, argp, size, &thread->userStack) == ERR)
950 {
951 return ERR;
952 }
953 uint64_t result = vfs_ioctl(file, request, argp, size);
954 space_unpin(&process->space, argp, size);
955 return result;
956}
957
958SYSCALL_DEFINE(SYS_MMAP, void*, fd_t fd, void* address, uint64_t length, prot_t prot)
959{
960 process_t* process = sched_process();
961 space_t* space = &process->space;
962
963 if (address != NULL && space_check_access(space, address, length) == ERR)
964 {
965 return NULL;
966 }
967
969 if (flags == PML_NONE)
970 {
971 errno = EINVAL;
972 return NULL;
973 }
974
975 file_t* file = file_table_get(&process->fileTable, fd);
976 if (file == NULL)
977 {
978 return NULL;
979 }
981
982 if ((!(file->mode & MODE_READ) && (prot & PROT_READ)) || (!(file->mode & MODE_WRITE) && (prot & PROT_WRITE)) ||
983 (!(file->mode & MODE_EXECUTE) && (prot & PROT_EXECUTE)))
984 {
985 errno = EACCES;
986 return NULL;
987 }
988
989 return vfs_mmap(file, address, length, flags | PML_USER);
990}
991
993{
994 thread_t* thread = sched_thread();
995 process_t* process = thread->process;
996
997 if (amount == 0 || amount >= CONFIG_MAX_FD)
998 {
999 errno = EINVAL;
1000 return ERR;
1001 }
1002
1003 if (space_pin(&process->space, fds, sizeof(pollfd_t) * amount, &thread->userStack) == ERR)
1004 {
1005 errno = EFAULT;
1006 return ERR;
1007 }
1008
1010 for (uint64_t i = 0; i < amount; i++)
1011 {
1012 files[i].file = file_table_get(&process->fileTable, fds[i].fd);
1013 if (files[i].file == NULL)
1014 {
1015 for (uint64_t j = 0; j < i; j++)
1016 {
1017 UNREF(files[j].file);
1018 }
1019 if (errno == EBADF)
1020 {
1021 fds[i].revents = POLLNVAL;
1022 }
1023 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1024 return ERR;
1025 }
1026
1027 files[i].events = fds[i].events;
1028 files[i].revents = POLLNONE;
1029 }
1030
1031 uint64_t result = vfs_poll(files, amount, timeout);
1032 if (result != ERR)
1033 {
1034 for (uint64_t i = 0; i < amount; i++)
1035 {
1036 fds[i].revents = files[i].revents;
1037 }
1038 }
1039 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1040
1041 for (uint64_t i = 0; i < amount; i++)
1042 {
1043 UNREF(files[i].file);
1044 }
1045
1046 return result;
1047}
1048
1050{
1051 thread_t* thread = sched_thread();
1052 process_t* process = thread->process;
1053
1054 file_t* file = file_table_get(&process->fileTable, fd);
1055 if (file == NULL)
1056 {
1057 return ERR;
1058 }
1060
1061 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1062 {
1063 return ERR;
1064 }
1066 space_unpin(&process->space, buffer, count);
1067 return result;
1068}
1069
1070SYSCALL_DEFINE(SYS_STAT, uint64_t, const char* pathString, stat_t* buffer)
1071{
1072 thread_t* thread = sched_thread();
1073 process_t* process = thread->process;
1074
1075 pathname_t pathname;
1076 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1077 {
1078 return ERR;
1079 }
1080
1081 if (space_pin(&process->space, buffer, sizeof(stat_t), &thread->userStack) == ERR)
1082 {
1083 return ERR;
1084 }
1085 uint64_t result = vfs_stat(&pathname, buffer, process);
1086 space_unpin(&process->space, buffer, sizeof(stat_t));
1087 return result;
1088}
1089
1090SYSCALL_DEFINE(SYS_LINK, uint64_t, const char* oldPathString, const char* newPathString)
1091{
1092 thread_t* thread = sched_thread();
1093 process_t* process = thread->process;
1094
1095 pathname_t oldPathname;
1096 if (thread_copy_from_user_pathname(thread, &oldPathname, oldPathString) == ERR)
1097 {
1098 return ERR;
1099 }
1100
1101 pathname_t newPathname;
1102 if (thread_copy_from_user_pathname(thread, &newPathname, newPathString) == ERR)
1103 {
1104 return ERR;
1105 }
1106
1107 return vfs_link(&oldPathname, &newPathname, process);
1108}
1109
1110SYSCALL_DEFINE(SYS_REMOVE, uint64_t, const char* pathString)
1111{
1112 thread_t* thread = sched_thread();
1113 process_t* process = thread->process;
1114
1115 pathname_t pathname;
1116 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1117 {
1118 return ERR;
1119 }
1120
1121 return vfs_remove(&pathname, process);
1122}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define SEEK_END
Definition SEEK.h:6
#define assert(expression)
Definition assert.h:29
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:163
@ SYS_MMAP
Definition syscall.h:84
@ SYS_STAT
Definition syscall.h:83
@ SYS_WRITE
Definition syscall.h:78
@ SYS_LINK
Definition syscall.h:94
@ SYS_READ
Definition syscall.h:77
@ SYS_OPEN2
Definition syscall.h:75
@ SYS_POLL
Definition syscall.h:82
@ SYS_OPEN
Definition syscall.h:74
@ SYS_IOCTL
Definition syscall.h:80
@ SYS_OPENAT
Definition syscall.h:98
@ SYS_GETDENTS
Definition syscall.h:87
@ SYS_REMOVE
Definition syscall.h:93
@ SYS_SEEK
Definition syscall.h:79
path_t cwd_get(cwd_t *cwd)
Get the current working directory.
Definition cwd.c:18
bool dentry_is_positive(dentry_t *dentry)
Check if a dentry is positive.
Definition dentry.c:243
bool dentry_is_dir(dentry_t *dentry)
Check if the inode associated with a dentry is a directory.
Definition dentry.c:268
bool dentry_is_file(dentry_t *dentry)
Check if the inode associated with a dentry is a file.
Definition dentry.c:253
uint64_t file_table_free(file_table_t *table, fd_t fd)
Free a file descriptor.
Definition file_table.c:72
file_t * file_table_get(file_table_t *table, fd_t fd)
Get a file from its file descriptor.
Definition file_table.c:31
fd_t file_table_alloc(file_table_t *table, file_t *file)
Allocate a new file descriptor for a file.
Definition file_table.c:50
file_t * file_new(const path_t *path, mode_t mode)
Create a new file structure.
Definition file.c:32
void inode_notify_change(inode_t *inode)
Notify the inode that its metadata has changed.
Definition inode.c:109
void inode_notify_modify(inode_t *inode)
Notify the inode that its content has been modified.
Definition inode.c:97
void inode_notify_access(inode_t *inode)
Notify the inode that it has been accessed.
Definition inode.c:85
void inode_truncate(inode_t *inode)
Truncate the inode.
Definition inode.c:120
void path_put(path_t *path)
Put a path.
Definition path.c:246
#define PATH_CREATE(inMount, inDentry)
Helper to create a path.
Definition path.h:207
#define PATH_DEFER(path)
Defer path put.
Definition path.h:97
#define PATHNAME_IS_VALID(pathname)
Check if a pathname is valid.
Definition path.h:153
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
void path_copy(path_t *dest, const path_t *src)
Copy a path.
Definition path.c:221
#define PATH_EMPTY
Helper to create an empty path.
Definition path.h:194
@ 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_TRUNCATE
Definition path.h:83
@ MODE_WRITE
Definition path.h:77
@ MODE_READ
Definition path.h:76
@ MODE_EXCLUSIVE
Definition path.h:82
@ MODE_DIRECTORY
Definition path.h:84
@ PML_USER
@ PML_NONE
void space_unpin(space_t *space, const void *address, uint64_t length)
Unpins pages in a region previously pinned with space_pin() or space_pin_string().
Definition space.c:452
uint64_t space_check_access(space_t *space, const void *addr, uint64_t length)
Checks if a virtual memory region is within the allowed address range of the space.
Definition space.c:478
uint64_t space_pin(space_t *space, const void *address, uint64_t length, stack_pointer_t *userStack)
Pins pages within a region of the address space.
Definition space.c:330
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:138
clock_t clock_uptime(void)
Retrieve the time in nanoseconds since boot.
Definition clock.c:99
uint64_t thread_copy_to_user(thread_t *thread, void *dest, const void *userSrc, uint64_t length)
Safely copy data to user space.
Definition thread.c:200
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:259
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:103
uint64_t wait_block_commit(void)
Block the currently running thread.
Definition wait.c:199
void wait_block_cancel(void)
Cancels blocking of the currently running thread.
Definition wait.c:178
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:620
thread_t * sched_thread(void)
Retrieves the currently running thread.
Definition sched.c:612
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 UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:80
uint64_t vfs_ioctl(file_t *file, uint64_t request, void *argp, uint64_t size)
Perform an ioctl operation on a file.
Definition vfs.c:304
uint64_t vfs_seek(file_t *file, int64_t offset, seek_origin_t origin)
Seek in a file.
Definition vfs.c:286
void * vfs_mmap(file_t *file, void *address, uint64_t length, pml_flags_t flags)
Memory map a file.
Definition vfs.c:333
uint64_t vfs_poll(poll_file_t *files, uint64_t amount, clock_t timeout)
Poll multiple files.
Definition vfs.c:440
uint64_t vfs_getdents(file_t *file, dirent_t *buffer, uint64_t count)
Get directory entries from a directory file.
Definition vfs.c:515
uint64_t vfs_write(file_t *file, const void *buffer, uint64_t count)
Write to a file.
Definition vfs.c:239
file_t * vfs_open(const pathname_t *pathname, process_t *process)
Open a file.
Definition vfs.c:94
uint64_t vfs_remove(const pathname_t *pathname, process_t *process)
Remove a file or directory.
Definition vfs.c:698
uint64_t vfs_stat(const pathname_t *pathname, stat_t *buffer, process_t *process)
Get file information.
Definition vfs.c:556
uint64_t vfs_read(file_t *file, void *buffer, uint64_t count)
Read from a file.
Definition vfs.c:200
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:158
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:609
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:108
uint64_t vfs_id_get(void)
Generates a new unique ID, to be used for any VFS object.
Definition vfs.c:765
#define CONFIG_MAX_FD
Maximum file descriptor configuration.
Definition config.h:47
#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 EIO
I/O error.
Definition errno.h:57
#define ENOTDIR
Not a directory.
Definition errno.h:132
#define errno
Error number variable.
Definition errno.h:27
#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 EISDIR
Is a directory.
Definition errno.h:137
uint8_t seek_origin_t
Type for the seek() origin argument.
Definition io.h:231
poll_events_t
Poll events type.
Definition io.h:257
#define POLL_SPECIAL
Poll event values that will always be checked and included even if not specified.
Definition io.h:269
@ INODE_FILE
Is a file.
Definition io.h:314
@ INODE_DIR
Is a directory.
Definition io.h:315
@ POLLNONE
None.
Definition io.h:258
@ POLLNVAL
Invalid file descriptor.
Definition io.h:263
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
prot_t
Memory protection flags.
Definition proc.h:129
@ PROT_READ
Readable memory.
Definition proc.h:131
@ PROT_EXECUTE
Executable memory.
Definition proc.h:133
@ PROT_WRITE
Writable memory.
Definition proc.h:132
#define NULL
Pointer error value.
Definition NULL.h:23
#define FD_NONE
No file descriptor constant.
Definition fd_t.h:22
#define ERR
Integer error value.
Definition ERR.h:17
#define CLOCKS_REMAINING(deadline, uptime)
Safely calculate remaining time until deadline.
Definition clock_t.h:28
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
#define CLOCKS_DEADLINE(timeout, uptime)
Safely calculate deadline from timeout.
Definition clock_t.h:45
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static uintptr_t address
Mapped virtual address of the HPET registers.
Definition hpet.c:95
static list_t files
Definition file.c:9
static dentry_t * file
Definition log_file.c:22
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static socket_family_ops_t ops
Definition local.c:505
static const path_flag_t flags[]
Definition path.c:42
static atomic_long count
Definition main.c:10
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:32
static uint64_t rflags_read()
Definition regs.h:78
#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
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
__INT64_TYPE__ int64_t
Definition stdint.h:16
_PUBLIC char * strncpy(char *_RESTRICT s1, const char *_RESTRICT s2, size_t n)
Definition strncpy.c:3
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
uint64_t(* getdents)(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, mode_t mode)
Definition dentry.h:73
inode_t * inode
Will be NULL if the dentry is negative, once positive it will never be NULL.
Definition dentry.h:88
char name[MAX_NAME]
Constant after creation.
Definition dentry.h:87
const dentry_ops_t * ops
Definition dentry.h:94
dentry_t * parent
Definition dentry.h:90
superblock_t * superblock
Definition dentry.h:93
Directory entry struct.
Definition io.h:393
File structure.
Definition file.h:39
path_t path
Definition file.h:44
uint64_t(* remove)(inode_t *dir, dentry_t *target, mode_t mode)
Remove a file or directory.
Definition inode.h:128
uint64_t(* create)(inode_t *dir, dentry_t *target, mode_t mode)
Handles both directories and files depending on mode.
Definition inode.h:104
uint64_t(* link)(inode_t *dir, dentry_t *old, dentry_t *new)
Make the same file inode appear twice in the filesystem.
Definition inode.h:119
Inode structure.
Definition inode.h:56
uint64_t blocks
Definition inode.h:63
mutex_t mutex
Definition inode.h:72
time_t accessTime
Unix time stamp for the last inode access.
Definition inode.h:64
time_t createTime
Unix time stamp for the inode creation.
Definition inode.h:67
time_t modifyTime
Unix time stamp for last file content alteration.
Definition inode.h:65
inode_type_t type
Constant after creation.
Definition inode.h:59
inode_number_t number
Constant after creation.
Definition inode.h:58
const inode_ops_t * ops
Constant after creation.
Definition inode.h:70
uint64_t size
Definition inode.h:62
time_t changeTime
Unix time stamp for the last file metadata alteration.
Definition inode.h:66
mode_t mode
Specifies the maximum permissions for this mount and if it is a directory or a file.
Definition mount.h:52
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
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 io.h:276
poll_events_t revents
The events that occurred.
Definition io.h:279
poll_events_t events
The events to wait for.
Definition io.h:278
fd_t fd
The file descriptor to poll.
Definition io.h:277
Process structure.
Definition process.h:205
file_table_t fileTable
Definition process.h:213
namespace_t ns
Definition process.h:211
space_t space
Definition process.h:210
cwd_t cwd
Definition process.h:212
Virtual address space structure.
Definition space.h:79
Stat type.
Definition io.h:329
superblock_id_t id
Definition superblock.h:47
Thread of execution structure.
Definition thread.h:56
process_t * process
The parent process that the thread executes within.
Definition thread.h:57
stack_pointer_t userStack
The user stack of the thread.
Definition thread.h:69
uint16_t lookupTable[CONFIG_MAX_FD]
Definition vfs.c:367
wait_queue_t * queues[CONFIG_MAX_FD]
Definition vfs.c:366
uint16_t queueAmount
Definition vfs.c:368
The primitive that threads block on.
Definition wait.h:182
static uint64_t vfs_open_lookup(path_t *path, const pathname_t *pathname, namespace_t *namespace)
Definition vfs.c:79
static uint64_t vfs_create(path_t *path, const pathname_t *pathname, namespace_t *ns)
Definition vfs.c:33
static uint64_t vfs_poll_ctx_check_events(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:409
static uint64_t vfs_poll_ctx_init(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:371