use the -newos toolchain even if -elf is present.
[newos.git] / kernel / vfs.c
blobc199fa392950a6f4cfe03e5590bb63627dc06749
1 /*
2 ** Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
4 */
5 #include <kernel/kernel.h>
6 #include <boot/stage2.h>
7 #include <kernel/vfs.h>
8 #include <kernel/vm.h>
9 #include <kernel/vm_cache.h>
10 #include <kernel/debug.h>
11 #include <kernel/console.h>
12 #include <kernel/khash.h>
13 #include <kernel/lock.h>
14 #include <kernel/thread.h>
15 #include <kernel/heap.h>
16 #include <kernel/arch/cpu.h>
17 #include <kernel/elf.h>
18 #include <kernel/fs/rootfs.h>
19 #include <kernel/fs/bootfs.h>
20 #include <kernel/fs/devfs.h>
21 #include <kernel/fs/pipefs.h>
22 #include <newos/errors.h>
24 #include <kernel/fs/rootfs.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <fcntl.h>
30 #include <sys/resource.h>
32 #define MAKE_NOIZE 0
34 struct vnode {
35 struct vnode *next;
36 struct vnode *mount_prev;
37 struct vnode *mount_next;
38 struct vm_cache *cache;
39 fs_id fsid;
40 vnode_id vnid;
41 fs_vnode priv_vnode;
42 struct fs_mount *mount;
43 struct vnode *covered_by;
44 int ref_count;
45 bool delete_me;
46 bool busy;
48 struct vnode_hash_key {
49 fs_id fsid;
50 vnode_id vnid;
53 struct file_descriptor {
54 struct vnode *vnode;
55 file_cookie cookie;
56 int ref_count;
57 bool coe;
58 bool dir;
61 struct ioctx {
62 struct vnode *cwd;
63 mutex io_mutex;
64 int table_size;
65 int num_used_fds;
66 struct file_descriptor **fds;
69 struct fs_container {
70 struct fs_container *next;
71 struct fs_calls *calls;
72 const char *name;
74 static struct fs_container *fs_list;
76 struct fs_mount {
77 struct fs_mount *next;
78 struct fs_container *fs;
79 fs_id id;
80 void *fscookie;
81 char *mount_point;
82 recursive_lock rlock;
83 struct vnode *root_vnode;
84 struct vnode *covers_vnode;
85 struct vnode *vnodes_head;
86 struct vnode *vnodes_tail;
87 bool unmounting;
90 static mutex vfs_mutex;
91 static mutex vfs_mount_mutex;
92 static mutex vfs_mount_op_mutex;
93 static mutex vfs_vnode_mutex;
95 #define VNODE_HASH_TABLE_SIZE 1024
96 static void *vnode_table;
97 static struct vnode *root_vnode;
99 #define MOUNTS_HASH_TABLE_SIZE 16
100 static void *mounts_table;
101 static fs_id next_fsid = 0;
103 static int mount_compare(void *_m, const void *_key)
105 struct fs_mount *mount = _m;
106 const fs_id *id = _key;
108 if(mount->id == *id)
109 return 0;
110 else
111 return -1;
114 static unsigned int mount_hash(void *_m, const void *_key, unsigned int range)
116 struct fs_mount *mount = _m;
117 const fs_id *id = _key;
119 if(mount)
120 return mount->id % range;
121 else
122 return *id % range;
125 static struct fs_mount *fsid_to_mount(fs_id id)
127 struct fs_mount *mount;
129 mutex_lock(&vfs_mount_mutex);
131 mount = hash_lookup(mounts_table, &id);
133 mutex_unlock(&vfs_mount_mutex);
135 return mount;
138 static int vnode_compare(void *_v, const void *_key)
140 struct vnode *v = _v;
141 const struct vnode_hash_key *key = _key;
143 if(v->fsid == key->fsid && v->vnid == key->vnid)
144 return 0;
145 else
146 return -1;
149 static unsigned int vnode_hash(void *_v, const void *_key, unsigned int range)
151 struct vnode *v = _v;
152 const struct vnode_hash_key *key = _key;
154 #define VHASH(fsid, vnid) (((uint32)((vnid)>>32) + (uint32)(vnid)) ^ (uint32)(fsid))
156 if(v != NULL)
157 return (VHASH(v->fsid, v->vnid) % range);
158 else
159 return (VHASH(key->fsid, key->vnid) % range);
161 #undef VHASH
164 static int init_vnode(struct vnode *v)
166 #if MAKE_NOIZE
167 dprintf("init_vnode: v %p\n", v);
168 #endif
169 v->next = NULL;
170 v->mount_prev = NULL;
171 v->mount_next = NULL;
172 v->priv_vnode = NULL;
173 v->cache = NULL;
174 v->ref_count = 0;
175 v->vnid = 0;
176 v->fsid = 0;
177 v->delete_me = false;
178 v->busy = false;
179 v->covered_by = NULL;
180 v->mount = NULL;
182 return 0;
185 static void add_vnode_to_mount_list(struct vnode *v, struct fs_mount *mount)
187 recursive_lock_lock(&mount->rlock);
189 v->mount_next = mount->vnodes_head;
190 v->mount_prev = NULL;
191 if(v->mount_next)
192 v->mount_next->mount_prev = v;
194 mount->vnodes_head = v;
196 if(!mount->vnodes_tail)
197 mount->vnodes_tail = v;
199 // do a little bit of error checking
200 if(v->mount_prev == NULL)
201 ASSERT(mount->vnodes_head == v);
202 if(v->mount_next == NULL)
203 ASSERT(mount->vnodes_tail == v);
205 recursive_lock_unlock(&mount->rlock);
208 static void remove_vnode_from_mount_list(struct vnode *v, struct fs_mount *mount)
210 recursive_lock_lock(&mount->rlock);
212 // do a little bit of error checking
213 if(v->mount_prev == NULL)
214 ASSERT(mount->vnodes_head == v);
215 if(v->mount_next == NULL)
216 ASSERT(mount->vnodes_tail == v);
218 if(v->mount_next)
219 v->mount_next->mount_prev = v->mount_prev;
220 else
221 mount->vnodes_tail = v->mount_prev;
222 if(v->mount_prev)
223 v->mount_prev->mount_next = v->mount_next;
224 else
225 mount->vnodes_head = v->mount_next;
227 v->mount_prev = v->mount_next = NULL;
229 recursive_lock_unlock(&mount->rlock);
232 static struct vnode *create_new_vnode(void)
234 struct vnode *v;
236 v = (struct vnode *)kmalloc(sizeof(struct vnode));
237 if(v == NULL)
238 return NULL;
240 init_vnode(v);
241 return v;
244 static int dec_vnode_ref_count(struct vnode *v, bool free_mem, bool r)
246 int err;
247 int old_ref;
249 mutex_lock(&vfs_vnode_mutex);
251 if(v->busy == true)
252 panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", v);
254 old_ref = atomic_add(&v->ref_count, -1);
255 #if MAKE_NOIZE
256 dprintf("dec_vnode_ref_count: vnode %p, ref now %d, old_ref %d\n", v, v->ref_count, old_ref);
257 #endif
259 if(old_ref == 1) {
260 v->busy = true;
262 mutex_unlock(&vfs_vnode_mutex);
264 /* if we have a vm_cache attached, remove it */
265 if(v->cache)
266 vm_cache_release_ref((vm_cache_ref *)v->cache);
267 v->cache = NULL;
269 if(v->delete_me)
270 v->mount->fs->calls->fs_removevnode(v->mount->fscookie, v->priv_vnode, r);
271 else
272 v->mount->fs->calls->fs_putvnode(v->mount->fscookie, v->priv_vnode, r);
274 remove_vnode_from_mount_list(v, v->mount);
276 mutex_lock(&vfs_vnode_mutex);
277 hash_remove(vnode_table, v);
278 mutex_unlock(&vfs_vnode_mutex);
280 if(free_mem) {
281 #if MAKE_NOIZE
282 dprintf("dec_vnode_ref_count: freeing vnode %p\n", v);
283 #endif
284 kfree(v);
286 err = 1;
287 } else {
288 mutex_unlock(&vfs_vnode_mutex);
289 err = 0;
291 return err;
294 static int inc_vnode_ref_count(struct vnode *v)
296 int old_ref = atomic_add(&v->ref_count, 1);
297 #if MAKE_NOIZE
298 dprintf("inc_vnode_ref_count: vnode %p, ref now %d, old_ref %d\n", v, v->ref_count, old_ref);
299 #endif
300 return old_ref;
303 static struct vnode *lookup_vnode(fs_id fsid, vnode_id vnid)
305 struct vnode_hash_key key;
307 key.fsid = fsid;
308 key.vnid = vnid;
310 return hash_lookup(vnode_table, &key);
313 static int get_vnode(fs_id fsid, vnode_id vnid, struct vnode **outv, int r)
315 struct vnode *v;
316 int err;
318 #if MAKE_NOIZE
319 dprintf("get_vnode: fsid %d vnid 0x%Lx\n", fsid, vnid);
320 #endif
322 mutex_lock(&vfs_vnode_mutex);
324 for(;;) {
325 v = lookup_vnode(fsid, vnid);
326 if(v) {
327 if(v->busy) {
328 mutex_unlock(&vfs_vnode_mutex);
329 thread_snooze(10000); // 10 ms
330 mutex_lock(&vfs_vnode_mutex);
331 continue;
334 break;
337 #if MAKE_NOIZE
338 dprintf("get_vnode: tried to lookup vnode, got %p\n", v);
339 #endif
340 if(v) {
341 inc_vnode_ref_count(v);
342 } else {
343 // we need to create a new vnode and read it in
344 v = create_new_vnode();
345 if(!v) {
346 err = ERR_NO_MEMORY;
347 goto err;
349 v->fsid = fsid;
350 v->vnid = vnid;
351 v->mount = fsid_to_mount(fsid);
352 if(!v->mount) {
353 err = ERR_INVALID_HANDLE;
354 goto err;
356 v->busy = true;
357 hash_insert(vnode_table, v);
358 mutex_unlock(&vfs_vnode_mutex);
360 add_vnode_to_mount_list(v, v->mount);
362 err = v->mount->fs->calls->fs_getvnode(v->mount->fscookie, vnid, &v->priv_vnode, r);
364 if(err < 0)
365 remove_vnode_from_mount_list(v, v->mount);
367 mutex_lock(&vfs_vnode_mutex);
368 if(err < 0)
369 goto err1;
371 v->busy = false;
372 v->ref_count = 1;
375 mutex_unlock(&vfs_vnode_mutex);
376 #if MAKE_NOIZE
377 dprintf("get_vnode: returning %p\n", v);
378 #endif
379 *outv = v;
380 return NO_ERROR;
382 err1:
383 hash_remove(vnode_table, v);
384 err:
385 mutex_unlock(&vfs_vnode_mutex);
386 if(v)
387 kfree(v);
389 return err;
392 static void put_vnode(struct vnode *v)
394 dec_vnode_ref_count(v, true, false);
397 int vfs_get_vnode(fs_id fsid, vnode_id vnid, fs_vnode *fsv)
399 int err;
400 struct vnode *v;
402 #if MAKE_NOIZE
403 dprintf("vfs_get_vnode: fsid %d vnid 0x%Lx\n", fsid, vnid);
404 #endif
406 err = get_vnode(fsid, vnid, &v, true);
407 if(err < 0)
408 return err;
410 *fsv = v->priv_vnode;
411 return NO_ERROR;
414 int vfs_put_vnode(fs_id fsid, vnode_id vnid)
416 struct vnode *v;
418 #if MAKE_NOIZE
419 dprintf("vfs_put_vnode: fsid %d vnid 0x%Lx\n", fsid, vnid);
420 #endif
422 mutex_lock(&vfs_vnode_mutex);
424 v = lookup_vnode(fsid, vnid);
426 mutex_unlock(&vfs_vnode_mutex);
427 if(v)
428 dec_vnode_ref_count(v, true, true);
430 return NO_ERROR;
433 void vfs_vnode_acquire_ref(void *v)
435 #if MAKE_NOIZE
436 dprintf("vfs_vnode_acquire_ref: vnode %p\n", v);
437 #endif
438 inc_vnode_ref_count((struct vnode *)v);
441 void vfs_vnode_release_ref(void *v)
443 #if MAKE_NOIZE
444 dprintf("vfs_vnode_release_ref: vnode %p\n", v);
445 #endif
446 dec_vnode_ref_count((struct vnode *)v, true, false);
449 int vfs_remove_vnode(fs_id fsid, vnode_id vnid)
451 struct vnode *v;
453 mutex_lock(&vfs_vnode_mutex);
455 v = lookup_vnode(fsid, vnid);
456 if(v)
457 v->delete_me = true;
459 mutex_unlock(&vfs_vnode_mutex);
460 return 0;
463 void *vfs_get_cache_ptr(void *vnode)
465 return ((struct vnode *)vnode)->cache;
468 int vfs_set_cache_ptr(void *vnode, void *cache)
470 if(test_and_set((int *)&(((struct vnode *)vnode)->cache), (int)cache, 0) == 0)
471 return 0;
472 else
473 return -1;
476 static struct file_descriptor *alloc_fd(void)
478 struct file_descriptor *f;
480 f = kmalloc(sizeof(struct file_descriptor));
481 if(f) {
482 f->vnode = NULL;
483 f->cookie = NULL;
484 f->ref_count = 1;
485 f->coe = false;
486 f->dir = false;
488 return f;
491 static struct file_descriptor *get_fd(struct ioctx *ioctx, int fd)
493 struct file_descriptor *f;
495 mutex_lock(&ioctx->io_mutex);
497 if(fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) {
498 // valid fd
499 f = ioctx->fds[fd];
500 atomic_add(&f->ref_count, 1);
501 } else {
502 f = NULL;
505 mutex_unlock(&ioctx->io_mutex);
506 return f;
509 static void free_fd(struct file_descriptor *f)
511 if(!f->dir) {
512 f->vnode->mount->fs->calls->fs_close(f->vnode->mount->fscookie, f->vnode->priv_vnode, f->cookie);
513 f->vnode->mount->fs->calls->fs_freecookie(f->vnode->mount->fscookie, f->vnode->priv_vnode, f->cookie);
514 } else {
515 f->vnode->mount->fs->calls->fs_closedir(f->vnode->mount->fscookie, f->vnode->priv_vnode, f->cookie);
517 dec_vnode_ref_count(f->vnode, true, false);
518 kfree(f);
521 static void put_fd(struct file_descriptor *f)
523 if(atomic_add(&f->ref_count, -1) == 1) {
524 free_fd(f);
528 static void remove_fd(struct ioctx *ioctx, int fd)
530 struct file_descriptor *f;
532 mutex_lock(&ioctx->io_mutex);
534 if(fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) {
535 // valid fd
536 f = ioctx->fds[fd];
537 ioctx->fds[fd] = NULL;
538 ioctx->num_used_fds--;
539 } else {
540 f = NULL;
543 mutex_unlock(&ioctx->io_mutex);
545 if(f)
546 put_fd(f);
549 static int new_fd(struct ioctx *ioctx, struct file_descriptor *f)
551 int fd;
552 int i;
554 mutex_lock(&ioctx->io_mutex);
556 fd = -1;
557 for(i=0; i<ioctx->table_size; i++) {
558 if(!ioctx->fds[i]) {
559 fd = i;
560 break;
563 if(fd < 0) {
564 fd = ERR_NO_MORE_HANDLES;
565 goto err;
568 ioctx->fds[fd] = f;
569 ioctx->num_used_fds++;
571 err:
572 mutex_unlock(&ioctx->io_mutex);
574 return fd;
577 static struct vnode *get_vnode_from_fd(struct ioctx *ioctx, int fd)
579 struct file_descriptor *f;
580 struct vnode *v;
582 f = get_fd(ioctx, fd);
583 if(!f) {
584 return NULL;
587 v = f->vnode;
588 if(!v)
589 goto out;
590 inc_vnode_ref_count(v);
592 out:
593 put_fd(f);
595 return v;
598 static struct fs_container *find_fs(const char *fs_name)
600 struct fs_container *fs = fs_list;
601 while(fs != NULL) {
602 if(strcmp(fs_name, fs->name) == 0) {
603 return fs;
605 fs = fs->next;
607 return NULL;
610 static struct ioctx *get_current_ioctx(bool kernel)
612 struct ioctx *ioctx;
614 if(kernel) {
615 ioctx = proc_get_kernel_proc()->ioctx;
616 } else {
617 ioctx = thread_get_current_thread()->proc->ioctx;
619 return ioctx;
622 static int path_to_vnode(char *path, struct vnode **v, bool kernel)
624 char *p = path;
625 char *next_p;
626 struct vnode *curr_v;
627 struct vnode *next_v;
628 vnode_id vnid;
629 int err;
631 if(!p)
632 return ERR_INVALID_ARGS;
634 // figure out if we need to start at root or at cwd
635 if(*p == '/') {
636 while(*++p == '/')
638 curr_v = root_vnode;
639 inc_vnode_ref_count(curr_v);
640 } else {
641 struct ioctx *ioctx = get_current_ioctx(kernel);
643 mutex_lock(&ioctx->io_mutex);
644 curr_v = ioctx->cwd;
645 inc_vnode_ref_count(curr_v);
646 mutex_unlock(&ioctx->io_mutex);
649 for(;;) {
650 // dprintf("path_to_vnode: top of loop. p %p, *p = %c, p = '%s'\n", p, *p, p);
652 // done?
653 if(*p == '\0') {
654 err = 0;
655 break;
658 // walk to find the next component
659 for(next_p = p+1; *next_p != '\0' && *next_p != '/'; next_p++);
661 if(*next_p == '/') {
662 *next_p = '\0';
664 next_p++;
665 while(*next_p == '/');
668 // see if the .. is at the root of a mount
669 if(strcmp("..", p) == 0 && curr_v->mount->root_vnode == curr_v) {
670 // move to the covered vnode so we pass the '..' parse to the underlying filesystem
671 if(curr_v->mount->covers_vnode) {
672 next_v = curr_v->mount->covers_vnode;
673 inc_vnode_ref_count(next_v);
674 dec_vnode_ref_count(curr_v, true, false);
675 curr_v = next_v;
679 // tell the filesystem to parse this path
680 err = curr_v->mount->fs->calls->fs_lookup(curr_v->mount->fscookie, curr_v->priv_vnode, p, &vnid);
681 if(err < 0) {
682 dec_vnode_ref_count(curr_v, true, false);
683 goto out;
686 // lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
687 // from inside the filesystem, thus the vnode would have to be in the list and it's
688 // ref count incremented at this point
689 mutex_lock(&vfs_vnode_mutex);
690 next_v = lookup_vnode(curr_v->fsid, vnid);
691 mutex_unlock(&vfs_vnode_mutex);
693 if(!next_v) {
694 // pretty screwed up here
695 panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", curr_v->fsid, vnid);
696 err = ERR_VFS_PATH_NOT_FOUND;
697 dec_vnode_ref_count(curr_v, true, false);
698 goto out;
701 // decrease the ref count on the old dir we just looked up into
702 dec_vnode_ref_count(curr_v, true, false);
704 p = next_p;
705 curr_v = next_v;
707 // see if we hit a mount point
708 if(curr_v->covered_by) {
709 next_v = curr_v->covered_by;
710 inc_vnode_ref_count(next_v);
711 dec_vnode_ref_count(curr_v, true, false);
712 curr_v = next_v;
716 *v = curr_v;
718 out:
719 return err;
722 // returns the vnode in the next to last segment of the path, returns the last
723 // portion in filename
724 static int path_to_dir_vnode(char *path, struct vnode **v, char *filename, bool kernel)
726 char *p;
728 p = strrchr(path, '/');
729 if(!p) {
730 // this path is single segment with no '/' in it
731 // ex. "foo"
732 strcpy(filename, path);
733 strcpy(path, ".");
734 } else {
735 // replace the filename portion of the path with a '.'
736 strcpy(filename, p+1);
738 if(p[1] != '\0'){
739 p[1] = '.';
740 p[2] = '\0';
744 return path_to_vnode(path, v, kernel);
747 void *vfs_new_ioctx(void *_parent_ioctx)
749 size_t table_size;
750 struct ioctx *ioctx;
751 struct ioctx *parent_ioctx;
753 parent_ioctx = (struct ioctx *)_parent_ioctx;
754 if(parent_ioctx) {
755 table_size = parent_ioctx->table_size;
756 } else {
757 table_size = DEFAULT_FD_TABLE_SIZE;
760 ioctx = kmalloc(sizeof(struct ioctx));
761 if(ioctx == NULL)
762 return NULL;
764 memset(ioctx, 0, sizeof(struct ioctx));
766 ioctx->fds = kmalloc(sizeof(struct file_descriptor *) * table_size);
767 if(ioctx->fds == NULL) {
768 kfree(ioctx);
769 return NULL;
772 memset(ioctx->fds, 0, sizeof(struct file_descriptor *) * table_size);
774 if(mutex_init(&ioctx->io_mutex, "ioctx_mutex") < 0) {
775 kfree(ioctx->fds);
776 kfree(ioctx);
777 return NULL;
781 * copy parent files if they dont have the close-on-exec flag set
783 if(parent_ioctx) {
784 size_t i;
786 mutex_lock(&parent_ioctx->io_mutex);
788 ioctx->cwd= parent_ioctx->cwd;
789 if(ioctx->cwd) {
790 inc_vnode_ref_count(ioctx->cwd);
794 for(i = 0; i< table_size; i++) {
795 if(parent_ioctx->fds[i] && !parent_ioctx->fds[i]->coe) {
796 ioctx->fds[i]= parent_ioctx->fds[i];
797 atomic_add(&ioctx->fds[i]->ref_count, 1);
801 mutex_unlock(&parent_ioctx->io_mutex);
802 } else {
803 ioctx->cwd = root_vnode;
805 if(ioctx->cwd) {
806 inc_vnode_ref_count(ioctx->cwd);
810 ioctx->table_size = table_size;
812 return ioctx;
815 int vfs_free_ioctx(void *_ioctx)
817 struct ioctx *ioctx = (struct ioctx *)_ioctx;
818 int i;
820 if(ioctx->cwd)
821 dec_vnode_ref_count(ioctx->cwd, true, false);
823 mutex_lock(&ioctx->io_mutex);
825 for(i=0; i<ioctx->table_size; i++) {
826 if(ioctx->fds[i]) {
827 put_fd(ioctx->fds[i]);
831 mutex_unlock(&ioctx->io_mutex);
833 mutex_destroy(&ioctx->io_mutex);
835 kfree(ioctx->fds);
836 kfree(ioctx);
837 return 0;
840 int vfs_init(kernel_args *ka)
842 dprintf("vfs_init: entry\n");
843 kprintf("initializing fs layer...\n");
845 vnode_table = hash_init(VNODE_HASH_TABLE_SIZE, offsetof(struct vnode, next),
846 &vnode_compare, &vnode_hash);
847 if(vnode_table == NULL)
848 panic("vfs_init: error creating vnode hash table\n");
850 mounts_table = hash_init(MOUNTS_HASH_TABLE_SIZE, offsetof(struct fs_mount, next),
851 &mount_compare, &mount_hash);
852 if(mounts_table == NULL)
853 panic("vfs_init: error creating mounts hash table\n");
855 fs_list = NULL;
856 root_vnode = NULL;
858 if(mutex_init(&vfs_mutex, "vfs_lock") < 0)
859 panic("vfs_init: error allocating vfs lock\n");
861 if(mutex_init(&vfs_mount_op_mutex, "vfs_mount_op_lock") < 0)
862 panic("vfs_init: error allocating vfs_mount_op lock\n");
864 if(mutex_init(&vfs_mount_mutex, "vfs_mount_lock") < 0)
865 panic("vfs_init: error allocating vfs_mount lock\n");
867 if(mutex_init(&vfs_vnode_mutex, "vfs_vnode_lock") < 0)
868 panic("vfs_init: error allocating vfs_vnode lock\n");
870 return 0;
873 #if 0
874 int vfs_test(void)
876 int fd;
877 int err;
879 dprintf("vfs_test() entry\n");
881 fd = sys_open("/", STREAM_TYPE_DIR, 0);
882 dprintf("fd = %d\n", fd);
883 sys_close(fd);
885 fd = sys_open("/", STREAM_TYPE_DIR, 0);
886 dprintf("fd = %d\n", fd);
888 sys_create("/foo", STREAM_TYPE_DIR);
889 sys_create("/foo/bar", STREAM_TYPE_DIR);
890 sys_create("/foo/bar/gar", STREAM_TYPE_DIR);
891 sys_create("/foo/bar/tar", STREAM_TYPE_DIR);
893 #if 1
894 fd = sys_open("/foo/bar", STREAM_TYPE_DIR, 0);
895 if(fd < 0)
896 panic("unable to open /foo/bar\n");
899 char buf[64];
900 ssize_t len;
902 sys_seek(fd, 0, _SEEK_SET);
903 for(;;) {
904 len = sys_read(fd, buf, -1, sizeof(buf));
905 if(len < 0)
906 panic("readdir returned %Ld\n", (long long)len);
907 if(len > 0)
908 dprintf("readdir returned name = '%s'\n", buf);
909 else
910 break;
914 // do some unlink tests
915 err = sys_unlink("/foo/bar");
916 if(err == NO_ERROR)
917 panic("unlink of full directory should not have passed\n");
918 sys_unlink("/foo/bar/gar");
919 sys_unlink("/foo/bar/tar");
920 err = sys_unlink("/foo/bar");
921 if(err != NO_ERROR)
922 panic("unlink of empty directory should have worked\n");
924 sys_create("/test", STREAM_TYPE_DIR);
925 sys_create("/test", STREAM_TYPE_DIR);
926 err = sys_mount("/test", NULL, "rootfs", NULL);
927 if(err < 0)
928 panic("failed mount test\n");
930 #endif
931 #if 1
933 fd = sys_open("/boot", STREAM_TYPE_DIR, 0);
934 dprintf("fd = %d\n", fd);
935 sys_close(fd);
937 fd = sys_open("/boot", STREAM_TYPE_DIR, 0);
938 if(fd < 0)
939 panic("unable to open dir /boot\n");
941 char buf[64];
942 ssize_t len;
944 sys_seek(fd, 0, _SEEK_SET);
945 for(;;) {
946 len = sys_read(fd, buf, -1, sizeof(buf));
947 if(len < 0)
948 panic("readdir returned %Ld\n", (long long)len);
949 if(len > 0)
950 dprintf("readdir returned name = '%s'\n", buf);
951 else
952 break;
955 sys_close(fd);
957 fd = sys_open("/boot/kernel", STREAM_TYPE_FILE, 0);
958 if(fd < 0)
959 panic("unable to open kernel file '/boot/kernel'\n");
961 char buf[64];
962 ssize_t len;
964 len = sys_read(fd, buf, 0, sizeof(buf));
965 if(len < 0)
966 panic("failed on read\n");
967 dprintf("read returned %Ld\n", (long long)len);
969 sys_close(fd);
971 struct file_stat stat;
973 err = sys_rstat("/boot/kernel", &stat);
974 if(err < 0)
975 panic("err stating '/boot/kernel'\n");
976 dprintf("stat results:\n");
977 dprintf("\tvnid 0x%Lx\n\ttype %d\n\tsize 0x%Lx\n", stat.vnid, stat.type, stat.size);
980 #endif
981 dprintf("vfs_test() done\n");
982 panic("foo\n");
983 return 0;
985 #endif
987 int vfs_register_filesystem(const char *name, struct fs_calls *calls)
989 struct fs_container *container;
991 container = (struct fs_container *)kmalloc(sizeof(struct fs_container));
992 if(container == NULL)
993 return ERR_NO_MEMORY;
995 container->name = name;
996 container->calls = calls;
998 mutex_lock(&vfs_mutex);
1000 container->next = fs_list;
1001 fs_list = container;
1003 mutex_unlock(&vfs_mutex);
1004 return 0;
1007 int vfs_mount(char *path, const char *device, const char *fs_name, void *args, bool kernel)
1009 struct fs_mount *mount;
1010 int err = 0;
1011 struct vnode *covered_vnode = NULL;
1012 vnode_id root_id;
1014 #if MAKE_NOIZE
1015 dprintf("vfs_mount: entry. path = '%s', fs_name = '%s'\n", path, fs_name);
1016 #endif
1018 mutex_lock(&vfs_mount_op_mutex);
1020 mount = (struct fs_mount *)kmalloc(sizeof(struct fs_mount));
1021 if(mount == NULL) {
1022 err = ERR_NO_MEMORY;
1023 goto err;
1026 memset(mount, 0, sizeof(struct fs_mount));
1028 mount->mount_point = kstrdup(path);
1029 if(mount->mount_point == NULL) {
1030 err = ERR_NO_MEMORY;
1031 goto err1;
1034 mount->fs = find_fs(fs_name);
1035 if(mount->fs == NULL) {
1036 err = ERR_VFS_INVALID_FS;
1037 goto err2;
1040 recursive_lock_create(&mount->rlock);
1041 mount->id = next_fsid++;
1042 mount->unmounting = false;
1044 if(!root_vnode) {
1045 // we haven't mounted anything yet
1046 if(strcmp(path, "/") != 0) {
1047 err = ERR_VFS_GENERAL;
1048 goto err3;
1051 err = mount->fs->calls->fs_mount(&mount->fscookie, mount->id, device, NULL, &root_id);
1052 if(err < 0) {
1053 err = ERR_VFS_GENERAL;
1054 goto err3;
1057 mount->covers_vnode = NULL; // this is the root mount
1058 } else {
1059 err = path_to_vnode(path,&covered_vnode,kernel);
1060 if(err < 0) {
1061 goto err2;
1064 if(!covered_vnode) {
1065 err = ERR_VFS_GENERAL;
1066 goto err2;
1069 // XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be
1071 if((covered_vnode != root_vnode) && (covered_vnode->mount->root_vnode == covered_vnode)){
1072 err = ERR_VFS_ALREADY_MOUNTPOINT;
1073 goto err2;
1076 mount->covers_vnode = covered_vnode;
1078 // mount it
1079 err = mount->fs->calls->fs_mount(&mount->fscookie, mount->id, device, NULL, &root_id);
1080 if(err < 0)
1081 goto err4;
1084 mutex_lock(&vfs_mount_mutex);
1086 // insert mount struct into list
1087 hash_insert(mounts_table, mount);
1089 mutex_unlock(&vfs_mount_mutex);
1091 err = get_vnode(mount->id, root_id, &mount->root_vnode, 0);
1092 if(err < 0)
1093 goto err5;
1095 // XXX may be a race here
1096 if(mount->covers_vnode)
1097 mount->covers_vnode->covered_by = mount->root_vnode;
1099 if(!root_vnode)
1100 root_vnode = mount->root_vnode;
1102 mutex_unlock(&vfs_mount_op_mutex);
1104 return 0;
1106 err5:
1107 mount->fs->calls->fs_unmount(mount->fscookie);
1108 err4:
1109 if(mount->covers_vnode)
1110 dec_vnode_ref_count(mount->covers_vnode, true, false);
1111 err3:
1112 recursive_lock_destroy(&mount->rlock);
1113 err2:
1114 kfree(mount->mount_point);
1115 err1:
1116 kfree(mount);
1117 err:
1118 mutex_unlock(&vfs_mount_op_mutex);
1120 return err;
1123 int vfs_unmount(char *path, bool kernel)
1125 struct vnode *v;
1126 struct fs_mount *mount;
1127 int err;
1129 #if MAKE_NOIZE
1130 dprintf("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel);
1131 #endif
1133 err = path_to_vnode(path, &v, kernel);
1134 if(err < 0) {
1135 err = ERR_VFS_PATH_NOT_FOUND;
1136 goto err;
1139 mutex_lock(&vfs_mount_op_mutex);
1141 mount = fsid_to_mount(v->fsid);
1142 if(!mount) {
1143 panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", v);
1146 if(mount->root_vnode != v) {
1147 // not mountpoint
1148 dec_vnode_ref_count(v, true, false);
1149 err = ERR_VFS_NOT_MOUNTPOINT;
1150 goto err1;
1153 /* grab the vnode master mutex to keep someone from creating a vnode
1154 while we're figuring out if we can continue */
1155 mutex_lock(&vfs_vnode_mutex);
1157 /* simulate the root vnode having it's refcount decremented */
1158 mount->root_vnode->ref_count -= 2;
1160 /* cycle through the list of vnodes associated with this mount and
1161 make sure all of them are not busy or have refs on them */
1162 err = 0;
1163 for(v = mount->vnodes_head; v; v = v->mount_next) {
1164 if(v->busy || v->ref_count != 0) {
1165 mount->root_vnode->ref_count += 2;
1166 mutex_unlock(&vfs_vnode_mutex);
1167 dec_vnode_ref_count(mount->root_vnode, true, false);
1168 err = ERR_VFS_FS_BUSY;
1169 goto err1;
1173 /* we can safely continue, mark all of the vnodes busy and this mount
1174 structure in unmounting state */
1175 for(v = mount->vnodes_head; v; v = v->mount_next)
1176 if(v != mount->root_vnode)
1177 v->busy = true;
1178 mount->unmounting = true;
1180 /* add 2 back to the root vnode's ref */
1181 mount->root_vnode->ref_count += 2;
1183 mutex_unlock(&vfs_vnode_mutex);
1185 mount->covers_vnode->covered_by = NULL;
1186 dec_vnode_ref_count(mount->covers_vnode, true, false);
1188 /* release the ref on the root vnode twice */
1189 dec_vnode_ref_count(mount->root_vnode, true, false);
1190 dec_vnode_ref_count(mount->root_vnode, true, false);
1192 // XXX when full vnode cache in place, will need to force
1193 // a putvnode/removevnode here
1195 /* remove the mount structure from the hash table */
1196 mutex_lock(&vfs_mount_mutex);
1197 hash_remove(mounts_table, mount);
1198 mutex_unlock(&vfs_mount_mutex);
1200 mutex_unlock(&vfs_mount_op_mutex);
1202 mount->fs->calls->fs_unmount(mount->fscookie);
1204 kfree(mount->mount_point);
1205 kfree(mount);
1207 return 0;
1209 err1:
1210 mutex_unlock(&vfs_mount_op_mutex);
1211 err:
1212 return err;
1215 int vfs_sync(void)
1217 struct hash_iterator iter;
1218 struct fs_mount *mount;
1220 #if MAKE_NOIZE
1221 dprintf("vfs_sync: entry.\n");
1222 #endif
1224 /* cycle through and call sync on each mounted fs */
1225 mutex_lock(&vfs_mount_op_mutex);
1226 mutex_lock(&vfs_mount_mutex);
1228 hash_open(mounts_table, &iter);
1229 while((mount = hash_next(mounts_table, &iter))) {
1230 mount->fs->calls->fs_sync(mount->fscookie);
1232 hash_close(mounts_table, &iter, false);
1234 mutex_unlock(&vfs_mount_mutex);
1235 mutex_unlock(&vfs_mount_op_mutex);
1237 return 0;
1240 int vfs_opendir(char *path, bool kernel)
1242 struct vnode *v;
1243 dir_cookie cookie;
1244 int err;
1245 int fd;
1246 struct file_descriptor *f;
1248 #if MAKE_NOIZE
1249 dprintf("vfs_opendir: entry. path = '%s', kernel %d\n", path, kernel);
1250 #endif
1252 err = path_to_vnode(path, &v, kernel);
1253 if(err < 0)
1254 return err;
1256 err = v->mount->fs->calls->fs_opendir(v->mount->fscookie, v->priv_vnode, &cookie);
1257 if(err < 0)
1258 goto err1;
1260 // file is opened, create a fd
1261 f = alloc_fd();
1262 if(!f) {
1263 // xxx leaks
1264 err = ERR_NO_MEMORY;
1265 goto err1;
1267 f->vnode = v;
1268 f->cookie = cookie;
1269 f->coe = false;
1270 f->dir = true;
1272 fd = new_fd(get_current_ioctx(kernel), f);
1273 if(fd < 0) {
1274 err = ERR_VFS_FD_TABLE_FULL;
1275 goto err2;
1278 return fd;
1280 err2:
1281 free_fd(f); // calls dec_vnode_ref_count
1282 goto err;
1283 err1:
1284 dec_vnode_ref_count(v, true, false);
1285 err:
1286 return err;
1289 int vfs_closedir(int fd, bool kernel)
1291 struct file_descriptor *f;
1292 struct ioctx *ioctx;
1294 #if MAKE_NOIZE
1295 dprintf("vfs_closedir: entry. fd %d, kernel %d\n", fd, kernel);
1296 #endif
1298 ioctx = get_current_ioctx(kernel);
1300 f = get_fd(ioctx, fd);
1301 if(!f)
1302 return ERR_INVALID_HANDLE;
1304 if(!f->dir)
1305 return ERR_VFS_NOT_DIR;
1307 remove_fd(ioctx, fd);
1308 put_fd(f);
1310 return 0;
1313 int vfs_rewinddir(int fd, bool kernel)
1315 struct vnode *v;
1316 struct file_descriptor *f;
1317 int err;
1319 #if MAKE_NOIZE
1320 dprintf("vfs_rewinddir: fd = %d, kernel %d\n", fd, kernel);
1321 #endif
1323 f = get_fd(get_current_ioctx(kernel), fd);
1324 if(!f) {
1325 err = ERR_INVALID_HANDLE;
1326 goto err;
1329 if(!f->dir)
1330 return ERR_VFS_NOT_DIR;
1332 v = f->vnode;
1333 err = v->mount->fs->calls->fs_rewinddir(v->mount->fscookie, v->priv_vnode, f->cookie);
1335 put_fd(f);
1337 err:
1338 return err;
1342 int vfs_readdir(int fd, void *buf, size_t len, bool kernel)
1344 struct vnode *v;
1345 struct file_descriptor *f;
1346 int err;
1348 #if MAKE_NOIZE
1349 dprintf("vfs_readdir: fd = %d, buf %p, len 0x%lx, kernel %d\n", fd, buf, len, kernel);
1350 #endif
1352 f = get_fd(get_current_ioctx(kernel), fd);
1353 if(!f) {
1354 err = ERR_INVALID_HANDLE;
1355 goto err;
1358 if(!f->dir)
1359 return ERR_VFS_NOT_DIR;
1361 v = f->vnode;
1362 err = v->mount->fs->calls->fs_readdir(v->mount->fscookie, v->priv_vnode, f->cookie, buf, len);
1364 put_fd(f);
1366 err:
1367 return err;
1370 static int _vfs_open(struct vnode *v, int omode, bool kernel)
1372 int fd;
1373 file_cookie cookie;
1374 struct file_descriptor *f;
1375 int err;
1377 err = v->mount->fs->calls->fs_open(v->mount->fscookie, v->priv_vnode, &cookie, omode);
1378 if(err < 0)
1379 goto err1;
1381 // file is opened, create a fd
1382 f = alloc_fd();
1383 if(!f) {
1384 // xxx leaks
1385 err = ERR_NO_MEMORY;
1386 goto err1;
1388 f->vnode = v;
1389 f->cookie = cookie;
1390 f->coe = omode & O_CLOEXEC ? true : false;
1392 fd = new_fd(get_current_ioctx(kernel), f);
1393 if(fd < 0) {
1394 err = ERR_VFS_FD_TABLE_FULL;
1395 goto err2;
1398 return fd;
1400 err2:
1401 free_fd(f); // calls dec_vnode_ref_count
1402 goto err;
1403 err1:
1404 dec_vnode_ref_count(v, true, false);
1405 err:
1406 return err;
1409 int vfs_open(char *path, int omode, bool kernel)
1411 struct vnode *v;
1412 int err;
1414 #if MAKE_NOIZE
1415 dprintf("vfs_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel);
1416 #endif
1418 err = path_to_vnode(path, &v, kernel);
1419 if(err < 0)
1420 return err;
1422 return _vfs_open(v, omode, kernel);
1425 int vfs_open_vnid(fs_id fsid, vnode_id vnid, int omode, bool kernel)
1427 struct vnode *v;
1428 int err;
1430 #if MAKE_NOIZE
1431 dprintf("vfs_open_vnid: entry. fsid 0x%x, vnid 0x%Lx, omode %d, kernel %d\n", fsid, vnid, omode, kernel);
1432 #endif
1434 err = get_vnode(fsid, vnid, &v, 0);
1435 if(err < 0)
1436 return err;
1438 return _vfs_open(v, omode, kernel);
1441 int vfs_close(int fd, bool kernel)
1443 struct file_descriptor *f;
1444 struct ioctx *ioctx;
1446 #if MAKE_NOIZE
1447 dprintf("vfs_close: entry. fd %d, kernel %d\n", fd, kernel);
1448 #endif
1450 ioctx = get_current_ioctx(kernel);
1452 f = get_fd(ioctx, fd);
1453 if(!f)
1454 return ERR_INVALID_HANDLE;
1456 if(f->dir)
1457 return ERR_VFS_IS_DIR;
1459 remove_fd(ioctx, fd);
1460 put_fd(f);
1462 return 0;
1465 int vfs_fsync(int fd, bool kernel)
1467 struct file_descriptor *f;
1468 struct vnode *v;
1469 int err;
1471 #if MAKE_NOIZE
1472 dprintf("vfs_fsync: entry. fd %d kernel %d\n", fd, kernel);
1473 #endif
1475 f = get_fd(get_current_ioctx(kernel), fd);
1476 if(!f)
1477 return ERR_INVALID_HANDLE;
1479 v = f->vnode;
1480 err = v->mount->fs->calls->fs_fsync(v->mount->fscookie, v->priv_vnode);
1482 put_fd(f);
1484 return err;
1487 ssize_t vfs_read(int fd, void *buf, off_t pos, ssize_t len, bool kernel)
1489 struct vnode *v;
1490 struct file_descriptor *f;
1491 int err;
1493 #if MAKE_NOIZE
1494 dprintf("vfs_read: fd = %d, buf %p, pos 0x%Lx, len 0x%lx, kernel %d\n", fd, buf, pos, len, kernel);
1495 #endif
1497 f = get_fd(get_current_ioctx(kernel), fd);
1498 if(!f) {
1499 err = ERR_INVALID_HANDLE;
1500 goto err;
1503 v = f->vnode;
1504 err = v->mount->fs->calls->fs_read(v->mount->fscookie, v->priv_vnode, f->cookie, buf, pos, len);
1506 put_fd(f);
1508 err:
1509 return err;
1512 ssize_t vfs_write(int fd, const void *buf, off_t pos, ssize_t len, bool kernel)
1514 struct vnode *v;
1515 struct file_descriptor *f;
1516 int err;
1518 #if MAKE_NOIZE
1519 dprintf("vfs_write: fd = %d, buf %p, pos 0x%Lx, len 0x%lx, kernel %d\n", fd, buf, pos, len, kernel);
1520 #endif
1522 f = get_fd(get_current_ioctx(kernel), fd);
1523 if(!f) {
1524 err = ERR_INVALID_HANDLE;
1525 goto err;
1528 v = f->vnode;
1529 err = v->mount->fs->calls->fs_write(v->mount->fscookie, v->priv_vnode, f->cookie, buf, pos, len);
1531 put_fd(f);
1533 err:
1534 return err;
1537 int vfs_seek(int fd, off_t pos, seek_type seek_type, bool kernel)
1539 struct vnode *v;
1540 struct file_descriptor *f;
1541 int err;
1543 #if MAKE_NOIZE
1544 dprintf("vfs_seek: fd = %d, pos 0x%Lx, seek_type %d, kernel %d\n", fd, pos, seek_type, kernel);
1545 #endif
1547 f = get_fd(get_current_ioctx(kernel), fd);
1548 if(!f) {
1549 err = ERR_INVALID_HANDLE;
1550 goto err;
1553 v = f->vnode;
1554 err = v->mount->fs->calls->fs_seek(v->mount->fscookie, v->priv_vnode, f->cookie, pos, seek_type);
1556 put_fd(f);
1558 err:
1559 return err;
1562 int vfs_ioctl(int fd, int op, void *buf, size_t len, bool kernel)
1564 struct vnode *v;
1565 struct file_descriptor *f;
1566 int err;
1568 #if MAKE_NOIZE
1569 dprintf("vfs_ioctl: fd = %d, op 0x%x, buf %p, len 0x%lx, kernel %d\n", fd, op, buf, len, kernel);
1570 #endif
1572 f = get_fd(get_current_ioctx(kernel), fd);
1573 if(!f) {
1574 err = ERR_INVALID_HANDLE;
1575 goto err;
1578 v = f->vnode;
1579 err = v->mount->fs->calls->fs_ioctl(v->mount->fscookie, v->priv_vnode, f->cookie, op, buf, len);
1581 put_fd(f);
1583 err:
1584 return err;
1587 int vfs_create(char *path, void *args, bool kernel)
1589 int err;
1590 struct vnode *dir;
1591 struct vnode *v;
1592 char filename[SYS_MAX_NAME_LEN];
1593 vnode_id vnid;
1595 #if MAKE_NOIZE
1596 dprintf("vfs_create: path '%s', args %p, kernel %d\n", path, args, kernel);
1597 #endif
1599 err = path_to_dir_vnode(path, &dir, filename, kernel);
1600 if(err < 0)
1601 goto err;
1603 err = dir->mount->fs->calls->fs_create(dir->mount->fscookie, dir->priv_vnode, filename, args, &vnid);
1604 dec_vnode_ref_count(dir, true, false);
1605 if (err < 0)
1606 goto err;
1608 /* the file system has created a new vnode for us */
1609 // XXX for now just decrement a ref on it to kill it. We will
1610 // eventually create a new file handle and pass it back
1611 err = get_vnode(dir->fsid, vnid, &v, false);
1612 if (err < 0) {
1613 goto err;
1616 dec_vnode_ref_count(v, true, false);
1617 dec_vnode_ref_count(v, true, false);
1619 err = 0;
1621 err:
1622 return err;
1625 int vfs_unlink(char *path, bool kernel)
1627 int err;
1628 struct vnode *v;
1629 char filename[SYS_MAX_NAME_LEN];
1631 #if MAKE_NOIZE
1632 dprintf("vfs_unlink: path '%s', kernel %d\n", path, kernel);
1633 #endif
1635 err = path_to_dir_vnode(path, &v, filename, kernel);
1636 if(err < 0)
1637 goto err;
1639 err = v->mount->fs->calls->fs_unlink(v->mount->fscookie, v->priv_vnode, filename);
1641 dec_vnode_ref_count(v, true, false);
1642 err:
1643 return err;
1646 int vfs_rename(char *path, char *newpath, bool kernel)
1648 struct vnode *v1, *v2;
1649 char filename1[SYS_MAX_NAME_LEN];
1650 char filename2[SYS_MAX_NAME_LEN];
1651 int err;
1653 err = path_to_dir_vnode(path, &v1, filename1, kernel);
1654 if(err < 0)
1655 goto err;
1657 err = path_to_dir_vnode(path, &v2, filename2, kernel);
1658 if(err < 0)
1659 goto err1;
1661 if(v1->fsid != v2->fsid) {
1662 err = ERR_VFS_CROSS_FS_RENAME;
1663 goto err2;
1666 err = v1->mount->fs->calls->fs_rename(v1->mount->fscookie, v1->priv_vnode, filename1, v2->priv_vnode, filename2);
1668 err2:
1669 dec_vnode_ref_count(v2, true, false);
1670 err1:
1671 dec_vnode_ref_count(v1, true, false);
1672 err:
1673 return err;
1676 int vfs_mkdir(char *path, bool kernel)
1678 int err;
1679 struct vnode *v;
1680 char filename[SYS_MAX_NAME_LEN];
1682 #if MAKE_NOIZE
1683 dprintf("vfs_mkdir: path '%s', kernel %d\n", path, kernel);
1684 #endif
1686 err = path_to_dir_vnode(path, &v, filename, kernel);
1687 if(err < 0)
1688 goto err;
1690 err = v->mount->fs->calls->fs_mkdir(v->mount->fscookie, v->priv_vnode, filename);
1692 dec_vnode_ref_count(v, true, false);
1693 err:
1694 return err;
1697 int vfs_rmdir(char *path, bool kernel)
1699 int err;
1700 struct vnode *v;
1701 char filename[SYS_MAX_NAME_LEN];
1703 #if MAKE_NOIZE
1704 dprintf("vfs_rmdir: path '%s', kernel %d\n", path, kernel);
1705 #endif
1707 err = path_to_dir_vnode(path, &v, filename, kernel);
1708 if(err < 0)
1709 goto err;
1711 err = v->mount->fs->calls->fs_rmdir(v->mount->fscookie, v->priv_vnode, filename);
1713 dec_vnode_ref_count(v, true, false);
1714 err:
1715 return err;
1718 int vfs_rstat(char *path, struct file_stat *stat, bool kernel)
1720 int err;
1721 struct vnode *v;
1723 #if MAKE_NOIZE
1724 dprintf("vfs_rstat: path '%s', stat %p, kernel %d\n", path, stat, kernel);
1725 #endif
1727 err = path_to_vnode(path, &v, kernel);
1728 if(err < 0)
1729 goto err;
1731 err = v->mount->fs->calls->fs_rstat(v->mount->fscookie, v->priv_vnode, stat);
1733 dec_vnode_ref_count(v, true, false);
1734 err:
1735 return err;
1738 int vfs_wstat(char *path, struct file_stat *stat, int stat_mask, bool kernel)
1740 int err;
1741 struct vnode *v;
1743 #if MAKE_NOIZE
1744 dprintf("vfs_wstat: path '%s', stat %p, stat_mask %d, kernel %d\n", path, stat, stat_mask, kernel);
1745 #endif
1747 err = path_to_vnode(path, &v, kernel);
1748 if(err < 0)
1749 goto err;
1751 err = v->mount->fs->calls->fs_wstat(v->mount->fscookie, v->priv_vnode, stat, stat_mask);
1753 dec_vnode_ref_count(v, true, false);
1754 err:
1755 return err;
1758 int vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode)
1760 struct ioctx *ioctx;
1762 ioctx = get_current_ioctx(kernel);
1763 *vnode = get_vnode_from_fd(ioctx, fd);
1765 if(*vnode == NULL)
1766 return ERR_INVALID_HANDLE;
1768 return NO_ERROR;
1771 int vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode)
1773 struct vnode *v;
1774 int err;
1775 char buf[SYS_MAX_PATH_LEN+1];
1777 #if MAKE_NOIZE
1778 dprintf("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel);
1779 #endif
1781 strncpy(buf, path, SYS_MAX_PATH_LEN);
1782 buf[SYS_MAX_PATH_LEN] = 0;
1784 err = path_to_vnode(buf, &v, kernel);
1785 if(err < 0)
1786 goto err;
1788 *vnode = v;
1790 err:
1791 return err;
1794 int vfs_put_vnode_ptr(void *vnode)
1796 struct vnode *v = vnode;
1798 put_vnode(v);
1800 return 0;
1803 ssize_t vfs_canpage(void *_v)
1805 struct vnode *v = _v;
1807 #if MAKE_NOIZE
1808 dprintf("vfs_canpage: vnode %p\n", v);
1809 #endif
1811 return v->mount->fs->calls->fs_canpage(v->mount->fscookie, v->priv_vnode);
1814 ssize_t vfs_readpage(void *_v, iovecs *vecs, off_t pos)
1816 struct vnode *v = _v;
1818 #if MAKE_NOIZE
1819 dprintf("vfs_readpage: vnode %p, vecs %p, pos 0x%Lx\n", v, vecs, pos);
1820 #endif
1822 return v->mount->fs->calls->fs_readpage(v->mount->fscookie, v->priv_vnode, vecs, pos);
1825 ssize_t vfs_writepage(void *_v, iovecs *vecs, off_t pos)
1827 struct vnode *v = _v;
1829 #if MAKE_NOIZE
1830 dprintf("vfs_writepage: vnode %p, vecs %p, pos 0x%Lx\n", v, vecs, pos);
1831 #endif
1833 return v->mount->fs->calls->fs_writepage(v->mount->fscookie, v->priv_vnode, vecs, pos);
1836 static int vfs_get_cwd(char* buf, size_t size, bool kernel)
1838 // Get current working directory from io context
1839 // struct vnode* v = get_current_ioctx(kernel)->cwd;
1840 int rc;
1842 #if MAKE_NOIZE
1843 dprintf("vfs_get_cwd: buf %p, 0x%lx\n", buf, size);
1844 #endif
1845 //TODO: parse cwd back into a full path
1846 if (size >= 2) {
1847 buf[0] = '.';
1848 buf[1] = 0;
1850 rc = 0;
1851 } else {
1852 rc = ERR_VFS_INSUFFICIENT_BUF;
1855 // Tell caller all is ok
1856 return rc;
1859 static int vfs_set_cwd(char* path, bool kernel)
1861 struct ioctx* curr_ioctx;
1862 struct vnode* v = NULL;
1863 struct vnode* old_cwd;
1864 struct file_stat stat;
1865 int rc;
1867 #if MAKE_NOIZE
1868 dprintf("vfs_set_cwd: path='%s'\n", path);
1869 #endif
1871 // Get vnode for passed path, and bail if it failed
1872 rc = path_to_vnode(path, &v, kernel);
1873 if (rc < 0) {
1874 goto err;
1877 rc = v->mount->fs->calls->fs_rstat(v->mount->fscookie, v->priv_vnode, &stat);
1878 if(rc < 0) {
1879 goto err1;
1882 if(stat.type != STREAM_TYPE_DIR) {
1883 // nope, can't cwd to here
1884 rc = ERR_VFS_WRONG_STREAM_TYPE;
1885 goto err1;
1888 // Get current io context and lock
1889 curr_ioctx = get_current_ioctx(kernel);
1890 mutex_lock(&curr_ioctx->io_mutex);
1892 // save the old cwd
1893 old_cwd = curr_ioctx->cwd;
1895 // Set the new vnode
1896 curr_ioctx->cwd = v;
1898 // Unlock the ioctx
1899 mutex_unlock(&curr_ioctx->io_mutex);
1901 // Decrease ref count of previous working dir (as the ref is being replaced)
1902 if (old_cwd)
1903 dec_vnode_ref_count(old_cwd, true, false);
1905 return NO_ERROR;
1907 err1:
1908 dec_vnode_ref_count(v, true, false);
1909 err:
1910 return rc;
1913 static int vfs_dup(int fd, bool kernel)
1915 struct ioctx* curr_ioctx;
1916 struct file_descriptor *f;
1917 int rc;
1919 #if MAKE_NOIZE
1920 dprintf("vfs_dup: fd=%d\n", fd);
1921 #endif
1923 // Get current io context
1924 curr_ioctx = get_current_ioctx(kernel);
1926 // Try to get the fd structure
1927 f = get_fd(curr_ioctx, fd);
1928 if(!f) {
1929 rc = ERR_INVALID_HANDLE;
1930 goto err;
1933 // now put the fd in place
1934 rc = new_fd(curr_ioctx, f);
1936 if(rc < 0) {
1937 put_fd(f);
1940 err:
1941 return rc;
1944 static int vfs_dup2(int ofd, int nfd, bool kernel)
1946 struct ioctx* curr_ioctx;
1947 struct file_descriptor *evicted;
1948 int rc;
1950 #if MAKE_NOIZE
1951 dprintf("vfs_dup2: ofd=%d nfd=%d\n", ofd, nfd);
1952 #endif
1954 // quick check
1955 if((ofd < 0) || (nfd < 0)) {
1956 rc= ERR_INVALID_HANDLE;
1957 goto err;
1960 // Get current io context and lock
1961 curr_ioctx = get_current_ioctx(kernel);
1962 mutex_lock(&curr_ioctx->io_mutex);
1965 // Check for upper boundary, we do in the locked part
1966 // because in the future the fd table might be resizeable
1967 if((ofd >= curr_ioctx->table_size) || !curr_ioctx->fds[ofd]) {
1968 rc= ERR_INVALID_HANDLE;
1969 goto err_1;
1971 if((nfd >= curr_ioctx->table_size)) {
1972 rc= ERR_INVALID_HANDLE;
1973 goto err_1;
1977 // Check for identity, note that it cannot be made above
1978 // because we always want to return an error on invalid
1979 // handles
1980 if(ofd == nfd) {
1981 mutex_unlock(&curr_ioctx->io_mutex);
1982 goto success;
1986 // Now do the work
1987 evicted= curr_ioctx->fds[nfd];
1988 atomic_add(&curr_ioctx->fds[ofd]->ref_count, 1);
1989 curr_ioctx->fds[nfd]= curr_ioctx->fds[ofd];
1992 // Unlock the ioctx
1993 mutex_unlock(&curr_ioctx->io_mutex);
1996 // Say bye bye to the evicted fd
1997 if(evicted) {
1998 put_fd(evicted);
2001 success:
2002 rc= nfd;
2003 return nfd;
2005 err_1:
2006 mutex_unlock(&curr_ioctx->io_mutex);
2007 err:
2008 return rc;
2011 int sys_mount(const char *path, const char *device, const char *fs_name, void *args)
2013 char buf[SYS_MAX_PATH_LEN+1];
2015 strncpy(buf, path, SYS_MAX_PATH_LEN);
2016 buf[SYS_MAX_PATH_LEN] = 0;
2018 return vfs_mount(buf, device, fs_name, args, true);
2021 int sys_unmount(const char *path)
2023 char buf[SYS_MAX_PATH_LEN+1];
2025 strncpy(buf, path, SYS_MAX_PATH_LEN);
2026 buf[SYS_MAX_PATH_LEN] = 0;
2028 return vfs_unmount(buf, true);
2031 int sys_sync(void)
2033 return vfs_sync();
2036 int sys_opendir(const char *path)
2038 char buf[SYS_MAX_PATH_LEN+1];
2040 strncpy(buf, path, SYS_MAX_PATH_LEN);
2041 buf[SYS_MAX_PATH_LEN] = 0;
2043 return vfs_opendir(buf, true);
2046 int sys_closedir(int fd)
2048 return vfs_closedir(fd, true);
2051 int sys_rewinddir(int fd)
2053 return vfs_rewinddir(fd, true);
2056 int sys_readdir(int fd, void *buf, size_t len)
2058 return vfs_readdir(fd, buf, len, true);
2061 int sys_open(const char *path, int omode)
2063 char buf[SYS_MAX_PATH_LEN+1];
2065 strncpy(buf, path, SYS_MAX_PATH_LEN);
2066 buf[SYS_MAX_PATH_LEN] = 0;
2068 return vfs_open(buf, omode, true);
2071 int sys_close(int fd)
2073 return vfs_close(fd, true);
2076 int sys_fsync(int fd)
2078 return vfs_fsync(fd, true);
2081 ssize_t sys_read(int fd, void *buf, off_t pos, ssize_t len)
2083 return vfs_read(fd, buf, pos, len, true);
2086 ssize_t sys_write(int fd, const void *buf, off_t pos, ssize_t len)
2088 return vfs_write(fd, buf, pos, len, true);
2091 int sys_seek(int fd, off_t pos, seek_type seek_type)
2093 return vfs_seek(fd, pos, seek_type, true);
2096 int sys_ioctl(int fd, int op, void *buf, size_t len)
2098 return vfs_ioctl(fd, op, buf, len, true);
2101 int sys_create(const char *path)
2103 char buf[SYS_MAX_PATH_LEN+1];
2105 strncpy(buf, path, SYS_MAX_PATH_LEN);
2106 buf[SYS_MAX_PATH_LEN] = 0;
2108 return vfs_create(buf, NULL, true);
2111 int sys_unlink(const char *path)
2113 char buf[SYS_MAX_PATH_LEN+1];
2115 strncpy(buf, path, SYS_MAX_PATH_LEN);
2116 buf[SYS_MAX_PATH_LEN] = 0;
2118 return vfs_unlink(buf, true);
2121 int sys_rename(const char *oldpath, const char *newpath)
2123 char buf1[SYS_MAX_PATH_LEN+1];
2124 char buf2[SYS_MAX_PATH_LEN+1];
2126 strncpy(buf1, oldpath, SYS_MAX_PATH_LEN);
2127 buf1[SYS_MAX_PATH_LEN] = 0;
2129 strncpy(buf2, newpath, SYS_MAX_PATH_LEN);
2130 buf2[SYS_MAX_PATH_LEN] = 0;
2132 return vfs_rename(buf1, buf2, true);
2135 int sys_mkdir(const char *path)
2137 char buf[SYS_MAX_PATH_LEN+1];
2139 strncpy(buf, path, SYS_MAX_PATH_LEN);
2140 buf[SYS_MAX_PATH_LEN] = 0;
2142 return vfs_mkdir(buf, true);
2145 int sys_rmdir(const char *path)
2147 char buf[SYS_MAX_PATH_LEN+1];
2149 strncpy(buf, path, SYS_MAX_PATH_LEN);
2150 buf[SYS_MAX_PATH_LEN] = 0;
2152 return vfs_rmdir(buf, true);
2155 int sys_rstat(const char *path, struct file_stat *stat)
2157 char buf[SYS_MAX_PATH_LEN+1];
2159 strncpy(buf, path, SYS_MAX_PATH_LEN);
2160 buf[SYS_MAX_PATH_LEN] = 0;
2162 return vfs_rstat(buf, stat, true);
2165 int sys_wstat(const char *path, struct file_stat *stat, int stat_mask)
2167 char buf[SYS_MAX_PATH_LEN+1];
2169 strncpy(buf, path, SYS_MAX_PATH_LEN);
2170 buf[SYS_MAX_PATH_LEN] = 0;
2172 return vfs_wstat(buf, stat, stat_mask, true);
2175 char* sys_getcwd(char *buf, size_t size)
2177 char path[SYS_MAX_PATH_LEN];
2178 int rc;
2180 #if MAKE_NOIZE
2181 dprintf("sys_getcwd: buf %p, 0x%lx\n", buf, size);
2182 #endif
2184 // Call vfs to get current working directory
2185 rc = vfs_get_cwd(path,SYS_MAX_PATH_LEN-1,true);
2186 path[SYS_MAX_PATH_LEN-1] = 0;
2188 // Copy back the result
2189 strncpy(buf,path,size);
2191 // Return either NULL or the buffer address to indicate failure or success
2192 return (rc < 0) ? NULL : buf;
2195 int sys_setcwd(const char* _path)
2197 char path[SYS_MAX_PATH_LEN];
2199 #if MAKE_NOIZE
2200 dprintf("sys_setcwd: path=%p\n", _path);
2201 #endif
2203 // Copy new path to kernel space
2204 strncpy(path, _path, SYS_MAX_PATH_LEN-1);
2205 path[SYS_MAX_PATH_LEN-1] = 0;
2207 // Call vfs to set new working directory
2208 return vfs_set_cwd(path,true);
2211 int sys_dup(int fd)
2213 return vfs_dup(fd, true);
2216 int sys_dup2(int ofd, int nfd)
2218 return vfs_dup2(ofd, nfd, true);
2221 int user_mount(const char *upath, const char *udevice, const char *ufs_name, void *args)
2223 char path[SYS_MAX_PATH_LEN+1];
2224 char fs_name[SYS_MAX_OS_NAME_LEN+1];
2225 char device[SYS_MAX_PATH_LEN+1];
2226 int rc;
2228 if(is_kernel_address(upath))
2229 return ERR_VM_BAD_USER_MEMORY;
2231 if(is_kernel_address(ufs_name))
2232 return ERR_VM_BAD_USER_MEMORY;
2234 if(udevice) {
2235 if(is_kernel_address(udevice))
2236 return ERR_VM_BAD_USER_MEMORY;
2239 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
2240 if(rc < 0)
2241 return rc;
2242 path[SYS_MAX_PATH_LEN] = 0;
2244 rc = user_strncpy(fs_name, ufs_name, SYS_MAX_OS_NAME_LEN);
2245 if(rc < 0)
2246 return rc;
2247 fs_name[SYS_MAX_OS_NAME_LEN] = 0;
2249 if(udevice) {
2250 rc = user_strncpy(device, udevice, SYS_MAX_PATH_LEN);
2251 if(rc < 0)
2252 return rc;
2253 device[SYS_MAX_PATH_LEN] = 0;
2254 } else {
2255 device[0] = 0;
2258 return vfs_mount(path, device, fs_name, args, false);
2261 int user_unmount(const char *upath)
2263 char path[SYS_MAX_PATH_LEN+1];
2264 int rc;
2266 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
2267 if(rc < 0)
2268 return rc;
2269 path[SYS_MAX_PATH_LEN] = 0;
2271 return vfs_unmount(path, false);
2274 int user_sync(void)
2276 return vfs_sync();
2279 int user_opendir(const char *upath)
2281 char path[SYS_MAX_PATH_LEN];
2282 int rc;
2284 if(is_kernel_address(upath))
2285 return ERR_VM_BAD_USER_MEMORY;
2287 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2288 if(rc < 0)
2289 return rc;
2290 path[SYS_MAX_PATH_LEN-1] = 0;
2292 return vfs_opendir(path, false);
2295 int user_closedir(int fd)
2297 return vfs_closedir(fd, false);
2300 int user_rewinddir(int fd)
2302 return vfs_rewinddir(fd, false);
2305 int user_readdir(int fd, void *buf, size_t len)
2307 return vfs_readdir(fd, buf, len, false);
2310 int user_open(const char *upath, int omode)
2312 char path[SYS_MAX_PATH_LEN];
2313 int rc;
2315 if(is_kernel_address(upath))
2316 return ERR_VM_BAD_USER_MEMORY;
2318 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2319 if(rc < 0)
2320 return rc;
2321 path[SYS_MAX_PATH_LEN-1] = 0;
2323 return vfs_open(path, omode, false);
2326 int user_close(int fd)
2328 return vfs_close(fd, false);
2331 int user_fsync(int fd)
2333 return vfs_fsync(fd, false);
2336 ssize_t user_read(int fd, void *buf, off_t pos, ssize_t len)
2338 if(is_kernel_address(buf))
2339 return ERR_VM_BAD_USER_MEMORY;
2341 return vfs_read(fd, buf, pos, len, false);
2344 ssize_t user_write(int fd, const void *buf, off_t pos, ssize_t len)
2346 if(is_kernel_address(buf))
2347 return ERR_VM_BAD_USER_MEMORY;
2349 return vfs_write(fd, buf, pos, len, false);
2352 int user_seek(int fd, off_t pos, seek_type seek_type)
2354 return vfs_seek(fd, pos, seek_type, false);
2357 int user_ioctl(int fd, int op, void *buf, size_t len)
2359 if(is_kernel_address(buf))
2360 return ERR_VM_BAD_USER_MEMORY;
2361 return vfs_ioctl(fd, op, buf, len, false);
2364 int user_create(const char *upath)
2366 char path[SYS_MAX_PATH_LEN];
2367 int rc;
2369 if(is_kernel_address(upath))
2370 return ERR_VM_BAD_USER_MEMORY;
2372 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2373 if(rc < 0)
2374 return rc;
2375 path[SYS_MAX_PATH_LEN-1] = 0;
2377 return vfs_create(path, NULL, false);
2380 int user_unlink(const char *upath)
2382 char path[SYS_MAX_PATH_LEN+1];
2383 int rc;
2385 if(is_kernel_address(upath))
2386 return ERR_VM_BAD_USER_MEMORY;
2388 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
2389 if(rc < 0)
2390 return rc;
2391 path[SYS_MAX_PATH_LEN] = 0;
2393 return vfs_unlink(path, false);
2396 int user_rename(const char *uoldpath, const char *unewpath)
2398 char oldpath[SYS_MAX_PATH_LEN+1];
2399 char newpath[SYS_MAX_PATH_LEN+1];
2400 int rc;
2402 if(is_kernel_address(uoldpath))
2403 return ERR_VM_BAD_USER_MEMORY;
2405 if(is_kernel_address(unewpath))
2406 return ERR_VM_BAD_USER_MEMORY;
2408 rc = user_strncpy(oldpath, uoldpath, SYS_MAX_PATH_LEN);
2409 if(rc < 0)
2410 return rc;
2411 oldpath[SYS_MAX_PATH_LEN] = 0;
2413 rc = user_strncpy(newpath, unewpath, SYS_MAX_PATH_LEN);
2414 if(rc < 0)
2415 return rc;
2416 newpath[SYS_MAX_PATH_LEN] = 0;
2418 return vfs_rename(oldpath, newpath, false);
2421 int user_mkdir(const char *upath)
2423 char path[SYS_MAX_PATH_LEN];
2424 int rc;
2426 if(is_kernel_address(upath))
2427 return ERR_VM_BAD_USER_MEMORY;
2429 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2430 if(rc < 0)
2431 return rc;
2432 path[SYS_MAX_PATH_LEN-1] = 0;
2434 return vfs_mkdir(path, false);
2437 int user_rmdir(const char *upath)
2439 char path[SYS_MAX_PATH_LEN+1];
2440 int rc;
2442 if(is_kernel_address(upath))
2443 return ERR_VM_BAD_USER_MEMORY;
2445 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
2446 if(rc < 0)
2447 return rc;
2448 path[SYS_MAX_PATH_LEN] = 0;
2450 return vfs_rmdir(path, false);
2453 int user_rstat(const char *upath, struct file_stat *ustat)
2455 char path[SYS_MAX_PATH_LEN];
2456 struct file_stat stat;
2457 int rc, rc2;
2459 if(is_kernel_address(upath))
2460 return ERR_VM_BAD_USER_MEMORY;
2462 if(is_kernel_address(ustat))
2463 return ERR_VM_BAD_USER_MEMORY;
2465 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2466 if(rc < 0)
2467 return rc;
2468 path[SYS_MAX_PATH_LEN-1] = 0;
2470 rc = vfs_rstat(path, &stat, false);
2471 if(rc < 0)
2472 return rc;
2474 rc2 = user_memcpy(ustat, &stat, sizeof(struct file_stat));
2475 if(rc2 < 0)
2476 return rc2;
2478 return rc;
2481 int user_wstat(const char *upath, struct file_stat *ustat, int stat_mask)
2483 char path[SYS_MAX_PATH_LEN+1];
2484 struct file_stat stat;
2485 int rc;
2487 if(is_kernel_address(upath))
2488 return ERR_VM_BAD_USER_MEMORY;
2490 if(is_kernel_address(ustat))
2491 return ERR_VM_BAD_USER_MEMORY;
2493 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
2494 if(rc < 0)
2495 return rc;
2496 path[SYS_MAX_PATH_LEN] = 0;
2498 rc = user_memcpy(&stat, ustat, sizeof(struct file_stat));
2499 if(rc < 0)
2500 return rc;
2502 return vfs_wstat(path, &stat, stat_mask, false);
2505 int user_getcwd(char *buf, size_t size)
2507 char path[SYS_MAX_PATH_LEN];
2508 int rc, rc2;
2510 #if MAKE_NOIZE
2511 dprintf("user_getcwd: buf %p, 0x%lx\n", buf, size);
2512 #endif
2514 // Check if userspace address is inside "shared" kernel space
2515 if(is_kernel_address(buf))
2516 return NULL; //ERR_VM_BAD_USER_MEMORY;
2518 // Call vfs to get current working directory
2519 rc = vfs_get_cwd(path, SYS_MAX_PATH_LEN-1, false);
2520 if(rc < 0)
2521 return rc;
2523 // Copy back the result
2524 rc2 = user_strncpy(buf, path, size);
2525 if(rc2 < 0)
2526 return rc2;
2528 return rc;
2531 int user_setcwd(const char* upath)
2533 char path[SYS_MAX_PATH_LEN];
2534 int rc;
2536 #if MAKE_NOIZE
2537 dprintf("user_setcwd: path=%p\n", upath);
2538 #endif
2540 // Check if userspace address is inside "shared" kernel space
2541 if(is_kernel_address(upath))
2542 return ERR_VM_BAD_USER_MEMORY;
2544 // Copy new path to kernel space
2545 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2546 if (rc < 0) {
2547 return rc;
2549 path[SYS_MAX_PATH_LEN-1] = 0;
2551 // Call vfs to set new working directory
2552 return vfs_set_cwd(path,false);
2555 int user_dup(int fd)
2557 return vfs_dup(fd, false);
2560 int user_dup2(int ofd, int nfd)
2562 return vfs_dup2(ofd, nfd, false);
2565 image_id vfs_load_fs_module(const char *name)
2567 image_id id;
2568 void (*bootstrap)();
2569 char path[SYS_MAX_PATH_LEN];
2571 sprintf(path, "/boot/addons/fs/%s", name);
2573 id = elf_load_kspace(path, "");
2574 if(id < 0)
2575 return id;
2577 bootstrap = (void *)elf_lookup_symbol(id, "fs_bootstrap");
2578 if(!bootstrap)
2579 return ERR_VFS_INVALID_FS;
2581 bootstrap();
2583 return id;
2586 int vfs_bootstrap_all_filesystems(void)
2588 int err;
2589 int fd;
2591 kprintf("bootstrapping all built in file systems...\n");
2593 // bootstrap the root filesystem
2594 bootstrap_rootfs();
2596 kprintf("\tmounting /");
2597 err = sys_mount("/", NULL, "rootfs", NULL);
2598 if(err < 0)
2599 panic("error mounting rootfs!\n");
2601 sys_setcwd("/");
2603 // bootstrap the bootfs
2604 bootstrap_bootfs();
2606 kprintf(" /boot");
2607 sys_mkdir("/boot");
2608 err = sys_mount("/boot", NULL, "bootfs", NULL);
2609 if(err < 0)
2610 panic("error mounting bootfs\n");
2612 // bootstrap the devfs
2613 bootstrap_devfs();
2615 kprintf(" /dev");
2616 sys_mkdir("/dev");
2617 err = sys_mount("/dev", NULL, "devfs", NULL);
2618 if(err < 0)
2619 panic("error mounting devfs\n");
2621 // bootstrap the pipefs
2622 bootstrap_pipefs();
2624 kprintf(" /pipe");
2625 sys_mkdir("/pipe");
2626 err = sys_mount("/pipe", NULL, "pipefs", NULL);
2627 if(err < 0)
2628 panic("error mounting pipefs\n");
2630 kprintf("\n");
2632 fd = sys_opendir("/boot/addons/fs");
2633 if(fd >= 0) {
2634 ssize_t len;
2635 char buf[SYS_MAX_NAME_LEN];
2637 while((len = sys_readdir(fd, buf, sizeof(buf))) > 0) {
2638 dprintf("loading '%s' fs module\n", buf);
2639 vfs_load_fs_module(buf);
2641 sys_closedir(fd);
2644 return NO_ERROR;
2647 int vfs_getrlimit(int resource, struct rlimit * rlp)
2649 if (!rlp) {
2650 return -1;
2653 switch (resource) {
2654 case RLIMIT_NOFILE:
2656 struct ioctx * ioctx = get_current_ioctx(false);
2658 mutex_lock(&ioctx->io_mutex);
2660 rlp->rlim_cur = ioctx->table_size;
2661 rlp->rlim_max = MAX_FD_TABLE_SIZE;
2663 mutex_unlock(&ioctx->io_mutex);
2665 return 0;
2668 default:
2669 return -1;
2673 static int vfs_resize_fd_table(struct ioctx * ioctx, const int new_size)
2675 void * new_fds;
2676 int ret;
2678 if (new_size < 0 || new_size > MAX_FD_TABLE_SIZE) {
2679 return -1;
2682 mutex_lock(&ioctx->io_mutex);
2684 if (new_size < ioctx->table_size) {
2685 int i;
2687 /* Make sure none of the fds being dropped are in use */
2688 for(i = new_size; i < ioctx->table_size; i++) {
2689 if (ioctx->fds[i]) {
2690 ret = -1;
2691 goto error;
2695 new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size);
2696 if (!new_fds) {
2697 ret = -1;
2698 goto error;
2701 memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * new_size);
2702 } else {
2703 new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size);
2704 if (!new_fds) {
2705 ret = -1;
2706 goto error;
2709 memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * ioctx->table_size);
2710 memset(((char *)new_fds) + (sizeof(struct file_descriptor *) * ioctx->table_size), 0,
2711 (sizeof(struct file_descriptor *) * new_size) - (sizeof(struct file_descriptor *) * ioctx->table_size));
2714 kfree(ioctx->fds);
2715 ioctx->fds = new_fds;
2716 ioctx->table_size = new_size;
2718 mutex_unlock(&ioctx->io_mutex);
2720 return 0;
2722 error:
2723 mutex_unlock(&ioctx->io_mutex);
2725 return ret;
2728 int vfs_setrlimit(int resource, const struct rlimit * rlp)
2730 if (!rlp) {
2731 return -1;
2734 switch (resource) {
2735 case RLIMIT_NOFILE:
2736 return vfs_resize_fd_table(get_current_ioctx(false), rlp->rlim_cur);
2738 default:
2739 return -1;