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