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");
240 proccreate(srv, 0, 32 * 1024);
241 if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0)
242 sysfatal("post9pservice");
244 procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
249 srvname = smprint("/srv/%s", defsrv);
250 fd = create(srvname, OWRITE|ORCLOSE, 0666);
252 sysfatal("create %s: %r", srvname);
253 if(fprint(fd, "%d", srvfd) < 0)
254 sysfatal("write %s: %r", srvname);
258 if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
259 sysfatal("mount %s: %r", defmnt);
277 fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
278 threadexitsall("usage");
282 rversion(Fid *unused)
288 for(f = fids; f; f = f->next)
293 return vtstrdup("version: message size too small");
294 messagesize = rhdr.msize;
295 if(messagesize > sizeof mdata)
296 messagesize = sizeof mdata;
297 thdr.msize = messagesize;
298 if(strncmp(rhdr.version, "9P2000", 6) != 0)
299 return vtstrdup("unrecognized 9P version");
300 thdr.version = "9P2000";
315 return vtstrdup("vacfs: authentication not required");
321 /* no authentication for the momment */
325 file = vacfsgetroot(fs);
327 rerrstr(err, sizeof err);
328 return vtstrdup(err);
333 f->qid.path = vacfilegetid(f->file);
338 f->user = vtstrdup(rhdr.uname);
347 VacFile *file, *nfile;
356 if(rhdr.fid != rhdr.newfid){
358 return vtstrdup(Eisopen);
360 return vtstrdup(Enotexist);
361 nf = newfid(rhdr.newfid);
363 return vtstrdup(Eisopen);
367 nf->file = vacfileincref(f->file);
368 nf->user = vtstrdup(f->user);
372 nwname = rhdr.nwname;
384 for(nqid = 0; nqid < nwname; nqid++){
385 if((qid.type & QTDIR) == 0){
389 if(!permf(file, f->user, Pexec)) {
393 nfile = vacfilewalk(file, rhdr.wname[nqid]);
399 if(vacfileisdir(file))
402 if(vacfilegetmode(file)&ModeLink)
403 qid.type = QTSYMLINK;
405 qid.vers = vacfilegetmcount(file);
406 qid.path = vacfilegetid(file);
407 thdr.wqid[nqid] = qid;
414 f->qid = thdr.wqid[nqid-1];
415 vacfiledecref(f->file);
424 /* only error on the first element */
426 return vtstrdup(err);
437 return vtstrdup(Eisopen);
439 return vtstrdup(Enotexist);
442 thdr.iounit = messagesize - IOHDRSZ;
443 if(f->qid.type & QTDIR){
445 return vtstrdup(Eperm);
447 return vtstrdup(Eperm);
454 return vtstrdup(Erdonly);
455 trunc = mode & OTRUNC;
457 if(mode==OWRITE || mode==ORDWR || trunc)
459 return vtstrdup(Eperm);
460 if(mode==OREAD || mode==ORDWR)
462 return vtstrdup(Eperm);
465 return vtstrdup(Eperm);
467 thdr.iounit = messagesize - IOHDRSZ;
479 return vtstrdup(Eisopen);
481 return vtstrdup(Enotexist);
482 if(fs->mode & ModeSnapshot)
483 return vtstrdup(Erdonly);
485 if(!vacfileisdir(vf))
486 return vtstrdup(Enotdir);
487 if(!permf(vf, fid->user, Pwrite))
488 return vtstrdup(Eperm);
490 mode = rhdr.perm & 0777;
492 if(rhdr.perm & DMDIR){
493 if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
494 return vtstrdup(Emode);
495 switch(rhdr.mode & OPERM){
497 return vtstrdup(Emode);
503 return vtstrdup(Eperm);
507 vf = vacfilecreate(vf, rhdr.name, mode);
510 rerrstr(err, sizeof err);
512 return vtstrdup(err);
515 vacfiledecref(fid->file);
518 fid->qid.type = QTFILE;
520 fid->qid.type = QTDIR;
521 fid->qid.vers = vacfilegetmcount(vf);
522 fid->qid.path = vacfilegetid(vf);
525 thdr.iounit = messagesize - IOHDRSZ;
541 return vtstrdup(Enotexist);
547 if(f->qid.type & QTDIR)
548 n = vacdirread(f, buf, off, cnt);
549 else if(vacfilegetmode(f->file)&ModeDevice)
550 return vtstrdup("device");
551 else if(vacfilegetmode(f->file)&ModeLink)
552 return vtstrdup("symbolic link");
553 else if(vacfilegetmode(f->file)&ModeNamedPipe)
554 return vtstrdup("named pipe");
556 n = vacfileread(vf, buf, cnt, off);
558 rerrstr(err, sizeof err);
559 return vtstrdup(err);
569 return vtstrdup(Erdonly);
580 vacfiledecref(f->file);
595 return vtstrdup(Enotexist);
597 vfp = vacfilegetparent(vf);
599 if(!permf(vfp, f->user, Pwrite)) {
604 if(!vacfileremove(vf)) {
605 rerrstr(errbuf, sizeof errbuf);
612 return vtstrdup(err);
619 static uchar statbuf[1024];
623 return vtstrdup(Enotexist);
624 parent = vacfilegetparent(f->file);
625 vacfilegetdir(f->file, &dir);
627 thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
629 vacfiledecref(parent);
637 return vtstrdup(Enotexist);
638 return vtstrdup(Erdonly);
642 vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
653 memset(&dir, 0, sizeof(dir));
655 dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
657 dir.qid.path += vd->qidoffset;
658 dir.qid.vers = vd->mcount;
659 dir.mode = vd->mode & 0777;
660 if(vd->mode & ModeAppend){
661 dir.qid.type |= QTAPPEND;
662 dir.mode |= DMAPPEND;
664 if(vd->mode & ModeExclusive){
665 dir.qid.type |= QTEXCL;
668 if(vd->mode & ModeDir){
669 dir.qid.type |= QTDIR;
674 if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
675 vf = vacfilewalk(parent, vd->elem);
678 vacfilegetsize(vf, &size);
679 ext = malloc(size+1);
682 n = vacfileread(vf, ext, size, 0);
685 if(vd->mode & ModeLink){
686 dir.qid.type |= QTSYMLINK;
687 dir.mode |= DMSYMLINK;
689 if(vd->mode & ModeDevice)
690 dir.mode |= DMDEVICE;
691 if(vd->mode & ModeNamedPipe)
692 dir.mode |= DMNAMEDPIPE;
696 dir.atime = vd->atime;
697 dir.mtime = vd->mtime;
698 dir.length = vd->size;
706 dir.uidnum = atoi(vd->uid);
707 dir.gidnum = atoi(vd->gid);
710 ret = convD2M(&dir, p, np);
718 vacdirread(Fid *f, char *p, long off, long cnt)
724 * special case of rewinding a directory
725 * otherwise ignore the offset
727 if(off == 0 && f->vde){
733 f->vde = vdeopen(f->file);
738 for(nb = 0; nb < cnt; nb += n) {
739 i = vderead(f->vde, &vd);
744 n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
761 for(f = fids; f; f = f->next)
764 else if(!ff && !f->busy)
770 f = vtmallocz(sizeof *f);
784 n = read9pmsg(mfd[0], mdata, sizeof mdata);
787 if(convM2S(mdata, n, &rhdr) != n)
788 sysfatal("convM2S conversion error");
791 fprint(2, "vacfs:<-%F\n", &rhdr);
793 thdr.data = (char*)mdata + IOHDRSZ;
794 if(!fcalls[rhdr.type])
795 err = "bad fcall type";
797 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
805 thdr.type = rhdr.type + 1;
810 fprint(2, "vacfs:->%F\n", &thdr);
811 n = convS2M(&thdr, mdata, messagesize);
813 sysfatal("convS2M conversion error");
817 if(write(mfd[1], mdata, n) != n)
818 sysfatal("mount write: %r");
823 permf(VacFile *vf, char *user, int p)
828 if(vacfilegetdir(vf, &dir))
830 perm = dir.mode & 0777;
834 if((p*Pother) & perm)
836 if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
838 if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
850 return permf(f->file, f->user, p);
858 for(f = fids; f; f = f->next) {