1/*
2  This file contains the vnode layer used by the file system construction
3  kit.  It is the file system independent layer and managed hooking up
4  requests from the test program (fsh and tstfs) to the actual file system
5  routines.  It provides a rather posix-like interface generally with
6  the routines preceded by a "sys_" prefix.
7
8  THIS CODE COPYRIGHT DOMINIC GIAMPAOLO.  NO WARRANTY IS EXPRESSED
9  OR IMPLIED.  YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
10  NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
11
12  FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
13
14  Dominic Giampaolo
15  dbg@be.com
16*/
17#include "compat.h"
18
19#include "skiplist.h"
20#include "lock.h"
21#include "fsproto.h"
22#include "kprotos.h"
23
24#if USED_IN_FS_SHELL
25#	include "tracker.h"
26#endif
27
28#define TRACE_KERNEL 0
29#if TRACE_KERNEL
30#	define FUNCTION() puts(__FUNCTION__)
31#	define TRACE(x...) printf(x)
32#else
33#	define FUNCTION()
34#	define TRACE(x...)
35#endif
36
37#include <sys/stat.h>
38
39#define     OMODE_MASK      (MY_O_RDONLY | MY_O_WRONLY | MY_O_RDWR)
40#define     SLEEP_TIME      (10000.0)
41#define     MAX_SYM_LINKS   16
42
43#define     FREE_LIST       0
44#define     USED_LIST       1
45#define     LOCKED_LIST     2
46#define     LIST_NUM        3
47
48#define     FD_FILE         1
49#define     FD_DIR          2
50#define     FD_WD           4
51#define     FD_ATTR_DIR     8
52
53#define     FD_ALL          (FD_FILE | FD_DIR | FD_WD | FD_ATTR_DIR)
54
55#define     DEFAULT_FD_NUM  (128)
56#define     VNNUM           256
57
58typedef unsigned long       fsystem_id;
59
60typedef struct vnode vnode;
61typedef struct vnlist vnlist;
62typedef struct vnlink vnlink;
63typedef struct fsystem fsystem;
64typedef struct nspace nspace;
65typedef struct ofile ofile;
66typedef struct ioctx ioctx;
67typedef struct fdarray fdarray;
68
69struct vnlist {
70    vnode           *head;
71    vnode           *tail;
72    int             num;
73};
74
75struct vnlink {
76    vnode           *prev;
77    vnode           *next;
78};
79
80struct vnode {
81    vnode_id        vnid;
82    nspace *        ns;
83    nspace *        mounted;
84    char            remove;
85    char            busy;
86    char            inlist;
87    char            watched;
88    vnlink          nspace;
89    vnlink          list;
90    int             rcnt;
91    void *          data;
92};
93
94struct fsystem {
95    fsystem_id          fsid;
96    int                fixed;
97    image_id            aid;
98    char                name[IDENT_NAME_LENGTH];
99    int                 rcnt;
100    vnode_ops           ops;
101};
102
103struct nspace {
104    nspace_id           nsid;
105    my_dev_t            dev;
106    my_ino_t            ino;
107    fsystem             *fs;
108    vnlist              vnodes;
109    void                *data;
110    vnode *             root;
111    vnode *             mount;
112    nspace *            prev;
113    nspace *            next;
114    char                shutdown;
115};
116
117struct ofile {
118    short           type;
119    ushort          flags;
120    vnode *         vn;
121    void *          cookie;
122    long            rcnt;
123    long            ocnt;
124
125    fs_off_t            pos;
126    int             omode;
127};
128
129
130struct ioctx {
131    lock            lock;
132    int             kerrno;
133    vnode *         cwd;
134    fdarray *       fds;
135};
136
137struct fdarray {
138    long            rcnt;
139    lock            lock;
140    int             num;
141    ulong           *alloc;
142    ulong           *coes;
143    ofile           *fds[1];
144};
145
146extern struct {
147    const char *    name;
148    vnode_ops *     ops;
149} fixed_fs[];
150
151static vnode_id     invalid_vnid = 0;
152static vnode *      rootvn;
153static int          max_glb_file;
154static fdarray *    global_fds;
155static vnlist       lists[LIST_NUM];
156static nspace *     nshead;
157static lock         vnlock;
158static lock         fstablock;
159static nspace **    nstab;
160static fsystem **   fstab;
161static int          nns;
162static int          nfs;
163static fsystem_id   nxfsid;
164static nspace_id    nxnsid;
165static SkipList     skiplist;
166static int          vnnum;
167static int          usdvnnum;
168
169
170
171static fsystem *    inc_file_system(const char *name);
172static int          dec_file_system(fsystem *fs);
173static ioctx *		get_cur_ioctx(void);
174
175static int      get_dir_fd(int kernel, int fd, const char *path, char *filename,
176                    vnode **dvn);
177static int      get_file_fd(int kernel, int fd, const char *path,
178                    int eatsymlink, vnode **vn);
179static int      get_file_vn(nspace_id nsid, vnode_id vnid, const char *path,
180                    int eatsymlink, vnode **vn);
181static int      parse_path_fd(int kerne, int fd, char **pstart,
182                    int eatsymlink, vnode **vn);
183static int      parse_path_vn(nspace_id nsid, vnode_id vnid, char **start,
184                    int eatsymlink, vnode **vn);
185static int      parse_path(vnode *bvn, char **pstart, char *path,
186                    int eatsymlink, vnode **vn);
187
188static char *   cat_paths(char *a, char *b);
189
190static int      load_vnode(nspace_id nsid, vnode_id vnid, char r, vnode **vnp);
191static vnode *  lookup_vnode(nspace_id nsid, vnode_id vnid);
192static void     move_vnode(vnode *vn, int list);
193static vnode *  steal_vnode(int list);
194static void     flush_vnode(vnode *vn, char r);
195static int      sort_vnode(vnode *vn);
196static void     clear_vnode(vnode *vn);
197static void     inc_vnode(vnode *vn);
198static void     dec_vnode(vnode *vn, char r);
199static int      compare_vnode(vnode *vna, vnode *vnb);
200
201static nspace * nsidtons(nspace_id nsid);
202//static int      alloc_wd_fd(int kernel, vnode *vn, int coe, int *fdp);
203
204static int      is_root(vnode *root, vnode **mount);
205static int      is_mount_vnode(vnode *mount, vnode **root);
206static int      is_mount_vnid(nspace_id nsid, vnode_id vnid, vnode_id *mount);
207
208static ofile *      get_fd(int kernel, int fd, int type);
209static int          put_fd(ofile *f);
210static int          new_fd(int kernel, int nfd, ofile *f, int fd, int coe);
211static int          remove_fd(int kernel, int fd, int type);
212//static int          get_coe(int kernel, int fd, int type, int *coe);
213//static int          set_coe(int kernel, int fd, int type, int coe);
214//static int          get_omode(int kernel, int fd, int type, int *omode);
215static int          invoke_close(ofile *f);
216static int          invoke_free(ofile *f);
217
218static fdarray *    new_fds(int num);
219//static int          free_fds(fdarray *fds);
220
221
222#define BITSZ(n)        (((n) + 31) & ~31)
223#define SETBIT(a,i,v)   *((a)+(i)/32) = (*((a)+(i)/32) & ~(1<<((i)%32))) | (v<<((i)%32))
224#define GETBIT(a,i)     ((*((a)+(i)/32) & (1<<((i)%32))) >> ((i)%32))
225
226/* ---------------------------------------------------------------- */
227
228#include <stdio.h>
229
230static void
231PANIC(char *s, ...)
232{
233	va_list list;
234
235	va_start(list, s);
236	vfprintf(stdout, s, list);
237	va_end(list);
238
239    debugger("fs shell kernel panic!");
240}
241
242
243#ifndef USER
244#ifdef DEBUG
245int
246dump_fsystem(int argc, char **argv)
247{
248    struct fsystem *fs;
249
250    if (argv[1] == NULL) {
251        kprintf("%s needs an address argument\n", argv[0]);
252        return 1;
253    }
254
255    fs = (struct fsystem *)strtoul(argv[1], NULL, 0);
256
257    kprintf("fs @ 0x%x name %s rcnt %d ops @ 0x%x\n", fs, fs->name,
258            fs->rcnt, &fs->ops);
259}
260
261int
262dump_ioctx(int argc, char **argv)
263{
264    struct ioctx *ioctx;
265
266    if (argv[1] == NULL) {
267        kprintf("%s needs an address argument\n", argv[0]);
268        return 1;
269    }
270
271    ioctx = (struct ioctx *)strtoul(argv[1], NULL, 0);
272
273    kprintf("ioctx @ 0x%x, kerrno %d, cwd 0x%x, fdarray 0x%x\n", ioctx,
274            ioctx->kerrno, ioctx->cwd, ioctx->fds);
275}
276
277
278int
279dump_vnode(int argc, char **argv)
280{
281    struct vnode *vn;
282
283    if (argv[1] == NULL) {
284        kprintf("%s needs an address argument\n", argv[0]);
285        return 1;
286    }
287
288    vn = (vnode *)strtoul(argv[1], NULL, 0);
289
290    kprintf("vnode @ 0x%x vnid 0x%x ns 0x%x mounted 0x%x\n", vn, vn->vnid,
291            vn->ns, vn->mounted);
292    kprintf("remove %d busy %d inlist %d\n", vn->remove, vn->busy, vn->inlist);
293    kprintf("nspace 0x%x list 0x%x rcnt 0x%x data 0x%x\n", &vn->nspace,
294            &vn->list, vn->rcnt, vn->data);
295}
296
297
298int
299dump_fdarray(int argc, char **argv)
300{
301    int             i;
302    struct fdarray *fds;
303
304    if (argv[1] == NULL) {
305        kprintf("%s needs an address argument\n", argv[0]);
306        return 1;
307    }
308
309    fds = (struct fdarray *)strtoul(argv[1], NULL, 0);
310
311    kprintf("fdarray @ 0x%x  rcnt %d lock %d num %d\n", fds, fds->rcnt,
312            fds->num);
313    kprintf("alloc 0x%x coes 0x%x\n", fds->alloc, fds->coes);
314    for(i=0; i < fds->num; i++)
315        if (fds->fds[i])
316            kprintf("fd %3d @ 0x%x\n", i, fds->fds[i]);
317}
318
319
320int
321dump_ofile(int argc, char **argv)
322{
323    struct ofile *ofile;
324
325    if (argv[1] == NULL) {
326        kprintf("%s needs an address argument\n", argv[0]);
327        return 1;
328    }
329
330    ofile = (struct ofile *)strtoul(argv[1], NULL, 0);
331
332    kprintf("ofile @ 0x%x type %d flags %d vn 0x%x cookie 0x%x\n",
333            ofile, ofile->type, ofile->flags, ofile->vn, ofile->cookie);
334    kprintf("rcnt %d ocnt %d pos 0x%x omode 0x%x\n", ofile->rcnt, ofile->ocnt,
335            ofile->pos, ofile->omode);
336}
337
338int
339dump_nspace(int argc, char **argv)
340{
341    struct nspace *ns;
342
343    if (argv[1] == NULL) {
344        kprintf("%s needs an address argument\n", argv[0]);
345        return 1;
346    }
347
348    ns = (struct nspace *)strtoul(argv[1], NULL, 0);
349
350    kprintf("ns @ 0x%x nsid %d vnlist @ 0x%x data 0x%x\n", ns, ns->nsid,
351            &ns->vnodes, ns->data);
352    kprintf("root 0x%x mount 0x%x prev 0x%x next 0x%x\n", ns->root, ns->mount,
353            ns->prev, ns->next);
354    kprintf("shutdown %d fs @ 0x%x\n", ns->shutdown, ns->fs);
355}
356
357void
358do_dump_io_info(thread_rec *thr)
359{
360    int i;
361    struct fdarray *fds;
362
363    if (thr->ioctx == NULL || thr->ioctx->fds == NULL) {
364        kprintf("thread: %d (%s)\n  No io info?!?\n", thr->thid, thr->name);
365        return;
366    }
367
368    kprintf("thread: %d (%s)\n", thr->thid, thr->name);
369    fds = thr->ioctx->fds;
370
371    for(i=0; i < fds->num; i++)
372        if (fds->fds[i])
373            kprintf("  fd %3d vnode @ 0x%.8x (vnid 0x%.8x, data 0x%.8x)\n", i,
374                    fds->fds[i]->vn, fds->fds[i]->vn->vnid,
375                    fds->fds[i]->vn->data);
376}
377
378
379int
380dump_io_info(int argc, char **argv)
381{
382    int             i;
383    thread_rec     *thr;
384
385    if (argv[1] == NULL) {
386        kprintf("%s needs an thread name/address argument\n", argv[0]);
387        return 1;
388    }
389
390    if (strcmp(argv[1], "-n") == 0) {
391        int len;
392
393        /* hunt for the name in argv[2] */
394        if (argv[2] == NULL) {
395            kprintf("thread: the `-name' option requires an argument\n");
396            return 0;
397        }
398
399        len = strlen(argv[2]);
400        for(i=0; i < nthreads; i++) {
401            if (thread_tab[i] == NULL)
402                continue;
403
404            if (mystrstr(thread_tab[i]->name, argv[2]) != NULL) {
405                thr = thread_tab[i];
406                do_dump_io_info(thr);
407            }
408        }
409    } else {
410        ulong num;
411
412        num = strtoul(argv[2], NULL, 0);
413
414        if (num < 0x2ffff && isbadthid(num) == 0)
415            thr = thread_tab[thidtoslot(num)];
416        else
417            thr = (thread_rec *)num;
418
419        if (thr == 0)
420            return 0;
421
422        do_dump_io_info(thr);
423    }
424
425    return 1;
426}
427
428
429
430int
431find_vn(int argc, char **argv)
432{
433    nspace      *ns;
434    vnode       *vn;
435    vnode       fakevn;
436    vnode_id    vnid;
437
438    if (argv[1] == NULL) {
439        kprintf("%s needs a vnid argument\n", argv[0]);
440        return 1;
441    }
442
443    vnid = (vnode_id)strtoul(argv[1], NULL, 0);
444
445    for(ns=nshead; ns; ns=ns->next) {
446        fakevn.ns = ns;
447        fakevn.vnid = vnid;
448        vn = SearchSL(skiplist, &fakevn);
449        if (vn)
450            kprintf("vn = 0x%x (nsid = %d)\n", vn, vn->ns->nsid);
451    }
452
453    return 0;
454}
455
456#endif /* DEBUG */
457#endif /* USER*/
458
459
460/* ---------------------------------------------------------------- */
461
462#ifdef USER
463int memsize = 8 * 1024 * 1024;
464#endif
465
466int
467init_vnode_layer(void)
468{
469    int         err;
470    vnode       *vns;
471    vnode_id    vnid;
472    int         i;
473    fsystem     *fs;
474    nspace      *ns;
475    void        *data;
476    extern vnode_ops rootfs;  /* XXXdbg */
477    ioctx       *io;
478
479    /*
480    compute vnnum based on memsize. 256 vnodes with 8MB.
481    compute usdvnnum based on vnnum. only 1/4 of total vnodes should
482    remain unlocked.
483    */
484
485    vnnum = memsize >> 15;
486    usdvnnum = vnnum >> 2;
487
488    vns = (vnode *) calloc(sizeof(vnode) * vnnum, 1);
489    for(i=0; i<vnnum; i++) {
490        vns[i].vnid = invalid_vnid;
491        vns[i].ns = NULL;
492        vns[i].mounted = NULL;
493        vns[i].remove = FALSE;
494        vns[i].busy = FALSE;
495        vns[i].inlist = FREE_LIST;
496        vns[i].nspace.next = vns[i].nspace.prev = NULL;
497        vns[i].list.next = (i == vnnum-1 ? NULL : &vns[i+1]);
498        vns[i].list.prev = (i == 0 ? NULL : &vns[i-1]);
499        vns[i].rcnt = 0;
500        vns[i].data = NULL;
501    }
502    lists[FREE_LIST].head = &vns[0];
503    lists[FREE_LIST].tail = &vns[vnnum-1];
504    lists[FREE_LIST].num = vnnum;
505    lists[USED_LIST].head = NULL;
506    lists[USED_LIST].tail = NULL;
507    lists[USED_LIST].num = 0;
508    lists[LOCKED_LIST].head = NULL;
509    lists[LOCKED_LIST].tail = NULL;
510    lists[LOCKED_LIST].num = 0;
511
512    skiplist = NewSL(&compare_vnode, NULL, NO_DUPLICATES);
513
514    /*
515    set max # of file systems and mount points.
516    with 8MB, up to 32 fs and 64 mount points.
517    */
518
519    nns = memsize >> 17;
520    nfs = memsize >> 18;
521
522    nxfsid = 1;
523    nxnsid = 1;
524    nstab = (nspace **) malloc(nns * sizeof(void *));
525    memset(nstab, 0, nns * sizeof(void *));
526    fstab = (fsystem **) malloc(nfs * sizeof(void *));
527    memset(fstab, 0, nfs * sizeof(void *));
528
529    new_lock(&vnlock, "vnlock");
530    new_lock(&fstablock, "fstablock");
531
532    /*
533    determine the max number of files the kernel can open.
534    8MB -> 256
535    */
536
537    max_glb_file = memsize >> 15;
538    global_fds = new_fds(max_glb_file);
539
540
541    /*
542    install file systems
543    */
544    install_file_system(&rootfs, "rootfs", TRUE, -1);
545
546    /*
547    mount the root file system
548    */
549
550    fs = inc_file_system("rootfs");
551
552    ns = (nspace *) malloc(sizeof(nspace));
553    ns->fs = fs;
554    ns->nsid = nxnsid++;
555    nstab[ns->nsid % nns] = ns;
556    ns->vnodes.head = ns->vnodes.tail = NULL;
557    ns->data = NULL;
558    ns->root = NULL;
559    ns->mount = NULL;
560    ns->shutdown = FALSE;
561    ns->prev = ns->next = NULL;
562    nshead = ns;
563
564    err = (*fs->ops.mount)(ns->nsid, NULL, 0, NULL, 0, &data, &vnid);
565    ns->data = data;
566    ns->root = lookup_vnode(ns->nsid, vnid);
567    rootvn = ns->root;
568
569    // set cwd to "/"
570    io = get_cur_ioctx();
571    inc_vnode(rootvn);
572    io->cwd = rootvn;
573
574#ifndef USER
575#ifdef DEBUG
576
577    add_debugger_cmd("ioctx",   dump_ioctx,   "dump a thread ioctx struct");
578    add_debugger_cmd("vnode",   dump_vnode,   "dump a vnode struct");
579    add_debugger_cmd("fdarray", dump_fdarray, "dump an fd array");
580    add_debugger_cmd("ofile",   dump_ofile,   "dump an ofile struct");
581    add_debugger_cmd("nspace",  dump_nspace,  "dump a nspace struct");
582    add_debugger_cmd("fsystem", dump_fsystem, "dump a fsystem struct");
583    add_debugger_cmd("ioinfo",  dump_io_info, "dump io info for a thread");
584    add_debugger_cmd("findvn",  find_vn,      "find a vnid (in all threads)");
585
586#endif /* DEBUG */
587#endif /* USER*/
588
589    return 0;
590}
591
592
593/* ---------------------------------------------------------------- */
594
595int
596sys_sync(void)
597{
598    nspace      *ns;
599    op_sync     *op;
600
601    LOCK(vnlock);
602    for(ns = nshead; ns; ns = ns->next) {
603        ns->root->rcnt++;
604        UNLOCK(vnlock);
605        op = ns->fs->ops.sync;
606        if (op)
607            (*op)(ns->data);
608        LOCK(vnlock);
609        ns->root->rcnt--;
610    }
611    UNLOCK(vnlock);
612    return 0;
613}
614
615static ioctx *
616get_cur_ioctx(void)
617{
618    static int init = 0;
619    static ioctx io;
620
621    if (init == 0) {
622		int error;
623        memset(&io, 0, sizeof(io));
624
625		error = new_lock(&io.lock, "IO context");
626		if (error < 0)
627			PANIC("Failed to init IO context lock: %s\n", fs_strerror(error));
628
629		init = 1;
630	}
631
632    return &io;
633}
634
635
636/*
637 * sys_chdir
638 */
639
640int
641sys_chdir(int kernel, int fd, const char *path)
642{
643    int              err;
644    ioctx           *io;
645    vnode           *vn;
646    op_rstat        *op;
647    struct my_stat   st;
648
649    err = get_file_fd(kernel, fd, path, TRUE, &vn);
650    if (err)
651        goto error1;
652    op = vn->ns->fs->ops.rstat;
653    if (!op) {
654        err = FS_EINVAL;
655        goto error2;
656    }
657    err = (*op)(vn->ns->data, vn->data, &st);
658    if (err)
659        goto error2;
660    if (!MY_S_ISDIR(st.mode)) {
661        err = FS_ENOTDIR;
662        goto error2;
663    }
664    io = get_cur_ioctx();
665    LOCK(io->lock);
666    dec_vnode(io->cwd, FALSE);
667    io->cwd = vn;
668    UNLOCK(io->lock);
669
670    return 0;
671
672error2:
673    dec_vnode(vn, FALSE);
674error1:
675    return err;
676}
677
678
679/*
680 * sys_access
681 */
682
683int
684sys_access(int kernel, int fd, const char *path, int mode)
685{
686    int         err;
687    vnode       *vn;
688    op_access   *op;
689
690    err = get_file_fd(kernel, fd, path, TRUE, &vn);
691    if (err)
692        goto error1;
693    op = vn->ns->fs->ops.access;
694    if (!op) {
695        err = FS_EINVAL;
696        goto error2;
697    }
698    err = (*op)(vn->ns->data, vn->data, mode);
699    if (err)
700        goto error2;
701    dec_vnode(vn, FALSE);
702    return 0;
703
704error2:
705    dec_vnode(vn, FALSE);
706error1:
707    return err;
708}
709
710/*
711 * sys_symlink
712 */
713
714int
715sys_symlink(int kernel, const char *oldpath, int nfd, const char *newpath)
716{
717    int             err;
718    char            filename[FILE_NAME_LENGTH];
719    char            *buf;
720    vnode           *dvn;
721    op_symlink      *op;
722
723    err = get_dir_fd(kernel, nfd, newpath, filename, &dvn);
724    if (err)
725        goto error1;
726    err = new_path(oldpath, &buf);
727    if (err)
728        goto error2;
729    op = dvn->ns->fs->ops.symlink;
730    if (!op) {
731        err = FS_EINVAL;
732        goto error3;
733    }
734    err = (*op)(dvn->ns->data, dvn->data, filename, buf);
735    if (err)
736        goto error3;
737
738    dec_vnode(dvn, FALSE);
739    free_path(buf);
740
741    return 0;
742
743error3:
744    free_path(buf);
745error2:
746    dec_vnode(dvn, FALSE);
747error1:
748    return err;
749}
750
751/*
752 * sys_readlink
753 */
754
755ssize_t
756sys_readlink(int kernel, int fd, const char *path, char *buf, size_t bufsize)
757{
758    int             err;
759    vnode           *vn;
760    op_readlink     *op;
761    size_t          sz;
762
763    err = get_file_fd(kernel, fd, path, FALSE, &vn);
764    if (err)
765        goto error1;
766    op = vn->ns->fs->ops.readlink;
767    if (!op) {
768        err = FS_EINVAL;
769        goto error2;
770    }
771    sz = bufsize;
772    err = (*op)(vn->ns->data, vn->data, buf, &sz);
773    if (err)
774        goto error2;
775    dec_vnode(vn, FALSE);
776
777    return sz;
778
779error2:
780    dec_vnode(vn, FALSE);
781error1:
782    return err;
783}
784
785/*
786 * sys_mkdir
787 */
788
789int
790sys_mkdir(int kernel, int fd, const char *path, int perms)
791{
792    int             err;
793    char            filename[FILE_NAME_LENGTH];
794    vnode           *dvn;
795    op_mkdir        *op;
796
797    err = get_dir_fd(kernel, fd, path, filename, &dvn);
798    if (err)
799        goto error1;
800    op = dvn->ns->fs->ops.mkdir;
801    if (!op) {
802        err = FS_EINVAL;
803        goto error2;
804    }
805    err = (*op)(dvn->ns->data, dvn->data, filename, perms);
806    if (err)
807        goto error2;
808
809    dec_vnode(dvn, FALSE);
810
811    return 0;
812
813error2:
814    dec_vnode(dvn, FALSE);
815error1:
816    return err;
817}
818
819
820/*
821 * opendir.
822 */
823
824int
825sys_opendir(int kernel, int fd, const char *path, int coe)
826{
827    int             err;
828    op_opendir      *op;
829    op_free_cookie  *opf;
830    ofile           *f;
831    int             nfd;
832    vnode           *vn;
833    void            *cookie;
834
835    err = get_file_fd(kernel, fd, path, TRUE, &vn);
836    if (err)
837        goto error1;
838    op = vn->ns->fs->ops.opendir;
839    if (!op) {
840        err = FS_EINVAL;
841        goto error2;
842    }
843    err = (*op)(vn->ns->data, vn->data, &cookie);
844    if (err)
845        goto error2;
846
847    /*
848    find a file descriptor
849    */
850
851    f = (ofile *) calloc(sizeof(ofile), 1);
852    if (!f) {
853        err = FS_ENOMEM;
854        goto error3;
855    }
856
857    f->type = FD_DIR;
858    f->vn = vn;
859    f->cookie = cookie;
860    f->rcnt = 0;
861    f->ocnt = 0;
862
863    nfd = new_fd(kernel, -1, f, -1, coe);
864    if (nfd < 0) {
865        err = FS_EMFILE;
866        goto error4;
867    }
868
869    return nfd;
870
871error4:
872    free(f);
873error3:
874    (*vn->ns->fs->ops.closedir)(vn->ns->data, vn->data, cookie);
875    opf = vn->ns->fs->ops.free_dircookie;
876    if (opf)
877        (*opf)(vn->ns->data, vn->data, cookie);
878error2:
879    dec_vnode(vn, FALSE);
880error1:
881    if (err > 0)        /* XXXdbg -- a hack for linux */
882        err = -err;
883
884    return err;
885}
886
887
888/*
889 * closedir
890 */
891
892int
893sys_closedir(int kernel, int fd)
894{
895    return remove_fd(kernel, fd, FD_DIR | FD_ATTR_DIR);
896}
897
898/*
899 * readdir.
900 */
901
902int
903sys_readdir(int kernel, int fd, struct my_dirent *buf, size_t bufsize,
904        long count)
905{
906    ofile            *f;
907    int               err;
908    vnode            *vn;
909    struct my_dirent *p;
910    struct my_stat    st;
911    long              i;
912    nspace_id         nsid;
913    vnode_id          vnid;
914    long              nm;
915
916    f = get_fd(kernel, fd, FD_DIR | FD_ATTR_DIR);
917    if (!f) {
918        err = FS_EBADF;
919        goto error1;
920    }
921    vn = f->vn;
922    nm = count;
923    if (f->type == FD_DIR) {
924	    err = (*vn->ns->fs->ops.readdir)(vn->ns->data, vn->data, f->cookie,
925    	        &nm, buf, bufsize);
926    } else {
927	    err = (*vn->ns->fs->ops.read_attrdir)(vn->ns->data, vn->data, f->cookie,
928    	        &nm, buf, bufsize);
929    }
930    if (err)
931        goto error1;
932
933
934	// set d_pdev and d_pino
935	buf->d_pdev = vn->ns->nsid;
936	buf->d_pino = vn->vnid;
937
938	/*
939    patch the mount points and the root.
940    */
941
942	if (f->type == FD_DIR) {
943	    LOCK(vnlock);
944	    nsid = vn->ns->nsid;
945	    p = buf;
946	    for(i=0; i<nm; i++) {
947	        if (is_mount_vnid(nsid, p->d_ino, &vnid))
948	            p->d_ino = vnid;
949	        if (vn->ns->mount && !strcmp(p->d_name, "..")) {
950	            UNLOCK(vnlock);
951	            err = sys_rstat(kernel, fd, "..", &st, FALSE);
952	            if (err)
953	                goto error2;
954	            LOCK(vnlock);
955	            p->d_ino = st.ino;
956	        }
957	        p = (struct my_dirent *) ((char *) p + p->d_reclen);
958	    }
959	    UNLOCK(vnlock);
960	}
961
962    put_fd(f);
963    return nm;
964
965error2:
966    put_fd(f);
967error1:
968    return err;
969}
970
971
972/*
973 * rewinddir
974 */
975
976int
977sys_rewinddir(int kernel, int fd)
978{
979    ofile       *f;
980    int         err;
981    vnode       *vn;
982
983    f = get_fd(kernel, fd, FD_DIR | FD_ATTR_DIR);
984    if (!f)
985        return FS_EBADF;
986    vn = f->vn;
987    if (f->type == FD_DIR) {
988	    err = (*vn->ns->fs->ops.rewinddir)(vn->ns->data, vn->data, f->cookie);
989    } else {
990	    err = (*vn->ns->fs->ops.rewind_attrdir)(vn->ns->data, vn->data,
991	    	f->cookie);
992    }
993    put_fd(f);
994    return err;
995}
996
997
998/*
999 * open/create files.
1000 */
1001
1002int
1003sys_open(int kernel, int fd, const char *path, int omode, int perms,
1004        int coe)
1005{
1006    int             err;
1007    char            filename[FILE_NAME_LENGTH];
1008    vnode           *vn, *dvn;
1009    vnode_id        vnid;
1010    void            *cookie;
1011    ofile           *f;
1012    int             nfd;
1013    op_create       *opc;
1014    op_open         *opo;
1015    op_free_cookie  *opf;
1016
1017    if (omode & MY_O_CREAT) {
1018        err = get_dir_fd(kernel, fd, path, filename, &dvn);
1019        if (err)
1020            goto errorA;
1021        opc = dvn->ns->fs->ops.create;
1022        if (!opc) {
1023            err = FS_EINVAL;
1024            goto errorB;
1025        }
1026        err = (*opc)(dvn->ns->data, dvn->data, filename, omode, perms, &vnid,
1027                        &cookie);
1028        if (err)
1029            goto errorB;
1030        LOCK(vnlock);
1031        vn = lookup_vnode(dvn->ns->nsid, vnid);
1032        UNLOCK(vnlock);
1033
1034        dec_vnode(dvn, FALSE);
1035    } else {
1036        err = get_file_fd(kernel, fd, path, !(omode & MY_O_NOTRAVERSE), &vn);
1037        if (err)
1038            goto error1;
1039        opo = vn->ns->fs->ops.open;
1040        if (!opo) {
1041            err = FS_EINVAL;
1042            goto error2;
1043        }
1044        err = (*opo)(vn->ns->data, vn->data, omode, &cookie);
1045        if (err)
1046            goto error2;
1047    }
1048
1049    /*
1050    find a file descriptor
1051    */
1052
1053    f = (ofile *) calloc(sizeof(ofile), 1);
1054    if (!f) {
1055        err = FS_ENOMEM;
1056        goto error3;
1057    }
1058
1059    f->type = FD_FILE;
1060    f->vn = vn;
1061    f->cookie = cookie;
1062    f->ocnt = 0;
1063    f->rcnt = 0;
1064    f->pos = 0;
1065    f->omode = omode;
1066
1067    nfd = new_fd(kernel, -1, f, -1, coe);
1068    if (nfd < 0) {
1069        err = FS_EMFILE;
1070        goto error4;
1071    }
1072
1073    return nfd;
1074
1075error4:
1076    free(f);
1077error3:
1078    (*vn->ns->fs->ops.close)(vn->ns->data, vn->data, cookie);
1079    opf = vn->ns->fs->ops.free_cookie;
1080    if (opf)
1081        (*opf)(vn->ns->data, vn->data, cookie);
1082    if (omode & MY_O_CREAT)
1083        goto errorC;
1084error2:
1085    dec_vnode(vn, FALSE);
1086error1:
1087    return err;
1088
1089errorC:
1090    (*vn->ns->fs->ops.unlink)(dvn->ns->data, dvn->data, filename);
1091    dec_vnode(vn, FALSE);
1092errorB:
1093    dec_vnode(dvn, FALSE);
1094errorA:
1095    if (err > 0)        /* XXXdbg -- a hack for linux */
1096        err = -err;
1097
1098    return err;
1099}
1100
1101
1102int
1103sys_open_entry_ref(int kernel, nspace_id device, vnode_id parent, const char *name,
1104	int openMode, int coe)
1105{
1106    int             err;
1107    vnode           *vn;
1108    void            *cookie;
1109    ofile           *f;
1110    int             nfd;
1111    op_open         *opo;
1112    op_free_cookie  *opf;
1113
1114	err = get_file_vn(device, parent, name, TRUE, &vn);
1115	if (err)
1116		return err;
1117
1118	opo = vn->ns->fs->ops.open;
1119	if (!opo) {
1120		err = FS_EINVAL;
1121		goto error1;
1122	}
1123	err = (*opo)(vn->ns->data, vn->data, openMode, &cookie);
1124	if (err)
1125		goto error1;
1126
1127	/*
1128	 *	find a file descriptor
1129	 */
1130
1131	f = (ofile *)calloc(sizeof(ofile), 1);
1132    if (!f) {
1133		err = FS_ENOMEM;
1134		goto error2;
1135	}
1136
1137	f->type = FD_FILE;
1138	f->vn = vn;
1139	f->cookie = cookie;
1140	f->ocnt = 0;
1141	f->rcnt = 0;
1142	f->pos = 0;
1143	f->omode = openMode;
1144
1145	nfd = new_fd(kernel, -1, f, -1, coe);
1146	if (nfd < 0) {
1147		err = FS_EMFILE;
1148		goto error3;
1149	}
1150
1151	return nfd;
1152
1153error3:
1154    free(f);
1155error2:
1156    (*vn->ns->fs->ops.close)(vn->ns->data, vn->data, cookie);
1157    opf = vn->ns->fs->ops.free_cookie;
1158    if (opf)
1159        (*opf)(vn->ns->data, vn->data, cookie);
1160
1161error1:
1162    dec_vnode(vn, FALSE);
1163    return err;
1164}
1165
1166
1167/*
1168 * sys_close
1169 */
1170
1171int
1172sys_close(int kernel, int fd)
1173{
1174    return remove_fd(kernel, fd, FD_FILE);
1175}
1176
1177
1178/*
1179 * sys_lseek
1180 */
1181
1182fs_off_t
1183sys_lseek(int kernel, int fd, fs_off_t pos, int whence)
1184{
1185    ofile           *f;
1186    int              err;
1187    struct my_stat   st;
1188    vnode           *vn;
1189    op_rstat        *op;
1190
1191    f = get_fd(kernel, fd, FD_FILE);
1192    if (!f) {
1193        err = FS_EBADF;
1194        goto error1;
1195    }
1196    switch(whence) {
1197    case MY_SEEK_SET:
1198        f->pos = pos;
1199        break;
1200    case MY_SEEK_CUR:
1201        if ((f->omode & MY_O_APPEND) == 0)
1202            f->pos += pos;
1203        else {               /* we're in append mode so ask where the EOF is */
1204            vn = f->vn;
1205            op = vn->ns->fs->ops.rstat;
1206            if (!op) {
1207                err = FS_EINVAL;
1208                goto error2;
1209            }
1210            err = (*op)(vn->ns->data, vn->data, &st);
1211            if (err)
1212                goto error2;
1213            pos += st.size;
1214            f->pos = pos;
1215            break;
1216        }
1217        break;
1218    case MY_SEEK_END:
1219        vn = f->vn;
1220        op = vn->ns->fs->ops.rstat;
1221        if (!op) {
1222            err = FS_EINVAL;
1223            goto error2;
1224        }
1225        err = (*op)(vn->ns->data, vn->data, &st);
1226        if (err)
1227            goto error2;
1228        pos += st.size;
1229        f->pos = pos;
1230        break;
1231    default:
1232        put_fd(f);
1233        return FS_EINVAL;
1234    }
1235
1236    if (f->pos < 0) {
1237        f->pos = 0;
1238        err = FS_EINVAL;
1239        goto error2;
1240    }
1241
1242    pos = f->pos;
1243    put_fd(f);
1244    return pos;
1245
1246error2:
1247    put_fd(f);
1248error1:
1249    return err;
1250}
1251
1252
1253/*
1254 * sys_read
1255 */
1256
1257
1258ssize_t
1259sys_read(int kernel, int fd, void *buf, size_t len)
1260{
1261    ofile       *f;
1262    int         err;
1263    vnode       *vn;
1264    size_t      sz;
1265
1266
1267    f = get_fd(kernel, fd, FD_FILE);
1268    if (!f) {
1269        err = FS_EBADF;
1270        goto error1;
1271    }
1272    if ((f->omode & OMODE_MASK) == MY_O_WRONLY) {
1273        err = FS_EBADF;
1274        goto error2;
1275    }
1276    vn = f->vn;
1277    sz = len;
1278    err = (*vn->ns->fs->ops.read)(vn->ns->data, vn->data, f->cookie, f->pos,
1279        buf, &sz);
1280    if (err)
1281        goto error2;
1282
1283    /*
1284    the update of f->pos is not protected. does it matter?
1285    simultaneous I/Os on the same file are unpredictable anyway.
1286    */
1287
1288    f->pos += sz;
1289
1290    put_fd(f);
1291
1292    return sz;
1293
1294error2:
1295    put_fd(f);
1296error1:
1297    return err;
1298}
1299
1300
1301/*
1302 * sys_write
1303 */
1304
1305ssize_t
1306sys_write(int kernel, int fd, const void *buf, size_t len)
1307{
1308    ofile       *f;
1309    int         err;
1310    vnode       *vn;
1311    size_t      sz;
1312
1313    f = get_fd(kernel, fd, FD_FILE);
1314    if (!f) {
1315        err = FS_EBADF;
1316        goto error1;
1317    }
1318    if ((f->omode & OMODE_MASK) == MY_O_RDONLY) {
1319        err = FS_EBADF;
1320        goto error2;
1321    }
1322    vn = f->vn;
1323    sz = len;
1324    err = (*vn->ns->fs->ops.write)(vn->ns->data, vn->data, f->cookie, f->pos,
1325        buf, &sz);
1326    if (err)
1327        goto error2;
1328
1329    /*
1330    the update of f->pos is not protected. does it matter?
1331    simultaneous I/Os on the same file are unpredictable anyway.
1332    */
1333
1334    f->pos += sz;
1335
1336    put_fd(f);
1337    return sz;
1338
1339error2:
1340    put_fd(f);
1341error1:
1342    return err;
1343}
1344
1345
1346/*
1347 * sys_ioctl
1348 */
1349
1350int
1351sys_ioctl(int kernel, int fd, int cmd, void *arg, size_t sz)
1352{
1353    ofile       *f;
1354    int         err;
1355    vnode       *vn;
1356    op_ioctl    *op;
1357
1358    f = get_fd(kernel, fd, FD_FILE);
1359    if (!f) {
1360        err = FS_EBADF;
1361        goto error1;
1362    }
1363    vn = f->vn;
1364    op = vn->ns->fs->ops.ioctl;
1365    if (op)
1366        err = (*op)(vn->ns->data, vn->data, f->cookie, cmd, arg, sz);
1367    else
1368        err = FS_EINVAL;
1369    if (err)
1370        goto error2;
1371
1372    put_fd(f);
1373    return 0;
1374
1375error2:
1376    put_fd(f);
1377error1:
1378    return err;
1379}
1380
1381
1382/*
1383 * sys_link
1384 */
1385
1386int
1387sys_link(int kernel, int ofd, const char *oldpath, int nfd,
1388    const char *newpath)
1389{
1390    int             err;
1391    vnode           *vn, *dvn;
1392    char            filename[FILE_NAME_LENGTH];
1393    op_link         *op;
1394
1395    err = get_file_fd(kernel, ofd, oldpath, TRUE, &vn);
1396    if (err)
1397        goto error1;
1398    err = get_dir_fd(kernel, nfd, newpath, filename, &dvn);
1399    if (err)
1400        goto error2;
1401
1402    if (vn->ns != dvn->ns) {
1403        err = FS_EXDEV;
1404        goto error3;
1405    }
1406    op = dvn->ns->fs->ops.link;
1407    if (!op) {
1408        err = FS_EINVAL;
1409        goto error3;
1410    }
1411    err = (*op)(dvn->ns->data, dvn->data, filename, vn->data);
1412    if (err)
1413        goto error3;
1414
1415    dec_vnode(dvn, FALSE);
1416    dec_vnode(vn, FALSE);
1417    return 0;
1418
1419error3:
1420    dec_vnode(dvn, FALSE);
1421error2:
1422    dec_vnode(vn, FALSE);
1423error1:
1424    return err;
1425}
1426
1427/*
1428 * sys_unlink
1429 */
1430
1431int
1432sys_unlink(int kernel, int fd, const char *path)
1433{
1434    int             err;
1435    vnode           *dvn;
1436    char            filename[FILE_NAME_LENGTH];
1437    op_unlink       *op;
1438
1439    err = get_dir_fd(kernel, fd, path, filename, &dvn);
1440    if (err)
1441        goto error1;
1442
1443    op = dvn->ns->fs->ops.unlink;
1444    if (!op) {
1445        err = FS_EINVAL;
1446        goto error2;
1447    }
1448    err = (*op)(dvn->ns->data, dvn->data, filename);
1449    if (err)
1450        goto error2;
1451
1452    dec_vnode(dvn, FALSE);
1453    return 0;
1454
1455error2:
1456    dec_vnode(dvn, FALSE);
1457error1:
1458    return err;
1459}
1460
1461
1462/*
1463 * sys_rmdir
1464 */
1465
1466int
1467sys_rmdir(int kernel, int fd, const char *path)
1468{
1469    int             err;
1470    vnode           *dvn;
1471    char            filename[FILE_NAME_LENGTH];
1472    op_unlink       *op;
1473
1474    err = get_dir_fd(kernel, fd, path, filename, &dvn);
1475    if (err)
1476        goto error1;
1477
1478    op = dvn->ns->fs->ops.rmdir;
1479    if (!op) {
1480        err = FS_EINVAL;
1481        goto error2;
1482    }
1483    err = (*op)(dvn->ns->data, dvn->data, filename);
1484    if (err)
1485        goto error2;
1486
1487    dec_vnode(dvn, FALSE);
1488    return 0;
1489
1490error2:
1491    dec_vnode(dvn, FALSE);
1492error1:
1493    return err;
1494}
1495
1496/*
1497 * sys_rename
1498 */
1499
1500int
1501sys_rename(int kernel, int ofd, const char *oldpath,
1502    int nfd, const char *newpath)
1503{
1504    int             err;
1505    char            newname[FILE_NAME_LENGTH], oldname[FILE_NAME_LENGTH];
1506    vnode           *odvn, *ndvn;
1507    op_rename       *op;
1508
1509    err = get_dir_fd(kernel, ofd, oldpath, oldname, &odvn);
1510    if (err)
1511        goto error1;
1512    err = get_dir_fd(kernel, nfd, newpath, newname, &ndvn);
1513    if (err)
1514        goto error2;
1515
1516    if (odvn->ns != ndvn->ns) {
1517        err = FS_EXDEV;
1518        goto error2;
1519    }
1520
1521    op = odvn->ns->fs->ops.rename;
1522    if (!op) {
1523        err = FS_EINVAL;
1524        goto error3;
1525    }
1526    err = (*op)(odvn->ns->data, odvn->data, oldname, ndvn->data, newname);
1527    if (err)
1528        goto error3;
1529
1530    dec_vnode(odvn, FALSE);
1531    dec_vnode(ndvn, FALSE);
1532
1533    return 0;
1534
1535error3:
1536    dec_vnode(ndvn, FALSE);
1537error2:
1538    dec_vnode(odvn, FALSE);
1539error1:
1540    return err;
1541}
1542
1543/*
1544 * sys_rstat
1545 */
1546
1547int
1548sys_rstat(int kernel, int fd, const char *path, struct my_stat *st, int eatlink)
1549{
1550    int         err;
1551    vnode       *vn;
1552    op_rstat    *op;
1553
1554	FUNCTION();
1555
1556    err = get_file_fd(kernel, fd, path, eatlink, &vn);
1557    if (err)
1558        goto error1;
1559    op = vn->ns->fs->ops.rstat;
1560    if (!op) {
1561        err = FS_EINVAL;
1562        goto error2;
1563    }
1564    err = (*op)(vn->ns->data, vn->data, st);
1565    if (err)
1566        goto error2;
1567    dec_vnode(vn, FALSE);
1568
1569    return 0;
1570
1571error2:
1572    dec_vnode(vn, FALSE);
1573error1:
1574    return err;
1575}
1576
1577/*
1578 * sys_wstat
1579 */
1580
1581int
1582sys_wstat(int kernel, int fd, const char *path, struct my_stat *st, long mask,
1583        int eatlink)
1584{
1585    int         err;
1586    vnode       *vn;
1587    op_wstat    *op;
1588
1589    err = get_file_fd(kernel, fd, path, eatlink, &vn);
1590    if (err)
1591        goto error1;
1592    op = vn->ns->fs->ops.wstat;
1593    if (!op) {
1594        err = FS_EINVAL;
1595        goto error2;
1596    }
1597    err = (*op)(vn->ns->data, vn->data, st, mask);
1598    if (err)
1599        goto error2;
1600    dec_vnode(vn, FALSE);
1601
1602    return 0;
1603
1604error2:
1605    dec_vnode(vn, FALSE);
1606error1:
1607    return err;
1608}
1609
1610
1611void
1612kill_device_vnodes(dev_t id)
1613{
1614	fsystem *fs;
1615	nspace *ns;
1616
1617	LOCK(vnlock);
1618
1619	ns = nsidtons(id);
1620
1621	if (!ns) {
1622		UNLOCK(vnlock);
1623		return;
1624	}
1625
1626	fs = ns->fs;
1627
1628	while (ns->vnodes.head) {
1629		int err;
1630
1631		struct vnode *vn = ns->vnodes.head;
1632		UNLOCK(vnlock);
1633		err = (*fs->ops.write_vnode)(vn->ns->data, vn->data, FALSE);
1634		LOCK(vnlock);
1635		if (err)
1636			PANIC("ERROR WRITING VNODE!!!\n");
1637		vn->busy = FALSE;
1638		clear_vnode(vn);
1639		move_vnode(vn, FREE_LIST);
1640	}
1641
1642	UNLOCK(vnlock);
1643}
1644
1645
1646void
1647remove_nspace(nspace *ns)
1648{
1649	fsystem *fs = ns->fs;
1650	vnode *vn;
1651
1652	ns->shutdown = TRUE;
1653	for (vn = ns->vnodes.head; vn; vn = vn->nspace.next)
1654		vn->busy = TRUE;
1655
1656	while (ns->vnodes.head) {
1657		int err;
1658
1659		vn = ns->vnodes.head;
1660		UNLOCK(vnlock);
1661		err = (*fs->ops.write_vnode)(vn->ns->data, vn->data, FALSE);
1662		LOCK(vnlock);
1663		if (err)
1664			PANIC("ERROR WRITING VNODE!!!\n");
1665		vn->busy = FALSE;
1666		clear_vnode(vn);
1667		move_vnode(vn, FREE_LIST);
1668	}
1669
1670	nstab[ns->nsid % nns] = NULL;
1671
1672	if (ns->prev)
1673		ns->prev->next = ns->next;
1674	else
1675		nshead = ns->next;
1676	if (ns->next)
1677		ns->next->prev = ns->prev;
1678}
1679
1680
1681status_t
1682add_nspace(nspace *ns, fsystem *fs, const char *fileSystem, dev_t dev, ino_t ino)
1683{
1684	int i;
1685
1686	if (fileSystem != NULL)
1687		fs = inc_file_system(fileSystem);
1688	if (!fs)
1689		return FS_ENODEV;
1690
1691	for (i = 0; i < nns; i++, nxnsid++) {
1692		if (!nstab[nxnsid % nns]) {
1693			nstab[nxnsid % nns] = ns;
1694			ns->nsid = nxnsid;
1695			nxnsid++;
1696			break;
1697		}
1698	}
1699	if (i == nns) {
1700		dec_file_system(fs);
1701		return FS_EMFILE;
1702	}
1703
1704	nstab[ns->nsid % nns] = ns;
1705	ns->fs = fs;
1706	ns->vnodes.head = ns->vnodes.tail = NULL;
1707	ns->data = NULL;
1708	ns->root = NULL;
1709	ns->mount = NULL;
1710	ns->prev = NULL;
1711	ns->next = nshead;
1712	ns->shutdown = FALSE;
1713	ns->dev = dev;
1714	ns->ino = ino;
1715
1716	if (nshead)
1717		nshead->prev = ns;
1718	nshead = ns;
1719
1720	return FS_OK;
1721}
1722
1723
1724int
1725sys_open_attr_dir(int kernel, int fd, const char *path)
1726{
1727    int             err;
1728    op_open_attrdir *op;
1729    op_free_cookie  *opf;
1730    ofile           *f;
1731    int             nfd;
1732    vnode           *vn;
1733    void            *cookie;
1734
1735    err = get_file_fd(kernel, fd, path, TRUE, &vn);
1736    if (err)
1737        goto error1;
1738    op = vn->ns->fs->ops.open_attrdir;
1739    if (!op) {
1740        err = FS_EINVAL;
1741        goto error2;
1742    }
1743    err = (*op)(vn->ns->data, vn->data, &cookie);
1744    if (err)
1745        goto error2;
1746
1747    /*
1748    find a file descriptor
1749    */
1750
1751    f = (ofile *) calloc(sizeof(ofile), 1);
1752    if (!f) {
1753        err = FS_ENOMEM;
1754        goto error3;
1755    }
1756
1757    f->type = FD_ATTR_DIR;
1758    f->vn = vn;
1759    f->cookie = cookie;
1760    f->rcnt = 0;
1761    f->ocnt = 0;
1762
1763    nfd = new_fd(kernel, -1, f, -1, TRUE);
1764    if (nfd < 0) {
1765        err = FS_EMFILE;
1766        goto error4;
1767    }
1768
1769    return nfd;
1770
1771error4:
1772    free(f);
1773error3:
1774    (*vn->ns->fs->ops.close_attrdir)(vn->ns->data, vn->data, cookie);
1775    opf = vn->ns->fs->ops.free_attrdircookie;
1776    if (opf)
1777        (*opf)(vn->ns->data, vn->data, cookie);
1778error2:
1779    dec_vnode(vn, FALSE);
1780error1:
1781    return err;
1782}
1783
1784
1785ssize_t
1786sys_read_attr(int kernel, int fd, const char *name, int type, void *buffer, size_t len, off_t pos)
1787{
1788    ofile       *f;
1789    int         err;
1790    vnode       *vn;
1791    size_t      sz;
1792
1793    f = get_fd(kernel, fd, FD_FILE);
1794    if (!f) {
1795        err = FS_EBADF;
1796        goto error1;
1797    }
1798
1799    vn = f->vn;
1800    sz = len;
1801    err = (*vn->ns->fs->ops.read_attr)(vn->ns->data, vn->data, name, type, buffer, &sz, pos);
1802    if (err)
1803        goto error2;
1804
1805    put_fd(f);
1806
1807    return sz;
1808
1809error2:
1810    put_fd(f);
1811error1:
1812    return err;
1813}
1814
1815
1816ssize_t
1817sys_write_attr(int kernel, int fd, const char *name,int type,
1818	const void *buffer, size_t len, off_t pos)
1819{
1820    ofile       *f;
1821    int         err;
1822    vnode       *vn;
1823    size_t      sz;
1824
1825    f = get_fd(kernel, fd, FD_FILE);
1826    if (!f) {
1827        err = FS_EBADF;
1828        goto error1;
1829    }
1830
1831    vn = f->vn;
1832    sz = len;
1833    err = (*vn->ns->fs->ops.write_attr)(vn->ns->data, vn->data, name, type, buffer, &sz, pos);
1834    if (err)
1835        goto error2;
1836
1837    put_fd(f);
1838    return sz;
1839
1840error2:
1841    put_fd(f);
1842error1:
1843    return err;
1844}
1845
1846
1847ssize_t
1848sys_remove_attr(int kernel, int fd, const char *name)
1849{
1850    ofile       *f;
1851    int         err;
1852    vnode       *vn;
1853
1854    f = get_fd(kernel, fd, FD_FILE);
1855    if (!f) {
1856        err = FS_EBADF;
1857        goto error1;
1858    }
1859
1860    vn = f->vn;
1861    err = (*vn->ns->fs->ops.remove_attr)(vn->ns->data, vn->data, name);
1862    if (err)
1863        goto error2;
1864
1865    put_fd(f);
1866
1867    return 0;
1868
1869error2:
1870    put_fd(f);
1871error1:
1872    return err;
1873}
1874
1875
1876int
1877sys_stat_attr(int kernel, int fd, const char *path, const char *name,
1878	my_attr_info *info)
1879{
1880    int         err;
1881    vnode       *vn;
1882    op_stat_attr *op;
1883
1884    err = get_file_fd(kernel, fd, path, TRUE, &vn);
1885    if (err)
1886        goto error1;
1887    op = vn->ns->fs->ops.stat_attr;
1888    if (!op) {
1889        err = FS_EINVAL;
1890        goto error2;
1891    }
1892    err = (*op)(vn->ns->data, vn->data, name, info);
1893    if (err)
1894        goto error2;
1895    dec_vnode(vn, FALSE);
1896
1897    return 0;
1898
1899error2:
1900    dec_vnode(vn, FALSE);
1901error1:
1902    return err;
1903}
1904
1905
1906/*
1907 * sys_mount
1908 */
1909
1910void *
1911sys_mount(int kernel, const char *filesystem, int fd, const char *where,
1912	const char *device, ulong flags, void *parms, size_t len)
1913{
1914    int                 err;
1915    vnode_id            vnid;
1916    vnode               *mount;
1917    fsystem             *fs;
1918    nspace              *ns, *ans;
1919    void                *data;
1920    struct stat         st;
1921    struct my_stat      mst;
1922    my_dev_t            dev;
1923    my_ino_t            ino;
1924
1925    dev = -1;
1926    ino = -1;
1927    if (device) {
1928        err = stat(device, &st);
1929        if (err)
1930            return NULL;
1931        dev = st.st_dev;
1932        ino = st.st_ino;
1933    }
1934
1935    err = get_file_fd(TRUE, fd, where, TRUE, &mount);
1936    if (err)
1937        goto error1;
1938
1939    err = (*mount->ns->fs->ops.rstat)(mount->ns->data, mount->data, &mst);
1940    if (err)
1941        goto error2;
1942    if (!MY_S_ISDIR(mst.mode)) {
1943        err = FS_ENOTDIR;
1944        goto error2;
1945    }
1946
1947    ns = (nspace *)malloc(sizeof(nspace));
1948    if (!ns) {
1949        err = FS_ENOMEM;
1950        goto error2;
1951    }
1952
1953    fs = inc_file_system(filesystem);
1954    if (!fs) {
1955        err = FS_ENODEV;
1956        goto error3;
1957    }
1958
1959    LOCK(vnlock);
1960
1961    if (device) {
1962        for(ans=nshead; ans; ans=ans->next)
1963            if ((ans->dev == dev) && (ans->ino == ino)) {
1964                UNLOCK(vnlock);
1965				printf("KERNEL: trying to mount %s twice (already mounted as %s)\n",
1966					device, ans->fs->name);
1967                err = FS_ENODEV;
1968                goto error4;
1969            }
1970    }
1971
1972	err = add_nspace(ns, fs, NULL, dev, ino);
1973
1974    UNLOCK(vnlock);
1975
1976	if (err != FS_OK)
1977		goto error5;
1978
1979    err = (*fs->ops.mount)(ns->nsid, device, flags, parms, len, &data, &vnid);
1980    if (err)
1981        goto error5;
1982
1983    LOCK(vnlock);
1984    ns->root = lookup_vnode(ns->nsid, vnid);
1985    ns->data = data;
1986
1987    if ((mount == rootvn) || (mount->mounted)) {
1988        err = FS_EBUSY;
1989        goto error6;
1990    }
1991    mount->mounted = ns;
1992    ns->mount = mount;
1993
1994    UNLOCK(vnlock);
1995
1996    return data;
1997
1998error6:
1999    dec_vnode(ns->root, FALSE);
2000    (*fs->ops.unmount)(data);
2001error5:
2002    LOCK(vnlock);
2003    remove_nspace(ns);
2004    UNLOCK(vnlock);
2005error4:
2006error3:
2007    free(ns);
2008error2:
2009    dec_vnode(mount, FALSE);
2010error1:
2011    errno = err;
2012    return NULL;
2013}
2014
2015
2016/*
2017 * sys_unmount
2018 */
2019
2020int
2021sys_unmount(int kernel, int fd, const char *where)
2022{
2023    int             err;
2024    nspace          *ns;
2025    fsystem         *fs;
2026    vnode           *root, *vn, *mount;
2027
2028    err = get_file_fd(TRUE, fd, where, TRUE, &root);
2029    if (err)
2030        goto error1;
2031
2032    LOCK(vnlock);
2033
2034    ns = root->ns;
2035    fs = ns->fs;
2036    if (ns->root != root) {
2037        err = FS_EINVAL;
2038        goto error2;
2039    }
2040
2041
2042    /*
2043    don't allow to unmount the root file system
2044    */
2045
2046    if (root == rootvn) {
2047        err = FS_EBUSY;
2048        goto error2;
2049    }
2050
2051    /*
2052    decrement twice root: one for the mount, one for the get_file.
2053    */
2054
2055    root->rcnt -= 2;
2056
2057    for(vn = ns->vnodes.head; vn; vn = vn->nspace.next)
2058        if (vn->busy || (vn->rcnt != 0)) {
2059            err = FS_EBUSY;
2060            goto error3;
2061        }
2062
2063    mount = ns->mount;
2064    mount->mounted = NULL;
2065
2066	remove_nspace(ns);
2067    UNLOCK(vnlock);
2068
2069    (*fs->ops.unmount)(ns->data);
2070
2071    free(ns);
2072
2073    dec_file_system(fs);
2074    dec_vnode(mount, FALSE);
2075
2076    return 0;
2077
2078error3:
2079    root->rcnt++;
2080error2:
2081    UNLOCK(vnlock);
2082error1:
2083    return err;
2084}
2085
2086
2087int
2088sys_write_fs_info(int kernel, dev_t device, struct fs_info *info, int mask)
2089{
2090	int status = FS_EINVAL;
2091	fsystem	*fs = NULL;
2092	vnode *root = NULL;
2093	nspace *ns;
2094
2095	LOCK(vnlock);
2096	ns = nsidtons(device);
2097	if (ns != NULL) {
2098		fs = ns->fs;
2099		if (fs->ops.wfsstat != NULL) {
2100			status = FS_OK;
2101			root = ns->root;
2102			root->rcnt++;
2103		}
2104	}
2105	UNLOCK(vnlock);
2106
2107	if (status == FS_OK) {
2108		status = (*fs->ops.wfsstat)(ns->data, info, mask);
2109		dec_vnode(root, FALSE);
2110	}
2111
2112	return status;
2113}
2114
2115
2116int
2117sys_mkindex(int kernel, dev_t device, const char *index, int type, int flags)
2118{
2119	int status = FS_EINVAL;
2120	fsystem	*fs = NULL;
2121	vnode *root = NULL;
2122	nspace *ns;
2123
2124	LOCK(vnlock);
2125	ns = nsidtons(device);
2126	if (ns != NULL) {
2127		fs = ns->fs;
2128		if (fs->ops.create_index != NULL) {
2129			status = FS_OK;
2130			root = ns->root;
2131			root->rcnt++;
2132		}
2133	}
2134	UNLOCK(vnlock);
2135
2136	if (status == FS_OK) {
2137		status = (*fs->ops.create_index)(ns->data, index, type, flags);
2138		dec_vnode(root, FALSE);
2139	}
2140
2141	TRACE("sys_mkindex() -- end: %d\n", status);
2142	return status;
2143}
2144
2145
2146int
2147sys_open_query(int kernel, int fd, const char *path, const char *query, ulong flags, port_id port, ulong token, void **cookie)
2148{
2149	int		err;
2150	nspace	*ns;
2151	fsystem	*fs;
2152	vnode	*root;
2153
2154	TRACE("sys_open_query() -- start\n");
2155	err = get_file_fd(TRUE, fd, path, TRUE, &root);
2156	if (err)
2157		return err;
2158
2159	ns = root->ns;
2160	fs = ns->fs;
2161	if (ns->root != root)
2162		return FS_EINVAL;
2163
2164	if (fs->ops.open_query == NULL) {
2165		dec_vnode(root, FALSE);
2166		return FS_EPERM;
2167	}
2168	err = (*fs->ops.open_query)(ns->data, query, flags, port, token, cookie);
2169	TRACE("sys_open_query() -- end: %d\n",err);
2170	dec_vnode(root, FALSE);
2171
2172	return err;
2173}
2174
2175
2176int
2177sys_close_query(int kernel, int fd, const char *path, void *cookie)
2178{
2179	int		err;
2180	nspace	*ns;
2181	fsystem	*fs;
2182	vnode	*root;
2183
2184    err = get_file_fd(TRUE, fd, path, TRUE, &root);
2185    if (err)
2186        return err;
2187
2188    ns = root->ns;
2189    fs = ns->fs;
2190    if (ns->root != root)
2191        return FS_EINVAL;
2192
2193	if (fs->ops.close_query == NULL) {
2194		dec_vnode(root, FALSE);
2195		return FS_EPERM;
2196	}
2197
2198	err = (*fs->ops.close_query)(ns->data, cookie);
2199	(*fs->ops.free_querycookie)(ns->data, NULL, cookie);
2200
2201	dec_vnode(root, FALSE);
2202
2203	return err;
2204}
2205
2206
2207int
2208sys_read_query(int kernel, int fd, const char *path, void *cookie,struct my_dirent *dent,size_t bufferSize,long count)
2209{
2210	int		err;
2211	nspace	*ns;
2212	fsystem	*fs;
2213	vnode	*root;
2214	long	num;
2215
2216    err = get_file_fd(TRUE, fd, path, TRUE, &root);
2217    if (err)
2218        return err;
2219
2220    ns = root->ns;
2221    fs = ns->fs;
2222    if (ns->root != root)
2223        return FS_EINVAL;
2224
2225	if (fs->ops.close_query == NULL) {
2226		dec_vnode(root, FALSE);
2227		return FS_EPERM;
2228	}
2229
2230	num = count;
2231	err = (*fs->ops.read_query)(ns->data, cookie, &num, dent, bufferSize);
2232
2233	dec_vnode(root, FALSE);
2234
2235	if (err == 0)
2236		return num;
2237
2238	return err;
2239}
2240
2241/*
2242 * get_dir and get_file: basic functions to parse a path and get the vnode
2243 * for either the parent directory or the file itself.
2244 */
2245
2246static int
2247get_dir_fd(int kernel, int fd, const char *path, char *filename, vnode **dvn)
2248{
2249    int         err;
2250    char        *p, *np;
2251
2252    err = new_path(path, &p);
2253    if (err)
2254        goto error1;
2255    np = strrchr(p, '/');
2256    if (!np) {
2257        strcpy(filename, p);
2258        strcpy(p, ".");
2259    } else {
2260        strcpy(filename, np+1);
2261        np[1] = '.';
2262        np[2] = '\0';
2263    }
2264    err = parse_path_fd(kernel, fd, &p, TRUE, dvn);
2265    if (err)
2266        goto error2;
2267    free_path(p);
2268    return 0;
2269
2270error2:
2271    free_path(p);
2272error1:
2273    return err;
2274}
2275
2276static int
2277get_file_fd(int kernel, int fd, const char *path, int eatsymlink, vnode **vn)
2278{
2279    int         err;
2280    char        *p;
2281
2282    err = new_path(path, &p);
2283    if (err)
2284        goto error1;
2285    err = parse_path_fd(kernel, fd, &p, eatsymlink, vn);
2286    if (err)
2287        goto error2;
2288    free_path(p);
2289    return 0;
2290
2291error2:
2292    free_path(p);
2293error1:
2294    return err;
2295}
2296
2297static int
2298get_file_vn(nspace_id nsid, vnode_id vnid, const char *path, int eatsymlink,
2299        vnode **vn)
2300{
2301    int         err;
2302    char        *p;
2303
2304    err = new_path(path, &p);
2305    if (err)
2306        goto error1;
2307    err = parse_path_vn(nsid, vnid, &p, eatsymlink, vn);
2308    if (err)
2309        goto error2;
2310    free_path(p);
2311    return 0;
2312
2313error2:
2314    free_path(p);
2315error1:
2316    return err;
2317}
2318
2319static int
2320parse_path_fd(int kernel, int fd, char **pstart, int eatsymlink, vnode **vnp)
2321{
2322    vnode           *bvn;
2323    ofile           *f;
2324    ioctx           *io;
2325    char            *path;
2326
2327    path = *pstart;
2328    if (path && (*path == '/')) {
2329        do
2330            path++;
2331        while (*path == '/');
2332        bvn = rootvn;
2333        inc_vnode(bvn);
2334    } else
2335        if (fd >= 0) {
2336            f = get_fd(kernel, fd, FD_ALL);
2337            if (!f)
2338                return FS_EBADF;
2339            bvn = f->vn;
2340            inc_vnode(bvn);
2341            put_fd(f);
2342        } else {
2343            io = get_cur_ioctx();
2344            LOCK(io->lock);
2345            bvn = io->cwd;
2346            inc_vnode(bvn);
2347            UNLOCK(io->lock);
2348        }
2349    return parse_path(bvn, pstart, path, eatsymlink, vnp);
2350}
2351
2352static int
2353parse_path_vn(nspace_id nsid, vnode_id vnid, char **pstart, int eatsymlink,
2354    vnode **vnp)
2355{
2356    int             err;
2357    vnode           *bvn;
2358    char            *path;
2359
2360    path = *pstart;
2361    if (path && (*path == '/')) {
2362        do
2363            path++;
2364        while (*path == '/');
2365        bvn = rootvn;
2366        inc_vnode(bvn);
2367    } else {
2368        err = load_vnode(nsid, vnid, FALSE, &bvn);
2369        if (err)
2370            return err;
2371    }
2372    return parse_path(bvn, pstart, path, eatsymlink, vnp);
2373}
2374
2375
2376static int
2377parse_path(vnode *bvn, char **pstart, char *path, int eatsymlink, vnode **vnp)
2378{
2379    int             err;
2380    int             iter;
2381    char            *p, *np, *newpath, **fred;
2382    vnode_id        vnid;
2383    vnode           *vn;
2384
2385	TRACE("parse_path(path = %s)\n", path);
2386
2387    if (!path) {
2388        *vnp = bvn;
2389        return 0;
2390    }
2391
2392    iter = 0;
2393    p = path;
2394    vn = NULL;
2395
2396    while(TRUE) {
2397
2398    /*
2399    exit if we're done
2400    */
2401
2402        if (*p == '\0') {
2403            err = 0;
2404            break;
2405        }
2406
2407    /*
2408    isolate the next component
2409    */
2410
2411        np = strchr(p+1, '/');
2412        if (np) {
2413            *np = '\0';
2414            do
2415                np++;
2416            while (*np == '/');
2417        } else
2418            np = strchr(p+1, '\0');
2419
2420    /*
2421    filter '..' if at the root of a namespace
2422    */
2423
2424        if (!strcmp(p, "..") && is_root(bvn, &vn)) {
2425            dec_vnode(bvn, FALSE);
2426            bvn = vn;
2427        }
2428
2429    /*
2430    ask the file system to eat this component
2431    */
2432
2433        newpath = NULL;
2434        fred = &newpath;
2435        if (!eatsymlink && (*np == '\0'))
2436            fred = NULL;
2437
2438        err = (*bvn->ns->fs->ops.walk)(bvn->ns->data, bvn->data, p, fred,
2439                &vnid);
2440        p = np;
2441        if (!err) {
2442            if (newpath)
2443                vn = bvn;
2444            else {
2445                LOCK(vnlock);
2446                vn = lookup_vnode(bvn->ns->nsid, vnid);
2447                UNLOCK(vnlock);
2448                dec_vnode(bvn, FALSE);
2449            }
2450        } else {
2451            dec_vnode(bvn, FALSE);
2452            break;
2453        }
2454
2455    /*
2456    deal with symbolic links
2457    */
2458
2459        if (newpath) {
2460
2461    /*
2462    protection against cyclic graphs (with bad symbolic links).
2463    */
2464
2465            iter++;
2466            if (iter > MAX_SYM_LINKS) {
2467                dec_vnode(vn, FALSE);
2468                err = FS_ELOOP;
2469                break;
2470            }
2471
2472            p = cat_paths(newpath, np);
2473            if (!p) {
2474                dec_vnode(vn, FALSE);
2475                err = FS_ENOMEM;
2476                break;
2477            }
2478            free_path(*pstart);
2479            *pstart = p;
2480            if (*p == '/') {
2481                do
2482                    p++;
2483                while (*p == '/');
2484                dec_vnode(vn, FALSE);
2485                bvn = rootvn;
2486                inc_vnode(bvn);
2487            } else
2488                bvn = vn;
2489            continue;
2490        }
2491
2492    /*
2493    reached a mounting point
2494    */
2495
2496        if (is_mount_vnode(vn, &bvn)) {
2497            dec_vnode(vn, FALSE);
2498            continue;
2499        }
2500
2501        bvn = vn;
2502    }
2503
2504    if (!err) {
2505    	TRACE("parse_path() got vnode %Ld\n", bvn->vnid);
2506        *vnp = bvn;
2507    }
2508
2509    return err;
2510}
2511
2512
2513
2514/*
2515 * get_vnode
2516 */
2517
2518status_t
2519get_vnode(nspace_id nsid, vnode_id vnid, void **data)
2520{
2521    int         err;
2522    vnode       *vn;
2523
2524    err = load_vnode(nsid, vnid, TRUE, &vn);
2525    if (err)
2526        return err;
2527    *data = vn->data;
2528    return 0;
2529}
2530
2531
2532/*
2533 * put_vnode
2534 */
2535
2536status_t
2537put_vnode(nspace_id nsid, vnode_id vnid)
2538{
2539    vnode           *vn;
2540
2541    LOCK(vnlock);
2542    vn = lookup_vnode(nsid, vnid);
2543    if (!vn) {
2544        UNLOCK(vnlock);
2545        return FS_ENOENT;
2546    }
2547    UNLOCK(vnlock);
2548    dec_vnode(vn, TRUE);
2549    return 0;
2550}
2551
2552/*
2553 * new_vnode
2554 */
2555
2556status_t
2557new_vnode(nspace_id nsid, vnode_id vnid, void *data)
2558{
2559//    int retries = 20;
2560    vnode *vn;
2561    int err;
2562
2563	LOCK(vnlock);
2564
2565restart:
2566	if ((vn = lookup_vnode(nsid, vnid)) != NULL) {
2567		// oh, we requested a new vnode although there already
2568		// exist one - compare the private node data and bail
2569		// out if needed.
2570
2571		if (vn->busy) {
2572			TRACE("new_vnode(): vnode exists and is busy!\n");
2573			UNLOCK(vnlock);
2574			snooze(5000);
2575			LOCK(vnlock);
2576
2577//			if (retries-- >= 0)
2578				goto restart;
2579
2580//			printf("new_vnode(): still busy, but continue to our doom!\n");
2581		}
2582
2583		if (vn->data != data)
2584			PANIC("new_vnode(): vnode already exists with different data (vnode id = %Ld)!\n", vnid);
2585		else {
2586			printf("new_vnode(): vnode already exists with the same data (vnode id = %Ld)\n", vnid);
2587			vn->rcnt++;
2588        	UNLOCK(vnlock);
2589			return 0;
2590		}
2591	}
2592
2593	vn = steal_vnode(FREE_LIST);
2594    if (!vn) {
2595        vn = steal_vnode(USED_LIST);
2596        if (!vn) {
2597            PANIC("OUT OF VNODE!!!\n");
2598            UNLOCK(vnlock);
2599            return FS_ENOMEM;
2600        }
2601        flush_vnode(vn, TRUE);
2602    }
2603
2604    vn->ns = nsidtons(nsid);
2605    if (!vn->ns) {
2606        UNLOCK(vnlock);
2607        return FS_ENOENT;
2608    }
2609    vn->vnid = vnid;
2610    vn->data = data;
2611    vn->rcnt = 1;
2612    err = sort_vnode(vn);
2613    UNLOCK(vnlock);
2614    return err;
2615}
2616
2617/*
2618 * remove_vnode
2619 */
2620
2621status_t
2622remove_vnode(nspace_id nsid, vnode_id vnid)
2623{
2624    vnode       *vn;
2625
2626    LOCK(vnlock);
2627    vn = lookup_vnode(nsid, vnid);
2628    if (!vn || (vn->rcnt == 0)) {
2629        UNLOCK(vnlock);
2630        return FS_ENOENT;
2631    }
2632    vn->remove = TRUE;
2633    UNLOCK(vnlock);
2634    return 0;
2635}
2636
2637/*
2638 * unremove_vnode
2639 */
2640
2641status_t
2642unremove_vnode(nspace_id nsid, vnode_id vnid)
2643{
2644    vnode       *vn;
2645
2646    LOCK(vnlock);
2647    vn = lookup_vnode(nsid, vnid);
2648    if (!vn || (vn->rcnt == 0)) {
2649        UNLOCK(vnlock);
2650        return FS_ENOENT;
2651    }
2652    vn->remove = FALSE;
2653    UNLOCK(vnlock);
2654    return 0;
2655}
2656
2657/*
2658 * is_vnode_removed
2659 */
2660
2661status_t
2662is_vnode_removed(nspace_id nsid, vnode_id vnid)
2663{
2664    vnode       *vn;
2665    int         res;
2666
2667    LOCK(vnlock);
2668    vn = lookup_vnode(nsid, vnid);
2669    if (!vn) {
2670        UNLOCK(vnlock);
2671        return FS_ENOENT;
2672    }
2673    res = vn->remove;
2674    UNLOCK(vnlock);
2675    return res;
2676}
2677
2678/*
2679 * miscelleanous vnode functions
2680 */
2681
2682
2683static void
2684inc_vnode(vnode *vn)
2685{
2686	TRACE("inc_vnode(id = %Ld)\n", vn->vnid);
2687
2688    LOCK(vnlock);
2689    vn->rcnt++;
2690    UNLOCK(vnlock);
2691}
2692
2693static void
2694dec_vnode(vnode *vn, char r)
2695{
2696    vnode       *ovn;
2697
2698    LOCK(vnlock);
2699    vn->rcnt--;
2700	TRACE("dec_vnode(): id = %Ld, rcnt = %d (after decreasing)\n", vn->vnid, vn->rcnt);
2701    if (vn->rcnt == 0) {
2702        if (vn->remove) {
2703            vn->busy = TRUE;
2704            move_vnode(vn, LOCKED_LIST);
2705            UNLOCK(vnlock);
2706            (*vn->ns->fs->ops.remove_vnode)(vn->ns->data, vn->data, r);
2707            LOCK(vnlock);
2708            clear_vnode(vn);
2709            move_vnode(vn, FREE_LIST);
2710        } else {
2711            move_vnode(vn, USED_LIST);
2712            if (lists[USED_LIST].num > usdvnnum) {
2713                ovn = steal_vnode(USED_LIST);
2714                flush_vnode(ovn, r);
2715                move_vnode(ovn, FREE_LIST);
2716            }
2717        }
2718	}
2719    UNLOCK(vnlock);
2720
2721    return;
2722}
2723
2724static void
2725clear_vnode(vnode *vn)
2726{
2727    DeleteSL(skiplist, vn);
2728
2729    if (vn->nspace.prev)
2730        vn->nspace.prev->nspace.next = vn->nspace.next;
2731    else
2732        vn->ns->vnodes.head = vn->nspace.next;
2733    if (vn->nspace.next)
2734        vn->nspace.next->nspace.prev = vn->nspace.prev;
2735    else
2736        vn->ns->vnodes.tail = vn->nspace.prev;
2737    vn->nspace.next = vn->nspace.prev = NULL;
2738
2739    vn->vnid = invalid_vnid;
2740    vn->ns = NULL;
2741    vn->remove = FALSE;
2742    vn->data = NULL;
2743    vn->rcnt = 0;
2744    vn->busy = FALSE;
2745    vn->mounted = NULL;
2746}
2747
2748static int
2749sort_vnode(vnode *vn)
2750{
2751    if (!InsertSL(skiplist, vn))
2752        return FS_ENOMEM;
2753
2754    vn->nspace.next = vn->ns->vnodes.head;
2755    vn->nspace.prev = NULL;
2756    if (vn->ns->vnodes.head)
2757        vn->ns->vnodes.head->nspace.prev = vn;
2758    else
2759        vn->ns->vnodes.tail = vn;
2760    vn->ns->vnodes.head = vn;
2761    return 0;
2762}
2763
2764static void
2765move_vnode(vnode *vn, int list)
2766{
2767    if (vn->list.prev)
2768        vn->list.prev->list.next = vn->list.next;
2769    else
2770        lists[(int)vn->inlist].head = vn->list.next;
2771    if (vn->list.next)
2772        vn->list.next->list.prev = vn->list.prev;
2773    else
2774        lists[(int)vn->inlist].tail = vn->list.prev;
2775    lists[(int)vn->inlist].num--;
2776    vn->inlist = list;
2777    vn->list.next = NULL;
2778    vn->list.prev = lists[list].tail;
2779    if (vn->list.prev)
2780        vn->list.prev->list.next = vn;
2781    else
2782        lists[list].head = vn;
2783    lists[list].tail = vn;
2784    lists[list].num++;
2785}
2786
2787static vnode *
2788steal_vnode(int list)
2789{
2790    vnode       *vn;
2791
2792    vn = lists[list].head;
2793    if (!vn)
2794        return NULL;
2795    move_vnode(vn, LOCKED_LIST);
2796    return vn;
2797}
2798
2799static void
2800flush_vnode(vnode *vn, char r)
2801{
2802    int     err;
2803
2804    vn->busy = TRUE;
2805    UNLOCK(vnlock);
2806    err = (*vn->ns->fs->ops.write_vnode)(vn->ns->data, vn->data, r);
2807    if (err)
2808        PANIC("ERROR WRITING VNODE!!!\n");
2809    LOCK(vnlock);
2810    vn->busy = FALSE;
2811    clear_vnode(vn);
2812}
2813
2814static vnode *
2815lookup_vnode(nspace_id nsid, vnode_id vnid)
2816{
2817    vnode       fakevn;
2818    nspace      fakens;
2819
2820    fakens.nsid = nsid;
2821    fakevn.ns = &fakens;
2822    fakevn.vnid = vnid;
2823    return SearchSL(skiplist, &fakevn);
2824}
2825
2826static int
2827load_vnode(nspace_id nsid, vnode_id vnid, char r, vnode **vnp)
2828{
2829    int             err;
2830    vnode           *vn;
2831
2832    LOCK(vnlock);
2833    while (TRUE) {
2834        vn = lookup_vnode(nsid, vnid);
2835        if (vn) {
2836            if (vn->busy) {
2837                UNLOCK(vnlock);
2838                snooze(SLEEP_TIME);
2839                LOCK(vnlock);
2840                continue;
2841            } else
2842                break;
2843		}
2844
2845        vn = steal_vnode(FREE_LIST);
2846        if (!vn) {
2847            vn = steal_vnode(USED_LIST);
2848            if (!vn)
2849                PANIC("OUT OF VNODE!!!\n");
2850        } else
2851            break;
2852
2853        flush_vnode(vn, r);
2854        move_vnode(vn, FREE_LIST);
2855    }
2856
2857    if (vn->ns == NULL) {
2858        vn->ns = nsidtons(nsid);
2859        if (!vn->ns) {
2860            err = FS_ENOENT;
2861            goto error1;
2862        }
2863        vn->vnid = vnid;
2864        vn->busy = TRUE;
2865        err = sort_vnode(vn);
2866        if (err)
2867            goto error2;
2868        move_vnode(vn, LOCKED_LIST);
2869        UNLOCK(vnlock);
2870        err = (*vn->ns->fs->ops.read_vnode)(vn->ns->data, vnid, r, &vn->data);
2871        LOCK(vnlock);
2872        vn->busy = FALSE;
2873        if (err)
2874            goto error2;
2875        vn->rcnt = 1;
2876    } else {
2877        vn->rcnt++;
2878        if (vn->rcnt == 1)
2879            move_vnode(vn, LOCKED_LIST);
2880    }
2881    *vnp = vn;
2882    UNLOCK(vnlock);
2883    return 0;
2884
2885error2:
2886    clear_vnode(vn);
2887error1:
2888    move_vnode(vn, FREE_LIST);
2889    UNLOCK(vnlock);
2890    return err;
2891}
2892
2893static int
2894compare_vnode(vnode *vna, vnode *vnb)
2895{
2896    if (vna->vnid > vnb->vnid)
2897        return 1;
2898    else
2899        if (vna->vnid < vnb->vnid)
2900            return -1;
2901        else
2902            if (vna->ns->nsid > vnb->ns->nsid)
2903                return 1;
2904            else
2905                if (vna->ns->nsid < vnb->ns->nsid)
2906                    return -1;
2907                else
2908                    return 0;
2909}
2910
2911/*
2912 * path management functions
2913 */
2914
2915int
2916new_path(const char *path, char **copy)
2917{
2918    const char  *q, *r;
2919    char        *p;
2920    int         l, s;
2921
2922    if (!path) {
2923        *copy = NULL;
2924        return 0;
2925    }
2926    l = strlen(path);
2927    if (l == 0)
2928        return FS_ENOENT;
2929    s = l;
2930    if (path[l-1] == '/')
2931        s++;
2932
2933    if (l >= MAXPATHLEN)
2934        return FS_ENAMETOOLONG;
2935
2936    q = path;
2937    while (*q != '\0') {
2938        while (*q == '/')
2939            q++;
2940        r = q;
2941        while ((*q != '/') && (*q != '\0'))
2942            q++;
2943        if (q - r >= FILE_NAME_LENGTH)
2944            return FS_ENAMETOOLONG;
2945    }
2946
2947    p = (char *) malloc(s+1);
2948    if (!p)
2949        return FS_ENOMEM;
2950
2951    /* ### do real checking: MAXPATHLEN, max file name len, buffer address... */
2952
2953    strcpy(p, path);
2954    if (p[l-1] == '/') {
2955        p[l] = '.';
2956        p[l+1] = '\0';
2957    }
2958    *copy = p;
2959    return 0;
2960}
2961
2962void
2963free_path(char *p)
2964{
2965    if (p) {
2966        free(p);
2967    }
2968}
2969
2970static char *
2971cat_paths(char *a, char *b)
2972{
2973    char        *p;
2974
2975    p = (char *) realloc(a, strlen(a) + strlen(b) + 2);
2976    if (!p)
2977        return NULL;
2978    strcat(p, "/");
2979    strcat(p, b);
2980    return p;
2981}
2982
2983/*
2984 * mount point management functions
2985 */
2986
2987static int
2988is_mount_vnode(vnode *mount, vnode **root)
2989{
2990    nspace      *ns;
2991
2992    LOCK(vnlock);
2993    ns = mount->mounted;
2994    if (ns) {
2995        *root = ns->root;
2996        ns->root->rcnt++;
2997    }
2998    UNLOCK(vnlock);
2999    return (ns != NULL);
3000}
3001
3002static int
3003is_mount_vnid(nspace_id nsid, vnode_id vnid, vnode_id *mount)
3004{
3005    nspace      *ns;
3006
3007    for(ns = nshead; ns; ns = ns->next) {
3008        if (!ns->mount)
3009            continue;
3010        if (ns->mount->ns->nsid != nsid)
3011            continue;
3012        if (ns->mount->vnid != vnid)
3013            continue;
3014        *mount = ns->root->vnid;
3015        return TRUE;
3016    }
3017    return FALSE;
3018}
3019
3020static int
3021is_root(vnode *root, vnode **mount)
3022{
3023    if ((root->ns->root == root) && root->ns->mount) {
3024        *mount = root->ns->mount;
3025        inc_vnode(*mount);
3026        return TRUE;
3027    } else
3028        return FALSE;
3029}
3030
3031/*
3032 * file descriptor management functions
3033 */
3034
3035static ofile *
3036get_fd(int kernel, int fd, int type)
3037{
3038    ofile       *f;
3039    fdarray     *fds;
3040
3041    f = NULL;
3042    if (kernel)
3043        fds = global_fds;
3044    else
3045        fds = get_cur_ioctx()->fds;
3046    LOCK(fds->lock);
3047    if ((fd >= 0) && (fd < fds->num) && fds->fds[fd]) {
3048        f = fds->fds[fd];
3049        if (f->type & type)
3050            atomic_add(&f->rcnt, 1);
3051        else
3052            f = NULL;
3053    }
3054    UNLOCK(fds->lock);
3055    return f;
3056}
3057
3058
3059static int
3060put_fd(ofile *f)
3061{
3062    long            cnt;
3063
3064    cnt = atomic_add(&f->rcnt, -1);
3065    if (cnt == 1)
3066        invoke_free(f);
3067    return 0;
3068}
3069
3070static int
3071new_fd(int kernel, int nfd, ofile *f, int fd, int coe)
3072{
3073    int         i, j, num, end;
3074    fdarray     *fds;
3075    ofile       *of;
3076    int         err;
3077    long        cnt;
3078
3079    if (kernel)
3080        fds = global_fds;
3081    else
3082        fds = get_cur_ioctx()->fds;
3083
3084    LOCK(fds->lock);
3085
3086    num = fds->num;
3087
3088    if (!f) {
3089        if ((fd < 0) || (fd >= num)) {
3090            err = FS_EBADF;
3091            goto error1;
3092        }
3093        f = fds->fds[fd];
3094        if (!f) {
3095            err = FS_EBADF;
3096            goto error1;
3097        }
3098    }
3099
3100    atomic_add(&f->rcnt, 1);
3101    atomic_add(&f->ocnt, 1);
3102
3103    if (nfd >= 0) {
3104        if (nfd >= num) {
3105            err = FS_EBADF;
3106            goto error2;
3107        }
3108        of = fds->fds[nfd];
3109        fds->fds[nfd] = f;
3110        SETBIT(fds->alloc, nfd, TRUE);
3111        SETBIT(fds->coes, nfd, coe);
3112
3113        UNLOCK(fds->lock);
3114        if (of) {
3115            cnt = atomic_add(&of->ocnt, -1);
3116            if (cnt == 1)
3117                invoke_close(of);
3118            cnt = atomic_add(&of->rcnt, -1);
3119            if (cnt == 1)
3120                invoke_free(of);
3121        }
3122        return nfd;
3123    }
3124
3125    end = num & ~31;
3126    for(j=0; j<end; j+=32)
3127        if (fds->alloc[j/32] != 0xffffffff)
3128            for(i=j; i<j+32; i++)
3129                if (!GETBIT(fds->alloc, i))
3130                    goto found;
3131    for(i=end; i<num; i++)
3132        if (!GETBIT(fds->alloc, i))
3133            goto found;
3134
3135    err = FS_EMFILE;
3136    goto error2;
3137
3138found:
3139
3140    SETBIT(fds->alloc, i, 1);
3141    fds->fds[i] = f;
3142    SETBIT(fds->coes, i, coe);
3143    UNLOCK(fds->lock);
3144    return i;
3145
3146error2:
3147    atomic_add(&f->rcnt, -1);
3148    atomic_add(&f->ocnt, -1);
3149error1:
3150    UNLOCK(fds->lock);
3151    return err;
3152}
3153
3154static int
3155remove_fd(int kernel, int fd, int type)
3156{
3157    ofile       *f;
3158    fdarray     *fds;
3159    long        cnt;
3160    int         err;
3161
3162    f = NULL;
3163    if (kernel)
3164        fds = global_fds;
3165    else
3166        fds = get_cur_ioctx()->fds;
3167    LOCK(fds->lock);
3168    if ((fd >= 0) && (fd < fds->num) && fds->fds[fd]) {
3169        f = fds->fds[fd];
3170        if (f->type & type) {
3171            SETBIT(fds->alloc, fd, 0);
3172            fds->fds[fd] = NULL;
3173        } else
3174            f = NULL;
3175    }
3176    UNLOCK(fds->lock);
3177    if (f == NULL)
3178        return FS_EBADF;
3179
3180    err = 0;
3181    cnt = atomic_add(&f->ocnt, -1);
3182    if (cnt == 1)
3183        err = invoke_close(f);
3184    cnt = atomic_add(&f->rcnt, -1);
3185    if (cnt == 1)
3186        invoke_free(f);
3187    return err;
3188}
3189
3190#if 0
3191static int
3192get_coe(int kernel, int fd, int type, int *coe)
3193{
3194    ofile       *f;
3195    fdarray     *fds;
3196
3197    f = NULL;
3198    if (kernel)
3199        fds = global_fds;
3200    else
3201        fds = get_cur_ioctx()->fds;
3202    LOCK(fds->lock);
3203    if ((fd >= 0) && (fd < fds->num) && fds->fds[fd]) {
3204        f = fds->fds[fd];
3205        if (f->type == type) {
3206            *coe = GETBIT(fds->coes, fd);
3207            UNLOCK(fds->lock);
3208            return 0;
3209        }
3210    }
3211    UNLOCK(fds->lock);
3212    return FS_EBADF;
3213}
3214
3215static int
3216set_coe(int kernel, int fd, int type, int coe)
3217{
3218    ofile       *f;
3219    fdarray     *fds;
3220
3221    f = NULL;
3222    if (kernel)
3223        fds = global_fds;
3224    else
3225        fds = get_cur_ioctx()->fds;
3226    LOCK(fds->lock);
3227    if ((fd >= 0) && (fd < fds->num) && fds->fds[fd]) {
3228        f = fds->fds[fd];
3229        if (f->type == type) {
3230            SETBIT(fds->coes, fd, coe);
3231            UNLOCK(fds->lock);
3232            return 0;
3233        }
3234    }
3235    UNLOCK(fds->lock);
3236    return FS_EBADF;
3237}
3238
3239static int
3240get_omode(int kernel, int fd, int type, int *omode)
3241{
3242    ofile       *f;
3243    fdarray     *fds;
3244
3245    f = NULL;
3246    if (kernel)
3247        fds = global_fds;
3248    else
3249        fds = get_cur_ioctx()->fds;
3250    LOCK(fds->lock);
3251    if ((fd >= 0) && (fd < fds->num) && fds->fds[fd]) {
3252        f = fds->fds[fd];
3253        if (f->type == type) {
3254            *omode = f->omode;
3255            UNLOCK(fds->lock);
3256            return 0;
3257        }
3258    }
3259    UNLOCK(fds->lock);
3260    return FS_EBADF;
3261}
3262#endif
3263
3264static int
3265invoke_close(ofile *f)
3266{
3267    int     err;
3268    vnode   *vn;
3269
3270    vn = f->vn;
3271    switch (f->type) {
3272    case FD_FILE:
3273        err = (*vn->ns->fs->ops.close)(vn->ns->data, vn->data, f->cookie);
3274        break;
3275    case FD_DIR:
3276        err = (*vn->ns->fs->ops.closedir)(vn->ns->data, vn->data, f->cookie);
3277        break;
3278    case FD_ATTR_DIR:
3279        err = (*vn->ns->fs->ops.close_attrdir)(vn->ns->data, vn->data,
3280        	f->cookie);
3281        break;
3282    case FD_WD:
3283    default:
3284        err = 0;
3285        break;
3286    }
3287    return err;
3288}
3289
3290static int
3291invoke_free(ofile *f)
3292{
3293    vnode           *vn;
3294    op_free_cookie  *op = NULL;
3295
3296    vn = f->vn;
3297    switch(f->type) {
3298    case FD_FILE:
3299        op = vn->ns->fs->ops.free_cookie;
3300        break;
3301    case FD_DIR:
3302        op = vn->ns->fs->ops.free_dircookie;
3303        break;
3304    case FD_WD:
3305        op = NULL;
3306        break;
3307    case FD_ATTR_DIR:
3308        op = vn->ns->fs->ops.free_attrdircookie;
3309        break;
3310    }
3311    if (op)
3312        (*op)(vn->ns->data, vn->data, f->cookie);
3313    dec_vnode(vn, FALSE);
3314
3315    free(f);
3316    return 0;
3317}
3318
3319/*
3320 * other routines
3321 */
3322
3323static nspace *
3324nsidtons(nspace_id nsid)
3325{
3326    nspace      *ns;
3327
3328	if (nsid < 0)
3329		return NULL;
3330
3331    ns = nstab[nsid % nns];
3332    if (!ns || (ns->nsid != nsid) || ns->shutdown)
3333        return NULL;
3334    return ns;
3335}
3336
3337#if 0
3338static int
3339alloc_wd_fd(int kernel, vnode *vn, int coe, int *fdp)
3340{
3341    int             err;
3342    ofile           *f;
3343    int             nfd;
3344
3345    /*
3346    find a file descriptor
3347    */
3348
3349    f = (ofile *) calloc(sizeof(ofile), 1);
3350    if (!f) {
3351        err = FS_ENOMEM;
3352        goto error1;
3353    }
3354
3355    f->type = FD_WD;
3356    f->vn = vn;
3357    f->rcnt = 0;
3358    f->ocnt = 0;
3359
3360    nfd = new_fd(kernel, -1, f, -1, coe);
3361    if (nfd < 0) {
3362        err = FS_EMFILE;
3363        goto error2;
3364    }
3365
3366    *fdp = nfd;
3367    return 0;
3368
3369error2:
3370    free(f);
3371error1:
3372    return err;
3373}
3374#endif
3375
3376
3377/*
3378 * file system operations
3379 */
3380
3381void *
3382install_file_system(vnode_ops *ops, const char *name, int fixed, image_id aid)
3383{
3384    fsystem     *fs;
3385    int         i;
3386
3387    fs = (fsystem *) malloc(sizeof(fsystem));
3388    if (!fs)
3389        return NULL;
3390
3391    memcpy(&fs->ops, ops, sizeof(vnode_ops));
3392    strcpy(fs->name, name);
3393    fs->rcnt = 1;
3394    fs->fixed = fixed;
3395    fs->aid = aid;
3396
3397    for(i=0; i<nfs; i++, nxfsid++)
3398        if (!fstab[nxfsid % nfs]) {
3399            fstab[nxfsid % nfs] = fs;
3400            fs->fsid = nxfsid;
3401            nxfsid++;
3402            break;
3403        }
3404
3405    if (i == nfs) {
3406        free(fs);
3407        return NULL;
3408    }
3409    return (void *)fs;
3410}
3411
3412status_t
3413initialize_file_system(const char *device, const char *fsName, void *params,
3414	int paramLength)
3415{
3416	struct nspace *mount;
3417	status_t error;
3418
3419	fsystem *fs = inc_file_system(fsName);
3420	if (fs == NULL || fs->ops.initialize == NULL)
3421		return FS_ERROR;
3422
3423	mount = (nspace *)malloc(sizeof(nspace));
3424	if (add_nspace(mount, NULL, "myfs", -1, -1) < FS_OK) {
3425		error = FS_ERROR;
3426	} else {
3427	    error = (*fs->ops.initialize)(device, params, paramLength);
3428		remove_nspace(mount);
3429	}
3430
3431	dec_file_system(fs);
3432
3433	return error;
3434}
3435
3436static fsystem *
3437load_file_system(const char *name)
3438{
3439    return NULL;
3440}
3441
3442static int
3443unload_file_system(fsystem *fs)
3444{
3445    fstab[fs->fsid % nfs] = NULL;
3446    free(fs);
3447    return 0;
3448}
3449
3450
3451static fsystem *
3452inc_file_system(const char *name)
3453{
3454    fsystem         *fs;
3455    int             i;
3456
3457    fs = NULL;
3458    LOCK(fstablock);
3459
3460    for(i=0; i<nfs; i++)
3461        if (fstab[i] && !strcmp(fstab[i]->name, name)) {
3462            fs = fstab[i];
3463            fs->rcnt++;
3464            break;
3465        }
3466
3467    if (!fs)
3468        fs = load_file_system(name);
3469
3470    UNLOCK(fstablock);
3471
3472    return fs;
3473}
3474
3475static int
3476dec_file_system(fsystem *fs)
3477{
3478    LOCK(fstablock);
3479
3480    fs->rcnt--;
3481    if (!fs->fixed && (fs->rcnt == 0))
3482        unload_file_system(fs);
3483
3484    UNLOCK(fstablock);
3485    return 0;
3486}
3487
3488
3489static fdarray *
3490new_fds(int num)
3491{
3492    fdarray *fds;
3493    size_t      sz;
3494
3495    sz = sizeof(fdarray) + (num-1) * sizeof(void *) + 2*BITSZ(num);
3496    fds = (fdarray *) malloc(sz);
3497    if (!fds)
3498        return NULL;
3499    memset(fds, 0, sz);
3500    fds->rcnt = 1;
3501    if (new_lock(&fds->lock, "fdlock") < 0) {
3502        free(fds);
3503        return NULL;
3504    }
3505    fds->num = num;
3506    fds->alloc = (ulong *) &fds->fds[num];
3507    fds->coes = &fds->alloc[BITSZ(num) / sizeof(ulong)];
3508    return fds;
3509}
3510
3511#if 0
3512static int
3513free_fds(fdarray *fds)
3514{
3515    long    cnt;
3516    int     i;
3517    ofile   *f;
3518
3519    for(i=0; i<fds->num; i++)
3520        if (fds->fds[i]) {
3521            f = fds->fds[i];
3522            cnt = atomic_add(&f->ocnt, -1);
3523            if (cnt == 1)
3524                invoke_close(f);
3525            cnt = atomic_add(&f->rcnt, -1);
3526            if (cnt == 1)
3527                invoke_free(f);
3528        }
3529    delete_sem(fds->lock.s);
3530    free(fds);
3531    return 0;
3532}
3533#endif
3534
3535// dummies
3536
3537
3538status_t
3539notify_listener(int op, nspace_id nsid, vnode_id vnida,	vnode_id vnidb, vnode_id vnidc, const char *name)
3540{
3541#ifdef DEBUG
3542	printf("notify_listener: op = %d\n", op);
3543#endif
3544
3545#ifdef USED_IN_FS_SHELL
3546	return send_notification(0, 0, FSH_NOTIFY_LISTENER, op, nsid, -1, vnida, vnidb, vnidc, name);
3547#else
3548	return send_notification(0, 0, 0x666, op, nsid, -1, vnida, vnidb, vnidc, name);
3549#endif
3550}
3551
3552
3553status_t
3554send_notification(port_id port, long token, ulong what, long op, nspace_id nsida,
3555		nspace_id nsidb, vnode_id vnida, vnode_id vnidb, vnode_id vnidc,
3556		const char *name)
3557{
3558#ifdef USED_IN_FS_SHELL
3559	update_message message;
3560#endif
3561
3562#ifdef DEBUG
3563	char *text;
3564
3565	switch (op) {
3566		case B_ENTRY_CREATED:
3567			text = "B_ENTRY_CREATED";
3568			break;
3569		case B_ENTRY_REMOVED:
3570			text = "B_ENTRY_REMOVED";
3571			break;
3572		case B_ENTRY_MOVED:
3573			text = "B_ENTRY_MOVED";
3574			break;
3575		case B_STAT_CHANGED:
3576			text = "B_STAT_CHANGED";
3577			break;
3578		case B_ATTR_CHANGED:
3579			text = "B_ATTR_CHANGED";
3580			break;
3581		case B_DEVICE_MOUNTED:
3582			text = "B_DEVICE_MOUNTED";
3583			break;
3584		case B_DEVICE_UNMOUNTED:
3585			text = "B_DEVICE_UNMOUNTED";
3586			break;
3587		default:
3588			text = "unknown operation...";
3589			break;
3590	}
3591	printf("send_notification... op = %s, name = %s, port = %ld, token = %ld\n",
3592		text, name, port, token);
3593#endif
3594
3595#ifdef USED_IN_FS_SHELL
3596	message.op = op;
3597	message.device = nsida;
3598	message.toDevice = nsidb;
3599	message.parentNode = vnida;
3600	message.targetNode = vnidb;
3601	message.node = vnidc;
3602
3603	if (name != NULL) {
3604		strcpy(message.name, name);
3605			// name is 256 character at maximum
3606	} else
3607		message.name[0] = '\0';
3608
3609	return write_port(gTrackerPort, what, &message, sizeof(message));
3610#else
3611	return FS_OK;
3612#endif
3613}
3614
3615#ifdef COMPILE_FOR_R5
3616void
3617notify_select_event(selectsync *sync, uint32 ref)
3618{
3619}
3620#else
3621status_t
3622notify_select_event(selectsync *sync, uint32 ref, uint8 event)
3623{
3624	return FS_UNSUPPORTED;
3625}
3626#endif
3627
3628