tvacfs.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tvacfs.c (14671B)
       ---
            1 #include "stdinc.h"
            2 #include <fcall.h>
            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 }