5 typedef struct Fid Fid;
9 OPERM = 0x3 /* mask of all permission types in open mode */
39 uchar mdata[8192+IOHDRSZ];
40 int messagesize = sizeof mdata;
51 void vacshutdown(void);
54 int permf(VacFile*, char*, int);
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);
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*);
68 char *(*fcalls[Tmax])(Fid*);
73 fcalls[Tflush]= rflush;
74 fcalls[Tversion]= rversion;
75 fcalls[Tattach]= rattach;
79 fcalls[Tcreate]= rcreate;
81 fcalls[Twrite]= rwrite;
82 fcalls[Tclunk]= rclunk;
83 fcalls[Tremove]= rremove;
85 fcalls[Twstat]= rwstat;
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";
105 notifyf(void *a, char *s)
108 if(strncmp(s, "interrupt", 9) == 0)
113 #define TWID64 ~(u64int)0
122 n = strtoul(s, &es, 0);
123 if(*es == 'k' || *es == 'K'){
126 }else if(*es == 'm' || *es == 'M'){
129 }else if(*es == 'g' || *es == 'G'){
139 threadmain(int argc, char *argv[])
141 char *defsrv, *srvname;
149 fmtinstall('H', encodefmt);
150 fmtinstall('V', vtscorefmt);
151 fmtinstall('F', vtfcallfmt);
157 fmtinstall('F', fcallfmt);
167 host = EARGF(usage());
170 defsrv = EARGF(usage());
176 mem = unittoull(EARGF(usage()));
179 defmnt = EARGF(usage());
195 if(defsrv == nil && defmnt == nil && !stdio){
196 srvname = strchr(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;
208 if(defsrv == nil && defmnt == nil && !stdio)
212 sysfatal("cannot use -m with -i");
221 sysfatal("could not connect to server: %r");
223 if(vtconnect(conn) < 0)
224 sysfatal("vtconnect: %r");
226 fs = vacfsopen(conn, argv[0], VtOREAD, mem);
228 sysfatal("vacfsopen: %r");
232 sysfatal("pipe failed: %r");
238 srvname = smprint("/srv/%s", defsrv);
239 fd = create(srvname, OWRITE|ORCLOSE, 0666);
241 sysfatal("create %s: %r", srvname);
242 if(fprint(fd, "%d", srvfd) < 0)
243 sysfatal("write %s: %r", srvname);
251 proccreate(srv, 0, 32 * 1024);
252 if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0)
253 sysfatal("post9pservice");
255 procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
260 if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
261 sysfatal("mount %s: %r", defmnt);
279 fprint(2, "usage: %s [-sd] [-h host] [-m mountpoint] [-M mem] vacfile\n", argv0);
280 threadexitsall("usage");
284 rversion(Fid *unused)
290 for(f = fids; f; f = f->next)
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";
317 return vtstrdup("vacfs: authentication not required");
323 /* no authentication for the momment */
327 file = vacfsgetroot(fs);
329 rerrstr(err, sizeof err);
330 return vtstrdup(err);
335 f->qid.path = vacfilegetid(f->file);
340 f->user = vtstrdup(rhdr.uname);
349 VacFile *file, *nfile;
358 if(rhdr.fid != rhdr.newfid){
360 return vtstrdup(Eisopen);
362 return vtstrdup(Enotexist);
363 nf = newfid(rhdr.newfid);
365 return vtstrdup(Eisopen);
369 nf->file = vacfileincref(f->file);
370 nf->user = vtstrdup(f->user);
374 nwname = rhdr.nwname;
386 for(nqid = 0; nqid < nwname; nqid++){
387 if((qid.type & QTDIR) == 0){
391 if(!permf(file, f->user, Pexec)) {
395 nfile = vacfilewalk(file, rhdr.wname[nqid]);
401 if(vacfileisdir(file))
404 if(vacfilegetmode(file)&ModeLink)
405 qid.type = QTSYMLINK;
407 qid.vers = vacfilegetmcount(file);
408 qid.path = vacfilegetid(file);
409 thdr.wqid[nqid] = qid;
416 f->qid = thdr.wqid[nqid-1];
417 vacfiledecref(f->file);
426 /* only error on the first element */
428 return vtstrdup(err);
439 return vtstrdup(Eisopen);
441 return vtstrdup(Enotexist);
444 thdr.iounit = messagesize - IOHDRSZ;
445 if(f->qid.type & QTDIR){
447 return vtstrdup(Eperm);
449 return vtstrdup(Eperm);
456 return vtstrdup(Erdonly);
457 trunc = mode & OTRUNC;
459 if(mode==OWRITE || mode==ORDWR || trunc)
461 return vtstrdup(Eperm);
462 if(mode==OREAD || mode==ORDWR)
464 return vtstrdup(Eperm);
467 return vtstrdup(Eperm);
469 thdr.iounit = messagesize - IOHDRSZ;
481 return vtstrdup(Eisopen);
483 return vtstrdup(Enotexist);
484 if(fs->mode & ModeSnapshot)
485 return vtstrdup(Erdonly);
487 if(!vacfileisdir(vf))
488 return vtstrdup(Enotdir);
489 if(!permf(vf, fid->user, Pwrite))
490 return vtstrdup(Eperm);
492 mode = rhdr.perm & 0777;
494 if(rhdr.perm & DMDIR){
495 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
496 return vtstrdup(Emode);
497 switch(rhdr.mode & OPERM){
499 return vtstrdup(Emode);
505 return vtstrdup(Eperm);
509 vf = vacfilecreate(vf, rhdr.name, mode);
512 rerrstr(err, sizeof err);
514 return vtstrdup(err);
517 vacfiledecref(fid->file);
520 fid->qid.type = QTFILE;
522 fid->qid.type = QTDIR;
523 fid->qid.vers = vacfilegetmcount(vf);
524 fid->qid.path = vacfilegetid(vf);
527 thdr.iounit = messagesize - IOHDRSZ;
543 return vtstrdup(Enotexist);
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");
558 n = vacfileread(vf, buf, cnt, off);
560 rerrstr(err, sizeof err);
561 return vtstrdup(err);
571 return vtstrdup(Erdonly);
582 vacfiledecref(f->file);
597 return vtstrdup(Enotexist);
599 vfp = vacfilegetparent(vf);
601 if(!permf(vfp, f->user, Pwrite)) {
606 if(!vacfileremove(vf)) {
607 rerrstr(errbuf, sizeof errbuf);
614 return vtstrdup(err);
621 static uchar statbuf[1024];
625 return vtstrdup(Enotexist);
626 parent = vacfilegetparent(f->file);
627 vacfilegetdir(f->file, &dir);
629 thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
631 vacfiledecref(parent);
639 return vtstrdup(Enotexist);
640 return vtstrdup(Erdonly);
644 vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
655 memset(&dir, 0, sizeof(dir));
657 dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
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;
666 if(vd->mode & ModeExclusive){
667 dir.qid.type |= QTEXCL;
670 if(vd->mode & ModeDir){
671 dir.qid.type |= QTDIR;
676 if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
677 vf = vacfilewalk(parent, vd->elem);
680 vacfilegetsize(vf, &size);
681 ext = malloc(size+1);
684 n = vacfileread(vf, ext, size, 0);
688 if(vd->mode & ModeLink){
689 dir.qid.type |= QTSYMLINK;
690 dir.mode |= DMSYMLINK;
692 if(vd->mode & ModeDevice)
693 dir.mode |= DMDEVICE;
694 if(vd->mode & ModeNamedPipe)
695 dir.mode |= DMNAMEDPIPE;
699 dir.atime = vd->atime;
700 dir.mtime = vd->mtime;
701 dir.length = vd->size;
708 ret = convD2M(&dir, p, np);
716 vacdirread(Fid *f, char *p, long off, long cnt)
722 * special case of rewinding a directory
723 * otherwise ignore the offset
725 if(off == 0 && f->vde){
731 f->vde = vdeopen(f->file);
736 for(nb = 0; nb < cnt; nb += n) {
737 i = vderead(f->vde, &vd);
742 n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
759 for(f = fids; f; f = f->next)
762 else if(!ff && !f->busy)
768 f = vtmallocz(sizeof *f);
782 n = read9pmsg(mfd[0], mdata, sizeof mdata);
785 if(convM2S(mdata, n, &rhdr) != n)
786 sysfatal("convM2S conversion error");
789 fprint(2, "vacfs:<-%F\n", &rhdr);
791 thdr.data = (char*)mdata + IOHDRSZ;
792 if(!fcalls[rhdr.type])
793 err = "bad fcall type";
795 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
803 thdr.type = rhdr.type + 1;
808 fprint(2, "vacfs:->%F\n", &thdr);
809 n = convS2M(&thdr, mdata, messagesize);
811 sysfatal("convS2M conversion error");
815 if(write(mfd[1], mdata, n) != n)
816 sysfatal("mount write: %r");
821 permf(VacFile *vf, char *user, int p)
826 if(vacfilegetdir(vf, &dir))
828 perm = dir.mode & 0777;
832 if((p*Pother) & perm)
834 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
836 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
848 return permf(f->file, f->user, p);
856 for(f = fids; f; f = f->next) {