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; */
70 void vacshutdown(void);
73 int permf(VacFile*, char*, int);
75 void init(char*, char*, long, int);
76 DirBuf *dirBufAlloc(VacFile*);
77 VacDir *dirBufGet(DirBuf*);
78 int dirBufUnget(DirBuf*);
79 void dirBufFree(DirBuf*);
80 int vacdirread(Fid *f, char *p, long off, long cnt);
81 int vdStat(VacFile *parent, VacDir *vd, uchar *p, int np);
85 char *rflush(Fid*), *rversion(Fid*),
86 *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
87 *ropen(Fid*), *rcreate(Fid*),
88 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
89 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
91 char *(*fcalls[Tmax])(Fid*);
96 fcalls[Tflush]= rflush;
97 fcalls[Tversion]= rversion;
98 fcalls[Tattach]= rattach;
100 fcalls[Twalk]= rwalk;
101 fcalls[Topen]= ropen;
102 fcalls[Tcreate]= rcreate;
103 fcalls[Tread]= rread;
104 fcalls[Twrite]= rwrite;
105 fcalls[Tclunk]= rclunk;
106 fcalls[Tremove]= rremove;
107 fcalls[Tstat]= rstat;
108 fcalls[Twstat]= rwstat;
111 char Eperm[] = "permission denied";
112 char Enotdir[] = "not a directory";
113 char Enotexist[] = "file does not exist";
114 char Einuse[] = "file in use";
115 char Eexist[] = "file exists";
116 char Enotowner[] = "not owner";
117 char Eisopen[] = "file already open for I/O";
118 char Excl[] = "exclusive use file already open";
119 char Ename[] = "illegal name";
120 char Erdonly[] = "read only file system";
121 char Eio[] = "i/o error";
122 char Eempty[] = "directory is not empty";
123 char Emode[] = "illegal mode";
128 notifyf(void *a, char *s)
131 if(strncmp(s, "interrupt", 9) == 0)
137 threadmain(int argc, char *argv[])
146 fmtinstall('H', encodefmt);
147 fmtinstall('V', vtscorefmt);
148 fmtinstall('F', vtfcallfmt);
153 fmtinstall('F', fcallfmt);
157 ncache = atoi(EARGF(usage()));
165 host = EARGF(usage());
168 defsrv = EARGF(usage());
171 defmnt = EARGF(usage());
187 init(argv[0], host, ncache, readOnly);
190 sysfatal("pipe failed: %r");
194 proccreate(srv, 0, 32 * 1024);
196 if(defsrv == nil && defmnt == nil){
197 q = strrchr(argv[0], '/');
202 defsrv = vtmalloc(6+strlen(q)+1);
203 strcpy(defsrv, "vacfs.");
206 if(strcmp(defsrv+l-4, ".vac") == 0)
210 if(post9pservice(p[1], defsrv, defmnt) != 0)
211 sysfatal("post9pservice");
226 fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
227 threadexitsall("usage");
231 rversion(Fid *unused)
237 for(f = fids; f; f = f->next)
242 return vtstrdup("version: message size too small");
243 messagesize = rhdr.msize;
244 if(messagesize > sizeof mdata)
245 messagesize = sizeof mdata;
246 thdr.msize = messagesize;
247 if(strncmp(rhdr.version, "9P2000", 6) != 0)
248 return vtstrdup("unrecognized 9P version");
249 thdr.version = "9P2000";
250 if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
252 thdr.version = "9P2000.u";
268 return vtstrdup("vacfs: authentication not required");
274 /* no authentication for the momment */
278 file = vacfsgetroot(fs);
280 rerrstr(err, sizeof err);
281 return vtstrdup(err);
286 f->qid.path = vacfilegetid(f->file);
291 f->user = vtstrdup(rhdr.uname);
298 _vfWalk(VacFile *file, char *name)
302 n = vacfilewalk(file, name);
305 if(strcmp(name, "SLASH") == 0)
306 return vacfilewalk(file, "/");
313 VacFile *file, *nfile;
322 if(rhdr.fid != rhdr.newfid){
324 return vtstrdup(Eisopen);
326 return vtstrdup(Enotexist);
327 nf = newfid(rhdr.newfid);
329 return vtstrdup(Eisopen);
333 nf->file = vacfileincref(f->file);
334 nf->user = vtstrdup(f->user);
338 nwname = rhdr.nwname;
350 for(nqid = 0; nqid < nwname; nqid++){
351 if((qid.type & QTDIR) == 0){
355 if(!permf(file, f->user, Pexec)) {
359 nfile = _vfWalk(file, rhdr.wname[nqid]);
365 if(vacfileisdir(file))
367 if(vacfilegetmode(file)&ModeLink)
368 qid.type = QTSYMLINK;
369 qid.vers = vacfilegetmcount(file);
370 qid.path = vacfilegetid(file);
371 thdr.wqid[nqid] = qid;
378 f->qid = thdr.wqid[nqid-1];
379 vacfiledecref(f->file);
388 /* only error on the first element */
390 return vtstrdup(err);
401 return vtstrdup(Eisopen);
403 return vtstrdup(Enotexist);
406 thdr.iounit = messagesize - IOHDRSZ;
407 if(f->qid.type & QTDIR){
409 return vtstrdup(Eperm);
411 return vtstrdup(Eperm);
418 return vtstrdup(Erdonly);
419 trunc = mode & OTRUNC;
421 if(mode==OWRITE || mode==ORDWR || trunc)
423 return vtstrdup(Eperm);
424 if(mode==OREAD || mode==ORDWR)
426 return vtstrdup(Eperm);
429 return vtstrdup(Eperm);
431 thdr.iounit = messagesize - IOHDRSZ;
443 return vtstrdup(Eisopen);
445 return vtstrdup(Enotexist);
446 if(fs->mode & ModeSnapshot)
447 return vtstrdup(Erdonly);
449 if(!vacfileisdir(vf))
450 return vtstrdup(Enotdir);
451 if(!permf(vf, fid->user, Pwrite))
452 return vtstrdup(Eperm);
454 mode = rhdr.perm & 0777;
456 if(rhdr.perm & DMDIR){
457 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
458 return vtstrdup(Emode);
459 switch(rhdr.mode & OPERM){
461 return vtstrdup(Emode);
467 return vtstrdup(Eperm);
471 vf = vacfilecreate(vf, rhdr.name, mode, "none");
474 rerrstr(err, sizeof err);
476 return vtstrdup(err);
479 vacfiledecref(fid->file);
482 fid->qid.type = QTFILE;
484 fid->qid.type = QTDIR;
485 fid->qid.vers = vacfilegetmcount(vf);
486 fid->qid.path = vacfilegetid(vf);
489 thdr.iounit = messagesize - IOHDRSZ;
505 return vtstrdup(Enotexist);
511 if(f->qid.type & QTDIR)
512 n = vacdirread(f, buf, off, cnt);
513 else if(vacfilegetmode(f->file)&ModeDevice)
514 return vtstrdup("device");
515 else if(vacfilegetmode(f->file)&ModeLink)
516 return vtstrdup("symbolic link");
517 else if(vacfilegetmode(f->file)&ModeNamedPipe)
518 return vtstrdup("named pipe");
520 n = vacfileread(vf, buf, cnt, off);
522 rerrstr(err, sizeof err);
523 return vtstrdup(err);
538 return vtstrdup(Enotexist);
544 if(f->qid.type & QTDIR)
545 return "file is a directory";
546 thdr.count = vacfilewrite(vf, buf, cnt, off, "none");
550 rerrstr(err, sizeof err);
551 fprint(2, "write failed: %s\n", err);
552 return vtstrdup(err);
565 vacfiledecref(f->file);
580 return vtstrdup(Enotexist);
582 vfp = vacfilegetparent(vf);
584 if(!permf(vfp, f->user, Pwrite)) {
589 if(!vacfileremove(vf, "none")) {
590 rerrstr(errbuf, sizeof errbuf);
591 print("vfRemove failed: %s\n", errbuf);
599 return vtstrdup(err);
606 static uchar statbuf[1024];
610 return vtstrdup(Enotexist);
611 parent = vacfilegetparent(f->file);
612 vacfilegetdir(f->file, &dir);
614 thdr.nstat = vdStat(parent, &dir, thdr.stat, sizeof statbuf);
616 vacfiledecref(parent);
624 return vtstrdup(Enotexist);
625 return vtstrdup(Erdonly);
629 vdStat(VacFile *parent, VacDir *vd, uchar *p, int np)
637 memset(&dir, 0, sizeof(dir));
641 * Where do path and version come from
643 dir.qid.path = vd->qid;
644 dir.qid.vers = vd->mcount;
645 dir.mode = vd->mode & 0777;
646 if(vd->mode & ModeAppend){
647 dir.qid.type |= QTAPPEND;
648 dir.mode |= DMAPPEND;
650 if(vd->mode & ModeExclusive){
651 dir.qid.type |= QTEXCL;
654 if(vd->mode & ModeDir){
655 dir.qid.type |= QTDIR;
659 if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
660 vf = vacfilewalk(parent, vd->elem);
663 vacfilegetsize(vf, &size);
664 ext = malloc(size+1);
667 n = vacfileread(vf, ext, size, 0);
670 if(vd->mode & ModeLink){
671 dir.qid.type |= QTSYMLINK;
672 dir.mode |= DMSYMLINK;
674 if(vd->mode & ModeDevice)
675 dir.mode |= DMDEVICE;
676 if(vd->mode & ModeNamedPipe)
677 dir.mode |= DMNAMEDPIPE;
680 dir.atime = vd->atime;
681 dir.mtime = vd->mtime;
682 dir.length = vd->size;
689 dir.uidnum = atoi(vd->uid);
690 dir.gidnum = atoi(vd->gid);
692 ret = convD2Mu(&dir, p, np, dotu);
698 dirBufAlloc(VacFile *vf)
702 db = vtmallocz(sizeof(DirBuf));
703 db->vde = vdeopen(vf);
708 dirBufGet(DirBuf *db)
717 n = vderead(db->vde, db->buf);
728 vd = db->buf + db->i;
735 dirBufUnget(DirBuf *db)
743 dirBufFree(DirBuf *db)
750 for(i=db->i; i<db->n; i++)
751 vdcleanup(db->buf + i);
757 vacdirread(Fid *f, char *p, long off, long cnt)
763 * special case of rewinding a directory
764 * otherwise ignore the offset
766 if(off == 0 && f->db) {
772 f->db = dirBufAlloc(f->file);
774 for(nb = 0; nb < cnt; nb += n) {
775 vd = dirBufGet(f->db);
781 n = vdStat(f->file, vd, (uchar*)p, cnt-nb);
798 for(f = fids; f; f = f->next)
801 else if(!ff && !f->busy)
807 f = vtmallocz(sizeof *f);
821 n = read9pmsg(mfd[0], mdata, sizeof mdata);
824 if(convM2Su(mdata, n, &rhdr, dotu) != n)
825 sysfatal("convM2S conversion error");
828 fprint(2, "vacfs:<-%F\n", &rhdr);
830 thdr.data = (char*)mdata + IOHDRSZ;
831 if(!fcalls[rhdr.type])
832 err = "bad fcall type";
834 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
840 thdr.type = rhdr.type + 1;
845 fprint(2, "vacfs:->%F\n", &thdr);
846 n = convS2Mu(&thdr, mdata, messagesize, dotu);
848 sysfatal("convS2Mu conversion error");
852 if(write(mfd[1], mdata, n) != n)
853 sysfatal("mount write: %r");
858 permf(VacFile *vf, char *user, int p)
863 if(vacfilegetdir(vf, &dir))
865 perm = dir.mode & 0777;
869 if((p*Pother) & perm)
871 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
873 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
885 return permf(f->file, f->user, p);
889 init(char *file, char *host, long ncache, int readOnly)
896 sysfatal("could not connect to server: %r");
898 if(vtconnect(conn) < 0)
899 sysfatal("vtconnect: %r");
901 fs = vacfsopen(conn, file, /*readOnly ? ModeSnapshot :*/ VtOREAD, ncache);
903 sysfatal("vfsOpen: %r");
911 for(f = fids; f; f = f->next) {