6 #define convM2Su(a, b, c, d) convM2S(a, b, c)
7 #define convS2Mu(a, b, c, d) convS2M(a, b, c)
8 #define convM2Du(a, b, c, d) convM2D(a, b, c)
9 #define convD2Mu(a, b, c, d) convD2M(a, b, c)
12 typedef struct Fid Fid;
16 OPERM = 0x3 /* mask of all permission types in open mode */
46 uchar mdata[8192+IOHDRSZ];
47 int messagesize = sizeof mdata;
59 void vacshutdown(void);
62 int permf(VacFile*, char*, int);
64 void init(char*, char*, long, int);
65 int vacdirread(Fid *f, char *p, long off, long cnt);
66 int vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
70 char *rflush(Fid*), *rversion(Fid*),
71 *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
72 *ropen(Fid*), *rcreate(Fid*),
73 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
74 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
76 char *(*fcalls[Tmax])(Fid*);
81 fcalls[Tflush]= rflush;
82 fcalls[Tversion]= rversion;
83 fcalls[Tattach]= rattach;
87 fcalls[Tcreate]= rcreate;
89 fcalls[Twrite]= rwrite;
90 fcalls[Tclunk]= rclunk;
91 fcalls[Tremove]= rremove;
93 fcalls[Twstat]= rwstat;
96 char Eperm[] = "permission denied";
97 char Enotdir[] = "not a directory";
98 char Enotexist[] = "file does not exist";
99 char Einuse[] = "file in use";
100 char Eexist[] = "file exists";
101 char Enotowner[] = "not owner";
102 char Eisopen[] = "file already open for I/O";
103 char Excl[] = "exclusive use file already open";
104 char Ename[] = "illegal name";
105 char Erdonly[] = "read only file system";
106 char Eio[] = "i/o error";
107 char Eempty[] = "directory is not empty";
108 char Emode[] = "illegal mode";
113 notifyf(void *a, char *s)
116 if(strncmp(s, "interrupt", 9) == 0)
121 #define TWID64 ~(u64int)0
130 n = strtoul(s, &es, 0);
131 if(*es == 'k' || *es == 'K'){
134 }else if(*es == 'm' || *es == 'M'){
137 }else if(*es == 'g' || *es == 'G'){
147 threadmain(int argc, char *argv[])
149 char *defsrv, *srvname;
157 fmtinstall('H', encodefmt);
158 fmtinstall('V', vtscorefmt);
159 fmtinstall('F', vtfcallfmt);
165 fmtinstall('F', fcallfmt);
175 host = EARGF(usage());
178 defsrv = EARGF(usage());
184 mem = unittoull(EARGF(usage()));
187 defmnt = EARGF(usage());
203 if(defsrv == nil && defmnt == nil && !stdio){
204 srvname = strchr(argv[0], '/');
209 defsrv = vtmalloc(6+strlen(srvname)+1);
210 strcpy(defsrv, "vacfs.");
211 strcat(defsrv, srvname);
212 if(strcmp(defsrv+strlen(defsrv)-4, ".vac") == 0)
213 defsrv[strlen(defsrv)-4] = 0;
216 if(defsrv == nil && defmnt == nil && !stdio)
220 sysfatal("cannot use -m with -i");
229 sysfatal("could not connect to server: %r");
231 if(vtconnect(conn) < 0)
232 sysfatal("vtconnect: %r");
234 fs = vacfsopen(conn, argv[0], VtOREAD, mem);
236 sysfatal("vacfsopen: %r");
240 sysfatal("pipe failed: %r");
248 proccreate(srv, 0, 32 * 1024);
249 if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0)
250 sysfatal("post9pservice");
252 procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
257 srvname = smprint("/srv/%s", defsrv);
258 fd = create(srvname, OWRITE|ORCLOSE, 0666);
260 sysfatal("create %s: %r", srvname);
261 if(fprint(fd, "%d", srvfd) < 0)
262 sysfatal("write %s: %r", srvname);
266 if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
267 sysfatal("mount %s: %r", defmnt);
285 fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
286 threadexitsall("usage");
290 rversion(Fid *unused)
296 for(f = fids; f; f = f->next)
301 return vtstrdup("version: message size too small");
302 messagesize = rhdr.msize;
303 if(messagesize > sizeof mdata)
304 messagesize = sizeof mdata;
305 thdr.msize = messagesize;
306 if(strncmp(rhdr.version, "9P2000", 6) != 0)
307 return vtstrdup("unrecognized 9P version");
308 thdr.version = "9P2000";
309 if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
311 thdr.version = "9P2000.u";
327 return vtstrdup("vacfs: authentication not required");
333 /* no authentication for the momment */
337 file = vacfsgetroot(fs);
339 rerrstr(err, sizeof err);
340 return vtstrdup(err);
345 f->qid.path = vacfilegetid(f->file);
350 f->user = vtstrdup(rhdr.uname);
359 VacFile *file, *nfile;
368 if(rhdr.fid != rhdr.newfid){
370 return vtstrdup(Eisopen);
372 return vtstrdup(Enotexist);
373 nf = newfid(rhdr.newfid);
375 return vtstrdup(Eisopen);
379 nf->file = vacfileincref(f->file);
380 nf->user = vtstrdup(f->user);
384 nwname = rhdr.nwname;
396 for(nqid = 0; nqid < nwname; nqid++){
397 if((qid.type & QTDIR) == 0){
401 if(!permf(file, f->user, Pexec)) {
405 nfile = vacfilewalk(file, rhdr.wname[nqid]);
411 if(vacfileisdir(file))
414 if(vacfilegetmode(file)&ModeLink)
415 qid.type = QTSYMLINK;
417 qid.vers = vacfilegetmcount(file);
418 qid.path = vacfilegetid(file);
419 thdr.wqid[nqid] = qid;
426 f->qid = thdr.wqid[nqid-1];
427 vacfiledecref(f->file);
436 /* only error on the first element */
438 return vtstrdup(err);
449 return vtstrdup(Eisopen);
451 return vtstrdup(Enotexist);
454 thdr.iounit = messagesize - IOHDRSZ;
455 if(f->qid.type & QTDIR){
457 return vtstrdup(Eperm);
459 return vtstrdup(Eperm);
466 return vtstrdup(Erdonly);
467 trunc = mode & OTRUNC;
469 if(mode==OWRITE || mode==ORDWR || trunc)
471 return vtstrdup(Eperm);
472 if(mode==OREAD || mode==ORDWR)
474 return vtstrdup(Eperm);
477 return vtstrdup(Eperm);
479 thdr.iounit = messagesize - IOHDRSZ;
491 return vtstrdup(Eisopen);
493 return vtstrdup(Enotexist);
494 if(fs->mode & ModeSnapshot)
495 return vtstrdup(Erdonly);
497 if(!vacfileisdir(vf))
498 return vtstrdup(Enotdir);
499 if(!permf(vf, fid->user, Pwrite))
500 return vtstrdup(Eperm);
502 mode = rhdr.perm & 0777;
504 if(rhdr.perm & DMDIR){
505 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
506 return vtstrdup(Emode);
507 switch(rhdr.mode & OPERM){
509 return vtstrdup(Emode);
515 return vtstrdup(Eperm);
519 vf = vacfilecreate(vf, rhdr.name, mode);
522 rerrstr(err, sizeof err);
524 return vtstrdup(err);
527 vacfiledecref(fid->file);
530 fid->qid.type = QTFILE;
532 fid->qid.type = QTDIR;
533 fid->qid.vers = vacfilegetmcount(vf);
534 fid->qid.path = vacfilegetid(vf);
537 thdr.iounit = messagesize - IOHDRSZ;
553 return vtstrdup(Enotexist);
559 if(f->qid.type & QTDIR)
560 n = vacdirread(f, buf, off, cnt);
561 else if(vacfilegetmode(f->file)&ModeDevice)
562 return vtstrdup("device");
563 else if(vacfilegetmode(f->file)&ModeLink)
564 return vtstrdup("symbolic link");
565 else if(vacfilegetmode(f->file)&ModeNamedPipe)
566 return vtstrdup("named pipe");
568 n = vacfileread(vf, buf, cnt, off);
570 rerrstr(err, sizeof err);
571 return vtstrdup(err);
581 return vtstrdup(Erdonly);
592 vacfiledecref(f->file);
607 return vtstrdup(Enotexist);
609 vfp = vacfilegetparent(vf);
611 if(!permf(vfp, f->user, Pwrite)) {
616 if(!vacfileremove(vf)) {
617 rerrstr(errbuf, sizeof errbuf);
624 return vtstrdup(err);
631 static uchar statbuf[1024];
635 return vtstrdup(Enotexist);
636 parent = vacfilegetparent(f->file);
637 vacfilegetdir(f->file, &dir);
639 thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
641 vacfiledecref(parent);
649 return vtstrdup(Enotexist);
650 return vtstrdup(Erdonly);
654 vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
665 memset(&dir, 0, sizeof(dir));
667 dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
669 dir.qid.path += vd->qidoffset;
670 dir.qid.vers = vd->mcount;
671 dir.mode = vd->mode & 0777;
672 if(vd->mode & ModeAppend){
673 dir.qid.type |= QTAPPEND;
674 dir.mode |= DMAPPEND;
676 if(vd->mode & ModeExclusive){
677 dir.qid.type |= QTEXCL;
680 if(vd->mode & ModeDir){
681 dir.qid.type |= QTDIR;
686 if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
687 vf = vacfilewalk(parent, vd->elem);
690 vacfilegetsize(vf, &size);
691 ext = malloc(size+1);
694 n = vacfileread(vf, ext, size, 0);
697 if(vd->mode & ModeLink){
698 dir.qid.type |= QTSYMLINK;
699 dir.mode |= DMSYMLINK;
701 if(vd->mode & ModeDevice)
702 dir.mode |= DMDEVICE;
703 if(vd->mode & ModeNamedPipe)
704 dir.mode |= DMNAMEDPIPE;
708 dir.atime = vd->atime;
709 dir.mtime = vd->mtime;
710 dir.length = vd->size;
718 dir.uidnum = atoi(vd->uid);
719 dir.gidnum = atoi(vd->gid);
722 ret = convD2Mu(&dir, p, np, dotu);
730 vacdirread(Fid *f, char *p, long off, long cnt)
736 * special case of rewinding a directory
737 * otherwise ignore the offset
739 if(off == 0 && f->vde){
745 f->vde = vdeopen(f->file);
750 for(nb = 0; nb < cnt; nb += n) {
751 i = vderead(f->vde, &vd);
756 n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
773 for(f = fids; f; f = f->next)
776 else if(!ff && !f->busy)
782 f = vtmallocz(sizeof *f);
796 n = read9pmsg(mfd[0], mdata, sizeof mdata);
799 if(convM2Su(mdata, n, &rhdr, dotu) != n)
800 sysfatal("convM2S conversion error");
803 fprint(2, "vacfs:<-%F\n", &rhdr);
805 thdr.data = (char*)mdata + IOHDRSZ;
806 if(!fcalls[rhdr.type])
807 err = "bad fcall type";
809 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
817 thdr.type = rhdr.type + 1;
822 fprint(2, "vacfs:->%F\n", &thdr);
823 n = convS2Mu(&thdr, mdata, messagesize, dotu);
825 sysfatal("convS2Mu conversion error");
829 if(write(mfd[1], mdata, n) != n)
830 sysfatal("mount write: %r");
835 permf(VacFile *vf, char *user, int p)
840 if(vacfilegetdir(vf, &dir))
842 perm = dir.mode & 0777;
846 if((p*Pother) & perm)
848 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
850 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
862 return permf(f->file, f->user, p);
870 for(f = fids; f; f = f->next) {