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;
68 void vacshutdown(void);
71 int permf(VacFile*, char*, int);
73 void init(char*, char*, long, int);
74 DirBuf *dirBufAlloc(VacFile*);
75 VacDir *dirBufGet(DirBuf*);
76 int dirBufUnget(DirBuf*);
77 void dirBufFree(DirBuf*);
78 int vacdirread(Fid *f, char *p, long off, long cnt);
79 int vdStat(VacDir *vd, uchar *p, int np);
83 char *rflush(Fid*), *rversion(Fid*),
84 *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
85 *ropen(Fid*), *rcreate(Fid*),
86 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
87 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
89 char *(*fcalls[Tmax])(Fid*);
94 fcalls[Tflush]= rflush;
95 fcalls[Tversion]= rversion;
96 fcalls[Tattach]= rattach;
100 fcalls[Tcreate]= rcreate;
101 fcalls[Tread]= rread;
102 fcalls[Twrite]= rwrite;
103 fcalls[Tclunk]= rclunk;
104 fcalls[Tremove]= rremove;
105 fcalls[Tstat]= rstat;
106 fcalls[Twstat]= rwstat;
109 char Eperm[] = "permission denied";
110 char Enotdir[] = "not a directory";
111 char Enotexist[] = "file does not exist";
112 char Einuse[] = "file in use";
113 char Eexist[] = "file exists";
114 char Enotowner[] = "not owner";
115 char Eisopen[] = "file already open for I/O";
116 char Excl[] = "exclusive use file already open";
117 char Ename[] = "illegal name";
118 char Erdonly[] = "read only file system";
119 char Eio[] = "i/o error";
120 char Eempty[] = "directory is not empty";
121 char Emode[] = "illegal mode";
126 notifyf(void *a, char *s)
129 if(strncmp(s, "interrupt", 9) == 0)
135 threadmain(int argc, char *argv[])
147 fmtinstall('F', fcallfmt);
151 ncache = atoi(EARGF(usage()));
159 host = EARGF(usage());
162 defsrv = EARGF(usage());
175 init(argv[0], host, ncache, readOnly);
178 sysfatal("pipe failed: %r");
182 proccreate(srv, 0, 32 * 1024);
185 q = strrchr(argv[0], '/');
190 defsrv = vtmalloc(6+strlen(q)+1);
191 strcpy(defsrv, "vacfs.");
194 if(strcmp(defsrv+l-4, ".vac") == 0)
198 if(post9pservice(p[1], defsrv) != 0)
199 sysfatal("post9pservice");
215 fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
216 threadexitsall("usage");
220 rversion(Fid *unused)
226 for(f = fids; f; f = f->next)
231 return vtstrdup("version: message size too small");
232 messagesize = rhdr.msize;
233 if(messagesize > sizeof mdata)
234 messagesize = sizeof mdata;
235 thdr.msize = messagesize;
236 if(strncmp(rhdr.version, "9P2000", 6) != 0)
237 return vtstrdup("unrecognized 9P version");
238 thdr.version = "9P2000";
253 return vtstrdup("vacfs: authentication not required");
259 /* no authentication for the momment */
263 file = vacfsgetroot(fs);
265 rerrstr(err, sizeof err);
266 return vtstrdup(err);
271 f->qid.path = vacfilegetid(f->file);
276 f->user = vtstrdup(rhdr.uname);
283 _vfWalk(VacFile *file, char *name)
287 n = vacfilewalk(file, name);
290 if(strcmp(name, "SLASH") == 0)
291 return vacfilewalk(file, "/");
298 VacFile *file, *nfile;
307 if(rhdr.fid != rhdr.newfid){
309 return vtstrdup(Eisopen);
311 return vtstrdup(Enotexist);
312 nf = newfid(rhdr.newfid);
314 return vtstrdup(Eisopen);
318 nf->file = vacfileincref(f->file);
319 nf->user = vtstrdup(f->user);
323 nwname = rhdr.nwname;
335 for(nqid = 0; nqid < nwname; nqid++){
336 if((qid.type & QTDIR) == 0){
340 if(!permf(file, f->user, Pexec)) {
344 nfile = _vfWalk(file, rhdr.wname[nqid]);
350 if(vacfileisdir(file))
352 qid.vers = vacfilegetmcount(file);
353 qid.path = vacfilegetid(file);
354 thdr.wqid[nqid] = qid;
361 f->qid = thdr.wqid[nqid-1];
362 vacfiledecref(f->file);
371 /* only error on the first element */
373 return vtstrdup(err);
384 return vtstrdup(Eisopen);
386 return vtstrdup(Enotexist);
389 thdr.iounit = messagesize - IOHDRSZ;
390 if(f->qid.type & QTDIR){
392 return vtstrdup(Eperm);
394 return vtstrdup(Eperm);
401 return vtstrdup(Erdonly);
402 trunc = mode & OTRUNC;
404 if(mode==OWRITE || mode==ORDWR || trunc)
406 return vtstrdup(Eperm);
407 if(mode==OREAD || mode==ORDWR)
409 return vtstrdup(Eperm);
412 return vtstrdup(Eperm);
414 thdr.iounit = messagesize - IOHDRSZ;
426 return vtstrdup(Eisopen);
428 return vtstrdup(Enotexist);
429 if(fs->mode & ModeSnapshot)
430 return vtstrdup(Erdonly);
432 if(!vacfileisdir(vf))
433 return vtstrdup(Enotdir);
434 if(!permf(vf, fid->user, Pwrite))
435 return vtstrdup(Eperm);
437 mode = rhdr.perm & 0777;
439 if(rhdr.perm & DMDIR){
440 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
441 return vtstrdup(Emode);
442 switch(rhdr.mode & OPERM){
444 return vtstrdup(Emode);
450 return vtstrdup(Eperm);
454 vf = vacfilecreate(vf, rhdr.name, mode, "none");
457 rerrstr(err, sizeof err);
459 return vtstrdup(err);
462 vacfiledecref(fid->file);
465 fid->qid.type = QTFILE;
467 fid->qid.type = QTDIR;
468 fid->qid.vers = vacfilegetmcount(vf);
469 fid->qid.path = vacfilegetid(vf);
472 thdr.iounit = messagesize - IOHDRSZ;
488 return vtstrdup(Enotexist);
494 if(f->qid.type & QTDIR)
495 n = vacdirread(f, buf, off, cnt);
497 n = vacfileread(vf, buf, cnt, off);
499 rerrstr(err, sizeof err);
500 return vtstrdup(err);
515 return vtstrdup(Enotexist);
521 if(f->qid.type & QTDIR)
522 return "file is a directory";
523 thdr.count = vacfilewrite(vf, buf, cnt, off, "none");
527 rerrstr(err, sizeof err);
528 fprint(2, "write failed: %s\n", err);
529 return vtstrdup(err);
541 vacfiledecref(f->file);
556 return vtstrdup(Enotexist);
558 vfp = vacfilegetparent(vf);
560 if(!permf(vfp, f->user, Pwrite)) {
565 if(!vacfileremove(vf, "none")) {
566 rerrstr(errbuf, sizeof errbuf);
567 print("vfRemove failed: %s\n", errbuf);
575 return vtstrdup(err);
582 static uchar statbuf[1024];
585 return vtstrdup(Enotexist);
586 vacfilegetdir(f->file, &dir);
588 thdr.nstat = vdStat(&dir, thdr.stat, sizeof statbuf);
597 return vtstrdup(Enotexist);
598 return vtstrdup(Erdonly);
602 vdStat(VacDir *vd, uchar *p, int np)
606 memset(&dir, 0, sizeof(dir));
609 * Where do path and version come from
611 dir.qid.path = vd->qid;
612 dir.qid.vers = vd->mcount;
613 dir.mode = vd->mode & 0777;
614 if(vd->mode & ModeAppend){
615 dir.qid.type |= QTAPPEND;
616 dir.mode |= DMAPPEND;
618 if(vd->mode & ModeExclusive){
619 dir.qid.type |= QTEXCL;
622 if(vd->mode & ModeDir){
623 dir.qid.type |= QTDIR;
627 dir.atime = vd->atime;
628 dir.mtime = vd->mtime;
629 dir.length = vd->size;
636 return convD2M(&dir, p, np);
640 dirBufAlloc(VacFile *vf)
644 db = vtmallocz(sizeof(DirBuf));
645 db->vde = vdeopen(vf);
650 dirBufGet(DirBuf *db)
659 n = vderead(db->vde, db->buf);
670 vd = db->buf + db->i;
677 dirBufUnget(DirBuf *db)
685 dirBufFree(DirBuf *db)
692 for(i=db->i; i<db->n; i++)
693 vdcleanup(db->buf + i);
699 vacdirread(Fid *f, char *p, long off, long cnt)
705 * special case of rewinding a directory
706 * otherwise ignore the offset
708 if(off == 0 && f->db) {
714 f->db = dirBufAlloc(f->file);
716 for(nb = 0; nb < cnt; nb += n) {
717 vd = dirBufGet(f->db);
723 n = vdStat(vd, (uchar*)p, cnt-nb);
740 for(f = fids; f; f = f->next)
743 else if(!ff && !f->busy)
749 f = vtmallocz(sizeof *f);
764 * reading from a pipe or a network device
765 * will give an error after a few eof reads
766 * however, we cannot tell the difference
767 * between a zero-length read and an interrupt
768 * on the processes writing to us,
769 * so we wait for the error
771 n = read9pmsg(mfd[0], mdata, sizeof mdata);
776 if(convM2S(mdata, n, &rhdr) != n)
777 sysfatal("convM2S conversion error");
780 fprint(2, "vacfs:<-%F\n", &rhdr);
782 thdr.data = (char*)mdata + IOHDRSZ;
783 if(!fcalls[rhdr.type])
784 err = "bad fcall type";
786 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
791 thdr.type = rhdr.type + 1;
796 fprint(2, "vacfs:->%F\n", &thdr);
797 n = convS2M(&thdr, mdata, messagesize);
801 if(write(mfd[1], mdata, n) != n)
802 sysfatal("mount write: %r");
807 permf(VacFile *vf, char *user, int p)
812 if(vacfilegetdir(vf, &dir))
814 perm = dir.mode & 0777;
818 if((p*Pother) & perm)
820 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
822 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
834 return permf(f->file, f->user, p);
838 init(char *file, char *host, long ncache, int readOnly)
843 fmtinstall('V', vtscorefmt);
844 // fmtinstall('R', vtErrFmt);
848 sysfatal("could not connect to server: %r");
850 if(vtconnect(conn) < 0)
851 sysfatal("vtconnect: %r");
853 fs = vacfsopen(conn, file, /*readOnly ? ModeSnapshot :*/ VtOREAD, ncache);
855 sysfatal("vfsOpen: %r");
863 for(f = fids; f; f = f->next) {
866 fprint(2, "open fid: %d\n", f->fid);