7 typedef struct Fid Fid;
8 typedef struct DirBuf DirBuf;
12 OPERM = 0x3 /* mask of all permission types in open mode */
37 VacDir buf[DirBufSize];
56 uchar mdata[8192+IOHDRSZ];
57 int messagesize = sizeof mdata;
62 /* VtSession *session; */
69 void vacshutdown(void);
72 int permf(VacFile*, char*, int);
74 void init(char*, char*, long, int);
75 DirBuf *dirBufAlloc(VacFile*);
76 VacDir *dirBufGet(DirBuf*);
77 int dirBufUnget(DirBuf*);
78 void dirBufFree(DirBuf*);
79 int vacdirread(Fid *f, char *p, long off, long cnt);
80 int vdStat(VacFile *parent, VacDir *vd, uchar *p, int np);
84 char *rflush(Fid*), *rversion(Fid*),
85 *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
86 *ropen(Fid*), *rcreate(Fid*),
87 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
88 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
90 char *(*fcalls[Tmax])(Fid*);
95 fcalls[Tflush]= rflush;
96 fcalls[Tversion]= rversion;
97 fcalls[Tattach]= rattach;
100 fcalls[Topen]= ropen;
101 fcalls[Tcreate]= rcreate;
102 fcalls[Tread]= rread;
103 fcalls[Twrite]= rwrite;
104 fcalls[Tclunk]= rclunk;
105 fcalls[Tremove]= rremove;
106 fcalls[Tstat]= rstat;
107 fcalls[Twstat]= rwstat;
110 char Eperm[] = "permission denied";
111 char Enotdir[] = "not a directory";
112 char Enotexist[] = "file does not exist";
113 char Einuse[] = "file in use";
114 char Eexist[] = "file exists";
115 char Enotowner[] = "not owner";
116 char Eisopen[] = "file already open for I/O";
117 char Excl[] = "exclusive use file already open";
118 char Ename[] = "illegal name";
119 char Erdonly[] = "read only file system";
120 char Eio[] = "i/o error";
121 char Eempty[] = "directory is not empty";
122 char Emode[] = "illegal mode";
127 notifyf(void *a, char *s)
130 if(strncmp(s, "interrupt", 9) == 0)
136 threadmain(int argc, char *argv[])
145 fmtinstall('H', encodefmt);
146 fmtinstall('V', vtscorefmt);
147 fmtinstall('F', vtfcallfmt);
152 fmtinstall('F', fcallfmt);
156 ncache = atoi(EARGF(usage()));
164 host = EARGF(usage());
167 defsrv = EARGF(usage());
183 init(argv[0], host, ncache, readOnly);
186 sysfatal("pipe failed: %r");
190 proccreate(srv, 0, 32 * 1024);
193 q = strrchr(argv[0], '/');
198 defsrv = vtmalloc(6+strlen(q)+1);
199 strcpy(defsrv, "vacfs.");
202 if(strcmp(defsrv+l-4, ".vac") == 0)
206 if(post9pservice(p[1], defsrv) != 0)
207 sysfatal("post9pservice");
222 fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
223 threadexitsall("usage");
227 rversion(Fid *unused)
233 for(f = fids; f; f = f->next)
238 return vtstrdup("version: message size too small");
239 messagesize = rhdr.msize;
240 if(messagesize > sizeof mdata)
241 messagesize = sizeof mdata;
242 thdr.msize = messagesize;
243 if(strncmp(rhdr.version, "9P2000", 6) != 0)
244 return vtstrdup("unrecognized 9P version");
245 thdr.version = "9P2000";
246 if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
248 thdr.version = "9P2000.u";
264 return vtstrdup("vacfs: authentication not required");
270 /* no authentication for the momment */
274 file = vacfsgetroot(fs);
276 rerrstr(err, sizeof err);
277 return vtstrdup(err);
282 f->qid.path = vacfilegetid(f->file);
287 f->user = vtstrdup(rhdr.uname);
294 _vfWalk(VacFile *file, char *name)
298 n = vacfilewalk(file, name);
301 if(strcmp(name, "SLASH") == 0)
302 return vacfilewalk(file, "/");
309 VacFile *file, *nfile;
318 if(rhdr.fid != rhdr.newfid){
320 return vtstrdup(Eisopen);
322 return vtstrdup(Enotexist);
323 nf = newfid(rhdr.newfid);
325 return vtstrdup(Eisopen);
329 nf->file = vacfileincref(f->file);
330 nf->user = vtstrdup(f->user);
334 nwname = rhdr.nwname;
346 for(nqid = 0; nqid < nwname; nqid++){
347 if((qid.type & QTDIR) == 0){
351 if(!permf(file, f->user, Pexec)) {
355 nfile = _vfWalk(file, rhdr.wname[nqid]);
361 if(vacfileisdir(file))
363 if(vacfilegetmode(file)&ModeLink)
364 qid.type = QTSYMLINK;
365 qid.vers = vacfilegetmcount(file);
366 qid.path = vacfilegetid(file);
367 thdr.wqid[nqid] = qid;
374 f->qid = thdr.wqid[nqid-1];
375 vacfiledecref(f->file);
384 /* only error on the first element */
386 return vtstrdup(err);
397 return vtstrdup(Eisopen);
399 return vtstrdup(Enotexist);
402 thdr.iounit = messagesize - IOHDRSZ;
403 if(f->qid.type & QTDIR){
405 return vtstrdup(Eperm);
407 return vtstrdup(Eperm);
414 return vtstrdup(Erdonly);
415 trunc = mode & OTRUNC;
417 if(mode==OWRITE || mode==ORDWR || trunc)
419 return vtstrdup(Eperm);
420 if(mode==OREAD || mode==ORDWR)
422 return vtstrdup(Eperm);
425 return vtstrdup(Eperm);
427 thdr.iounit = messagesize - IOHDRSZ;
439 return vtstrdup(Eisopen);
441 return vtstrdup(Enotexist);
442 if(fs->mode & ModeSnapshot)
443 return vtstrdup(Erdonly);
445 if(!vacfileisdir(vf))
446 return vtstrdup(Enotdir);
447 if(!permf(vf, fid->user, Pwrite))
448 return vtstrdup(Eperm);
450 mode = rhdr.perm & 0777;
452 if(rhdr.perm & DMDIR){
453 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
454 return vtstrdup(Emode);
455 switch(rhdr.mode & OPERM){
457 return vtstrdup(Emode);
463 return vtstrdup(Eperm);
467 vf = vacfilecreate(vf, rhdr.name, mode, "none");
470 rerrstr(err, sizeof err);
472 return vtstrdup(err);
475 vacfiledecref(fid->file);
478 fid->qid.type = QTFILE;
480 fid->qid.type = QTDIR;
481 fid->qid.vers = vacfilegetmcount(vf);
482 fid->qid.path = vacfilegetid(vf);
485 thdr.iounit = messagesize - IOHDRSZ;
501 return vtstrdup(Enotexist);
507 if(f->qid.type & QTDIR)
508 n = vacdirread(f, buf, off, cnt);
509 else if(vacfilegetmode(f->file)&ModeDevice)
510 return vtstrdup("device");
511 else if(vacfilegetmode(f->file)&ModeLink)
512 return vtstrdup("symbolic link");
513 else if(vacfilegetmode(f->file)&ModeNamedPipe)
514 return vtstrdup("named pipe");
516 n = vacfileread(vf, buf, cnt, off);
518 rerrstr(err, sizeof err);
519 return vtstrdup(err);
534 return vtstrdup(Enotexist);
540 if(f->qid.type & QTDIR)
541 return "file is a directory";
542 thdr.count = vacfilewrite(vf, buf, cnt, off, "none");
546 rerrstr(err, sizeof err);
547 fprint(2, "write failed: %s\n", err);
548 return vtstrdup(err);
561 vacfiledecref(f->file);
576 return vtstrdup(Enotexist);
578 vfp = vacfilegetparent(vf);
580 if(!permf(vfp, f->user, Pwrite)) {
585 if(!vacfileremove(vf, "none")) {
586 rerrstr(errbuf, sizeof errbuf);
587 print("vfRemove failed: %s\n", errbuf);
595 return vtstrdup(err);
602 static uchar statbuf[1024];
606 return vtstrdup(Enotexist);
607 parent = vacfilegetparent(f->file);
608 vacfilegetdir(f->file, &dir);
610 thdr.nstat = vdStat(parent, &dir, thdr.stat, sizeof statbuf);
612 vacfiledecref(parent);
620 return vtstrdup(Enotexist);
621 return vtstrdup(Erdonly);
625 vdStat(VacFile *parent, VacDir *vd, uchar *p, int np)
633 memset(&dir, 0, sizeof(dir));
637 * Where do path and version come from
639 dir.qid.path = vd->qid;
640 dir.qid.vers = vd->mcount;
641 dir.mode = vd->mode & 0777;
642 if(vd->mode & ModeAppend){
643 dir.qid.type |= QTAPPEND;
644 dir.mode |= DMAPPEND;
646 if(vd->mode & ModeExclusive){
647 dir.qid.type |= QTEXCL;
650 if(vd->mode & ModeDir){
651 dir.qid.type |= QTDIR;
655 if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
656 vf = vacfilewalk(parent, vd->elem);
659 vacfilegetsize(vf, &size);
660 ext = malloc(size+1);
663 n = vacfileread(vf, ext, size, 0);
666 if(vd->mode & ModeLink){
667 dir.qid.type |= QTSYMLINK;
668 dir.mode |= DMSYMLINK;
670 if(vd->mode & ModeDevice)
671 dir.mode |= DMDEVICE;
672 if(vd->mode & ModeNamedPipe)
673 dir.mode |= DMNAMEDPIPE;
676 dir.atime = vd->atime;
677 dir.mtime = vd->mtime;
678 dir.length = vd->size;
685 dir.uidnum = atoi(vd->uid);
686 dir.gidnum = atoi(vd->gid);
688 ret = convD2Mu(&dir, p, np, dotu);
694 dirBufAlloc(VacFile *vf)
698 db = vtmallocz(sizeof(DirBuf));
699 db->vde = vdeopen(vf);
704 dirBufGet(DirBuf *db)
713 n = vderead(db->vde, db->buf);
724 vd = db->buf + db->i;
731 dirBufUnget(DirBuf *db)
739 dirBufFree(DirBuf *db)
746 for(i=db->i; i<db->n; i++)
747 vdcleanup(db->buf + i);
753 vacdirread(Fid *f, char *p, long off, long cnt)
759 * special case of rewinding a directory
760 * otherwise ignore the offset
762 if(off == 0 && f->db) {
768 f->db = dirBufAlloc(f->file);
770 for(nb = 0; nb < cnt; nb += n) {
771 vd = dirBufGet(f->db);
777 n = vdStat(f->file, vd, (uchar*)p, cnt-nb);
794 for(f = fids; f; f = f->next)
797 else if(!ff && !f->busy)
803 f = vtmallocz(sizeof *f);
818 * reading from a pipe or a network device
819 * will give an error after a few eof reads
820 * however, we cannot tell the difference
821 * between a zero-length read and an interrupt
822 * on the processes writing to us,
823 * so we wait for the error
825 n = read9pmsg(mfd[0], mdata, sizeof mdata);
830 if(convM2Su(mdata, n, &rhdr, dotu) != n)
831 sysfatal("convM2S conversion error");
834 fprint(2, "vacfs:<-%F\n", &rhdr);
836 thdr.data = (char*)mdata + IOHDRSZ;
837 if(!fcalls[rhdr.type])
838 err = "bad fcall type";
840 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
846 thdr.type = rhdr.type + 1;
851 fprint(2, "vacfs:->%F\n", &thdr);
852 n = convS2Mu(&thdr, mdata, messagesize, dotu);
854 sysfatal("convS2Mu conversion error");
858 if(write(mfd[1], mdata, n) != n)
859 sysfatal("mount write: %r");
864 permf(VacFile *vf, char *user, int p)
869 if(vacfilegetdir(vf, &dir))
871 perm = dir.mode & 0777;
875 if((p*Pother) & perm)
877 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
879 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
891 return permf(f->file, f->user, p);
895 init(char *file, char *host, long ncache, int readOnly)
902 sysfatal("could not connect to server: %r");
904 if(vtconnect(conn) < 0)
905 sysfatal("vtconnect: %r");
907 fs = vacfsopen(conn, file, /*readOnly ? ModeSnapshot :*/ VtOREAD, ncache);
909 sysfatal("vfsOpen: %r");
917 for(f = fids; f; f = f->next) {
920 fprint(2, "open fid: %d\n", f->fid);