tvacfs.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tvacfs.c (14671B)
---
     1 #include "stdinc.h"
     2 #include 
     3 #include "vac.h"
     4 
     5 typedef struct Fid Fid;
     6 
     7 enum
     8 {
     9         OPERM        = 0x3                /* mask of all permission types in open mode */
    10 };
    11 
    12 struct Fid
    13 {
    14         short busy;
    15         short open;
    16         int fid;
    17         char *user;
    18         Qid qid;
    19         VacFile *file;
    20         VacDirEnum *vde;
    21         Fid        *next;
    22 };
    23 
    24 enum
    25 {
    26         Pexec =                1,
    27         Pwrite =         2,
    28         Pread =         4,
    29         Pother =         1,
    30         Pgroup =         8,
    31         Powner =        64
    32 };
    33 
    34 Fid        *fids;
    35 uchar        *data;
    36 int        mfd[2];
    37 int        srvfd = -1;
    38 char        *user;
    39 uchar        mdata[8192+IOHDRSZ];
    40 int messagesize = sizeof mdata;
    41 Fcall        rhdr;
    42 Fcall        thdr;
    43 VacFs        *fs;
    44 VtConn  *conn;
    45 int        noperm;
    46 char *defmnt;
    47 
    48 Fid *        newfid(int);
    49 void        error(char*);
    50 void        io(void);
    51 void        vacshutdown(void);
    52 void        usage(void);
    53 int        perm(Fid*, int);
    54 int        permf(VacFile*, char*, int);
    55 ulong        getl(void *p);
    56 void        init(char*, char*, long, int);
    57 int        vacdirread(Fid *f, char *p, long off, long cnt);
    58 int        vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
    59 void         srv(void* a);
    60 
    61 
    62 char        *rflush(Fid*), *rversion(Fid*),
    63         *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
    64         *ropen(Fid*), *rcreate(Fid*),
    65         *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
    66         *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
    67 
    68 char         *(*fcalls[Tmax])(Fid*);
    69 
    70 void
    71 initfcalls(void)
    72 {
    73         fcalls[Tflush]=        rflush;
    74         fcalls[Tversion]=        rversion;
    75         fcalls[Tattach]=        rattach;
    76         fcalls[Tauth]=                rauth;
    77         fcalls[Twalk]=                rwalk;
    78         fcalls[Topen]=                ropen;
    79         fcalls[Tcreate]=        rcreate;
    80         fcalls[Tread]=                rread;
    81         fcalls[Twrite]=        rwrite;
    82         fcalls[Tclunk]=        rclunk;
    83         fcalls[Tremove]=        rremove;
    84         fcalls[Tstat]=                rstat;
    85         fcalls[Twstat]=        rwstat;
    86 }
    87 
    88 char        Eperm[] =        "permission denied";
    89 char        Enotdir[] =        "not a directory";
    90 char        Enotexist[] =        "file does not exist";
    91 char        Einuse[] =        "file in use";
    92 char        Eexist[] =        "file exists";
    93 char        Enotowner[] =        "not owner";
    94 char        Eisopen[] =         "file already open for I/O";
    95 char        Excl[] =         "exclusive use file already open";
    96 char        Ename[] =         "illegal name";
    97 char        Erdonly[] =         "read only file system";
    98 char        Eio[] =         "i/o error";
    99 char        Eempty[] =         "directory is not empty";
   100 char        Emode[] =        "illegal mode";
   101 
   102 int dflag;
   103 
   104 void
   105 notifyf(void *a, char *s)
   106 {
   107         USED(a);
   108         if(strncmp(s, "interrupt", 9) == 0)
   109                 noted(NCONT);
   110         noted(NDFLT);
   111 }
   112 
   113 #define TWID64 ~(u64int)0
   114 static u64int
   115 unittoull(char *s)
   116 {
   117         char *es;
   118         u64int n;
   119 
   120         if(s == nil)
   121                 return TWID64;
   122         n = strtoul(s, &es, 0);
   123         if(*es == 'k' || *es == 'K'){
   124                 n *= 1024;
   125                 es++;
   126         }else if(*es == 'm' || *es == 'M'){
   127                 n *= 1024*1024;
   128                 es++;
   129         }else if(*es == 'g' || *es == 'G'){
   130                 n *= 1024*1024*1024;
   131                 es++;
   132         }
   133         if(*es != '\0')
   134                 return TWID64;
   135         return n;
   136 }
   137 
   138 void
   139 threadmain(int argc, char *argv[])
   140 {
   141         char *defsrv, *srvname;
   142         int p[2], fd;
   143         int stdio;
   144         char *host = nil;
   145         ulong mem;
   146 
   147         mem = 16<<20;
   148         stdio = 0;
   149         fmtinstall('H', encodefmt);
   150         fmtinstall('V', vtscorefmt);
   151         fmtinstall('F', vtfcallfmt);
   152 
   153         defmnt = nil;
   154         defsrv = nil;
   155         ARGBEGIN{
   156         case 'd':
   157                 fmtinstall('F', fcallfmt);
   158                 dflag = 1;
   159                 break;
   160         case 'i':
   161                 defmnt = nil;
   162                 stdio = 1;
   163                 mfd[0] = 0;
   164                 mfd[1] = 1;
   165                 break;
   166         case 'h':
   167                 host = EARGF(usage());
   168                 break;
   169         case 'S':
   170                 defsrv = EARGF(usage());
   171                 break;
   172         case 's':
   173                 defsrv = "vacfs";
   174                 break;
   175         case 'M':
   176                 mem = unittoull(EARGF(usage()));
   177                 break;
   178         case 'm':
   179                 defmnt = EARGF(usage());
   180                 break;
   181         case 'p':
   182                 noperm = 1;
   183                 break;
   184         case 'V':
   185                 chattyventi = 1;
   186                 break;
   187         default:
   188                 usage();
   189         }ARGEND
   190 
   191         if(argc != 1)
   192                 usage();
   193 
   194 #ifdef PLAN9PORT
   195         if(defsrv == nil && defmnt == nil && !stdio){
   196                 srvname = strchr(argv[0], '/');
   197                 if(srvname)
   198                         srvname++;
   199                 else
   200                         srvname = argv[0];
   201                 defsrv = vtmalloc(6+strlen(srvname)+1);
   202                 strcpy(defsrv, "vacfs.");
   203                 strcat(defsrv, srvname);
   204                 if(strcmp(defsrv+strlen(defsrv)-4, ".vac") == 0)
   205                         defsrv[strlen(defsrv)-4] = 0;
   206         }
   207 #else
   208         if(defsrv == nil && defmnt == nil && !stdio)
   209                 defmnt = "/n/vac";
   210 #endif
   211         if(stdio && defmnt)
   212                 sysfatal("cannot use -m with -i");
   213 
   214         initfcalls();
   215 
   216         notify(notifyf);
   217         user = getuser();
   218 
   219         conn = vtdial(host);
   220         if(conn == nil)
   221                 sysfatal("could not connect to server: %r");
   222 
   223         if(vtconnect(conn) < 0)
   224                 sysfatal("vtconnect: %r");
   225 
   226         fs = vacfsopen(conn, argv[0], VtOREAD, mem);
   227         if(fs == nil)
   228                 sysfatal("vacfsopen: %r");
   229 
   230         if(!stdio){
   231                 if(pipe(p) < 0)
   232                         sysfatal("pipe failed: %r");
   233                 mfd[0] = p[0];
   234                 mfd[1] = p[0];
   235                 srvfd = p[1];
   236 #ifndef PLAN9PORT
   237                 if(defsrv){
   238                         srvname = smprint("/srv/%s", defsrv);
   239                         fd = create(srvname, OWRITE|ORCLOSE, 0666);
   240                         if(fd < 0)
   241                                 sysfatal("create %s: %r", srvname);
   242                         if(fprint(fd, "%d", srvfd) < 0)
   243                                 sysfatal("write %s: %r", srvname);
   244                         free(srvname);
   245                 }
   246 #endif
   247         }
   248 
   249 #ifdef PLAN9PORT
   250         USED(fd);
   251         proccreate(srv, 0, 32 * 1024);
   252         if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0)
   253                 sysfatal("post9pservice");
   254 #else
   255         procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
   256 
   257         if(!stdio){
   258                 close(p[0]);
   259                 if(defmnt){
   260                         if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
   261                                 sysfatal("mount %s: %r", defmnt);
   262                 }
   263         }
   264 #endif
   265         threadexits(0);
   266 }
   267 
   268 void
   269 srv(void *a)
   270 {
   271         USED(a);
   272         io();
   273         vacshutdown();
   274 }
   275 
   276 void
   277 usage(void)
   278 {
   279         fprint(2, "usage: %s [-sd] [-h host] [-m mountpoint] [-M mem] vacfile\n", argv0);
   280         threadexitsall("usage");
   281 }
   282 
   283 char*
   284 rversion(Fid *unused)
   285 {
   286         Fid *f;
   287 
   288         USED(unused);
   289 
   290         for(f = fids; f; f = f->next)
   291                 if(f->busy)
   292                         rclunk(f);
   293 
   294         if(rhdr.msize < 256)
   295                 return vtstrdup("version: message size too small");
   296         messagesize = rhdr.msize;
   297         if(messagesize > sizeof mdata)
   298                 messagesize = sizeof mdata;
   299         thdr.msize = messagesize;
   300         if(strncmp(rhdr.version, "9P2000", 6) != 0)
   301                 return vtstrdup("unrecognized 9P version");
   302         thdr.version = "9P2000";
   303         return nil;
   304 }
   305 
   306 char*
   307 rflush(Fid *f)
   308 {
   309         USED(f);
   310         return 0;
   311 }
   312 
   313 char*
   314 rauth(Fid *f)
   315 {
   316         USED(f);
   317         return vtstrdup("vacfs: authentication not required");
   318 }
   319 
   320 char*
   321 rattach(Fid *f)
   322 {
   323         /* no authentication for the momment */
   324         VacFile *file;
   325         char err[80];
   326 
   327         file = vacfsgetroot(fs);
   328         if(file == nil) {
   329                 rerrstr(err, sizeof err);
   330                 return vtstrdup(err);
   331         }
   332 
   333         f->busy = 1;
   334         f->file = file;
   335         f->qid.path = vacfilegetid(f->file);
   336         f->qid.vers = 0;
   337         f->qid.type = QTDIR;
   338         thdr.qid = f->qid;
   339         if(rhdr.uname[0])
   340                 f->user = vtstrdup(rhdr.uname);
   341         else
   342                 f->user = "none";
   343         return 0;
   344 }
   345 
   346 char*
   347 rwalk(Fid *f)
   348 {
   349         VacFile *file, *nfile;
   350         Fid *nf;
   351         int nqid, nwname;
   352         Qid qid;
   353         char *err = nil;
   354 
   355         if(f->busy == 0)
   356                 return Enotexist;
   357         nf = nil;
   358         if(rhdr.fid != rhdr.newfid){
   359                 if(f->open)
   360                         return vtstrdup(Eisopen);
   361                 if(f->busy == 0)
   362                         return vtstrdup(Enotexist);
   363                 nf = newfid(rhdr.newfid);
   364                 if(nf->busy)
   365                         return vtstrdup(Eisopen);
   366                 nf->busy = 1;
   367                 nf->open = 0;
   368                 nf->qid = f->qid;
   369                 nf->file = vacfileincref(f->file);
   370                 nf->user = vtstrdup(f->user);
   371                 f = nf;
   372         }
   373 
   374         nwname = rhdr.nwname;
   375 
   376         /* easy case */
   377         if(nwname == 0) {
   378                 thdr.nwqid = 0;
   379                 return 0;
   380         }
   381 
   382         file = f->file;
   383         vacfileincref(file);
   384         qid = f->qid;
   385 
   386         for(nqid = 0; nqid < nwname; nqid++){
   387                 if((qid.type & QTDIR) == 0){
   388                         err = Enotdir;
   389                         break;
   390                 }
   391                 if(!permf(file, f->user, Pexec)) {
   392                         err = Eperm;
   393                         break;
   394                 }
   395                 nfile = vacfilewalk(file, rhdr.wname[nqid]);
   396                 if(nfile == nil)
   397                         break;
   398                 vacfiledecref(file);
   399                 file = nfile;
   400                 qid.type = QTFILE;
   401                 if(vacfileisdir(file))
   402                         qid.type = QTDIR;
   403 #ifdef PLAN9PORT
   404                 if(vacfilegetmode(file)&ModeLink)
   405                         qid.type = QTSYMLINK;
   406 #endif
   407                 qid.vers = vacfilegetmcount(file);
   408                 qid.path = vacfilegetid(file);
   409                 thdr.wqid[nqid] = qid;
   410         }
   411 
   412         thdr.nwqid = nqid;
   413 
   414         if(nqid == nwname){
   415                 /* success */
   416                 f->qid = thdr.wqid[nqid-1];
   417                 vacfiledecref(f->file);
   418                 f->file = file;
   419                 return 0;
   420         }
   421 
   422         vacfiledecref(file);
   423         if(nf != nil)
   424                 rclunk(nf);
   425 
   426         /* only error on the first element */
   427         if(nqid == 0)
   428                 return vtstrdup(err);
   429 
   430         return 0;
   431 }
   432 
   433 char *
   434 ropen(Fid *f)
   435 {
   436         int mode, trunc;
   437 
   438         if(f->open)
   439                 return vtstrdup(Eisopen);
   440         if(!f->busy)
   441                 return vtstrdup(Enotexist);
   442 
   443         mode = rhdr.mode;
   444         thdr.iounit = messagesize - IOHDRSZ;
   445         if(f->qid.type & QTDIR){
   446                 if(mode != OREAD)
   447                         return vtstrdup(Eperm);
   448                 if(!perm(f, Pread))
   449                         return vtstrdup(Eperm);
   450                 thdr.qid = f->qid;
   451                 f->vde = nil;
   452                 f->open = 1;
   453                 return 0;
   454         }
   455         if(mode & ORCLOSE)
   456                 return vtstrdup(Erdonly);
   457         trunc = mode & OTRUNC;
   458         mode &= OPERM;
   459         if(mode==OWRITE || mode==ORDWR || trunc)
   460                 if(!perm(f, Pwrite))
   461                         return vtstrdup(Eperm);
   462         if(mode==OREAD || mode==ORDWR)
   463                 if(!perm(f, Pread))
   464                         return vtstrdup(Eperm);
   465         if(mode==OEXEC)
   466                 if(!perm(f, Pexec))
   467                         return vtstrdup(Eperm);
   468         thdr.qid = f->qid;
   469         thdr.iounit = messagesize - IOHDRSZ;
   470         f->open = 1;
   471         return 0;
   472 }
   473 
   474 char*
   475 rcreate(Fid* fid)
   476 {
   477         VacFile *vf;
   478         ulong mode;
   479 
   480         if(fid->open)
   481                 return vtstrdup(Eisopen);
   482         if(!fid->busy)
   483                 return vtstrdup(Enotexist);
   484         if(fs->mode & ModeSnapshot)
   485                 return vtstrdup(Erdonly);
   486         vf = fid->file;
   487         if(!vacfileisdir(vf))
   488                 return vtstrdup(Enotdir);
   489         if(!permf(vf, fid->user, Pwrite))
   490                 return vtstrdup(Eperm);
   491 
   492         mode = rhdr.perm & 0777;
   493 
   494         if(rhdr.perm & DMDIR){
   495                 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
   496                         return vtstrdup(Emode);
   497                 switch(rhdr.mode & OPERM){
   498                 default:
   499                         return vtstrdup(Emode);
   500                 case OEXEC:
   501                 case OREAD:
   502                         break;
   503                 case OWRITE:
   504                 case ORDWR:
   505                         return vtstrdup(Eperm);
   506                 }
   507                 mode |= ModeDir;
   508         }
   509         vf = vacfilecreate(vf, rhdr.name, mode);
   510         if(vf == nil) {
   511                 char err[80];
   512                 rerrstr(err, sizeof err);
   513 
   514                 return vtstrdup(err);
   515         }
   516 
   517         vacfiledecref(fid->file);
   518 
   519         fid->file = vf;
   520         fid->qid.type = QTFILE;
   521         if(vacfileisdir(vf))
   522                 fid->qid.type = QTDIR;
   523         fid->qid.vers = vacfilegetmcount(vf);
   524         fid->qid.path = vacfilegetid(vf);
   525 
   526         thdr.qid = fid->qid;
   527         thdr.iounit = messagesize - IOHDRSZ;
   528 
   529         return 0;
   530 }
   531 
   532 char*
   533 rread(Fid *f)
   534 {
   535         char *buf;
   536         vlong off;
   537         int cnt;
   538         VacFile *vf;
   539         char err[80];
   540         int n;
   541 
   542         if(!f->busy)
   543                 return vtstrdup(Enotexist);
   544         vf = f->file;
   545         thdr.count = 0;
   546         off = rhdr.offset;
   547         buf = thdr.data;
   548         cnt = rhdr.count;
   549         if(f->qid.type & QTDIR)
   550                 n = vacdirread(f, buf, off, cnt);
   551         else if(vacfilegetmode(f->file)&ModeDevice)
   552                 return vtstrdup("device");
   553         else if(vacfilegetmode(f->file)&ModeLink)
   554                 return vtstrdup("symbolic link");
   555         else if(vacfilegetmode(f->file)&ModeNamedPipe)
   556                 return vtstrdup("named pipe");
   557         else
   558                 n = vacfileread(vf, buf, cnt, off);
   559         if(n < 0) {
   560                 rerrstr(err, sizeof err);
   561                 return vtstrdup(err);
   562         }
   563         thdr.count = n;
   564         return 0;
   565 }
   566 
   567 char*
   568 rwrite(Fid *f)
   569 {
   570         USED(f);
   571         return vtstrdup(Erdonly);
   572 }
   573 
   574 char *
   575 rclunk(Fid *f)
   576 {
   577         f->busy = 0;
   578         f->open = 0;
   579         vtfree(f->user);
   580         f->user = nil;
   581         if(f->file)
   582                 vacfiledecref(f->file);
   583         f->file = nil;
   584         vdeclose(f->vde);
   585         f->vde = nil;
   586         return 0;
   587 }
   588 
   589 char *
   590 rremove(Fid *f)
   591 {
   592         VacFile *vf, *vfp;
   593         char errbuf[80];
   594         char *err = nil;
   595 
   596         if(!f->busy)
   597                 return vtstrdup(Enotexist);
   598         vf = f->file;
   599         vfp = vacfilegetparent(vf);
   600 
   601         if(!permf(vfp, f->user, Pwrite)) {
   602                 err = Eperm;
   603                 goto Exit;
   604         }
   605 
   606         if(!vacfileremove(vf)) {
   607                 rerrstr(errbuf, sizeof errbuf);
   608                 err = errbuf;
   609         }
   610 
   611 Exit:
   612         vacfiledecref(vfp);
   613         rclunk(f);
   614         return vtstrdup(err);
   615 }
   616 
   617 char *
   618 rstat(Fid *f)
   619 {
   620         VacDir dir;
   621         static uchar statbuf[1024];
   622         VacFile *parent;
   623 
   624         if(!f->busy)
   625                 return vtstrdup(Enotexist);
   626         parent = vacfilegetparent(f->file);
   627         vacfilegetdir(f->file, &dir);
   628         thdr.stat = statbuf;
   629         thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
   630         vdcleanup(&dir);
   631         vacfiledecref(parent);
   632         return 0;
   633 }
   634 
   635 char *
   636 rwstat(Fid *f)
   637 {
   638         if(!f->busy)
   639                 return vtstrdup(Enotexist);
   640         return vtstrdup(Erdonly);
   641 }
   642 
   643 int
   644 vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
   645 {
   646         int ret;
   647         Dir dir;
   648 #ifdef PLAN9PORT
   649         int n;
   650         VacFile *vf;
   651         uvlong size;
   652         char *ext = nil;
   653 #endif
   654 
   655         memset(&dir, 0, sizeof(dir));
   656 
   657         dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
   658         if(vd->qidspace)
   659                 dir.qid.path += vd->qidoffset;
   660         dir.qid.vers = vd->mcount;
   661         dir.mode = vd->mode & 0777;
   662         if(vd->mode & ModeAppend){
   663                 dir.qid.type |= QTAPPEND;
   664                 dir.mode |= DMAPPEND;
   665         }
   666         if(vd->mode & ModeExclusive){
   667                 dir.qid.type |= QTEXCL;
   668                 dir.mode |= DMEXCL;
   669         }
   670         if(vd->mode & ModeDir){
   671                 dir.qid.type |= QTDIR;
   672                 dir.mode |= DMDIR;
   673         }
   674 
   675 #ifdef PLAN9PORT
   676         if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
   677                 vf = vacfilewalk(parent, vd->elem);
   678                 if(vf == nil)
   679                         return 0;
   680                 vacfilegetsize(vf, &size);
   681                 ext = malloc(size+1);
   682                 if(ext == nil)
   683                         return 0;
   684                 n = vacfileread(vf, ext, size, 0);
   685                 USED(n);
   686                 ext[size] = 0;
   687                 vacfiledecref(vf);
   688                 if(vd->mode & ModeLink){
   689                         dir.qid.type |= QTSYMLINK;
   690                         dir.mode |= DMSYMLINK;
   691                 }
   692                 if(vd->mode & ModeDevice)
   693                         dir.mode |= DMDEVICE;
   694                 if(vd->mode & ModeNamedPipe)
   695                         dir.mode |= DMNAMEDPIPE;
   696         }
   697 #endif
   698 
   699         dir.atime = vd->atime;
   700         dir.mtime = vd->mtime;
   701         dir.length = vd->size;
   702 
   703         dir.name = vd->elem;
   704         dir.uid = vd->uid;
   705         dir.gid = vd->gid;
   706         dir.muid = vd->mid;
   707 
   708         ret = convD2M(&dir, p, np);
   709 #ifdef PLAN9PORT
   710         free(ext);
   711 #endif
   712         return ret;
   713 }
   714 
   715 int
   716 vacdirread(Fid *f, char *p, long off, long cnt)
   717 {
   718         int i, n, nb;
   719         VacDir vd;
   720 
   721         /*
   722          * special case of rewinding a directory
   723          * otherwise ignore the offset
   724          */
   725         if(off == 0 && f->vde){
   726                 vdeclose(f->vde);
   727                 f->vde = nil;
   728         }
   729 
   730         if(f->vde == nil){
   731                 f->vde = vdeopen(f->file);
   732                 if(f->vde == nil)
   733                         return -1;
   734         }
   735 
   736         for(nb = 0; nb < cnt; nb += n) {
   737                 i = vderead(f->vde, &vd);
   738                 if(i < 0)
   739                         return -1;
   740                 if(i == 0)
   741                         break;
   742                 n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
   743                 if(n <= BIT16SZ) {
   744                         vdeunread(f->vde);
   745                         break;
   746                 }
   747                 vdcleanup(&vd);
   748                 p += n;
   749         }
   750         return nb;
   751 }
   752 
   753 Fid *
   754 newfid(int fid)
   755 {
   756         Fid *f, *ff;
   757 
   758         ff = 0;
   759         for(f = fids; f; f = f->next)
   760                 if(f->fid == fid)
   761                         return f;
   762                 else if(!ff && !f->busy)
   763                         ff = f;
   764         if(ff){
   765                 ff->fid = fid;
   766                 return ff;
   767         }
   768         f = vtmallocz(sizeof *f);
   769         f->fid = fid;
   770         f->next = fids;
   771         fids = f;
   772         return f;
   773 }
   774 
   775 void
   776 io(void)
   777 {
   778         char *err;
   779         int n;
   780 
   781         for(;;){
   782                 n = read9pmsg(mfd[0], mdata, sizeof mdata);
   783                 if(n <= 0)
   784                         break;
   785                 if(convM2S(mdata, n, &rhdr) != n)
   786                         sysfatal("convM2S conversion error");
   787 
   788                 if(dflag)
   789                         fprint(2, "vacfs:<-%F\n", &rhdr);
   790 
   791                 thdr.data = (char*)mdata + IOHDRSZ;
   792                 if(!fcalls[rhdr.type])
   793                         err = "bad fcall type";
   794                 else
   795                         err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
   796                 if(err){
   797                         thdr.type = Rerror;
   798                         thdr.ename = err;
   799 #ifdef PLAN9PORT
   800                         thdr.errornum = 0;
   801 #endif
   802                 }else{
   803                         thdr.type = rhdr.type + 1;
   804                         thdr.fid = rhdr.fid;
   805                 }
   806                 thdr.tag = rhdr.tag;
   807                 if(dflag)
   808                         fprint(2, "vacfs:->%F\n", &thdr);
   809                 n = convS2M(&thdr, mdata, messagesize);
   810                 if(n <= BIT16SZ)
   811                         sysfatal("convS2M conversion error");
   812                 if(err)
   813                         vtfree(err);
   814 
   815                 if(write(mfd[1], mdata, n) != n)
   816                         sysfatal("mount write: %r");
   817         }
   818 }
   819 
   820 int
   821 permf(VacFile *vf, char *user, int p)
   822 {
   823         VacDir dir;
   824         ulong perm;
   825 
   826         if(vacfilegetdir(vf, &dir))
   827                 return 0;
   828         perm = dir.mode & 0777;
   829 
   830         if(noperm)
   831                 goto Good;
   832         if((p*Pother) & perm)
   833                 goto Good;
   834         if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
   835                 goto Good;
   836         if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
   837                 goto Good;
   838         vdcleanup(&dir);
   839         return 0;
   840 Good:
   841         vdcleanup(&dir);
   842         return 1;
   843 }
   844 
   845 int
   846 perm(Fid *f, int p)
   847 {
   848         return permf(f->file, f->user, p);
   849 }
   850 
   851 void
   852 vacshutdown(void)
   853 {
   854         Fid *f;
   855 
   856         for(f = fids; f; f = f->next) {
   857                 if(!f->busy)
   858                         continue;
   859                 rclunk(f);
   860         }
   861 
   862         vacfsclose(fs);
   863         vthangup(conn);
   864 }