roll in a bunch of bugfixes by Jeroen Iddekinge:
[newos.git] / kernel / vfs.c
blob4ac0d587762f11a94577b9a914bfb04fb8bd4580
1 /*
2 ** Copyright 2001, 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/khash.h>
12 #include <kernel/lock.h>
13 #include <kernel/thread.h>
14 #include <kernel/heap.h>
15 #include <kernel/arch/cpu.h>
16 #include <kernel/elf.h>
17 #include <kernel/fs/rootfs.h>
18 #include <kernel/fs/bootfs.h>
19 #include <kernel/fs/devfs.h>
20 #include <sys/errors.h>
22 #include <kernel/fs/rootfs.h>
24 #include <libc/string.h>
25 #include <libc/printf.h>
26 #include <libc/ctype.h>
28 #define MAKE_NOIZE 0
30 struct vnode {
31 struct vnode *next;
32 struct vnode *mount_prev;
33 struct vnode *mount_next;
34 struct vm_cache *cache;
35 fs_id fsid;
36 vnode_id vnid;
37 fs_vnode priv_vnode;
38 struct fs_mount *mount;
39 struct vnode *covered_by;
40 int ref_count;
41 bool delete_me;
42 bool busy;
44 struct vnode_hash_key {
45 fs_id fsid;
46 vnode_id vnid;
49 struct file_descriptor {
50 struct vnode *vnode;
51 file_cookie cookie;
52 int ref_count;
55 struct ioctx {
56 struct vnode *cwd;
57 mutex io_mutex;
58 int table_size;
59 int num_used_fds;
60 struct file_descriptor *fds[0];
63 struct fs_container {
64 struct fs_container *next;
65 struct fs_calls *calls;
66 const char *name;
68 static struct fs_container *fs_list;
70 struct fs_mount {
71 struct fs_mount *next;
72 struct fs_container *fs;
73 fs_id id;
74 void *fscookie;
75 char *mount_point;
76 recursive_lock rlock;
77 struct vnode *root_vnode;
78 struct vnode *covers_vnode;
79 struct vnode *vnodes_head;
80 struct vnode *vnodes_tail;
81 bool unmounting;
84 static mutex vfs_mutex;
85 static mutex vfs_mount_mutex;
86 static mutex vfs_mount_op_mutex;
87 static mutex vfs_vnode_mutex;
89 /* function declarations */
90 static int vfs_mount(char *path, const char *fs_name, bool kernel);
91 static int vfs_unmount(char *path, bool kernel);
92 static int vfs_open(char *path, stream_type st, int omode, bool kernel);
93 static int vfs_seek(int fd, off_t pos, seek_type seek_type, bool kernel);
94 static ssize_t vfs_read(int fd, void *buf, off_t pos, ssize_t len, bool kernel);
95 static ssize_t vfs_write(int fd, const void *buf, off_t pos, ssize_t len, bool kernel);
96 static int vfs_ioctl(int fd, int op, void *buf, size_t len, bool kernel);
97 static int vfs_close(int fd, bool kernel);
98 static int vfs_create(char *path, stream_type stream_type, void *args, bool kernel);
99 static int vfs_rstat(char *path, struct file_stat *stat, bool kernel);
101 #define VNODE_HASH_TABLE_SIZE 1024
102 static void *vnode_table;
103 static struct vnode *root_vnode;
104 static vnode_id next_vnode_id = 0;
106 #define MOUNTS_HASH_TABLE_SIZE 16
107 static void *mounts_table;
108 static fs_id next_fsid = 0;
110 static int mount_compare(void *_m, void *_key)
112 struct fs_mount *mount = _m;
113 fs_id *id = _key;
115 if(mount->id == *id)
116 return 0;
117 else
118 return -1;
121 static unsigned int mount_hash(void *_m, void *_key, int range)
123 struct fs_mount *mount = _m;
124 fs_id *id = _key;
126 if(mount)
127 return mount->id % range;
128 else
129 return *id % range;
132 static struct fs_mount *fsid_to_mount(fs_id id)
134 struct fs_mount *mount;
136 mutex_lock(&vfs_mount_mutex);
138 mount = hash_lookup(mounts_table, &id);
140 mutex_unlock(&vfs_mount_mutex);
142 return mount;
145 static int vnode_compare(void *_v, void *_key)
147 struct vnode *v = _v;
148 struct vnode_hash_key *key = _key;
150 if(v->fsid == key->fsid && v->vnid == key->vnid)
151 return 0;
152 else
153 return -1;
156 static unsigned int vnode_hash(void *_v, void *_key, int range)
158 struct vnode *v = _v;
159 struct vnode_hash_key *key = _key;
161 #define VHASH(fsid, vnid) (((uint32)((vnid)>>32) + (uint32)(vnid)) ^ (uint32)(fsid))
163 if(v != NULL)
164 return (VHASH(v->fsid, v->vnid) % range);
165 else
166 return (VHASH(key->fsid, key->vnid) % range);
168 #undef VHASH
171 static int init_vnode(struct vnode *v)
173 v->next = NULL;
174 v->mount_prev = NULL;
175 v->mount_next = NULL;
176 v->priv_vnode = NULL;
177 v->cache = NULL;
178 v->ref_count = 0;
179 v->vnid = 0;
180 v->fsid = 0;
181 v->delete_me = false;
182 v->busy = false;
183 v->covered_by = NULL;
184 v->mount = NULL;
186 return 0;
189 static void add_vnode_to_mount_list(struct vnode *v, struct fs_mount *mount)
191 recursive_lock_lock(&mount->rlock);
193 v->mount_next = mount->vnodes_head;
194 v->mount_prev = NULL;
195 mount->vnodes_head = v;
196 if(!mount->vnodes_tail)
197 mount->vnodes_tail = v;
199 recursive_lock_unlock(&mount->rlock);
202 static void remove_vnode_from_mount_list(struct vnode *v, struct fs_mount *mount)
204 recursive_lock_lock(&mount->rlock);
206 if(v->mount_next)
207 v->mount_next->mount_prev = v->mount_prev;
208 else
209 mount->vnodes_tail = v->mount_prev;
210 if(v->mount_prev)
211 v->mount_prev->mount_next = v->mount_next;
212 else
213 mount->vnodes_head = v->mount_next;
215 v->mount_prev = v->mount_next = NULL;
217 recursive_lock_unlock(&mount->rlock);
220 static struct vnode *create_new_vnode()
222 struct vnode *v;
224 v = (struct vnode *)kmalloc(sizeof(struct vnode));
225 if(v == NULL)
226 return NULL;
228 init_vnode(v);
229 return v;
232 static int dec_vnode_ref_count(struct vnode *v, bool free_mem, bool r)
234 int err;
236 mutex_lock(&vfs_vnode_mutex);
238 if(v->busy == true)
239 panic("dec_vnode_ref_count called on vnode that was busy! vnode 0x%x\n", v);
241 v->ref_count--;
243 #if MAKE_NOIZE
244 dprintf("dec_vnode_ref_count: vnode 0x%x, ref now %d\n", v, v->ref_count);
245 #endif
247 if(v->ref_count <= 0) {
248 v->busy = true;
250 mutex_unlock(&vfs_vnode_mutex);
252 /* if we have a vm_cache attached, remove it */
253 if(v->cache)
254 vm_cache_release_ref((vm_cache_ref *)v->cache);
255 v->cache = NULL;
257 if(v->delete_me)
258 v->mount->fs->calls->fs_removevnode(v->mount->fscookie, v->priv_vnode, r);
259 else
260 v->mount->fs->calls->fs_putvnode(v->mount->fscookie, v->priv_vnode, r);
262 remove_vnode_from_mount_list(v, v->mount);
264 mutex_lock(&vfs_vnode_mutex);
265 hash_remove(vnode_table, v);
266 mutex_unlock(&vfs_vnode_mutex);
268 if(free_mem)
269 kfree(v);
270 err = 1;
271 } else {
272 mutex_unlock(&vfs_vnode_mutex);
273 err = 0;
275 return err;
278 static int inc_vnode_ref_count(struct vnode *v, bool locked)
280 if(!locked)
281 mutex_lock(&vfs_vnode_mutex);
283 v->ref_count++;
285 #if MAKE_NOIZE
286 dprintf("inc_vnode_ref_count: vnode 0x%x, ref now %d\n", v, v->ref_count);
287 #endif
289 if(!locked)
290 mutex_unlock(&vfs_vnode_mutex);
291 return 0;
294 static struct vnode *lookup_vnode(fs_id fsid, vnode_id vnid)
296 struct vnode_hash_key key;
298 key.fsid = fsid;
299 key.vnid = vnid;
301 return hash_lookup(vnode_table, &key);
304 static int get_vnode(fs_id fsid, vnode_id vnid, struct vnode **outv, int r)
306 struct vnode *v;
307 int err;
309 #if MAKE_NOIZE
310 dprintf("get_vnode: fsid %d vnid 0x%x 0x%x\n", fsid, vnid);
311 #endif
313 mutex_lock(&vfs_vnode_mutex);
315 do {
316 v = lookup_vnode(fsid, vnid);
317 if(v) {
318 if(v->busy) {
319 mutex_unlock(&vfs_vnode_mutex);
320 thread_snooze(10000); // 10 ms
321 mutex_lock(&vfs_vnode_mutex);
322 continue;
325 } while(0);
327 #if MAKE_NOIZE
328 dprintf("get_vnode: tried to lookup vnode, got 0x%x\n", v);
329 #endif
330 if(v) {
331 inc_vnode_ref_count(v, true);
332 } else {
333 // we need to create a new vnode and read it in
334 v = create_new_vnode();
335 if(!v) {
336 err = ERR_NO_MEMORY;
337 goto err;
339 v->fsid = fsid;
340 v->vnid = vnid;
341 v->mount = fsid_to_mount(fsid);
342 if(!v->mount) {
343 err = ERR_INVALID_HANDLE;
344 goto err;
346 v->busy = true;
347 hash_insert(vnode_table, v);
348 mutex_unlock(&vfs_vnode_mutex);
350 add_vnode_to_mount_list(v, v->mount);
352 err = v->mount->fs->calls->fs_getvnode(v->mount->fscookie, vnid, &v->priv_vnode, r);
354 if(err < 0)
355 remove_vnode_from_mount_list(v, v->mount);
357 mutex_lock(&vfs_vnode_mutex);
358 if(err < 0)
359 goto err1;
361 v->busy = false;
362 v->ref_count = 1;
365 mutex_unlock(&vfs_vnode_mutex);
366 #if MAKE_NOIZE
367 dprintf("get_vnode: returning 0x%x\n", v);
368 #endif
369 *outv = v;
370 return NO_ERROR;
372 err1:
373 hash_remove(vnode_table, v);
374 err:
375 mutex_unlock(&vfs_vnode_mutex);
376 if(v)
377 kfree(v);
379 return err;
382 static void put_vnode(struct vnode *v)
384 dec_vnode_ref_count(v, true, false);
387 int vfs_get_vnode(fs_id fsid, vnode_id vnid, fs_vnode *fsv)
389 int err;
390 struct vnode *v;
392 err = get_vnode(fsid, vnid, &v, true);
393 if(err < 0)
394 return err;
396 *fsv = v->priv_vnode;
397 return NO_ERROR;
400 int vfs_put_vnode(fs_id fsid, vnode_id vnid)
402 struct vnode *v;
404 mutex_lock(&vfs_vnode_mutex);
406 v = lookup_vnode(fsid, vnid);
408 mutex_unlock(&vfs_vnode_mutex);
409 if(v)
410 dec_vnode_ref_count(v, true, true);
412 return NO_ERROR;
415 void vfs_vnode_acquire_ref(void *v)
417 #if MAKE_NOIZE
418 dprintf("vfs_vnode_acquire_ref: vnode 0x%x\n", v);
419 #endif
420 inc_vnode_ref_count((struct vnode *)v, false);
423 void vfs_vnode_release_ref(void *v)
425 #if MAKE_NOIZE
426 dprintf("vfs_vnode_release_ref: vnode 0x%x\n", v);
427 #endif
428 dec_vnode_ref_count((struct vnode *)v, true, false);
431 int vfs_remove_vnode(fs_id fsid, vnode_id vnid)
433 struct vnode *v;
435 mutex_lock(&vfs_vnode_mutex);
437 v = lookup_vnode(fsid, vnid);
438 if(v)
439 v->delete_me = true;
441 mutex_unlock(&vfs_vnode_mutex);
442 return 0;
445 void *vfs_get_cache_ptr(void *vnode)
447 return ((struct vnode *)vnode)->cache;
450 int vfs_set_cache_ptr(void *vnode, void *cache)
452 if(test_and_set((int *)&(((struct vnode *)vnode)->cache), (int)cache, 0) == 0)
453 return -1;
454 else
455 return 0;
458 static struct file_descriptor *alloc_fd()
460 struct file_descriptor *f;
462 f = kmalloc(sizeof(struct file_descriptor));
463 if(f) {
464 f->vnode = NULL;
465 f->cookie = NULL;
466 f->ref_count = 1;
468 return f;
471 static struct file_descriptor *get_fd(struct ioctx *ioctx, int fd)
473 struct file_descriptor *f;
475 mutex_lock(&ioctx->io_mutex);
477 if(fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) {
478 // valid fd
479 f = ioctx->fds[fd];
480 atomic_add(&f->ref_count, 1);
481 } else {
482 f = NULL;
485 mutex_unlock(&ioctx->io_mutex);
486 return f;
489 static void free_fd(struct file_descriptor *f)
491 f->vnode->mount->fs->calls->fs_close(f->vnode->mount->fscookie, f->vnode->priv_vnode, f->cookie);
492 f->vnode->mount->fs->calls->fs_freecookie(f->vnode->mount->fscookie, f->vnode->priv_vnode, f->cookie);
493 dec_vnode_ref_count(f->vnode, true, false);
494 kfree(f);
497 static void put_fd(struct file_descriptor *f)
499 if(atomic_add(&f->ref_count, -1) == 1) {
500 free_fd(f);
504 static void remove_fd(struct ioctx *ioctx, int fd)
506 struct file_descriptor *f;
508 mutex_lock(&ioctx->io_mutex);
510 if(fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) {
511 // valid fd
512 f = ioctx->fds[fd];
513 ioctx->fds[fd] = NULL;
514 ioctx->num_used_fds--;
515 } else {
516 f = NULL;
519 mutex_unlock(&ioctx->io_mutex);
521 if(f)
522 put_fd(f);
525 static int new_fd(struct ioctx *ioctx, struct file_descriptor *f)
527 int fd;
528 int i;
530 mutex_lock(&ioctx->io_mutex);
532 fd = -1;
533 for(i=0; i<ioctx->table_size; i++) {
534 if(!ioctx->fds[i]) {
535 fd = i;
536 break;
539 if(fd < 0)
540 goto err;
542 ioctx->fds[fd] = f;
543 ioctx->num_used_fds++;
545 err:
546 mutex_unlock(&ioctx->io_mutex);
548 return fd;
551 static struct vnode *get_vnode_from_fd(struct ioctx *ioctx, int fd)
553 struct file_descriptor *f;
554 struct vnode *v;
556 f = get_fd(ioctx, fd);
557 if(!f) {
558 return NULL;
561 v = f->vnode;
562 if(!v)
563 goto out;
564 inc_vnode_ref_count(v, false);
566 out:
567 put_fd(f);
569 return v;
572 static struct fs_container *find_fs(const char *fs_name)
574 struct fs_container *fs = fs_list;
575 while(fs != NULL) {
576 if(strcmp(fs_name, fs->name) == 0) {
577 return fs;
579 fs = fs->next;
581 return NULL;
584 static struct ioctx *get_current_ioctx(bool kernel)
586 struct ioctx *ioctx;
588 if(kernel) {
589 ioctx = proc_get_kernel_proc()->ioctx;
590 } else {
591 ioctx = thread_get_current_thread()->proc->ioctx;
593 return ioctx;
596 static int path_to_vnode(char *path, struct vnode **v, bool kernel)
598 char *p = path;
599 char *next_p;
600 struct vnode *curr_v;
601 struct vnode *next_v;
602 vnode_id vnid;
603 int err;
605 if(!p)
606 return ERR_INVALID_ARGS;
608 // figure out if we need to start at root or at cwd
609 if(*p == '/') {
610 while(*++p == '/')
612 curr_v = root_vnode;
613 inc_vnode_ref_count(curr_v, false);
614 } else {
615 struct ioctx *ioctx = get_current_ioctx(kernel);
617 mutex_lock(&ioctx->io_mutex);
618 curr_v = ioctx->cwd;
619 inc_vnode_ref_count(curr_v, false);
620 mutex_unlock(&ioctx->io_mutex);
623 for(;;) {
624 // dprintf("path_to_vnode: top of loop. p 0x%x, *p = %c, p = '%s'\n", p, *p, p);
626 // done?
627 if(*p == '\0') {
628 err = 0;
629 break;
632 // walk to find the next component
633 for(next_p = p+1; *next_p != '\0' && *next_p != '/'; next_p++);
635 if(*next_p == '/') {
636 *next_p = '\0';
638 next_p++;
639 while(*next_p == '/');
642 // see if the .. is at the root of a mount
643 if(strcmp("..", p) == 0 && curr_v->mount->root_vnode == curr_v) {
644 // move to the covered vnode so we pass the '..' parse to the underlying filesystem
645 if(curr_v->mount->covers_vnode) {
646 next_v = curr_v->mount->covers_vnode;
647 inc_vnode_ref_count(next_v, false);
648 dec_vnode_ref_count(curr_v, false, false);
649 curr_v = next_v;
653 // tell the filesystem to parse this path
654 err = curr_v->mount->fs->calls->fs_lookup(curr_v->mount->fscookie, curr_v->priv_vnode, p, &vnid);
655 if(err < 0) {
656 dec_vnode_ref_count(curr_v, false, false);
657 goto out;
660 // lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
661 // from inside the filesystem, thus the vnode would have to be in the list and it's
662 // ref count incremented at this point
663 mutex_lock(&vfs_vnode_mutex);
664 next_v = lookup_vnode(curr_v->fsid, vnid);
665 mutex_unlock(&vfs_vnode_mutex);
667 if(!next_v) {
668 // pretty screwed up here
669 panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%x 0x%x)\n", curr_v->fsid, vnid);
670 err = ERR_VFS_PATH_NOT_FOUND;
671 dec_vnode_ref_count(curr_v, false, false);
672 goto out;
675 // decrease the ref count on the old dir we just looked up into
676 dec_vnode_ref_count(curr_v, false, false);
678 p = next_p;
679 curr_v = next_v;
681 // see if we hit a mount point
682 if(curr_v->covered_by) {
683 next_v = curr_v->covered_by;
684 inc_vnode_ref_count(next_v, false);
685 dec_vnode_ref_count(curr_v, false, false);
686 curr_v = next_v;
690 *v = curr_v;
692 out:
693 return err;
696 // returns the vnode in the next to last segment of the path, returns the last
697 // portion in filename
698 static int path_to_dir_vnode(char *path, struct vnode **v, char *filename, bool kernel)
700 char *p;
702 p = strrchr(path, '/');
703 if(!p) {
704 // this path is single segment with no '/' in it
705 // ex. "foo"
706 strcpy(filename, path);
707 strcpy(path, ".");
708 } else {
709 // replace the filename portion of the path with a '.'
710 strcpy(filename, p+1);
711 p[1] = '.';
712 p[2] = '\0';
714 return path_to_vnode(path, v, kernel);
717 #define NEW_FD_TABLE_SIZE 32
718 void *vfs_new_ioctx()
720 struct ioctx *ioctx;
721 int i;
723 ioctx = kmalloc(sizeof(struct ioctx) + sizeof(struct file_descriptor) * NEW_FD_TABLE_SIZE);
724 if(ioctx == NULL)
725 return NULL;
728 memset(ioctx, 0, sizeof(struct ioctx) + sizeof(struct file_descriptor) * NEW_FD_TABLE_SIZE);
730 if(mutex_init(&ioctx->io_mutex, "ioctx_mutex") < 0) {
731 kfree(ioctx);
732 return NULL;
735 ioctx->cwd = root_vnode;
736 ioctx->table_size = NEW_FD_TABLE_SIZE;
738 if(ioctx->cwd)
739 inc_vnode_ref_count(ioctx->cwd, false);
741 return ioctx;
744 int vfs_free_ioctx(void *_ioctx)
746 struct ioctx *ioctx = (struct ioctx *)_ioctx;
747 int i;
749 if(ioctx->cwd)
750 dec_vnode_ref_count(ioctx->cwd, true, false);
752 mutex_lock(&ioctx->io_mutex);
754 for(i=0; i<ioctx->table_size; i++) {
755 if(ioctx->fds[i]) {
756 put_fd(ioctx->fds[i]);
760 mutex_unlock(&ioctx->io_mutex);
762 mutex_destroy(&ioctx->io_mutex);
764 kfree(ioctx);
765 return 0;
768 int vfs_init(kernel_args *ka)
770 int err;
772 dprintf("vfs_init: entry\n");
775 struct vnode *v;
776 vnode_table = hash_init(VNODE_HASH_TABLE_SIZE, (addr)&v->next - (addr)v,
777 &vnode_compare, &vnode_hash);
778 if(vnode_table == NULL)
779 panic("vfs_init: error creating vnode hash table\n");
782 struct fs_mount *mount;
783 mounts_table = hash_init(MOUNTS_HASH_TABLE_SIZE, (addr)&mount->next - (addr)mount,
784 &mount_compare, &mount_hash);
785 if(mounts_table == NULL)
786 panic("vfs_init: error creating mounts hash table\n");
788 fs_list = NULL;
789 root_vnode = NULL;
791 if(mutex_init(&vfs_mutex, "vfs_lock") < 0)
792 panic("vfs_init: error allocating vfs lock\n");
794 if(mutex_init(&vfs_mount_op_mutex, "vfs_mount_op_lock") < 0)
795 panic("vfs_init: error allocating vfs_mount_op lock\n");
797 if(mutex_init(&vfs_mount_mutex, "vfs_mount_lock") < 0)
798 panic("vfs_init: error allocating vfs_mount lock\n");
800 if(mutex_init(&vfs_vnode_mutex, "vfs_vnode_lock") < 0)
801 panic("vfs_init: error allocating vfs_vnode lock\n");
803 return 0;
806 int vfs_test()
808 int fd;
809 int err;
811 dprintf("vfs_test() entry\n");
813 fd = sys_open("/", STREAM_TYPE_DIR, 0);
814 dprintf("fd = %d\n", fd);
815 sys_close(fd);
817 fd = sys_open("/", STREAM_TYPE_DIR, 0);
818 dprintf("fd = %d\n", fd);
820 sys_create("/foo", STREAM_TYPE_DIR);
821 sys_create("/foo/bar", STREAM_TYPE_DIR);
822 sys_create("/foo/bar/gar", STREAM_TYPE_DIR);
823 sys_create("/foo/bar/tar", STREAM_TYPE_DIR);
825 #if 1
826 fd = sys_open("/foo/bar", STREAM_TYPE_DIR, 0);
827 if(fd < 0)
828 panic("unable to open /foo/bar\n");
831 char buf[64];
832 ssize_t len;
834 sys_seek(fd, 0, SEEK_SET);
835 for(;;) {
836 len = sys_read(fd, buf, -1, sizeof(buf));
837 if(len < 0)
838 panic("readdir returned %d\n", len);
839 if(len > 0)
840 dprintf("readdir returned name = '%s'\n", buf);
841 else
842 break;
846 // do some unlink tests
847 err = sys_unlink("/foo/bar");
848 if(err == NO_ERROR)
849 panic("unlink of full directory should not have passed\n");
850 sys_unlink("/foo/bar/gar");
851 sys_unlink("/foo/bar/tar");
852 err = sys_unlink("/foo/bar");
853 if(err != NO_ERROR)
854 panic("unlink of empty directory should have worked\n");
856 sys_create("/test", STREAM_TYPE_DIR);
857 sys_create("/test", STREAM_TYPE_DIR);
858 err = sys_mount("/test", "rootfs");
859 if(err < 0)
860 panic("failed mount test\n");
862 #endif
863 #if 1
865 fd = sys_open("/boot", STREAM_TYPE_DIR, 0);
866 dprintf("fd = %d\n", fd);
867 sys_close(fd);
869 fd = sys_open("/boot", STREAM_TYPE_DIR, 0);
870 if(fd < 0)
871 panic("unable to open dir /boot\n");
873 char buf[64];
874 ssize_t len;
876 sys_seek(fd, 0, SEEK_SET);
877 for(;;) {
878 len = sys_read(fd, buf, -1, sizeof(buf));
879 if(len < 0)
880 panic("readdir returned %d\n", len);
881 if(len > 0)
882 dprintf("readdir returned name = '%s'\n", buf);
883 else
884 break;
887 sys_close(fd);
889 fd = sys_open("/boot/kernel", STREAM_TYPE_FILE, 0);
890 if(fd < 0)
891 panic("unable to open kernel file '/boot/kernel'\n");
893 char buf[64];
894 ssize_t len;
896 len = sys_read(fd, buf, 0, sizeof(buf));
897 if(len < 0)
898 panic("failed on read\n");
899 dprintf("read returned %d\n", len);
901 sys_close(fd);
903 struct file_stat stat;
905 err = sys_rstat("/boot/kernel", &stat);
906 if(err < 0)
907 panic("err stating '/boot/kernel'\n");
908 dprintf("stat results:\n");
909 dprintf("\tvnid 0x%x 0x%x\n\ttype %d\n\tsize 0x%x 0x%x\n", stat.vnid, stat.type, stat.size);
912 #endif
913 dprintf("vfs_test() done\n");
914 panic("foo\n");
915 return 0;
919 int vfs_register_filesystem(const char *name, struct fs_calls *calls)
921 struct fs_container *container;
923 container = (struct fs_container *)kmalloc(sizeof(struct fs_container));
924 if(container == NULL)
925 return ERR_NO_MEMORY;
927 container->name = name;
928 container->calls = calls;
930 mutex_lock(&vfs_mutex);
932 container->next = fs_list;
933 fs_list = container;
935 mutex_unlock(&vfs_mutex);
936 return 0;
939 static int vfs_mount(char *path, const char *fs_name, bool kernel)
941 struct fs_mount *mount;
942 int err = 0;
943 struct vnode *covered_vnode = NULL;
944 vnode_id root_id;
946 #if MAKE_NOIZE
947 dprintf("vfs_mount: entry. path = '%s', fs_name = '%s'\n", path, fs_name);
948 #endif
950 mutex_lock(&vfs_mount_op_mutex);
952 mount = (struct fs_mount *)kmalloc(sizeof(struct fs_mount));
953 if(mount == NULL) {
954 err = ERR_NO_MEMORY;
955 goto err;
958 mount->mount_point = (char *)kmalloc(strlen(path)+1);
959 if(mount->mount_point == NULL) {
960 err = ERR_NO_MEMORY;
961 goto err1;
963 strcpy(mount->mount_point, path);
965 mount->fs = find_fs(fs_name);
966 if(mount->fs == NULL) {
967 err = ERR_VFS_INVALID_FS;
968 goto err2;
971 recursive_lock_create(&mount->rlock);
972 mount->id = next_fsid++;
973 mount->unmounting = false;
975 if(!root_vnode) {
976 // we haven't mounted anything yet
977 if(strcmp(path, "/") != 0) {
978 err = ERR_VFS_GENERAL;
979 goto err3;
982 err = mount->fs->calls->fs_mount(&mount->fscookie, mount->id, NULL, &root_id);
983 if(err < 0) {
984 err = ERR_VFS_GENERAL;
985 goto err3;
988 mount->covers_vnode = NULL; // this is the root mount
989 } else {
990 int fd;
991 struct ioctx *ioctx;
992 void *null_cookie;
994 err = path_to_vnode(path,&covered_vnode,kernel);
995 if(err < 0) {
996 goto err2;
999 if(!covered_vnode) {
1000 err = ERR_VFS_GENERAL;
1001 goto err2;
1004 // XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be
1006 if((covered_vnode != root_vnode) && (covered_vnode->mount->root_vnode == covered_vnode)){
1007 err = ERR_VFS_ALREADY_MOUNTPOINT;
1008 goto err2;
1011 mount->covers_vnode = covered_vnode;
1013 // mount it
1014 err = mount->fs->calls->fs_mount(&mount->fscookie, mount->id, NULL, &root_id);
1015 if(err < 0)
1016 goto err4;
1019 mutex_lock(&vfs_mount_mutex);
1021 // insert mount struct into list
1022 hash_insert(mounts_table, mount);
1024 mutex_unlock(&vfs_mount_mutex);
1026 err = get_vnode(mount->id, root_id, &mount->root_vnode, 0);
1027 if(err < 0)
1028 goto err5;
1030 // XXX may be a race here
1031 if(mount->covers_vnode)
1032 mount->covers_vnode->covered_by = mount->root_vnode;
1034 if(!root_vnode)
1035 root_vnode = mount->root_vnode;
1037 mutex_unlock(&vfs_mount_op_mutex);
1039 return 0;
1041 err5:
1042 mount->fs->calls->fs_unmount(mount->fscookie);
1043 err4:
1044 if(mount->covers_vnode)
1045 dec_vnode_ref_count(mount->covers_vnode, true, false);
1046 err3:
1047 recursive_lock_destroy(&mount->rlock);
1048 err2:
1049 kfree(mount->mount_point);
1050 err1:
1051 kfree(mount);
1052 err:
1053 mutex_unlock(&vfs_mount_op_mutex);
1055 return err;
1058 static int vfs_unmount(char *path, bool kernel)
1060 struct vnode *v;
1061 struct fs_mount *mount;
1062 int err;
1064 #if MAKE_NOIZE
1065 dprintf("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel);
1066 #endif
1068 err = path_to_vnode(path, &v, kernel);
1069 if(err < 0) {
1070 err = ERR_VFS_PATH_NOT_FOUND;
1071 goto err;
1074 mutex_lock(&vfs_mount_op_mutex);
1076 mount = fsid_to_mount(v->fsid);
1077 if(!mount) {
1078 panic("vfs_unmount: fsid_to_mount failed on root vnode @0x%x of mount\n", v);
1081 if(mount->root_vnode != v) {
1082 // not mountpoint
1083 dec_vnode_ref_count(v, true, false);
1084 err = ERR_VFS_NOT_MOUNTPOINT;
1085 goto err1;
1088 /* grab the vnode master mutex to keep someone from creating a vnode
1089 while we're figuring out if we can continue */
1090 mutex_lock(&vfs_vnode_mutex);
1092 /* simulate the root vnode having it's refcount decremented */
1093 mount->root_vnode->ref_count -= 2;
1095 /* cycle through the list of vnodes associated with this mount and
1096 make sure all of them are not busy or have refs on them */
1097 err = 0;
1098 for(v = mount->vnodes_head; v; v = v->mount_next) {
1099 if(v->busy || v->ref_count != 0) {
1100 mount->root_vnode->ref_count += 2;
1101 mutex_unlock(&vfs_vnode_mutex);
1102 dec_vnode_ref_count(mount->root_vnode, true, false);
1103 err = ERR_VFS_FS_BUSY;
1104 goto err1;
1108 /* we can safely continue, mark all of the vnodes busy and this mount
1109 structure in unmounting state */
1110 for(v = mount->vnodes_head; v; v = v->mount_next)
1111 if(v != mount->root_vnode)
1112 v->busy = true;
1113 mount->unmounting = true;
1115 mutex_unlock(&vfs_vnode_mutex);
1117 mount->covers_vnode->covered_by = NULL;
1118 dec_vnode_ref_count(mount->covers_vnode, true, false);
1120 /* release the ref on the root vnode twice */
1121 dec_vnode_ref_count(mount->root_vnode, true, false);
1122 dec_vnode_ref_count(mount->root_vnode, true, false);
1124 // XXX when full vnode cache in place, will need to force
1125 // a putvnode/removevnode here
1127 /* remove the mount structure from the hash table */
1128 mutex_lock(&vfs_mount_mutex);
1129 hash_remove(mounts_table, mount);
1130 mutex_unlock(&vfs_mount_mutex);
1132 mutex_unlock(&vfs_mount_op_mutex);
1134 mount->fs->calls->fs_unmount(mount->fscookie);
1136 kfree(mount->mount_point);
1137 kfree(mount);
1139 return 0;
1141 err1:
1142 mutex_unlock(&vfs_mount_op_mutex);
1143 err:
1144 return err;
1147 static int vfs_sync()
1149 struct hash_iterator iter;
1150 struct fs_mount *mount;
1152 #if MAKE_NOIZE
1153 dprintf("vfs_sync: entry.\n");
1154 #endif
1156 /* cycle through and call sync on each mounted fs */
1157 mutex_lock(&vfs_mount_op_mutex);
1158 mutex_lock(&vfs_mount_mutex);
1160 hash_open(mounts_table, &iter);
1161 while((mount = hash_next(mounts_table, &iter))) {
1162 mount->fs->calls->fs_sync(mount->fscookie);
1164 hash_close(mounts_table, &iter, false);
1166 mutex_unlock(&vfs_mount_mutex);
1167 mutex_unlock(&vfs_mount_op_mutex);
1169 return 0;
1172 static int vfs_open(char *path, stream_type st, int omode, bool kernel)
1174 int fd;
1175 struct vnode *v;
1176 file_cookie cookie;
1177 struct file_descriptor *f;
1178 int err;
1180 #if MAKE_NOIZE
1181 dprintf("vfs_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel);
1182 #endif
1184 err = path_to_vnode(path, &v, kernel);
1185 if(err < 0)
1186 goto err;
1188 err = v->mount->fs->calls->fs_open(v->mount->fscookie, v->priv_vnode, &cookie, st, omode);
1189 if(err < 0)
1190 goto err1;
1192 // file is opened, create a fd
1193 f = alloc_fd();
1194 if(!f) {
1195 // xxx leaks
1196 err = ERR_NO_MEMORY;
1197 goto err1;
1199 f->vnode = v;
1200 f->cookie = cookie;
1202 fd = new_fd(get_current_ioctx(kernel), f);
1203 if(fd < 0) {
1204 err = ERR_VFS_FD_TABLE_FULL;
1205 goto err1;
1208 return fd;
1210 err2:
1211 free_fd(f);
1212 err1:
1213 dec_vnode_ref_count(v, true, false);
1214 err:
1215 return err;
1218 static int vfs_close(int fd, bool kernel)
1220 struct file_descriptor *f;
1221 struct ioctx *ioctx;
1223 #if MAKE_NOIZE
1224 dprintf("vfs_close: entry. fd %d, kernel %d\n", fd, kernel);
1225 #endif
1227 ioctx = get_current_ioctx(kernel);
1229 f = get_fd(ioctx, fd);
1230 if(!f)
1231 return ERR_INVALID_HANDLE;
1233 remove_fd(ioctx, fd);
1234 put_fd(f);
1236 return 0;
1239 static int vfs_fsync(int fd, bool kernel)
1241 struct file_descriptor *f;
1242 struct vnode *v;
1243 int err;
1245 #if MAKE_NOIZE
1246 dprintf("vfs_fsync: entry. fd %d kernel %d\n", fd, kernel);
1247 #endif
1249 f = get_fd(get_current_ioctx(kernel), fd);
1250 if(!f)
1251 return ERR_INVALID_HANDLE;
1253 v = f->vnode;
1254 err = v->mount->fs->calls->fs_fsync(v->mount->fscookie, v->priv_vnode);
1256 put_fd(f);
1258 return err;
1261 static ssize_t vfs_read(int fd, void *buf, off_t pos, ssize_t len, bool kernel)
1263 struct vnode *v;
1264 struct file_descriptor *f;
1265 int err;
1267 #if MAKE_NOIZE
1268 dprintf("vfs_read: fd = %d, buf 0x%x, pos 0x%x 0x%x, len 0x%x, kernel %d\n", fd, buf, pos, len, kernel);
1269 #endif
1271 f = get_fd(get_current_ioctx(kernel), fd);
1272 if(!f) {
1273 err = ERR_INVALID_HANDLE;
1274 goto err;
1277 v = f->vnode;
1278 err = v->mount->fs->calls->fs_read(v->mount->fscookie, v->priv_vnode, f->cookie, buf, pos, len);
1280 put_fd(f);
1282 err:
1283 return err;
1286 static ssize_t vfs_write(int fd, const void *buf, off_t pos, ssize_t len, bool kernel)
1288 struct vnode *v;
1289 struct file_descriptor *f;
1290 int err;
1292 #if MAKE_NOIZE
1293 dprintf("vfs_write: fd = %d, buf 0x%x, pos 0x%x 0x%x, len 0x%x, kernel %d\n", fd, buf, pos, len, kernel);
1294 #endif
1296 f = get_fd(get_current_ioctx(kernel), fd);
1297 if(!f) {
1298 err = ERR_INVALID_HANDLE;
1299 goto err;
1302 v = f->vnode;
1303 err = v->mount->fs->calls->fs_write(v->mount->fscookie, v->priv_vnode, f->cookie, buf, pos, len);
1305 put_fd(f);
1307 err:
1308 return err;
1311 static int vfs_seek(int fd, off_t pos, seek_type seek_type, bool kernel)
1313 struct vnode *v;
1314 struct file_descriptor *f;
1315 int err;
1317 #if MAKE_NOIZE
1318 dprintf("vfs_seek: fd = %d, pos 0x%x 0x%x, seek_type %d, kernel %d\n", fd, pos, seek_type, kernel);
1319 #endif
1321 f = get_fd(get_current_ioctx(kernel), fd);
1322 if(!f) {
1323 err = ERR_INVALID_HANDLE;
1324 goto err;
1327 v = f->vnode;
1328 err = v->mount->fs->calls->fs_seek(v->mount->fscookie, v->priv_vnode, f->cookie, pos, seek_type);
1330 put_fd(f);
1332 err:
1333 return err;
1337 static int vfs_ioctl(int fd, int op, void *buf, size_t len, bool kernel)
1339 struct vnode *v;
1340 struct file_descriptor *f;
1341 int err;
1343 #if MAKE_NOIZE
1344 dprintf("vfs_ioctl: fd = %d, op 0x%x, buf 0x%x, len 0x%x, kernel %d\n", fd, op, buf, len, kernel);
1345 #endif
1347 f = get_fd(get_current_ioctx(kernel), fd);
1348 if(!f) {
1349 err = ERR_INVALID_HANDLE;
1350 goto err;
1353 v = f->vnode;
1354 err = v->mount->fs->calls->fs_ioctl(v->mount->fscookie, v->priv_vnode, f->cookie, op, buf, len);
1356 put_fd(f);
1358 err:
1359 return err;
1362 static int vfs_create(char *path, stream_type stream_type, void *args, bool kernel)
1364 int err;
1365 struct vnode *v;
1366 char filename[SYS_MAX_NAME_LEN];
1367 vnode_id vnid;
1369 #if MAKE_NOIZE
1370 dprintf("vfs_create: path '%s', stream_type %d, args 0x%x, kernel %d\n", path, stream_type, args, kernel);
1371 #endif
1373 err = path_to_dir_vnode(path, &v, filename, kernel);
1374 if(err < 0)
1375 goto err;
1377 err = v->mount->fs->calls->fs_create(v->mount->fscookie, v->priv_vnode, filename, stream_type, args, &vnid);
1379 err1:
1380 dec_vnode_ref_count(v, true, false);
1381 err:
1382 return err;
1385 static int vfs_unlink(char *path, bool kernel)
1387 int err;
1388 struct vnode *v;
1389 char filename[SYS_MAX_NAME_LEN];
1391 #if MAKE_NOIZE
1392 dprintf("vfs_unlink: path '%s', kernel %d\n", path, kernel);
1393 #endif
1395 err = path_to_dir_vnode(path, &v, filename, kernel);
1396 if(err < 0)
1397 goto err;
1399 err = v->mount->fs->calls->fs_unlink(v->mount->fscookie, v->priv_vnode, filename);
1401 err1:
1402 dec_vnode_ref_count(v, true, false);
1403 err:
1404 return err;
1407 static int vfs_rename(char *path, char *newpath, bool kernel)
1409 struct vnode *v1, *v2;
1410 char filename1[SYS_MAX_NAME_LEN];
1411 char filename2[SYS_MAX_NAME_LEN];
1412 int err;
1414 err = path_to_dir_vnode(path, &v1, filename1, kernel);
1415 if(err < 0)
1416 goto err;
1418 err = path_to_dir_vnode(path, &v2, filename2, kernel);
1419 if(err < 0)
1420 goto err1;
1422 if(v1->fsid != v2->fsid) {
1423 err = ERR_VFS_CROSS_FS_RENAME;
1424 goto err2;
1427 err = v1->mount->fs->calls->fs_rename(v1->mount->fscookie, v1->priv_vnode, filename1, v2->priv_vnode, filename2);
1429 err2:
1430 dec_vnode_ref_count(v2, true, false);
1431 err1:
1432 dec_vnode_ref_count(v1, true, false);
1433 err:
1434 return err;
1437 static int vfs_rstat(char *path, struct file_stat *stat, bool kernel)
1439 int err;
1440 struct vnode *v;
1442 #if MAKE_NOIZE
1443 dprintf("vfs_rstat: path '%s', stat 0x%x, kernel %d\n", path, stat, kernel);
1444 #endif
1446 err = path_to_vnode(path, &v, kernel);
1447 if(err < 0)
1448 goto err;
1450 err = v->mount->fs->calls->fs_rstat(v->mount->fscookie, v->priv_vnode, stat);
1452 err1:
1453 dec_vnode_ref_count(v, true, false);
1454 err:
1455 return err;
1458 static int vfs_wstat(char *path, struct file_stat *stat, int stat_mask, bool kernel)
1460 int err;
1461 struct vnode *v;
1463 #if MAKE_NOIZE
1464 dprintf("vfs_wstat: path '%s', stat 0x%x, stat_mask %d, kernel %d\n", path, stat, stat_mask, kernel);
1465 #endif
1467 err = path_to_vnode(path, &v, kernel);
1468 if(err < 0)
1469 goto err;
1471 err = v->mount->fs->calls->fs_wstat(v->mount->fscookie, v->priv_vnode, stat, stat_mask);
1473 err1:
1474 dec_vnode_ref_count(v, true, false);
1475 err:
1476 return err;
1479 int vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode)
1481 struct ioctx *ioctx;
1482 int err;
1484 ioctx = get_current_ioctx(kernel);
1485 *vnode = get_vnode_from_fd(ioctx, fd);
1487 if(*vnode == NULL)
1488 return ERR_INVALID_HANDLE;
1490 return NO_ERROR;
1493 int vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode)
1495 struct vnode *v;
1496 int err;
1497 char buf[SYS_MAX_PATH_LEN+1];
1499 #if MAKE_NOIZE
1500 dprintf("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel);
1501 #endif
1503 strncpy(buf, path, SYS_MAX_PATH_LEN);
1504 buf[SYS_MAX_PATH_LEN] = 0;
1506 err = path_to_vnode(buf, &v, kernel);
1507 if(err < 0)
1508 goto err;
1510 *vnode = v;
1512 err:
1513 return err;
1516 int vfs_put_vnode_ptr(void *vnode)
1518 struct vnode *v = vnode;
1520 put_vnode(v);
1522 return 0;
1525 ssize_t vfs_canpage(void *_v)
1527 struct vnode *v = _v;
1529 #if MAKE_NOIZE
1530 dprintf("vfs_canpage: vnode 0x%x\n", v);
1531 #endif
1533 return v->mount->fs->calls->fs_canpage(v->mount->fscookie, v->priv_vnode);
1536 ssize_t vfs_readpage(void *_v, iovecs *vecs, off_t pos)
1538 struct vnode *v = _v;
1540 #if MAKE_NOIZE
1541 dprintf("vfs_readpage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos);
1542 #endif
1544 return v->mount->fs->calls->fs_readpage(v->mount->fscookie, v->priv_vnode, vecs, pos);
1547 ssize_t vfs_writepage(void *_v, iovecs *vecs, off_t pos)
1549 struct vnode *v = _v;
1551 #if MAKE_NOIZE
1552 dprintf("vfs_writepage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos);
1553 #endif
1555 return v->mount->fs->calls->fs_writepage(v->mount->fscookie, v->priv_vnode, vecs, pos);
1558 int vfs_get_cwd(char* buf, size_t size, bool kernel)
1560 // Get current working directory from io context
1561 struct vnode* v = get_current_ioctx(kernel)->cwd;
1562 int rc;
1564 #if MAKE_NOIZE
1565 dprintf("vfs_get_cwd: buf 0x%x, 0x%x\n", buf, size);
1566 #endif
1567 //TODO: parse cwd back into a full path
1568 if (size >= 2) {
1569 buf[0] = '.';
1570 buf[1] = 0;
1572 rc = 0;
1573 } else {
1574 rc = ERR_VFS_INSUFFICIENT_BUF;
1577 // Tell caller all is ok
1578 return rc;
1581 int vfs_set_cwd(char* path, bool kernel)
1583 struct ioctx* curr_ioctx;
1584 struct vnode* v = NULL;
1585 struct vnode* old_cwd;
1586 struct file_stat stat;
1587 int rc;
1589 #if MAKE_NOIZE
1590 dprintf("vfs_set_cwd: path=\'%s\'\n", path);
1591 #endif
1593 // Get vnode for passed path, and bail if it failed
1594 rc = path_to_vnode(path, &v, kernel);
1595 if (rc < 0) {
1596 goto err;
1599 rc = v->mount->fs->calls->fs_rstat(v->mount->fscookie, v->priv_vnode, &stat);
1600 if(rc < 0) {
1601 goto err1;
1604 if(stat.type != STREAM_TYPE_DIR) {
1605 // nope, can't cwd to here
1606 rc = ERR_VFS_WRONG_STREAM_TYPE;
1607 goto err1;
1610 // Get current io context and lock
1611 curr_ioctx = get_current_ioctx(kernel);
1612 mutex_lock(&curr_ioctx->io_mutex);
1614 // save the old cwd
1615 old_cwd = curr_ioctx->cwd;
1617 // Set the new vnode
1618 curr_ioctx->cwd = v;
1620 // Unlock the ioctx
1621 mutex_unlock(&curr_ioctx->io_mutex);
1623 // Decrease ref count of previous working dir (as the ref is being replaced)
1624 if (old_cwd)
1625 dec_vnode_ref_count(old_cwd, true, false);
1627 return NO_ERROR;
1629 err1:
1630 dec_vnode_ref_count(v, true, false);
1631 err:
1632 return rc;
1635 int sys_mount(const char *path, const char *fs_name)
1637 char buf[SYS_MAX_PATH_LEN+1];
1639 strncpy(buf, path, SYS_MAX_PATH_LEN);
1640 buf[SYS_MAX_PATH_LEN] = 0;
1642 return vfs_mount(buf, fs_name, true);
1645 int sys_unmount(const char *path)
1647 char buf[SYS_MAX_PATH_LEN+1];
1649 strncpy(buf, path, SYS_MAX_PATH_LEN);
1650 buf[SYS_MAX_PATH_LEN] = 0;
1652 return vfs_unmount(buf, true);
1655 int sys_sync()
1657 return vfs_sync();
1660 int sys_open(const char *path, stream_type st, int omode)
1662 char buf[SYS_MAX_PATH_LEN+1];
1664 strncpy(buf, path, SYS_MAX_PATH_LEN);
1665 buf[SYS_MAX_PATH_LEN] = 0;
1667 return vfs_open(buf, st, omode, true);
1670 int sys_close(int fd)
1672 return vfs_close(fd, true);
1675 int sys_fsync(int fd)
1677 return vfs_fsync(fd, true);
1680 ssize_t sys_read(int fd, void *buf, off_t pos, ssize_t len)
1682 return vfs_read(fd, buf, pos, len, true);
1685 ssize_t sys_write(int fd, const void *buf, off_t pos, ssize_t len)
1687 return vfs_write(fd, buf, pos, len, true);
1690 int sys_seek(int fd, off_t pos, seek_type seek_type)
1692 return vfs_seek(fd, pos, seek_type, true);
1695 int sys_ioctl(int fd, int op, void *buf, size_t len)
1697 return vfs_ioctl(fd, op, buf, len, true);
1700 int sys_create(const char *path, stream_type stream_type)
1702 char buf[SYS_MAX_PATH_LEN+1];
1704 strncpy(buf, path, SYS_MAX_PATH_LEN);
1705 buf[SYS_MAX_PATH_LEN] = 0;
1707 return vfs_create(buf, stream_type, NULL, true);
1710 int sys_unlink(const char *path)
1712 char buf[SYS_MAX_PATH_LEN+1];
1714 strncpy(buf, path, SYS_MAX_PATH_LEN);
1715 buf[SYS_MAX_PATH_LEN] = 0;
1717 return vfs_unlink(buf, true);
1720 int sys_rename(const char *oldpath, const char *newpath)
1722 char buf1[SYS_MAX_PATH_LEN+1];
1723 char buf2[SYS_MAX_PATH_LEN+1];
1725 strncpy(buf1, oldpath, SYS_MAX_PATH_LEN);
1726 buf1[SYS_MAX_PATH_LEN] = 0;
1728 strncpy(buf2, newpath, SYS_MAX_PATH_LEN);
1729 buf2[SYS_MAX_PATH_LEN] = 0;
1731 return vfs_rename(buf1, buf2, true);
1734 int sys_rstat(const char *path, struct file_stat *stat)
1736 char buf[SYS_MAX_PATH_LEN+1];
1738 strncpy(buf, path, SYS_MAX_PATH_LEN);
1739 buf[SYS_MAX_PATH_LEN] = 0;
1741 return vfs_rstat(buf, stat, true);
1744 int sys_wstat(const char *path, struct file_stat *stat, int stat_mask)
1746 char buf[SYS_MAX_PATH_LEN+1];
1748 strncpy(buf, path, SYS_MAX_PATH_LEN);
1749 buf[SYS_MAX_PATH_LEN] = 0;
1751 return vfs_wstat(buf, stat, stat_mask, true);
1754 char* sys_getcwd(char *buf, size_t size)
1756 char path[SYS_MAX_PATH_LEN];
1757 int rc;
1759 #if MAKE_NOIZE
1760 dprintf("sys_getcwd: buf 0x%x, 0x%x\n", buf, size);
1761 #endif
1763 // Call vfs to get current working directory
1764 rc = vfs_get_cwd(path,SYS_MAX_PATH_LEN-1,true);
1765 path[SYS_MAX_PATH_LEN-1] = 0;
1767 // Copy back the result
1768 strncpy(buf,path,size);
1770 // Return either NULL or the buffer address to indicate failure or success
1771 return (rc < 0) ? NULL : buf;
1774 int sys_setcwd(const char* _path)
1776 char path[SYS_MAX_PATH_LEN];
1778 #if MAKE_NOIZE
1779 dprintf("sys_setcwd: path=0x%x\n", _path);
1780 #endif
1782 // Copy new path to kernel space
1783 strncpy(path, _path, SYS_MAX_PATH_LEN-1);
1784 path[SYS_MAX_PATH_LEN-1] = 0;
1786 // Call vfs to set new working directory
1787 return vfs_set_cwd(path,true);
1790 int user_mount(const char *upath, const char *ufs_name)
1792 char path[SYS_MAX_PATH_LEN+1];
1793 char fs_name[SYS_MAX_OS_NAME_LEN+1];
1794 int rc;
1796 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1797 return ERR_VM_BAD_USER_MEMORY;
1799 if((addr)ufs_name >= KERNEL_BASE && (addr)ufs_name <= KERNEL_TOP)
1800 return ERR_VM_BAD_USER_MEMORY;
1802 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
1803 if(rc < 0)
1804 return rc;
1805 path[SYS_MAX_PATH_LEN] = 0;
1807 rc = user_strncpy(fs_name, ufs_name, SYS_MAX_PATH_LEN);
1808 if(rc < 0)
1809 return rc;
1810 fs_name[SYS_MAX_PATH_LEN] = 0;
1812 return vfs_mount(path, fs_name, false);
1815 int user_unmount(const char *upath)
1817 char path[SYS_MAX_PATH_LEN+1];
1818 int rc;
1820 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
1821 if(rc < 0)
1822 return rc;
1823 path[SYS_MAX_PATH_LEN] = 0;
1825 return vfs_unmount(path, false);
1828 int user_sync()
1830 return vfs_sync();
1833 int user_open(const char *upath, stream_type st, int omode)
1835 char path[SYS_MAX_PATH_LEN];
1836 int rc;
1838 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1839 return ERR_VM_BAD_USER_MEMORY;
1841 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
1842 if(rc < 0)
1843 return rc;
1844 path[SYS_MAX_PATH_LEN-1] = 0;
1846 return vfs_open(path, st, omode, false);
1849 int user_close(int fd)
1851 return vfs_close(fd, false);
1854 int user_fsync(int fd)
1856 return vfs_fsync(fd, false);
1859 ssize_t user_read(int fd, void *buf, off_t pos, ssize_t len)
1861 if((addr)buf >= KERNEL_BASE && (addr)buf <= KERNEL_TOP)
1862 return ERR_VM_BAD_USER_MEMORY;
1864 return vfs_read(fd, buf, pos, len, false);
1867 ssize_t user_write(int fd, const void *buf, off_t pos, ssize_t len)
1869 if((addr)buf >= KERNEL_BASE && (addr)buf <= KERNEL_TOP)
1870 return ERR_VM_BAD_USER_MEMORY;
1872 return vfs_write(fd, buf, pos, len, false);
1875 int user_seek(int fd, off_t pos, seek_type seek_type)
1877 return vfs_seek(fd, pos, seek_type, false);
1880 int user_ioctl(int fd, int op, void *buf, size_t len)
1882 if((addr)buf >= KERNEL_BASE && (addr)buf <= KERNEL_TOP)
1883 return ERR_VM_BAD_USER_MEMORY;
1884 return vfs_ioctl(fd, op, buf, len, false);
1887 int user_create(const char *upath, stream_type stream_type)
1889 char path[SYS_MAX_PATH_LEN];
1890 int rc;
1892 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1893 return ERR_VM_BAD_USER_MEMORY;
1895 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
1896 if(rc < 0)
1897 return rc;
1898 path[SYS_MAX_PATH_LEN-1] = 0;
1900 return vfs_create(path, stream_type, NULL, false);
1903 int user_unlink(const char *upath)
1905 char path[SYS_MAX_PATH_LEN+1];
1906 int rc;
1908 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1909 return ERR_VM_BAD_USER_MEMORY;
1911 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
1912 if(rc < 0)
1913 return rc;
1914 path[SYS_MAX_PATH_LEN] = 0;
1916 return vfs_unlink(path, false);
1919 int user_rename(const char *uoldpath, const char *unewpath)
1921 char oldpath[SYS_MAX_PATH_LEN+1];
1922 char newpath[SYS_MAX_PATH_LEN+1];
1923 int rc;
1925 if((addr)uoldpath >= KERNEL_BASE && (addr)uoldpath <= KERNEL_TOP)
1926 return ERR_VM_BAD_USER_MEMORY;
1928 if((addr)unewpath >= KERNEL_BASE && (addr)unewpath <= KERNEL_TOP)
1929 return ERR_VM_BAD_USER_MEMORY;
1931 rc = user_strncpy(oldpath, uoldpath, SYS_MAX_PATH_LEN);
1932 if(rc < 0)
1933 return rc;
1934 oldpath[SYS_MAX_PATH_LEN] = 0;
1936 rc = user_strncpy(newpath, unewpath, SYS_MAX_PATH_LEN);
1937 if(rc < 0)
1938 return rc;
1939 newpath[SYS_MAX_PATH_LEN] = 0;
1941 return vfs_rename(oldpath, newpath, false);
1944 int user_rstat(const char *upath, struct file_stat *ustat)
1946 char path[SYS_MAX_PATH_LEN];
1947 struct file_stat stat;
1948 int rc, rc2;
1950 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1951 return ERR_VM_BAD_USER_MEMORY;
1953 if((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP)
1954 return ERR_VM_BAD_USER_MEMORY;
1956 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
1957 if(rc < 0)
1958 return rc;
1959 path[SYS_MAX_PATH_LEN-1] = 0;
1961 rc = vfs_rstat(path, &stat, false);
1962 if(rc < 0)
1963 return rc;
1965 rc2 = user_memcpy(ustat, &stat, sizeof(struct file_stat));
1966 if(rc2 < 0)
1967 return rc2;
1969 return rc;
1972 int user_wstat(const char *upath, struct file_stat *ustat, int stat_mask)
1974 char path[SYS_MAX_PATH_LEN+1];
1975 struct file_stat stat;
1976 int rc;
1978 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
1979 return ERR_VM_BAD_USER_MEMORY;
1981 if((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP)
1982 return ERR_VM_BAD_USER_MEMORY;
1984 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN);
1985 if(rc < 0)
1986 return rc;
1987 path[SYS_MAX_PATH_LEN] = 0;
1989 rc = user_memcpy(&stat, ustat, sizeof(struct file_stat));
1990 if(rc < 0)
1991 return rc;
1993 return vfs_wstat(path, &stat, stat_mask, false);
1996 int user_getcwd(char *buf, size_t size)
1998 char path[SYS_MAX_PATH_LEN];
1999 int rc, rc2;
2001 #if MAKE_NOIZE
2002 dprintf("user_getcwd: buf 0x%x, 0x%x\n", buf, size);
2003 #endif
2005 // Check if userspace address is inside "shared" kernel space
2006 if((addr)buf >= KERNEL_BASE && (addr)buf <= KERNEL_TOP)
2007 return NULL; //ERR_VM_BAD_USER_MEMORY;
2009 // Call vfs to get current working directory
2010 rc = vfs_get_cwd(path, SYS_MAX_PATH_LEN-1, false);
2011 if(rc < 0)
2012 return rc;
2014 // Copy back the result
2015 rc2 = user_strncpy(buf, path, size);
2016 if(rc2 < 0)
2017 return rc2;
2019 return rc;
2022 int user_setcwd(const char* upath)
2024 char path[SYS_MAX_PATH_LEN];
2025 int rc;
2027 #if MAKE_NOIZE
2028 dprintf("user_setcwd: path=0x%x\n", upath);
2029 #endif
2031 // Check if userspace address is inside "shared" kernel space
2032 if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP)
2033 return ERR_VM_BAD_USER_MEMORY;
2035 // Copy new path to kernel space
2036 rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1);
2037 if (rc < 0) {
2038 return rc;
2040 path[SYS_MAX_PATH_LEN-1] = 0;
2042 // Call vfs to set new working directory
2043 return vfs_set_cwd(path,false);
2046 image_id vfs_load_fs_module(const char *name)
2048 image_id id;
2049 void (*bootstrap)();
2050 char path[SYS_MAX_PATH_LEN];
2052 sprintf(path, "/boot/addons/fs/%s", name);
2054 id = elf_load_kspace(path, "");
2055 if(id < 0)
2056 return id;
2058 bootstrap = (void *)elf_lookup_symbol(id, "fs_bootstrap");
2059 if(!bootstrap)
2060 return ERR_VFS_INVALID_FS;
2062 bootstrap();
2064 return id;
2067 int vfs_bootstrap_all_filesystems()
2069 int err;
2070 int fd;
2072 // bootstrap the root filesystem
2073 bootstrap_rootfs();
2075 err = sys_mount("/", "rootfs");
2076 if(err < 0)
2077 panic("error mounting rootfs!\n");
2079 sys_setcwd("/");
2081 // bootstrap the bootfs
2082 bootstrap_bootfs();
2084 sys_create("/boot", STREAM_TYPE_DIR);
2085 err = sys_mount("/boot", "bootfs");
2086 if(err < 0)
2087 panic("error mounting bootfs\n");
2089 // bootstrap the devfs
2090 bootstrap_devfs();
2092 sys_create("/dev", STREAM_TYPE_DIR);
2093 err = sys_mount("/dev", "devfs");
2094 if(err < 0)
2095 panic("error mounting devfs\n");
2098 fd = sys_open("/boot/addons/fs", STREAM_TYPE_DIR, 0);
2099 if(fd >= 0) {
2100 ssize_t len;
2101 char buf[SYS_MAX_NAME_LEN];
2103 while((len = sys_read(fd, buf, 0, sizeof(buf))) > 0) {
2104 dprintf("loading '%s' fs module\n", buf);
2105 vfs_load_fs_module(buf);
2107 sys_close(fd);
2110 return NO_ERROR;