PatchworkOS
Loading...
Searching...
No Matches
vfs.c
Go to the documentation of this file.
1#include <kernel/fs/vfs.h>
2
3#include "sys/list.h"
5#include <kernel/fs/dentry.h>
6#include <kernel/fs/inode.h>
7#include <kernel/fs/key.h>
8#include <kernel/fs/mount.h>
9#include <kernel/fs/path.h>
10#include <kernel/fs/sysfs.h>
11#include <kernel/fs/vfs_ctx.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/timer.h>
18#include <kernel/sched/wait.h>
19#include <kernel/sync/mutex.h>
20#include <kernel/sync/rwlock.h>
21#include <kernel/utils/ref.h>
22
23#include <kernel/cpu/regs.h>
24
25#include <assert.h>
26#include <errno.h>
27#include <stdint.h>
28#include <string.h>
29#include <sys/io.h>
30
31static _Atomic(uint64_t) newVfsId = ATOMIC_VAR_INIT(0);
32
33static vfs_list_t superblocks;
34static vfs_list_t filesystems;
35
36static vfs_map_t dentryCache;
37static vfs_map_t inodeCache;
38
39static dentry_t* root = NULL;
40
41static map_key_t inode_cache_key(superblock_id_t superblockId, inode_number_t number)
42{
43 struct
44 {
45 superblock_id_t superblockId;
46 inode_number_t number;
47 } buffer;
48 buffer.superblockId = superblockId;
49 buffer.number = number;
50
51 return map_key_buffer(&buffer, sizeof(buffer));
52}
53
54static map_key_t dentry_cache_key(dentry_id_t parentId, const char* name)
55{
56 struct
57 {
58 dentry_id_t parentId;
59 char name[MAX_NAME];
60 } buffer;
61 buffer.parentId = parentId;
62 memset(buffer.name, 0, sizeof(buffer.name));
63 strncpy_s(buffer.name, sizeof(buffer.name), name, MAX_NAME - 1);
64
65 return map_key_buffer(&buffer, sizeof(buffer));
66}
67
68static void vfs_list_init(vfs_list_t* list)
69{
70 list_init(&list->list);
71 rwlock_init(&list->lock);
72}
73
75{
76 if (map_init(&map->map) == ERR)
77 {
78 panic(NULL, "vfs: failed to initialize map");
79 }
80 rwlock_init(&map->lock);
81}
82
83void vfs_init(void)
84{
85 vfs_list_init(&superblocks);
86 vfs_list_init(&filesystems);
87
88 vfs_map_init(&dentryCache);
89 vfs_map_init(&inodeCache);
90
92 key_init();
93
94 LOG_INFO("virtual file system initialized\n");
95}
96
98{
99 return atomic_fetch_add(&newVfsId, 1);
100}
101
103{
104 if (fs == NULL || strnlen_s(fs->name, MAX_NAME) > MAX_NAME)
105 {
106 errno = EINVAL;
107 return ERR;
108 }
109
110 RWLOCK_WRITE_SCOPE(&filesystems.lock);
111
112 filesystem_t* existing;
113 LIST_FOR_EACH(existing, &filesystems.list, entry)
114 {
115 if (strcmp(existing->name, fs->name) == 0)
116 {
117 errno = EEXIST;
118 return ERR;
119 }
120 }
121
123 list_push(&filesystems.list, &fs->entry);
124 return 0;
125}
126
128{
129 if (fs == NULL)
130 {
131 errno = EINVAL;
132 return ERR;
133 }
134
135 RWLOCK_WRITE_SCOPE(&filesystems.lock);
136 RWLOCK_READ_SCOPE(&superblocks.lock);
137
138 superblock_t* superblock;
139 LIST_FOR_EACH(superblock, &superblocks.list, entry)
140 {
141 if (strcmp(superblock->fs->name, fs->name) == 0)
142 {
143 errno = EBUSY;
144 return ERR;
145 }
146 }
147
148 list_remove(&filesystems.list, &fs->entry);
149 return 0;
150}
151
152filesystem_t* vfs_get_fs(const char* name)
153{
154 RWLOCK_READ_SCOPE(&filesystems.lock);
155
156 filesystem_t* fs;
157 LIST_FOR_EACH(fs, &filesystems.list, entry)
158 {
159 if (strcmp(fs->name, name) == 0)
160 {
161 return fs;
162 }
163 }
164
165 return NULL;
166}
167
169{
170 if (superblock == NULL)
171 {
172 return NULL;
173 }
174
175 map_key_t key = inode_cache_key(superblock->id, number);
176
177 RWLOCK_READ_SCOPE(&inodeCache.lock);
178
179 inode_t* inode = CONTAINER_OF_SAFE(map_get(&inodeCache.map, &key), inode_t, mapEntry);
180 if (inode == NULL)
181 {
182 errno = ENOENT;
183 return NULL;
184 }
185
186 if (atomic_load(&inode->ref.count) == 0) // Is currently being removed
187 {
188 errno = ESTALE;
189 return NULL;
190 }
191
192 return REF(inode);
193}
194
196{
197 RWLOCK_READ_SCOPE(&dentryCache.lock);
198
199 dentry_t* dentry = CONTAINER_OF_SAFE(map_get(&dentryCache.map, key), dentry_t, mapEntry);
200 if (dentry == NULL)
201 {
202 errno = ENOENT;
203 return NULL;
204 }
205
206 if (atomic_load(&dentry->ref.count) == 0) // Is currently being removed
207 {
208 errno = ESTALE;
209 return NULL;
210 }
211
212 return REF(dentry);
213}
214
215dentry_t* vfs_get_dentry(const dentry_t* parent, const char* name)
216{
217 if (parent == NULL || name == NULL)
218 {
219 errno = EINVAL;
220 return NULL;
221 }
222
223 map_key_t key = dentry_cache_key(parent->id, name);
224 return vfs_get_dentry_internal(&key);
225}
226
227dentry_t* vfs_get_or_lookup_dentry(const path_t* parent, const char* name)
228{
229 if (parent == NULL || parent->dentry == NULL || parent->mount == NULL || name == NULL)
230 {
231 errno = EINVAL;
232 return NULL;
233 }
234
235 map_key_t key = dentry_cache_key(parent->dentry->id, name);
236 dentry_t* dentry = vfs_get_dentry_internal(&key);
237 if (dentry != NULL)
238 {
239 return dentry;
240 }
241
242 if (parent->dentry->inode == NULL || parent->dentry->inode->ops == NULL ||
243 parent->dentry->inode->ops->lookup == NULL)
244 {
245 errno = ENOENT;
246 return NULL;
247 }
248
249 dentry = dentry_new(parent->dentry->superblock, parent->dentry, name);
250 if (dentry == NULL)
251 {
252 // This logic is a bit complex, but im pretty confident its correct.
253 if (errno == EEXIST) // Dentry was created after we called vfs_get_dentry_internal but before dentry_new
254 {
255 // If this fails then the dentry was deleted in between dentry_new and here, which should be fine?
256 return vfs_get_dentry_internal(&key);
257 }
258 return NULL;
259 }
260 DEREF_DEFER(dentry);
261
262 inode_t* dir = parent->dentry->inode;
263 MUTEX_SCOPE(&dir->mutex);
264
266 if (dir->ops->lookup(dir, dentry) == ERR)
267 {
268 vfs_remove_dentry(dentry);
269 return NULL;
270 }
271
272 return REF(dentry);
273}
274
276{
277 map_key_t key = inode_cache_key(inode->superblock->id, inode->number);
278
279 RWLOCK_WRITE_SCOPE(&inodeCache.lock);
280 if (map_insert(&inodeCache.map, &key, &inode->mapEntry) == ERR)
281 {
282 return ERR;
283 }
284
285 return 0;
286}
287
289{
290 map_key_t key = dentry_cache_key(dentry->parent->id, dentry->name);
291
292 RWLOCK_WRITE_SCOPE(&dentryCache.lock);
293 if (map_insert(&dentryCache.map, &key, &dentry->mapEntry) == ERR)
294 {
295 return ERR;
296 }
297
298 return 0;
299}
300
302{
303 if (superblock == NULL)
304 {
305 return;
306 }
307
308 RWLOCK_WRITE_SCOPE(&superblocks.lock);
309 list_remove(&superblocks.list, &superblock->entry);
310}
311
313{
314 if (inode == NULL)
315 {
316 return;
317 }
318
319 RWLOCK_WRITE_SCOPE(&inodeCache.lock);
320 map_key_t key = inode_cache_key(inode->superblock->id, inode->number);
321 map_remove(&inodeCache.map, &key);
322}
323
325{
326 if (dentry == NULL)
327 {
328 return;
329 }
330
331 RWLOCK_WRITE_SCOPE(&dentryCache.lock);
332 map_key_t key = dentry_cache_key(dentry->parent->id, dentry->name);
333 map_remove(&dentryCache.map, &key);
334}
335
337{
338 return REF(root);
339}
340
341uint64_t vfs_walk(path_t* outPath, const pathname_t* pathname, walk_flags_t flags, process_t* process)
342{
343 if (outPath == NULL || !PATHNAME_IS_VALID(pathname) || process == NULL)
344 {
345 errno = EINVAL;
346 return ERR;
347 }
348
349 path_t cwd = PATH_EMPTY;
350 if (vfs_ctx_get_cwd(&process->vfsCtx, &cwd) == ERR)
351 {
352 return ERR;
353 }
354 PATH_DEFER(&cwd);
355
356 return path_walk(outPath, pathname, &cwd, flags, &process->namespace);
357}
358
359uint64_t vfs_walk_parent(path_t* outPath, const pathname_t* pathname, char* outLastName, walk_flags_t flags,
360 process_t* process)
361{
362 if (outPath == NULL || !PATHNAME_IS_VALID(pathname) || process == NULL)
363 {
364 errno = EINVAL;
365 return ERR;
366 }
367
368 path_t cwd = PATH_EMPTY;
369 if (vfs_ctx_get_cwd(&process->vfsCtx, &cwd) == ERR)
370 {
371 return ERR;
372 }
373 PATH_DEFER(&cwd);
374
375 return path_walk_parent(outPath, pathname, &cwd, outLastName, flags, &process->namespace);
376}
377
378uint64_t vfs_walk_parent_and_child(path_t* outParent, path_t* outChild, const pathname_t* pathname, walk_flags_t flags,
379 process_t* process)
380{
381 char lastName[MAX_NAME];
382 path_t parent = PATH_EMPTY;
383 if (vfs_walk_parent(&parent, pathname, lastName, WALK_NONE, process) == ERR)
384 {
385 return ERR;
386 }
387 PATH_DEFER(&parent);
388
389 path_t child = PATH_EMPTY;
390 if (path_walk_single_step(&child, &parent, lastName, flags, &process->namespace) == ERR)
391 {
392 return ERR;
393 }
394 PATH_DEFER(&child);
395
396 path_copy(outParent, &parent);
397 path_copy(outChild, &child);
398 return 0;
399}
400
401bool vfs_is_name_valid(const char* name)
402{
403 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
404 {
405 return false;
406 }
407
408 for (uint64_t i = 0; i < MAX_NAME - 1; i++)
409 {
410 if (name[i] == '\0')
411 {
412 return true;
413 }
414 if (!PATH_VALID_CHAR(name[i]))
415 {
416 return false;
417 }
418 }
419
420 return false;
421}
422
423static uint64_t vfs_create(path_t* outPath, const pathname_t* pathname, process_t* process)
424{
425 char lastComponent[MAX_NAME];
426 path_t parent = PATH_EMPTY;
427 path_t target = PATH_EMPTY;
428 if (vfs_walk_parent_and_child(&parent, &target, pathname, WALK_NEGATIVE_IS_OK, process) == ERR)
429 {
430 return ERR;
431 }
432 PATH_DEFER(&parent);
433 PATH_DEFER(&target);
434
435 if (parent.dentry->inode == NULL || parent.dentry->inode->type != INODE_DIR)
436 {
437 errno = ENOTDIR;
438 return ERR;
439 }
440
441 if (parent.dentry->inode->ops == NULL || parent.dentry->inode->ops->create == NULL)
442 {
443 errno = ENOSYS;
444 return ERR;
445 }
446
447 if (!(atomic_load(&target.dentry->flags) & DENTRY_NEGATIVE))
448 {
449 if (pathname->flags & PATH_EXCLUSIVE)
450 {
451 errno = EEXIST;
452 return ERR;
453 }
454
455 if ((pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_DIR)
456 {
457 errno = ENOTDIR;
458 return ERR;
459 }
460
461 if (!(pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_FILE)
462 {
463 errno = EISDIR;
464 return ERR;
465 }
466
467 path_copy(outPath, &target);
468 return 0;
469 }
470
471 inode_t* dir = parent.dentry->inode;
472 MUTEX_SCOPE(&dir->mutex);
473
475 if (dir->ops->create(dir, target.dentry, pathname->flags) == ERR)
476 {
477 return ERR;
478 }
479
480 if (atomic_load(&target.dentry->flags) & DENTRY_NEGATIVE)
481 {
482 errno = EIO;
483 return ERR;
484 }
485
486 path_copy(outPath, &target);
487 return 0;
488}
489
490static uint64_t vfs_open_lookup(path_t* outPath, const pathname_t* pathname, process_t* process)
491{
492 path_t target = PATH_EMPTY;
493 if (pathname->flags & PATH_CREATE)
494 {
495 if (vfs_create(&target, pathname, process) == ERR)
496 {
497 return ERR;
498 }
499 }
500 else // Dont create dentry
501 {
502 if (vfs_walk(&target, pathname, WALK_NONE, process) == ERR)
503 {
504 return ERR;
505 }
506 }
507 PATH_DEFER(&target);
508
509 if (target.dentry->inode == NULL)
510 {
511 errno = ENOENT;
512 return ERR;
513 }
514
515 if ((pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_DIR)
516 {
517 errno = ENOTDIR;
518 return ERR;
519 }
520
521 if (!(pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_FILE)
522 {
523 errno = EISDIR;
524 return ERR;
525 }
526
527 path_copy(outPath, &target);
528 return 0;
529}
530
531file_t* vfs_open(const pathname_t* pathname, process_t* process)
532{
533 if (!PATHNAME_IS_VALID(pathname) || process == NULL)
534 {
535 errno = EINVAL;
536 return NULL;
537 }
538
539 path_t path = PATH_EMPTY;
540 if (vfs_open_lookup(&path, pathname, process) == ERR)
541 {
542 return NULL;
543 }
544 PATH_DEFER(&path);
545
546 file_t* file = file_new(path.dentry->inode, &path, pathname->flags);
547 if (file == NULL)
548 {
549 return NULL;
550 }
552
553 if (pathname->flags & PATH_TRUNCATE && path.dentry->inode->type == INODE_FILE)
554 {
556 }
557
558 if (file->ops != NULL && file->ops->open != NULL)
559 {
561 uint64_t result = file->ops->open(file);
562 if (result == ERR)
563 {
564 return NULL;
565 }
566 }
567
569 return REF(file);
570}
571
572SYSCALL_DEFINE(SYS_OPEN, fd_t, const char* pathString)
573{
574 thread_t* thread = sched_thread();
575 process_t* process = thread->process;
576
577 pathname_t pathname;
578 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
579 {
580 return ERR;
581 }
582
583 file_t* file = vfs_open(&pathname, process);
584 if (file == NULL)
585 {
586 return ERR;
587 }
589
590 return vfs_ctx_alloc_fd(&process->vfsCtx, file);
591}
592
593uint64_t vfs_open2(const pathname_t* pathname, file_t* files[2], process_t* process)
594{
595 if (!PATHNAME_IS_VALID(pathname) || files == NULL || process == NULL)
596 {
597 errno = EINVAL;
598 return ERR;
599 }
600
601 path_t path = PATH_EMPTY;
602 if (vfs_open_lookup(&path, pathname, process) == ERR)
603 {
604 return ERR;
605 }
606 PATH_DEFER(&path);
607
608 files[0] = file_new(path.dentry->inode, &path, pathname->flags);
609 if (files[0] == NULL)
610 {
611 return ERR;
612 }
613 DEREF_DEFER(files[0]);
614
615 files[1] = file_new(path.dentry->inode, &path, pathname->flags);
616 if (files[1] == NULL)
617 {
618 return ERR;
619 }
620 DEREF_DEFER(files[1]);
621
622 if (pathname->flags & PATH_TRUNCATE && path.dentry->inode->type == INODE_FILE)
623 {
625 }
626
627 if (files[0]->ops == NULL || files[0]->ops->open2 == NULL)
628 {
629 errno = ENOSYS;
630 return ERR;
631 }
632
634 uint64_t result = files[0]->ops->open2(files);
635 if (result == ERR)
636 {
637 return ERR;
638 }
639
640 inode_notify_access(files[0]->inode);
641 REF(files[0]);
642 REF(files[1]);
643 return 0;
644}
645
646SYSCALL_DEFINE(SYS_OPEN2, uint64_t, const char* pathString, fd_t fds[2])
647{
648 if (fds == NULL)
649 {
650 errno = EINVAL;
651 return ERR;
652 }
653
654 thread_t* thread = sched_thread();
655 process_t* process = thread->process;
656
657 pathname_t pathname;
658 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
659 {
660 return ERR;
661 }
662
663 file_t* files[2];
664 if (vfs_open2(&pathname, files, process) == ERR)
665 {
666 return ERR;
667 }
668 DEREF_DEFER(files[0]);
669 DEREF_DEFER(files[1]);
670
671 fd_t fdsLocal[2];
672 fdsLocal[0] = vfs_ctx_alloc_fd(&process->vfsCtx, files[0]);
673 if (fdsLocal[0] == ERR)
674 {
675 return ERR;
676 }
677 fdsLocal[1] = vfs_ctx_alloc_fd(&process->vfsCtx, files[1]);
678 if (fdsLocal[1] == ERR)
679 {
680 vfs_ctx_free_fd(&process->vfsCtx, fdsLocal[0]);
681 return ERR;
682 }
683
684 if (thread_copy_to_user(thread, fds, fdsLocal, sizeof(fd_t) * 2) == ERR)
685 {
686 vfs_ctx_free_fd(&process->vfsCtx, fdsLocal[0]);
687 vfs_ctx_free_fd(&process->vfsCtx, fdsLocal[1]);
688 return ERR;
689 }
690
691 return 0;
692}
693
695{
696 if (file == NULL || buffer == NULL)
697 {
698 errno = EINVAL;
699 return ERR;
700 }
701
702 if (file->inode->type == INODE_DIR)
703 {
704 errno = EISDIR;
705 return ERR;
706 }
707
708 if (file->ops == NULL || file->ops->read == NULL)
709 {
710 errno = ENOSYS;
711 return ERR;
712 }
713
715 uint64_t offset = file->pos;
716 uint64_t result = file->ops->read(file, buffer, count, &offset);
717 file->pos = offset;
718
719 if (result != ERR)
720 {
722 }
723
724 return result;
725}
726
728{
729 thread_t* thread = sched_thread();
730 process_t* process = thread->process;
731
732 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
733 if (file == NULL)
734 {
735 return ERR;
736 }
738
739 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
740 {
741 return ERR;
742 }
743 uint64_t result = vfs_read(file, buffer, count);
744 space_unpin(&process->space, buffer, count);
745 return result;
746}
747
749{
750 if (file == NULL || buffer == NULL)
751 {
752 errno = EINVAL;
753 return ERR;
754 }
755
756 if (file->inode->type == INODE_DIR)
757 {
758 errno = EISDIR;
759 return ERR;
760 }
761
762 if (file->ops == NULL || file->ops->write == NULL)
763 {
764 errno = ENOSYS;
765 return ERR;
766 }
767
768 if (file->flags & PATH_APPEND && file->ops->seek != NULL && file->ops->seek(file, 0, SEEK_END) == ERR)
769 {
770 return ERR;
771 }
772
774 uint64_t offset = file->pos;
775 uint64_t result = file->ops->write(file, buffer, count, &offset);
776 file->pos = offset;
777
778 if (result != ERR)
779 {
781 }
782
783 return result;
784}
785
787{
788 thread_t* thread = sched_thread();
789 process_t* process = thread->process;
790
791 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
792 if (file == NULL)
793 {
794 return ERR;
795 }
797
798 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
799 {
800 return ERR;
801 }
802 uint64_t result = vfs_write(file, buffer, count);
803 space_unpin(&process->space, buffer, count);
804 return result;
805}
806
808{
809 if (file == NULL)
810 {
811 errno = EINVAL;
812 return ERR;
813 }
814
815 if (file->ops != NULL && file->ops->seek != NULL)
816 {
818 return file->ops->seek(file, offset, origin);
819 }
820
821 errno = ESPIPE;
822 return ERR;
823}
824
826{
827 process_t* process = sched_process();
828
829 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
830 if (file == NULL)
831 {
832 return ERR;
833 }
835
836 return vfs_seek(file, offset, origin);
837}
838
839uint64_t vfs_ioctl(file_t* file, uint64_t request, void* argp, uint64_t size)
840{
841 if (file == NULL)
842 {
843 errno = EINVAL;
844 return ERR;
845 }
846
847 if (file->inode->type == INODE_DIR)
848 {
849 errno = EISDIR;
850 return ERR;
851 }
852
853 if (file->ops == NULL || file->ops->ioctl == NULL)
854 {
855 errno = ENOTTY;
856 return ERR;
857 }
858
860 uint64_t result = file->ops->ioctl(file, request, argp, size);
861 if (result != ERR)
862 {
864 }
865 return result;
866}
867
868SYSCALL_DEFINE(SYS_IOCTL, uint64_t, fd_t fd, uint64_t request, void* argp, uint64_t size)
869{
870 thread_t* thread = sched_thread();
871 process_t* process = thread->process;
872
873 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
874 if (file == NULL)
875 {
876 return ERR;
877 }
879
880 if (space_pin(&process->space, argp, size, &thread->userStack) == ERR)
881 {
882 return ERR;
883 }
884 uint64_t result = vfs_ioctl(file, request, argp, size);
885 space_unpin(&process->space, argp, size);
886 return result;
887}
888
889void* vfs_mmap(file_t* file, void* address, uint64_t length, pml_flags_t flags)
890{
891 if (file == NULL)
892 {
893 return NULL;
894 }
895
896 if (file->inode->type == INODE_DIR)
897 {
898 errno = EISDIR;
899 return NULL;
900 }
901
902 if (file->ops == NULL || file->ops->mmap == NULL)
903 {
904 return NULL;
905 }
906
908 uint64_t offset = file->pos;
909 void* result = file->ops->mmap(file, address, length, &offset, flags);
910 if (result != NULL)
911 {
913 file->pos = offset;
914 }
915 return result;
916}
917
918SYSCALL_DEFINE(SYS_MMAP, void*, fd_t fd, void* address, uint64_t length, prot_t prot)
919{
920 process_t* process = sched_process();
921 space_t* space = &process->space;
922
923 if (address != NULL && space_check_access(space, address, length) == ERR)
924 {
925 return NULL;
926 }
927
928 pml_flags_t flags = vmm_prot_to_flags(prot);
929 if (flags == PML_NONE)
930 {
931 errno = EINVAL;
932 return NULL;
933 }
934
935 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
936 if (file == NULL)
937 {
938 return NULL;
939 }
941
942 return vfs_mmap(file, address, length, flags | PML_USER);
943}
944
951
953{
954 memset(ctx->queues, 0, sizeof(wait_queue_t*) * CONFIG_MAX_FD);
955 memset(ctx->lookupTable, 0, sizeof(uint16_t) * CONFIG_MAX_FD);
956 ctx->queueAmount = 0;
957
958 for (uint64_t i = 0; i < amount; i++)
959 {
960 files[i].revents = POLLNONE;
961 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &files[i].revents);
962 if (queue == NULL)
963 {
964 return ERR;
965 }
966
967 // Avoid duplicate queues.
968 bool found = false;
969 for (uint16_t j = 0; j < ctx->queueAmount; j++)
970 {
971 if (ctx->queues[j] == queue)
972 {
973 found = true;
974 ctx->lookupTable[i] = j;
975 break;
976 }
977 }
978
979 if (!found)
980 {
981 ctx->queues[ctx->queueAmount] = queue;
982 ctx->lookupTable[i] = ctx->queueAmount;
983 ctx->queueAmount++;
984 }
985 }
986
987 return 0;
988}
989
991{
992 uint64_t readyCount = 0;
993
994 for (uint64_t i = 0; i < amount; i++)
995 {
996 poll_events_t revents = POLLNONE;
997 wait_queue_t* queue = files[i].file->ops->poll(files[i].file, &revents);
998 if (queue == NULL)
999 {
1000 return ERR;
1001 }
1002
1003 files[i].revents = (revents & (files[i].events | POLL_SPECIAL));
1004
1005 // Make sure the queue hasn't changed, just for debugging.
1006 if (queue != ctx->queues[ctx->lookupTable[i]])
1007 {
1008 errno = EIO;
1009 return ERR;
1010 }
1011
1012 if ((files[i].revents & (files[i].events | POLL_SPECIAL)) != 0)
1013 {
1014 readyCount++;
1015 }
1016 }
1017
1018 return readyCount;
1019}
1020
1022{
1023 if (files == NULL || amount == 0 || amount > CONFIG_MAX_FD)
1024 {
1025 errno = EINVAL;
1026 return ERR;
1027 }
1028
1029 for (uint64_t i = 0; i < amount; i++)
1030 {
1031 if (files[i].file == NULL)
1032 {
1033 errno = EINVAL;
1034 return ERR;
1035 }
1036
1037 if (files[i].file->inode->type == INODE_DIR)
1038 {
1039 errno = EISDIR;
1040 return ERR;
1041 }
1042
1043 if (files[i].file->ops == NULL || files[i].file->ops->poll == NULL)
1044 {
1045 errno = ENOSYS;
1046 return ERR;
1047 }
1048 }
1049
1050 vfs_poll_ctx_t ctx;
1051 if (vfs_poll_ctx_init(&ctx, files, amount) == ERR)
1052 {
1053 return ERR;
1054 }
1055
1057
1058 clock_t deadline;
1059 if (timeout == CLOCKS_NEVER)
1060 {
1061 deadline = CLOCKS_NEVER;
1062 }
1063 else if (timeout > CLOCKS_NEVER - uptime)
1064 {
1065 deadline = CLOCKS_NEVER;
1066 }
1067 else
1068 {
1069 deadline = uptime + timeout;
1070 }
1071
1072 uint64_t readyCount = 0;
1073 while (true)
1074 {
1075 uptime = timer_uptime();
1076 clock_t remaining = (deadline == CLOCKS_NEVER) ? CLOCKS_NEVER : deadline - uptime;
1077
1078 if (wait_block_setup(ctx.queues, ctx.queueAmount, remaining) == ERR)
1079 {
1080 return ERR;
1081 }
1082
1083 readyCount = vfs_poll_ctx_check_events(&ctx, files, amount);
1084 if (readyCount == ERR)
1085 {
1087 return ERR;
1088 }
1089
1090 if (readyCount > 0 || uptime >= deadline)
1091 {
1093 break;
1094 }
1095
1096 if (wait_block_commit() == ERR)
1097 {
1098 if (errno == ETIMEDOUT)
1099 {
1100 break;
1101 }
1102 return ERR;
1103 }
1104 }
1105
1106 return readyCount;
1107}
1108
1110{
1111 thread_t* thread = sched_thread();
1112 process_t* process = thread->process;
1113
1114 if (amount == 0 || amount >= CONFIG_MAX_FD)
1115 {
1116 errno = EINVAL;
1117 return ERR;
1118 }
1119
1120 if (space_pin(&process->space, fds, sizeof(pollfd_t) * amount, &thread->userStack) == ERR)
1121 {
1122 errno = EFAULT;
1123 return ERR;
1124 }
1125
1127 for (uint64_t i = 0; i < amount; i++)
1128 {
1129 files[i].file = vfs_ctx_get_file(&process->vfsCtx, fds[i].fd);
1130 if (files[i].file == NULL)
1131 {
1132 for (uint64_t j = 0; j < i; j++)
1133 {
1134 DEREF(files[j].file);
1135 }
1136 if (errno == EBADF)
1137 {
1138 files[i].revents = POLLNVAL;
1139 }
1140 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1141 return ERR;
1142 }
1143
1144 files[i].events = fds[i].events;
1145 files[i].revents = POLLNONE;
1146 }
1147 space_unpin(&process->space, fds, sizeof(pollfd_t) * amount);
1148
1149 uint64_t result = vfs_poll(files, amount, timeout);
1150 if (result != ERR)
1151 {
1152 for (uint64_t i = 0; i < amount; i++)
1153 {
1154 fds[i].revents = files[i].revents;
1155 }
1156 }
1157
1158 for (uint64_t i = 0; i < amount; i++)
1159 {
1160 DEREF(files[i].file);
1161 }
1162
1163 return result;
1164}
1165
1167{
1168 if (file == NULL || (buffer == NULL && count > 0))
1169 {
1170 errno = EINVAL;
1171 return ERR;
1172 }
1173
1174 if (file->inode == NULL || file->inode->type != INODE_DIR)
1175 {
1176 errno = ENOTDIR;
1177 return ERR;
1178 }
1179
1180 if (file->path.dentry == NULL || file->path.dentry->parent == NULL)
1181 {
1182 errno = EINVAL;
1183 return ERR;
1184 }
1185
1186 if (file->path.dentry->ops == NULL || file->path.dentry->ops->getdents == NULL)
1187 {
1188 errno = ENOSYS;
1189 return ERR;
1190 }
1191
1193 uint64_t result = file->path.dentry->ops->getdents(file->path.dentry, buffer, count, &file->pos, file->flags);
1194 if (result != ERR)
1195 {
1197 }
1198 return result;
1199}
1200
1202{
1203 thread_t* thread = sched_thread();
1204 process_t* process = thread->process;
1205
1206 file_t* file = vfs_ctx_get_file(&process->vfsCtx, fd);
1207 if (file == NULL)
1208 {
1209 return ERR;
1210 }
1212
1213 if (space_pin(&process->space, buffer, count, &thread->userStack) == ERR)
1214 {
1215 return ERR;
1216 }
1218 space_unpin(&process->space, buffer, count);
1219 return result;
1220}
1221
1223{
1224 if (!PATHNAME_IS_VALID(pathname) || buffer == NULL || process == NULL)
1225 {
1226 errno = EINVAL;
1227 return ERR;
1228 }
1229
1230 if (pathname->flags != PATH_NONE)
1231 {
1232 errno = EBADFLAG;
1233 return ERR;
1234 }
1235
1236 path_t path = PATH_EMPTY;
1237 if (vfs_walk(&path, pathname, WALK_NONE, process) == ERR)
1238 {
1239 return ERR;
1240 }
1241 PATH_DEFER(&path);
1242
1243 memset(buffer, 0, sizeof(stat_t));
1244
1245 MUTEX_SCOPE(&path.dentry->inode->mutex);
1246 buffer->number = path.dentry->inode->number;
1247 buffer->type = path.dentry->inode->type;
1248 buffer->size = path.dentry->inode->size;
1249 buffer->blocks = path.dentry->inode->blocks;
1250 buffer->linkAmount = path.dentry->inode->linkCount;
1251 buffer->accessTime = path.dentry->inode->accessTime;
1252 buffer->modifyTime = path.dentry->inode->modifyTime;
1253 buffer->changeTime = path.dentry->inode->changeTime;
1254 buffer->createTime = path.dentry->inode->createTime;
1255 strncpy(buffer->name, path.dentry->name, MAX_NAME - 1);
1256 buffer->name[MAX_NAME - 1] = '\0';
1257
1258 return 0;
1259}
1260
1261SYSCALL_DEFINE(SYS_STAT, uint64_t, const char* pathString, stat_t* buffer)
1262{
1263 thread_t* thread = sched_thread();
1264 process_t* process = thread->process;
1265
1266 pathname_t pathname;
1267 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1268 {
1269 return ERR;
1270 }
1271
1272 if (space_pin(&process->space, buffer, sizeof(stat_t), &thread->userStack) == ERR)
1273 {
1274 return ERR;
1275 }
1276 uint64_t result = vfs_stat(&pathname, buffer, process);
1277 space_unpin(&process->space, buffer, sizeof(stat_t));
1278 return result;
1279}
1280
1281uint64_t vfs_link(const pathname_t* oldPathname, const pathname_t* newPathname, process_t* process)
1282{
1283 if (!PATHNAME_IS_VALID(oldPathname) || !PATHNAME_IS_VALID(newPathname) || process == NULL)
1284 {
1285 errno = EINVAL;
1286 return ERR;
1287 }
1288
1289 if (oldPathname->flags != PATH_NONE || newPathname->flags != PATH_NONE)
1290 {
1291 errno = EBADFLAG;
1292 return ERR;
1293 }
1294
1295 path_t oldParent = PATH_EMPTY;
1296 path_t old = PATH_EMPTY;
1297 if (vfs_walk_parent_and_child(&oldParent, &old, oldPathname, WALK_NONE, process) == ERR)
1298 {
1299 return ERR;
1300 }
1301 PATH_DEFER(&oldParent);
1302 PATH_DEFER(&old);
1303
1304 path_t newParent = PATH_EMPTY;
1305 path_t target = PATH_EMPTY;
1306 if (vfs_walk_parent_and_child(&newParent, &target, newPathname, WALK_NEGATIVE_IS_OK, process) == ERR)
1307 {
1308 return ERR;
1309 }
1310 PATH_DEFER(&newParent);
1311 PATH_DEFER(&target);
1312
1313 if (oldParent.dentry->superblock->id != newParent.dentry->superblock->id)
1314 {
1315 errno = EXDEV;
1316 return ERR;
1317 }
1318
1319 if (oldParent.dentry->inode == NULL || oldParent.dentry->inode->ops == NULL ||
1320 oldParent.dentry->inode->ops->link == NULL)
1321 {
1322
1323 errno = ENOSYS;
1324 return ERR;
1325 }
1326
1328 mutex_acquire(&newParent.dentry->inode->mutex);
1329
1330 uint64_t result = 0;
1331 if (!(atomic_load(&target.dentry->flags) & DENTRY_NEGATIVE))
1332 {
1333 errno = EEXIST;
1334 result = ERR;
1335 }
1336
1337 if (result != ERR)
1338 {
1340 result = newParent.dentry->inode->ops->link(old.dentry, newParent.dentry->inode, target.dentry);
1341 }
1342
1343 mutex_release(&newParent.dentry->inode->mutex);
1345
1346 if (result == ERR)
1347 {
1348 return ERR;
1349 }
1350
1351 inode_notify_modify(newParent.dentry->inode);
1353
1354 return 0;
1355}
1356
1357SYSCALL_DEFINE(SYS_LINK, uint64_t, const char* oldPathString, const char* newPathString)
1358{
1359 thread_t* thread = sched_thread();
1360 process_t* process = thread->process;
1361
1362 pathname_t oldPathname;
1363 if (thread_copy_from_user_pathname(thread, &oldPathname, oldPathString) == ERR)
1364 {
1365 return ERR;
1366 }
1367
1368 pathname_t newPathname;
1369 if (thread_copy_from_user_pathname(thread, &newPathname, newPathString) == ERR)
1370 {
1371 return ERR;
1372 }
1373
1374 return vfs_link(&oldPathname, &newPathname, process);
1375}
1376
1377uint64_t vfs_remove(const pathname_t* pathname, process_t* process)
1378{
1379 if (!PATHNAME_IS_VALID(pathname) || process == NULL)
1380 {
1381 errno = EINVAL;
1382 return ERR;
1383 }
1384
1385 path_t parent = PATH_EMPTY;
1386 path_t target = PATH_EMPTY;
1387 if (vfs_walk_parent_and_child(&parent, &target, pathname, WALK_NONE, process) == ERR)
1388 {
1389 return ERR;
1390 }
1391 PATH_DEFER(&parent);
1392 PATH_DEFER(&target);
1393
1394 if ((pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_DIR)
1395 {
1396 errno = ENOTDIR;
1397 return ERR;
1398 }
1399
1400 if (!(pathname->flags & PATH_DIRECTORY) && target.dentry->inode->type != INODE_FILE)
1401 {
1402 errno = EISDIR;
1403 return ERR;
1404 }
1405
1406 inode_t* dir = parent.dentry->inode;
1407 if (dir->ops == NULL || dir->ops->remove == NULL)
1408 {
1409 errno = EPERM;
1410 return ERR;
1411 }
1412
1413 mutex_acquire(&dir->mutex);
1415 uint64_t result = dir->ops->remove(dir, target.dentry, pathname->flags);
1416 if (result != ERR)
1417 {
1418 vfs_remove_dentry(target.dentry);
1419 }
1420 mutex_release(&dir->mutex);
1421
1423
1424 return result;
1425}
1426
1427SYSCALL_DEFINE(SYS_REMOVE, uint64_t, const char* pathString)
1428{
1429 thread_t* thread = sched_thread();
1430 process_t* process = thread->process;
1431
1432 pathname_t pathname;
1433 if (thread_copy_from_user_pathname(thread, &pathname, pathString) == ERR)
1434 {
1435 return ERR;
1436 }
1437
1438 return vfs_remove(&pathname, process);
1439}
#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 CLOCKS_NEVER
Definition clock_t.h:16
#define SYS_REMOVE
Definition syscalls.h:50
#define SYS_GETDENTS
Definition syscalls.h:44
#define SYS_MMAP
Definition syscalls.h:41
#define SYS_OPEN2
Definition syscalls.h:32
#define SYS_WRITE
Definition syscalls.h:35
#define SYS_READ
Definition syscalls.h:34
#define SYS_OPEN
Definition syscalls.h:31
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscalls.h:100
#define SYS_STAT
Definition syscalls.h:40
#define SYS_SEEK
Definition syscalls.h:36
#define SYS_POLL
Definition syscalls.h:39
#define SYS_LINK
Definition syscalls.h:51
#define SYS_IOCTL
Definition syscalls.h:37
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:51
uint64_t dentry_id_t
Dentry ID type.
Definition dentry.h:33
@ DENTRY_NEGATIVE
Definition dentry.h:59
file_t * file_new(inode_t *inode, const path_t *path, path_flags_t flags)
Create a new file structure.
Definition file.c:31
void inode_notify_change(inode_t *inode)
Notify the inode that its metadata has changed.
Definition inode.c:119
void inode_notify_modify(inode_t *inode)
Notify the inode that its content has been modified.
Definition inode.c:106
void inode_notify_access(inode_t *inode)
Notify the inode that it has been accessed.
Definition inode.c:93
void inode_truncate(inode_t *inode)
Truncate the inode.
Definition inode.c:131
void key_init(void)
Initializes the key subsystem.
Definition key.c:60
uint64_t path_walk_parent(path_t *outPath, const pathname_t *pathname, const path_t *start, char *outLastName, walk_flags_t flags, namespace_t *ns)
Traverse a pathname to its parent and get the last component name.
Definition path.c:511
#define PATH_CREATE(inMount, inDentry)
Helper to create a path.
Definition path.h:195
uint64_t path_walk(path_t *outPath, const pathname_t *pathname, const path_t *start, walk_flags_t flags, namespace_t *ns)
Traverse a pathname from a specified starting path.
Definition path.c:376
#define PATH_DEFER(path)
Defer path put.
Definition path.h:53
uint64_t path_walk_single_step(path_t *outPath, const path_t *parent, const char *name, walk_flags_t flags, namespace_t *ns)
Traverse a single component from a parent path.
Definition path.c:329
walk_flags_t
Flags for walking a path.
Definition path.h:100
#define PATH_VALID_CHAR(ch)
Check if a char is valid.
Definition path.h:66
#define PATHNAME_IS_VALID(pathname)
Check if a pathname is valid.
Definition path.h:143
void path_flags_init(void)
Initialize path flags resolution.
Definition path.c:66
void path_copy(path_t *dest, const path_t *src)
Copy a path.
Definition path.c:232
#define PATH_EMPTY
Helper to create an empty path.
Definition path.h:182
@ PATH_EXCLUSIVE
Definition path.h:88
@ PATH_NONE
Definition path.h:84
@ PATH_TRUNCATE
Definition path.h:89
@ PATH_DIRECTORY
Definition path.h:90
@ PATH_APPEND
Definition path.h:86
@ WALK_NONE
No flags.
Definition path.h:101
@ WALK_NEGATIVE_IS_OK
If a negative dentry is ok, if not specified then it is considered an error.
Definition path.h:102
uint64_t superblock_id_t
Superblock ID type.
Definition superblock.h:35
uint64_t vfs_ctx_get_cwd(vfs_ctx_t *ctx, path_t *outCwd)
Definition vfs_ctx.c:67
fd_t vfs_ctx_alloc_fd(vfs_ctx_t *ctx, file_t *file)
Allocate a new file descriptor in a VFS context.
Definition vfs_ctx.c:142
uint64_t vfs_ctx_free_fd(vfs_ctx_t *ctx, fd_t fd)
Free a file descriptor in a VFS context.
Definition vfs_ctx.c:191
file_t * vfs_ctx_get_file(vfs_ctx_t *ctx, fd_t fd)
Get a file from a VFS context.
Definition vfs_ctx.c:48
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:839
uint64_t vfs_register_fs(filesystem_t *fs)
Registers a filesystem.
Definition vfs.c:102
uint64_t vfs_unregister_fs(filesystem_t *fs)
Unregisters a filesystem.
Definition vfs.c:127
uint64_t vfs_get_new_id(void)
Generates a new unique ID.
Definition vfs.c:97
uint64_t vfs_seek(file_t *file, int64_t offset, seek_origin_t origin)
Seek in a file.
Definition vfs.c:807
void * vfs_mmap(file_t *file, void *address, uint64_t length, pml_flags_t flags)
Memory map a file.
Definition vfs.c:889
void vfs_remove_inode(inode_t *inode)
Remove an inode from the inode cache.
Definition vfs.c:312
bool vfs_is_name_valid(const char *name)
Check if a name is valid.
Definition vfs.c:401
uint64_t vfs_walk_parent_and_child(path_t *outParent, path_t *outChild, const pathname_t *pathname, walk_flags_t flags, process_t *process)
Walk a pathname to path and its parent path, starting from the current process's working directory.
Definition vfs.c:378
filesystem_t * vfs_get_fs(const char *name)
Gets a filesystem by name.
Definition vfs.c:152
uint64_t vfs_poll(poll_file_t *files, uint64_t amount, clock_t timeout)
Poll multiple files.
Definition vfs.c:1021
uint64_t vfs_getdents(file_t *file, dirent_t *buffer, uint64_t count)
Get directory entries from a directory file.
Definition vfs.c:1166
void vfs_remove_dentry(dentry_t *dentry)
Remove a dentry from the dentry cache.
Definition vfs.c:324
uint64_t vfs_write(file_t *file, const void *buffer, uint64_t count)
Write to a file.
Definition vfs.c:748
file_t * vfs_open(const pathname_t *pathname, process_t *process)
Open a file.
Definition vfs.c:531
uint64_t vfs_add_dentry(dentry_t *dentry)
Add a dentry to the dentry cache.
Definition vfs.c:288
dentry_t * vfs_get_or_lookup_dentry(const path_t *parent, const char *name)
Get or lookup a dentry for the given name. Will NOT traverse mountpoints.
Definition vfs.c:227
uint64_t vfs_remove(const pathname_t *pathname, process_t *process)
Remove a file or directory.
Definition vfs.c:1377
dentry_t * vfs_get_dentry(const dentry_t *parent, const char *name)
Get a dentry for the given name. Will NOT traverse mountpoints.
Definition vfs.c:215
uint64_t vfs_stat(const pathname_t *pathname, stat_t *buffer, process_t *process)
Get file information.
Definition vfs.c:1222
uint64_t vfs_walk_parent(path_t *outPath, const pathname_t *pathname, char *outLastName, walk_flags_t flags, process_t *process)
Walk a pathname to its parent path, starting from the current process's working directory.
Definition vfs.c:359
void vfs_remove_superblock(superblock_t *superblock)
Remove a superblock from the superblock list.
Definition vfs.c:301
uint64_t vfs_read(file_t *file, void *buffer, uint64_t count)
Read from a file.
Definition vfs.c:694
uint64_t vfs_walk(path_t *outPath, const pathname_t *pathname, walk_flags_t flags, process_t *process)
Walk a pathname to a path, starting from the current process's working directory.
Definition vfs.c:341
void vfs_init(void)
Initializes the VFS.
Definition vfs.c:83
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:1281
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:593
inode_t * vfs_get_inode(superblock_t *superblock, inode_number_t number)
Get an inode for the given superblock and inode number.
Definition vfs.c:168
uint64_t vfs_add_inode(inode_t *inode)
Add a inode to the inode cache.
Definition vfs.c:275
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
#define LOG_INFO(format,...)
Definition log.h:87
@ 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:448
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:474
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:334
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:143
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:248
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:307
uint64_t wait_block_commit(void)
Block the currently running thread.
Definition wait.c:321
uint64_t wait_block_setup(wait_queue_t **waitQueues, uint64_t amount, clock_t timeout)
Setup blocking but dont block yet.
Definition wait.c:227
void wait_block_cancel(void)
Cancel blocking.
Definition wait.c:300
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:164
thread_t * sched_thread(void)
Retrieves the currently running thread.
Definition sched.c:157
void mutex_release(mutex_t *mtx)
Releases a mutex.
Definition mutex.c:103
void mutex_acquire(mutex_t *mtx)
Acquires a mutex, blocking until it is available.
Definition mutex.c:26
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
#define RWLOCK_READ_SCOPE(lock)
Acquires a rwlock for reading for the reminder of the current scope.
Definition rwlock.h:27
void rwlock_init(rwlock_t *lock)
Initializes a rwlock.
Definition rwlock.c:8
#define RWLOCK_WRITE_SCOPE(lock)
Acquires a rwlock for writing for the reminder of the current scope.
Definition rwlock.h:36
clock_t timer_uptime(void)
Time since boot.
Definition timer.c:73
static map_key_t map_key_buffer(const void *buffer, uint64_t length)
Create a map key from a buffer.
Definition map.h:99
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *value)
Insert a key-value pair into the map.
Definition map.c:191
uint64_t map_init(map_t *map)
Initialize a map.
Definition map.c:172
void map_remove(map_t *map, const map_key_t *key)
Remove a key-value pair from the map.
Definition map.c:258
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:236
#define DEREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#define CONFIG_MAX_FD
Maximum file descriptor configuration.
Definition config.h:47
#define ENOENT
No such file or directory.
Definition errno.h:42
#define ESTALE
Stale NFS file handle.
Definition errno.h:607
#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 EBUSY
Device or resource busy.
Definition errno.h:112
#define ENOTDIR
Not a directory.
Definition errno.h:132
#define EBADFLAG
Invalid path flag.
Definition errno.h:707
#define errno
Error number variable.
Definition errno.h:27
#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
uint64_t inode_number_t
Inode number enum.
Definition io.h:353
uint8_t seek_origin_t
Type for the seek() origin argument.
Definition io.h:262
poll_events_t
Poll events type.
Definition io.h:288
#define POLL_SPECIAL
Poll event values that will always be checked and included even if not specified.
Definition io.h:300
@ INODE_FILE
Is a file.
Definition io.h:345
@ INODE_DIR
Is a directory.
Definition io.h:346
@ POLLNONE
None.
Definition io.h:289
@ POLLNVAL
Invalid file descriptor.
Definition io.h:294
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
prot_t
Memory protection flags.
Definition proc.h:170
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static uintptr_t address
Definition hpet.c:12
static list_t files
Definition file.c:9
static dentry_t * file
Definition log_file.c:17
boot_memory_map_t * map
Definition mem.c:19
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static socket_family_ops_t ops
Definition local.c:505
static atomic_long count
Definition main.c:9
#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 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
errno_t strncpy_s(char *_RESTRICT s1, rsize_t s1max, const char *_RESTRICT s2, rsize_t n)
Definition strncpy_s.c:9
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
uint64_t(* getdents)(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, path_flags_t flags)
Used to now what is in a directory.
Definition dentry.h:74
Directory entry structure.
Definition dentry.h:83
inode_t * inode
Definition dentry.h:87
char name[MAX_NAME]
Definition dentry.h:86
ref_t ref
Definition dentry.h:84
dentry_id_t id
Definition dentry.h:85
const dentry_ops_t * ops
Definition dentry.h:93
dentry_t * parent
Definition dentry.h:88
superblock_t * superblock
Definition dentry.h:92
map_entry_t mapEntry
Definition dentry.h:95
Directory entry struct.
Definition io.h:424
File structure.
Definition file.h:37
Filesystem structure, represents a filesystem type, e.g. fat32, ramfs, sysfs, etc.
Definition vfs.h:45
list_entry_t entry
Definition vfs.h:46
const char * name
Definition vfs.h:47
uint64_t(* create)(inode_t *dir, dentry_t *target, path_flags_t flags)
Handles both directories and files, works the same as lookup.
Definition inode.h:91
uint64_t(* remove)(inode_t *parent, dentry_t *target, path_flags_t flags)
Handles both directories and files.
Definition inode.h:97
uint64_t(* link)(dentry_t *old, inode_t *dir, dentry_t *target)
Definition inode.h:93
uint64_t(* lookup)(inode_t *dir, dentry_t *target)
Should set the target dentry to be positive (give it an inode), if the entry does not exist the opera...
Definition inode.h:87
Inode structure.
Definition inode.h:54
uint64_t blocks
Definition inode.h:61
mutex_t mutex
Definition inode.h:70
ref_t ref
Definition inode.h:55
time_t accessTime
Unix time stamp for the last inode access.
Definition inode.h:62
time_t createTime
Unix time stamp for the inode creation.
Definition inode.h:65
time_t modifyTime
Unix time stamp for last file content alteration.
Definition inode.h:63
inode_type_t type
Constant after creation.
Definition inode.h:57
inode_number_t number
Constant after creation.
Definition inode.h:56
superblock_t * superblock
Constant after creation.
Definition inode.h:67
const inode_ops_t * ops
Constant after creation.
Definition inode.h:68
uint64_t size
Definition inode.h:60
time_t changeTime
Unix time stamp for the last file metadata alteration.
Definition inode.h:64
uint64_t linkCount
Definition inode.h:59
map_entry_t mapEntry
Protected by the inodeCache lock.
Definition inode.h:71
Map key stucture.
Definition map.h:45
Path structure.
Definition path.h:110
mount_t * mount
Definition path.h:111
dentry_t * dentry
Definition path.h:112
Pathname structure.
Definition path.h:122
path_flags_t flags
Definition path.h:124
A entry in a page table without a specified address or callback ID.
Structure for polling multiple files.
Definition file.h:74
Poll file descriptor structure.
Definition io.h:307
poll_events_t revents
The events that occurred.
Definition io.h:310
poll_events_t events
The events to wait for.
Definition io.h:309
fd_t fd
The file descriptor to poll.
Definition io.h:308
Process structure.
Definition process.h:53
space_t space
Definition process.h:59
vfs_ctx_t vfsCtx
Definition process.h:61
atomic_uint32_t count
Atomic reference counter.
Definition ref.h:40
Virtual address space structure.
Definition space.h:79
Stat type.
Definition io.h:360
Superblock structure.
Definition superblock.h:44
const filesystem_t * fs
Definition superblock.h:54
list_entry_t entry
Definition superblock.h:46
superblock_id_t id
Definition superblock.h:47
Thread of execution structure.
Definition thread.h:55
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
Helper structure for lists with a lock.
Definition vfs.h:55
list_t list
Definition vfs.h:56
rwlock_t lock
Definition vfs.h:57
Helper structure for maps with a lock.
Definition vfs.h:64
map_t map
Definition vfs.h:65
rwlock_t lock
Definition vfs.h:66
uint16_t lookupTable[CONFIG_MAX_FD]
Definition vfs.c:948
wait_queue_t * queues[CONFIG_MAX_FD]
Definition vfs.c:947
uint16_t queueAmount
Definition vfs.c:949
Wait queue structure.
Definition wait.h:166
static void vfs_map_init(vfs_map_t *map)
Definition vfs.c:74
static uint64_t vfs_poll_ctx_check_events(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:990
static dentry_t * vfs_get_dentry_internal(map_key_t *key)
Definition vfs.c:195
static map_key_t dentry_cache_key(dentry_id_t parentId, const char *name)
Definition vfs.c:54
static uint64_t vfs_create(path_t *outPath, const pathname_t *pathname, process_t *process)
Definition vfs.c:423
static uint64_t vfs_poll_ctx_init(vfs_poll_ctx_t *ctx, poll_file_t *files, uint64_t amount)
Definition vfs.c:952
static uint64_t vfs_open_lookup(path_t *outPath, const pathname_t *pathname, process_t *process)
Definition vfs.c:490
dentry_t * vfs_get_root_dentry(void)
Definition vfs.c:336
static void vfs_list_init(vfs_list_t *list)
Definition vfs.c:68