Blob


1 /*
2 * 9P to FUSE translator. Acts as FUSE server, 9P client.
3 * Mounts 9P servers via FUSE kernel module.
4 *
5 * There are four procs in this threaded program
6 * (ignoring the one that runs main and then exits).
7 * The first proc reads FUSE requests from /dev/fuse.
8 * It sends the requests over a channel to a second proc,
9 * which serves the requests. Each request runs in a
10 * thread in that second proc. Those threads do write
11 * FUSE replies, which in theory might block, but in practice don't.
12 * The 9P interactions are handled by lib9pclient, which
13 * allocates two more procs, one for reading and one for
14 * writing the 9P connection. Thus the many threads in the
15 * request proc can do 9P interactions without blocking.
16 */
18 #define _GNU_SOURCE 1 /* for O_DIRECTORY on Linux */
19 #include "a.h"
21 /* GNUisms */
22 #ifndef O_DIRECTORY
23 #define O_DIRECTORY 0
24 #endif
26 #ifndef O_LARGEFILE
27 # define O_LARGEFILE 0
28 #endif
30 /*
31 * Work around glibc's broken <bits/fcntl.h> which defines
32 * O_LARGEFILE to 0 on 64 bit architectures. But, on those same
33 * architectures, linux _forces_ O_LARGEFILE (which is always
34 * 0100000 in the kernel) at each file open. FUSE is all too
35 * happy to pass the flag onto us, where we'd have no idea what
36 * to do with it if we trusted glibc.
37 *
38 * On ARM however, the O_LARGEFILE is set correctly.
39 */
41 #if defined(__linux__) && !defined(__arm__)
42 # undef O_LARGEFILE
43 # define O_LARGEFILE 0100000
44 #endif
46 #ifndef O_CLOEXEC
47 # if defined(__linux__)
48 # define O_CLOEXEC 02000000 /* Sigh */
49 # else
50 # define O_CLOEXEC 0
51 # endif
52 #endif
54 #ifndef FMODE_EXEC
55 # if defined(__linux__)
56 # define FMODE_EXEC 040
57 # else
58 # define FMODE_EXEC 0
59 # endif
60 #endif
62 int debug;
63 char *argv0;
64 char *aname = "";
65 void fusedispatch(void*);
66 Channel *fusechan;
68 enum
69 {
70 STACK = 8192
71 };
73 /*
74 * The number of seconds that the kernel can cache
75 * returned file attributes. FUSE's default is 1.0.
76 * I haven't experimented with using 0.
77 */
78 double attrtimeout = 1.0;
80 /*
81 * The number of seconds that the kernel can cache
82 * the returned entry nodeids returned by lookup.
83 * I haven't experimented with other values.
84 */
85 double entrytimeout = 1.0;
87 CFsys *fsys;
88 CFid *fsysroot;
89 void init9p(char*, char*);
91 void
92 usage(void)
93 {
94 fprint(2, "usage: 9pfuse [-D] [-A attrtimeout] [-a aname] address mtpt\n");
95 exit(1);
96 }
98 void fusereader(void*);
99 void watchfd(void*);
101 void
102 threadmain(int argc, char **argv)
104 ARGBEGIN{
105 case 'D':
106 chatty9pclient++;
107 debug++;
108 break;
109 case 'A':
110 attrtimeout = atof(EARGF(usage()));
111 break;
112 case 'a':
113 aname = EARGF(usage());
114 break;
115 default:
116 usage();
117 }ARGEND
119 if(argc != 2)
120 usage();
122 quotefmtinstall();
123 fmtinstall('F', fcallfmt);
124 fmtinstall('M', dirmodefmt);
125 fmtinstall('G', fusefmt);
127 setsid(); /* won't be able to use console, but can't be interrupted */
129 init9p(argv[0], aname);
130 initfuse(argv[1]);
132 fusechan = chancreate(sizeof(void*), 0);
133 proccreate(fusedispatch, nil, STACK);
134 sendp(fusechan, nil); /* sync */
136 proccreate(fusereader, nil, STACK);
137 /*
138 * Now that we're serving FUSE, we can wait
139 * for the mount to finish and exit back to the user.
140 */
141 waitfuse();
142 threadexits(0);
145 void
146 fusereader(void *v)
148 FuseMsg *m;
150 while((m = readfusemsg()) != nil)
151 sendp(fusechan, m);
153 fusemtpt = nil; /* no need to unmount */
154 threadexitsall(0);
157 void
158 init9p(char *addr, char *spec)
160 int fd;
162 if(strcmp(addr, "-") == 0)
163 fd = 0;
164 else
165 if((fd = dial(netmkaddr(addr, "tcp", "564"), nil, nil, nil)) < 0)
166 sysfatal("dial %s: %r", addr);
167 proccreate(watchfd, (void*)(uintptr)fd, STACK);
168 if((fsys = fsmount(fd, spec)) == nil)
169 sysfatal("fsmount: %r");
170 fsysroot = fsroot(fsys);
173 /*
174 * FUSE uses nodeids to refer to active "struct inodes"
175 * (9P's unopened fids). FUSE uses fhs to refer to active
176 * "struct fuse_files" (9P's opened fids). The choice of
177 * numbers is up to us except that nodeid 1 is the root directory.
178 * We use the same number space for both and call the
179 * bookkeeping structure a FuseFid.
181 * FUSE requires nodeids to have associated generation
182 * numbers. If we reuse a nodeid, we have to bump the
183 * generation number to guarantee that the nodeid,gen
184 * combination is never reused.
186 * There are also inode numbers returned in directory reads
187 * and file attributes, but these do NOT need to match the nodeids.
188 * We use a combination of qid.path and qid.type as the inode
189 * number.
190 */
191 /*
192 * TO DO: reference count the fids.
193 */
194 typedef struct Fusefid Fusefid;
195 struct Fusefid
197 Fusefid *next;
198 CFid *fid;
199 int ref;
200 int id;
201 int gen;
202 int isnodeid;
204 /* directory read state */
205 Dir *d0;
206 Dir *d;
207 int nd;
208 int off;
209 };
211 Fusefid **fusefid;
212 int nfusefid;
213 Fusefid *freefusefidlist;
215 Fusefid*
216 allocfusefid(void)
218 Fusefid *f;
220 if((f = freefusefidlist) == nil){
221 f = emalloc(sizeof *f);
222 fusefid = erealloc(fusefid, (nfusefid+1)*sizeof *fusefid);
223 f->id = nfusefid;
224 fusefid[f->id] = f;
225 nfusefid++;
226 }else
227 freefusefidlist = f->next;
228 f->next = nil;
229 f->ref = 1;
230 f->isnodeid = -1;
231 return f;
234 void
235 freefusefid(Fusefid *f)
237 if(--f->ref > 0)
238 return;
239 assert(f->ref == 0);
240 if(f->fid)
241 fsclose(f->fid);
242 if(f->d0)
243 free(f->d0);
244 f->off = 0;
245 f->d0 = nil;
246 f->fid = nil;
247 f->d = nil;
248 f->nd = 0;
249 f->next = freefusefidlist;
250 f->isnodeid = -1;
251 freefusefidlist = f;
254 uvlong
255 _alloc(CFid *fid, int isnodeid)
257 Fusefid *ff;
259 ff = allocfusefid();
260 ff->fid = fid;
261 ff->isnodeid = isnodeid;
262 ff->gen++;
263 return ff->id+2; /* skip 0 and 1 */
266 uvlong
267 allocfh(CFid *fid)
269 return _alloc(fid, 0);
272 uvlong
273 allocnodeid(CFid *fid)
275 return _alloc(fid, 1);
278 Fusefid*
279 lookupfusefid(uvlong id, int isnodeid)
281 Fusefid *ff;
282 if(id < 2 || id >= nfusefid+2)
283 return nil;
284 ff = fusefid[(int)id-2];
285 if(ff->isnodeid != isnodeid)
286 return nil;
287 return ff;
290 CFid*
291 _lookupcfid(uvlong id, int isnodeid)
293 Fusefid *ff;
295 if((ff = lookupfusefid(id, isnodeid)) == nil)
296 return nil;
297 return ff->fid;
300 CFid*
301 fh2fid(uvlong fh)
303 return _lookupcfid(fh, 0);
306 CFid*
307 nodeid2fid(uvlong nodeid)
309 if(nodeid == 1)
310 return fsysroot;
311 return _lookupcfid(nodeid, 1);
314 uvlong
315 qid2inode(Qid q)
317 return q.path | ((uvlong)q.type<<56);
320 void
321 dir2attr(Dir *d, struct fuse_attr *attr)
323 attr->ino = qid2inode(d->qid);
324 attr->size = d->length;
325 attr->blocks = (d->length+8191)/8192;
326 attr->atime = d->atime;
327 attr->mtime = d->mtime;
328 attr->ctime = d->mtime; /* not right */
329 attr->atimensec = 0;
330 attr->mtimensec = 0;
331 attr->ctimensec = 0;
332 attr->mode = d->mode&0777;
333 if(d->mode&DMDIR)
334 attr->mode |= S_IFDIR;
335 else if(d->mode&DMSYMLINK)
336 attr->mode |= S_IFLNK;
337 else
338 attr->mode |= S_IFREG;
339 attr->nlink = 1; /* works for directories! - see FUSE FAQ */
340 attr->uid = getuid();
341 attr->gid = getgid();
342 attr->rdev = 0;
345 void
346 f2timeout(double f, __u64 *s, __u32 *ns)
348 *s = f;
349 *ns = (f - (int)f)*1e9;
352 void
353 dir2attrout(Dir *d, struct fuse_attr_out *out)
355 f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec);
356 dir2attr(d, &out->attr);
359 /*
360 * Lookup. Walk to the name given as the argument.
361 * The response is a fuse_entry_out giving full stat info.
362 */
363 void
364 fuselookup(FuseMsg *m)
366 char *name;
367 Fusefid *ff;
368 CFid *fid, *newfid;
369 Dir *d;
370 struct fuse_entry_out out;
372 name = m->tx;
373 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
374 replyfuseerrno(m, ESTALE);
375 return;
377 if(strchr(name, '/')){
378 replyfuseerrno(m, ENOENT);
379 return;
381 if((newfid = fswalk(fid, name)) == nil){
382 replyfuseerrstr(m);
383 return;
385 if((d = fsdirfstat(newfid)) == nil){
386 fsclose(newfid);
387 replyfuseerrstr(m);
388 return;
390 out.nodeid = allocnodeid(newfid);
391 ff = lookupfusefid(out.nodeid, 1);
392 out.generation = ff->gen;
393 f2timeout(attrtimeout, &out.attr_valid, &out.attr_valid_nsec);
394 f2timeout(entrytimeout, &out.entry_valid, &out.entry_valid_nsec);
395 dir2attr(d, &out.attr);
396 free(d);
397 replyfuse(m, &out, sizeof out);
400 /*
401 * Forget. Reference-counted clunk for nodeids.
402 * Does not send a reply.
403 * Each lookup response gives the kernel an additional reference
404 * to the returned nodeid. Forget says "drop this many references
405 * to this nodeid". Our fuselookup, when presented with the same query,
406 * does not return the same results (it allocates a new nodeid for each
407 * call), but if that ever changes, fuseforget already handles the ref
408 * counts properly.
409 */
410 void
411 fuseforget(FuseMsg *m)
413 struct fuse_forget_in *in;
414 Fusefid *ff;
416 in = m->tx;
417 if((ff = lookupfusefid(m->hdr->nodeid, 1)) == nil)
418 return;
419 if(ff->ref > in->nlookup){
420 ff->ref -= in->nlookup;
421 return;
423 if(ff->ref < in->nlookup)
424 fprint(2, "bad count in forget\n");
425 ff->ref = 1;
426 freefusefid(ff);
427 freefusemsg(m);
430 /*
431 * Getattr.
432 * Replies with a fuse_attr_out structure giving the
433 * attr for the requested nodeid in out.attr.
434 * Out.attr_valid and out.attr_valid_nsec give
435 * the amount of time that the attributes can
436 * be cached.
438 * Empirically, though, if I run ls -ld on the root
439 * twice back to back, I still get two getattrs,
440 * even with a one second attribute timeout!
441 */
442 void
443 fusegetattr(FuseMsg *m)
445 CFid *fid;
446 struct fuse_attr_out out;
447 Dir *d;
449 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
450 replyfuseerrno(m, ESTALE);
451 return;
453 if((d = fsdirfstat(fid)) == nil){
454 replyfuseerrstr(m);
455 return;
457 memset(&out, 0, sizeof out);
458 dir2attrout(d, &out);
459 free(d);
460 replyfuse(m, &out, sizeof out);
463 /*
464 * Setattr.
465 * FUSE treats the many Unix attribute setting routines
466 * more or less like 9P does, with a single message.
467 */
468 void
469 fusesetattr(FuseMsg *m)
471 CFid *fid, *nfid;
472 Dir d, *dd;
473 struct fuse_setattr_in *in;
474 struct fuse_attr_out out;
476 in = m->tx;
477 if(in->valid&FATTR_FH){
478 if((fid = fh2fid(in->fh)) == nil){
479 replyfuseerrno(m, ESTALE);
480 return;
482 }else{
483 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
484 replyfuseerrno(m, ESTALE);
485 return;
487 /*
488 * Special case: Linux issues a size change to
489 * truncate a file before opening it OTRUNC.
490 * Synthetic file servers (e.g., plumber) honor
491 * open(OTRUNC) but not wstat.
492 */
493 if(in->valid == FATTR_SIZE && in->size == 0){
494 if((nfid = fswalk(fid, nil)) == nil){
495 replyfuseerrstr(m);
496 return;
498 if(fsfopen(nfid, OWRITE|OTRUNC) < 0){
499 replyfuseerrstr(m);
500 fsclose(nfid);
501 return;
503 fsclose(nfid);
504 goto stat;
508 nulldir(&d);
509 if(in->valid&FATTR_SIZE)
510 d.length = in->size;
511 if(in->valid&FATTR_ATIME)
512 d.atime = in->atime;
513 if(in->valid&FATTR_MTIME)
514 d.mtime = in->mtime;
515 if(in->valid&FATTR_MODE)
516 d.mode = in->mode & 0777;
517 if((in->mode&S_IFMT) == S_IFDIR)
518 d.mode |= DMDIR;
519 if((in->valid&FATTR_UID) || (in->valid&FATTR_GID)){
520 /*
521 * I can't be bothered with these yet.
522 */
523 replyfuseerrno(m, EPERM);
524 return;
526 if(fsdirfwstat(fid, &d) < 0){
527 replyfuseerrstr(m);
528 return;
530 stat:
531 if((dd = fsdirfstat(fid)) == nil){
532 replyfuseerrstr(m);
533 return;
535 memset(&out, 0, sizeof out);
536 dir2attrout(dd, &out);
537 free(dd);
538 replyfuse(m, &out, sizeof out);
541 CFid*
542 _fuseopenfid(uvlong nodeid, int isdir, int openmode, int *err)
544 CFid *fid, *newfid;
546 if((fid = nodeid2fid(nodeid)) == nil){
547 *err = ESTALE;
548 return nil;
550 if(isdir && !(fsqid(fid).type&QTDIR)){
551 *err = ENOTDIR;
552 return nil;
554 if(openmode != OREAD && fsqid(fid).type&QTDIR){
555 *err = EISDIR;
556 return nil;
559 /* Clone fid to get one we can open. */
560 newfid = fswalk(fid, nil);
561 if(newfid == nil){
562 *err = errstr2errno();
563 return nil;
566 if(fsfopen(newfid, openmode) < 0){
567 *err = errstr2errno();
568 fsclose(newfid);
569 return nil;
572 return newfid;
575 /*
576 * Open & Opendir.
577 * Argument is a struct fuse_open_in.
578 * The mode field is ignored (presumably permission bits)
579 * and flags is the open mode.
580 * Replies with a struct fuse_open_out.
581 */
582 void
583 _fuseopen(FuseMsg *m, int isdir)
585 struct fuse_open_in *in;
586 struct fuse_open_out out;
587 CFid *fid;
588 int openmode, flags, err;
590 in = m->tx;
591 flags = in->flags;
592 openmode = flags&3;
593 flags &= ~3;
594 flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|FMODE_EXEC);
595 #ifdef O_NOFOLLOW
596 flags &= ~O_NOFOLLOW;
597 #endif
598 #ifdef O_LARGEFILE
599 flags &= ~O_LARGEFILE;
600 #endif
602 /*
603 * Discarding O_APPEND here is not completely wrong,
604 * because the host kernel will rewrite the offsets
605 * of write system calls for us. That's the best we
606 * can do on Unix anyway.
607 */
608 flags &= ~O_APPEND;
609 if(flags & O_TRUNC){
610 openmode |= OTRUNC;
611 flags &= ~O_TRUNC;
614 /*
615 * Could translate but not standard 9P:
616 * O_DIRECT -> ODIRECT
617 * O_NONBLOCK -> ONONBLOCK
618 */
619 if(flags){
620 fprint(2, "unexpected open flags requested=%#uo unhandled=%#uo\n", (uint)in->flags, (uint)flags);
621 replyfuseerrno(m, EACCES);
622 return;
624 if((fid = _fuseopenfid(m->hdr->nodeid, isdir, openmode, &err)) == nil){
625 replyfuseerrno(m, err);
626 return;
628 out.fh = allocfh(fid);
629 out.open_flags = FOPEN_DIRECT_IO; /* no page cache */
630 replyfuse(m, &out, sizeof out);
633 void
634 fuseopen(FuseMsg *m)
636 _fuseopen(m, 0);
639 void
640 fuseopendir(FuseMsg *m)
642 _fuseopen(m, 1);
645 /*
646 * Create & Mkdir.
647 */
648 CFid*
649 _fusecreate(uvlong nodeid, char *name, int perm, int ismkdir, int omode, struct fuse_entry_out *out, int *err)
651 CFid *fid, *newfid, *newfid2;
652 Dir *d;
653 Fusefid *ff;
655 if((fid = nodeid2fid(nodeid)) == nil){
656 *err = ESTALE;
657 return nil;
659 perm &= 0777;
660 if(ismkdir)
661 perm |= DMDIR;
662 if(ismkdir && omode != OREAD){
663 *err = EPERM;
664 return nil;
666 if((newfid = fswalk(fid, nil)) == nil){
667 *err = errstr2errno();
668 return nil;
670 if(fsfcreate(newfid, name, omode, perm) < 0){
671 *err = errstr2errno();
672 fsclose(newfid);
673 return nil;
675 if((d = fsdirfstat(newfid)) == nil){
676 *err = errstr2errno();
677 fsfremove(newfid);
678 return nil;
680 /*
681 * This fid is no good, because it's open.
682 * We need an unopened fid. Sigh.
683 */
684 if((newfid2 = fswalk(fid, name)) == nil){
685 *err = errstr2errno();
686 free(d);
687 fsfremove(newfid);
688 return nil;
690 out->nodeid = allocnodeid(newfid2);
691 ff = lookupfusefid(out->nodeid, 1);
692 out->generation = ff->gen;
693 f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec);
694 f2timeout(entrytimeout, &out->entry_valid, &out->entry_valid_nsec);
695 dir2attr(d, &out->attr);
696 free(d);
697 return newfid;
700 void
701 fusemkdir(FuseMsg *m)
703 struct fuse_mkdir_in *in;
704 struct fuse_entry_out out;
705 CFid *fid;
706 int err;
707 char *name;
709 in = m->tx;
710 name = (char*)(in+1);
711 if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 1, OREAD, &out, &err)) == nil){
712 replyfuseerrno(m, err);
713 return;
715 /* Toss the open fid. */
716 fsclose(fid);
717 replyfuse(m, &out, sizeof out);
720 void
721 fusecreate(FuseMsg *m)
723 struct fuse_open_in *in;
724 struct fuse_create_out out;
725 CFid *fid;
726 int err, openmode, flags;
727 char *name;
729 in = m->tx;
730 flags = in->flags;
731 openmode = in->flags&3;
732 flags &= ~3;
733 flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE|O_EXCL);
734 flags &= ~O_APPEND; /* see comment in _fuseopen */
735 flags &= ~(O_CREAT|O_TRUNC); /* huh? */
736 if(flags){
737 fprint(2, "bad mode %#uo\n", in->flags);
738 replyfuseerrno(m, EACCES);
739 return;
741 name = (char*)(in+1);
742 if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 0, openmode, &out.e, &err)) == nil){
743 replyfuseerrno(m, err);
744 return;
746 out.o.fh = allocfh(fid);
747 out.o.open_flags = FOPEN_DIRECT_IO; /* no page cache */
748 replyfuse(m, &out, sizeof out);
751 /*
752 * Access.
753 * Lib9pclient implements this just as Plan 9 does,
754 * by opening the file (or not) and then closing it.
755 */
756 void
757 fuseaccess(FuseMsg *m)
759 struct fuse_access_in *in;
760 CFid *fid;
761 int err, omode;
762 static int a2o[] = {
763 0,
764 OEXEC,
765 OWRITE,
766 ORDWR,
767 OREAD,
768 OEXEC,
769 ORDWR,
770 ORDWR
771 };
773 in = m->tx;
774 if(in->mask >= nelem(a2o)){
775 replyfuseerrno(m, EINVAL);
776 return;
778 omode = a2o[in->mask];
779 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
780 replyfuseerrno(m, ESTALE);
781 return;
783 if(fsqid(fid).type&QTDIR)
784 omode = OREAD;
785 if((fid = _fuseopenfid(m->hdr->nodeid, 0, omode, &err)) == nil){
786 replyfuseerrno(m, err);
787 return;
789 fsclose(fid);
790 replyfuse(m, nil, 0);
793 /*
794 * Release.
795 * Equivalent of clunk for file handles.
796 * in->flags is the open mode used in Open or Opendir.
797 */
798 void
799 fuserelease(FuseMsg *m)
801 struct fuse_release_in *in;
802 Fusefid *ff;
804 in = m->tx;
805 if((ff = lookupfusefid(in->fh, 0)) != nil)
806 freefusefid(ff);
807 else
808 fprint(2, "fuserelease: fh not found\n");
809 replyfuse(m, nil, 0);
812 void
813 fusereleasedir(FuseMsg *m)
815 fuserelease(m);
818 /*
819 * Read.
820 * Read from file handle in->fh at offset in->offset for size in->size.
821 * We truncate size to maxwrite just to keep the buffer reasonable.
822 */
823 void
824 fuseread(FuseMsg *m)
826 int n;
827 uchar *buf;
828 CFid *fid;
829 struct fuse_read_in *in;
831 in = m->tx;
832 if((fid = fh2fid(in->fh)) == nil){
833 replyfuseerrno(m, ESTALE);
834 return;
836 n = in->size;
837 if(n > fusemaxwrite)
838 n = fusemaxwrite;
839 buf = emalloc(n);
840 n = fspread(fid, buf, n, in->offset);
841 if(n < 0){
842 free(buf);
843 replyfuseerrstr(m);
844 return;
846 replyfuse(m, buf, n);
847 free(buf);
850 /*
851 * Readlink.
852 */
853 void
854 fusereadlink(FuseMsg *m)
856 Dir *d;
857 CFid *fid;
859 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
860 replyfuseerrno(m, ESTALE);
861 return;
863 if((d = fsdirfstat(fid)) == nil){
864 replyfuseerrstr(m);
865 return;
867 if(!(d->mode&DMSYMLINK)){
868 replyfuseerrno(m, EINVAL);
869 return;
871 replyfuse(m, d->ext, strlen(d->ext));
872 free(d);
873 return;
876 /*
877 * Readdir.
878 * Read from file handle in->fh at offset in->offset for size in->size.
879 * We truncate size to maxwrite just to keep the buffer reasonable.
880 * We assume 9P directory read semantics: a read at offset 0 rewinds
881 * and a read at any other offset starts where we left off.
882 * If it became necessary, we could implement a crude seek
883 * or cache the entire list of directory entries.
884 * Directory entries read from 9P but not yet handed to FUSE
885 * are stored in m->d,nd,d0.
886 */
887 int canpack(Dir*, uvlong, uchar**, uchar*);
888 Dir *dotdir(CFid*);
889 void
890 fusereaddir(FuseMsg *m)
892 struct fuse_read_in *in;
893 uchar *buf, *p, *ep;
894 int n;
895 Fusefid *ff;
897 in = m->tx;
898 if((ff = lookupfusefid(in->fh, 0)) == nil){
899 replyfuseerrno(m, ESTALE);
900 return;
902 if(in->offset == 0){
903 fsseek(ff->fid, 0, 0);
904 free(ff->d0);
905 ff->d0 = ff->d = dotdir(ff->fid);
906 ff->nd = 1;
908 n = in->size;
909 if(n > fusemaxwrite)
910 n = fusemaxwrite;
911 buf = emalloc(n);
912 p = buf;
913 ep = buf + n;
914 for(;;){
915 while(ff->nd > 0){
916 if(!canpack(ff->d, ff->off, &p, ep))
917 goto out;
918 ff->off++;
919 ff->d++;
920 ff->nd--;
922 free(ff->d0);
923 ff->d0 = nil;
924 ff->d = nil;
925 if((ff->nd = fsdirread(ff->fid, &ff->d0)) < 0){
926 replyfuseerrstr(m);
927 free(buf);
928 return;
930 if(ff->nd == 0)
931 break;
932 ff->d = ff->d0;
934 out:
935 replyfuse(m, buf, p - buf);
936 free(buf);
939 /*
940 * Fuse assumes that it can always read two directory entries.
941 * If it gets just one, it will double it in the dirread results.
942 * Thus if a directory contains just "a", you see "a" twice.
943 * Adding . as the first directory entry works around this.
944 * We could add .. too, but it isn't necessary.
945 */
946 Dir*
947 dotdir(CFid *f)
949 Dir *d;
951 d = emalloc(1*sizeof *d);
952 d[0].name = ".";
953 d[0].qid = fsqid(f);
954 return d;
957 int
958 canpack(Dir *d, uvlong off, uchar **pp, uchar *ep)
960 uchar *p;
961 struct fuse_dirent *de;
962 int pad, size;
964 p = *pp;
965 size = FUSE_NAME_OFFSET + strlen(d->name);
966 pad = 0;
967 if(size%8)
968 pad = 8 - size%8;
969 if(size+pad > ep - p)
970 return 0;
971 de = (struct fuse_dirent*)p;
972 de->ino = qid2inode(d->qid);
973 de->off = off;
974 de->namelen = strlen(d->name);
975 memmove(de->name, d->name, de->namelen);
976 if(pad > 0)
977 memset(de->name+de->namelen, 0, pad);
978 *pp = p+size+pad;
979 return 1;
982 /*
983 * Write.
984 * Write from file handle in->fh at offset in->offset for size in->size.
985 * Don't know what in->write_flags means.
987 * Apparently implementations are allowed to buffer these writes
988 * and wait until Flush is sent, but FUSE docs say flush may be
989 * called zero, one, or even more times per close. So better do the
990 * actual writing here. Also, errors that happen during Flush just
991 * show up in the close() return status, which no one checks anyway.
992 */
993 void
994 fusewrite(FuseMsg *m)
996 struct fuse_write_in *in;
997 struct fuse_write_out out;
998 void *a;
999 CFid *fid;
1000 int n;
1002 in = m->tx;
1003 a = in+1;
1004 if((fid = fh2fid(in->fh)) == nil){
1005 replyfuseerrno(m, ESTALE);
1006 return;
1008 if(in->size > fusemaxwrite){
1009 replyfuseerrno(m, EINVAL);
1010 return;
1012 n = fspwrite(fid, a, in->size, in->offset);
1013 if(n < 0){
1014 replyfuseerrstr(m);
1015 return;
1017 out.size = n;
1018 replyfuse(m, &out, sizeof out);
1022 * Flush. Supposed to flush any buffered writes. Don't use this.
1024 * Flush is a total crock. It gets called on close() of a file descriptor
1025 * associated with this open file. Some open files have multiple file
1026 * descriptors and thus multiple closes of those file descriptors.
1027 * In those cases, Flush is called multiple times. Some open files
1028 * have file descriptors that are closed on process exit instead of
1029 * closed explicitly. For those files, Flush is never called.
1030 * Even more amusing, Flush gets called before close() of read-only
1031 * file descriptors too!
1033 * This is just a bad idea.
1035 void
1036 fuseflush(FuseMsg *m)
1038 replyfuse(m, nil, 0);
1042 * Unlink & Rmdir.
1044 void
1045 _fuseremove(FuseMsg *m, int isdir)
1047 char *name;
1048 CFid *fid, *newfid;
1050 name = m->tx;
1051 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
1052 replyfuseerrno(m, ESTALE);
1053 return;
1055 if(strchr(name, '/')){
1056 replyfuseerrno(m, ENOENT);
1057 return;
1059 if((newfid = fswalk(fid, name)) == nil){
1060 replyfuseerrstr(m);
1061 return;
1063 if(isdir && !(fsqid(newfid).type&QTDIR)){
1064 replyfuseerrno(m, ENOTDIR);
1065 fsclose(newfid);
1066 return;
1068 if(!isdir && (fsqid(newfid).type&QTDIR)){
1069 replyfuseerrno(m, EISDIR);
1070 fsclose(newfid);
1071 return;
1073 if(fsfremove(newfid) < 0){
1074 replyfuseerrstr(m);
1075 return;
1077 replyfuse(m, nil, 0);
1080 void
1081 fuseunlink(FuseMsg *m)
1083 _fuseremove(m, 0);
1086 void
1087 fusermdir(FuseMsg *m)
1089 _fuseremove(m, 1);
1093 * Rename.
1095 * FUSE sends the nodeid for the source and destination
1096 * directory and then the before and after names as strings.
1097 * 9P can only do the rename if the source and destination
1098 * are the same. If the same nodeid is used for source and
1099 * destination, we're fine, but if FUSE gives us different nodeids
1100 * that happen to correspond to the same directory, we have
1101 * no way of figuring that out. Let's hope it doesn't happen too often.
1103 void
1104 fuserename(FuseMsg *m)
1106 struct fuse_rename_in *in;
1107 char *before, *after;
1108 CFid *fid, *newfid;
1109 Dir d;
1111 in = m->tx;
1112 if(in->newdir != m->hdr->nodeid){
1113 replyfuseerrno(m, EXDEV);
1114 return;
1116 before = (char*)(in+1);
1117 after = before + strlen(before) + 1;
1118 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
1119 replyfuseerrno(m, ESTALE);
1120 return;
1122 if(strchr(before, '/') || strchr(after, '/')){
1123 replyfuseerrno(m, ENOENT);
1124 return;
1126 if((newfid = fswalk(fid, before)) == nil){
1127 replyfuseerrstr(m);
1128 return;
1130 nulldir(&d);
1131 d.name = after;
1132 if(fsdirfwstat(newfid, &d) < 0){
1133 replyfuseerrstr(m);
1134 fsclose(newfid);
1135 return;
1137 fsclose(newfid);
1138 replyfuse(m, nil, 0);
1142 * Fsync. Commit file info to stable storage.
1143 * Not sure what in->fsync_flags are.
1145 void
1146 fusefsync(FuseMsg *m)
1148 struct fuse_fsync_in *in;
1149 CFid *fid;
1150 Dir d;
1152 in = m->tx;
1153 if((fid = fh2fid(in->fh)) == nil){
1154 replyfuseerrno(m, ESTALE);
1155 return;
1157 nulldir(&d);
1158 if(fsdirfwstat(fid, &d) < 0){
1159 replyfuseerrstr(m);
1160 return;
1162 replyfuse(m, nil, 0);
1166 * Fsyncdir. Commit dir info to stable storage?
1168 void
1169 fusefsyncdir(FuseMsg *m)
1171 fusefsync(m);
1175 * Statfs. Send back information about file system.
1176 * Not really worth implementing, except that if we
1177 * reply with ENOSYS, programs like df print messages like
1178 * df: `/tmp/z': Function not implemented
1179 * and that gets annoying. Returning all zeros excludes
1180 * us from df without appearing to cause any problems.
1182 void
1183 fusestatfs(FuseMsg *m)
1185 struct fuse_statfs_out out;
1187 memset(&out, 0, sizeof out);
1188 replyfuse(m, &out, sizeof out);
1191 void (*fusehandlers[100])(FuseMsg*);
1193 struct {
1194 int op;
1195 void (*fn)(FuseMsg*);
1196 } fuselist[] = {
1197 { FUSE_LOOKUP, fuselookup },
1198 { FUSE_FORGET, fuseforget },
1199 { FUSE_GETATTR, fusegetattr },
1200 { FUSE_SETATTR, fusesetattr },
1202 * FUSE_SYMLINK, FUSE_MKNOD are unimplemented.
1204 { FUSE_READLINK, fusereadlink },
1205 { FUSE_MKDIR, fusemkdir },
1206 { FUSE_UNLINK, fuseunlink },
1207 { FUSE_RMDIR, fusermdir },
1208 { FUSE_RENAME, fuserename },
1210 * FUSE_LINK is unimplemented.
1212 { FUSE_OPEN, fuseopen },
1213 { FUSE_READ, fuseread },
1214 { FUSE_WRITE, fusewrite },
1215 { FUSE_STATFS, fusestatfs },
1216 { FUSE_RELEASE, fuserelease },
1217 { FUSE_FSYNC, fusefsync },
1219 * FUSE_SETXATTR, FUSE_GETXATTR, FUSE_LISTXATTR, and
1220 * FUSE_REMOVEXATTR are unimplemented.
1221 * FUSE will stop sending these requests after getting
1222 * an -ENOSYS reply (see dispatch below).
1224 { FUSE_FLUSH, fuseflush },
1226 * FUSE_INIT is handled in initfuse and should not be seen again.
1228 { FUSE_OPENDIR, fuseopendir },
1229 { FUSE_READDIR, fusereaddir },
1230 { FUSE_RELEASEDIR, fusereleasedir },
1231 { FUSE_FSYNCDIR, fusefsyncdir },
1232 { FUSE_ACCESS, fuseaccess },
1233 { FUSE_CREATE, fusecreate },
1236 void
1237 fusethread(void *v)
1239 FuseMsg *m;
1241 m = v;
1242 if((uint)m->hdr->opcode >= nelem(fusehandlers)
1243 || !fusehandlers[m->hdr->opcode]){
1244 replyfuseerrno(m, ENOSYS);
1245 return;
1247 fusehandlers[m->hdr->opcode](m);
1250 void
1251 fusedispatch(void *v)
1253 int i;
1254 FuseMsg *m;
1256 eofkill9pclient = 1; /* threadexitsall on 9P eof */
1257 atexit(unmountatexit);
1259 recvp(fusechan); /* sync */
1261 for(i=0; i<nelem(fuselist); i++){
1262 if(fuselist[i].op >= nelem(fusehandlers))
1263 sysfatal("make fusehandlers bigger op=%d", fuselist[i].op);
1264 fusehandlers[fuselist[i].op] = fuselist[i].fn;
1267 while((m = recvp(fusechan)) != nil) {
1268 switch(m->hdr->opcode) {
1269 case FUSE_FORGET:
1270 fusehandlers[m->hdr->opcode](m);
1271 break;
1272 default:
1273 threadcreate(fusethread, m, STACK);
1278 void*
1279 emalloc(uint n)
1281 void *p;
1283 p = malloc(n);
1284 if(p == nil)
1285 sysfatal("malloc(%d): %r", n);
1286 memset(p, 0, n);
1287 return p;
1290 void*
1291 erealloc(void *p, uint n)
1293 p = realloc(p, n);
1294 if(p == nil)
1295 sysfatal("realloc(..., %d): %r", n);
1296 return p;
1299 char*
1300 estrdup(char *p)
1302 char *pp;
1303 pp = strdup(p);
1304 if(pp == nil)
1305 sysfatal("strdup(%.20s): %r", p);
1306 return pp;
1309 void
1310 watchfd(void *v)
1312 int fd = (int)(uintptr)v;
1314 /* wait for exception (file closed) */
1315 fd_set set;
1316 FD_ZERO(&set);
1317 FD_SET(fd, &set);
1318 if(select(fd+1, NULL, NULL, &set, NULL) >= 0)
1319 threadexitsall(nil);
1320 return;