|  | #include "stdinc.h" | 
|  | #include <fcall.h> | 
|  | #include "vac.h" | 
|  |  | 
|  | typedef struct Fid Fid; | 
|  |  | 
|  | enum | 
|  | { | 
|  | OPERM	= 0x3		/* mask of all permission types in open mode */ | 
|  | }; | 
|  |  | 
|  | struct Fid | 
|  | { | 
|  | short busy; | 
|  | short open; | 
|  | int fid; | 
|  | char *user; | 
|  | Qid qid; | 
|  | VacFile *file; | 
|  | VacDirEnum *vde; | 
|  | Fid	*next; | 
|  | }; | 
|  |  | 
|  | enum | 
|  | { | 
|  | Pexec =		1, | 
|  | Pwrite = 	2, | 
|  | Pread = 	4, | 
|  | Pother = 	1, | 
|  | Pgroup = 	8, | 
|  | Powner =	64 | 
|  | }; | 
|  |  | 
|  | Fid	*fids; | 
|  | uchar	*data; | 
|  | int	mfd[2]; | 
|  | int	srvfd = -1; | 
|  | char	*user; | 
|  | uchar	mdata[8192+IOHDRSZ]; | 
|  | int messagesize = sizeof mdata; | 
|  | Fcall	rhdr; | 
|  | Fcall	thdr; | 
|  | VacFs	*fs; | 
|  | VtConn  *conn; | 
|  | int	noperm; | 
|  | char *defmnt; | 
|  |  | 
|  | Fid *	newfid(int); | 
|  | void	error(char*); | 
|  | void	io(void); | 
|  | void	vacshutdown(void); | 
|  | void	usage(void); | 
|  | int	perm(Fid*, int); | 
|  | int	permf(VacFile*, char*, int); | 
|  | ulong	getl(void *p); | 
|  | void	init(char*, char*, long, int); | 
|  | int	vacdirread(Fid *f, char *p, long off, long cnt); | 
|  | int	vacstat(VacFile *parent, VacDir *vd, uchar *p, int np); | 
|  | void 	srv(void* a); | 
|  |  | 
|  |  | 
|  | char	*rflush(Fid*), *rversion(Fid*), | 
|  | *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*), | 
|  | *ropen(Fid*), *rcreate(Fid*), | 
|  | *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), | 
|  | *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); | 
|  |  | 
|  | char 	*(*fcalls[Tmax])(Fid*); | 
|  |  | 
|  | void | 
|  | initfcalls(void) | 
|  | { | 
|  | fcalls[Tflush]=	rflush; | 
|  | fcalls[Tversion]=	rversion; | 
|  | fcalls[Tattach]=	rattach; | 
|  | fcalls[Tauth]=		rauth; | 
|  | fcalls[Twalk]=		rwalk; | 
|  | fcalls[Topen]=		ropen; | 
|  | fcalls[Tcreate]=	rcreate; | 
|  | fcalls[Tread]=		rread; | 
|  | fcalls[Twrite]=	rwrite; | 
|  | fcalls[Tclunk]=	rclunk; | 
|  | fcalls[Tremove]=	rremove; | 
|  | fcalls[Tstat]=		rstat; | 
|  | fcalls[Twstat]=	rwstat; | 
|  | } | 
|  |  | 
|  | char	Eperm[] =	"permission denied"; | 
|  | char	Enotdir[] =	"not a directory"; | 
|  | char	Enotexist[] =	"file does not exist"; | 
|  | char	Einuse[] =	"file in use"; | 
|  | char	Eexist[] =	"file exists"; | 
|  | char	Enotowner[] =	"not owner"; | 
|  | char	Eisopen[] = 	"file already open for I/O"; | 
|  | char	Excl[] = 	"exclusive use file already open"; | 
|  | char	Ename[] = 	"illegal name"; | 
|  | char	Erdonly[] = 	"read only file system"; | 
|  | char	Eio[] = 	"i/o error"; | 
|  | char	Eempty[] = 	"directory is not empty"; | 
|  | char	Emode[] =	"illegal mode"; | 
|  |  | 
|  | int dflag; | 
|  |  | 
|  | void | 
|  | notifyf(void *a, char *s) | 
|  | { | 
|  | USED(a); | 
|  | if(strncmp(s, "interrupt", 9) == 0) | 
|  | noted(NCONT); | 
|  | noted(NDFLT); | 
|  | } | 
|  |  | 
|  | #define TWID64 ~(u64int)0 | 
|  | static u64int | 
|  | unittoull(char *s) | 
|  | { | 
|  | char *es; | 
|  | u64int n; | 
|  |  | 
|  | if(s == nil) | 
|  | return TWID64; | 
|  | n = strtoul(s, &es, 0); | 
|  | if(*es == 'k' || *es == 'K'){ | 
|  | n *= 1024; | 
|  | es++; | 
|  | }else if(*es == 'm' || *es == 'M'){ | 
|  | n *= 1024*1024; | 
|  | es++; | 
|  | }else if(*es == 'g' || *es == 'G'){ | 
|  | n *= 1024*1024*1024; | 
|  | es++; | 
|  | } | 
|  | if(*es != '\0') | 
|  | return TWID64; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | void | 
|  | threadmain(int argc, char *argv[]) | 
|  | { | 
|  | char *defsrv, *srvname; | 
|  | int p[2], fd; | 
|  | int stdio; | 
|  | char *host = nil; | 
|  | ulong mem; | 
|  |  | 
|  | mem = 16<<20; | 
|  | stdio = 0; | 
|  | fmtinstall('H', encodefmt); | 
|  | fmtinstall('V', vtscorefmt); | 
|  | fmtinstall('F', vtfcallfmt); | 
|  |  | 
|  | defmnt = nil; | 
|  | defsrv = nil; | 
|  | ARGBEGIN{ | 
|  | case 'd': | 
|  | fmtinstall('F', fcallfmt); | 
|  | dflag = 1; | 
|  | break; | 
|  | case 'i': | 
|  | defmnt = nil; | 
|  | stdio = 1; | 
|  | mfd[0] = 0; | 
|  | mfd[1] = 1; | 
|  | break; | 
|  | case 'h': | 
|  | host = EARGF(usage()); | 
|  | break; | 
|  | case 'S': | 
|  | defsrv = EARGF(usage()); | 
|  | break; | 
|  | case 's': | 
|  | defsrv = "vacfs"; | 
|  | break; | 
|  | case 'M': | 
|  | mem = unittoull(EARGF(usage())); | 
|  | break; | 
|  | case 'm': | 
|  | defmnt = EARGF(usage()); | 
|  | break; | 
|  | case 'p': | 
|  | noperm = 1; | 
|  | break; | 
|  | case 'V': | 
|  | chattyventi = 1; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | }ARGEND | 
|  |  | 
|  | if(argc != 1) | 
|  | usage(); | 
|  |  | 
|  | #ifdef PLAN9PORT | 
|  | if(defsrv == nil && defmnt == nil && !stdio){ | 
|  | srvname = strchr(argv[0], '/'); | 
|  | if(srvname) | 
|  | srvname++; | 
|  | else | 
|  | srvname = argv[0]; | 
|  | defsrv = vtmalloc(6+strlen(srvname)+1); | 
|  | strcpy(defsrv, "vacfs."); | 
|  | strcat(defsrv, srvname); | 
|  | if(strcmp(defsrv+strlen(defsrv)-4, ".vac") == 0) | 
|  | defsrv[strlen(defsrv)-4] = 0; | 
|  | } | 
|  | #else | 
|  | if(defsrv == nil && defmnt == nil && !stdio) | 
|  | defmnt = "/n/vac"; | 
|  | #endif | 
|  | if(stdio && defmnt) | 
|  | sysfatal("cannot use -m with -i"); | 
|  |  | 
|  | initfcalls(); | 
|  |  | 
|  | notify(notifyf); | 
|  | user = getuser(); | 
|  |  | 
|  | conn = vtdial(host); | 
|  | if(conn == nil) | 
|  | sysfatal("could not connect to server: %r"); | 
|  |  | 
|  | if(vtconnect(conn) < 0) | 
|  | sysfatal("vtconnect: %r"); | 
|  |  | 
|  | fs = vacfsopen(conn, argv[0], VtOREAD, mem); | 
|  | if(fs == nil) | 
|  | sysfatal("vacfsopen: %r"); | 
|  |  | 
|  | if(!stdio){ | 
|  | if(pipe(p) < 0) | 
|  | sysfatal("pipe failed: %r"); | 
|  | mfd[0] = p[0]; | 
|  | mfd[1] = p[0]; | 
|  | srvfd = p[1]; | 
|  | #ifndef PLAN9PORT | 
|  | if(defsrv){ | 
|  | srvname = smprint("/srv/%s", defsrv); | 
|  | fd = create(srvname, OWRITE|ORCLOSE, 0666); | 
|  | if(fd < 0) | 
|  | sysfatal("create %s: %r", srvname); | 
|  | if(fprint(fd, "%d", srvfd) < 0) | 
|  | sysfatal("write %s: %r", srvname); | 
|  | free(srvname); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #ifdef PLAN9PORT | 
|  | USED(fd); | 
|  | proccreate(srv, 0, 32 * 1024); | 
|  | if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0) | 
|  | sysfatal("post9pservice"); | 
|  | #else | 
|  | procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG); | 
|  |  | 
|  | if(!stdio){ | 
|  | close(p[0]); | 
|  | if(defmnt){ | 
|  | if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0) | 
|  | sysfatal("mount %s: %r", defmnt); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | threadexits(0); | 
|  | } | 
|  |  | 
|  | void | 
|  | srv(void *a) | 
|  | { | 
|  | USED(a); | 
|  | io(); | 
|  | vacshutdown(); | 
|  | } | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: %s [-sd] [-h host] [-m mountpoint] [-M mem] vacfile\n", argv0); | 
|  | threadexitsall("usage"); | 
|  | } | 
|  |  | 
|  | char* | 
|  | rversion(Fid *unused) | 
|  | { | 
|  | Fid *f; | 
|  |  | 
|  | USED(unused); | 
|  |  | 
|  | for(f = fids; f; f = f->next) | 
|  | if(f->busy) | 
|  | rclunk(f); | 
|  |  | 
|  | if(rhdr.msize < 256) | 
|  | return vtstrdup("version: message size too small"); | 
|  | messagesize = rhdr.msize; | 
|  | if(messagesize > sizeof mdata) | 
|  | messagesize = sizeof mdata; | 
|  | thdr.msize = messagesize; | 
|  | if(strncmp(rhdr.version, "9P2000", 6) != 0) | 
|  | return vtstrdup("unrecognized 9P version"); | 
|  | thdr.version = "9P2000"; | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rflush(Fid *f) | 
|  | { | 
|  | USED(f); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rauth(Fid *f) | 
|  | { | 
|  | USED(f); | 
|  | return vtstrdup("vacfs: authentication not required"); | 
|  | } | 
|  |  | 
|  | char* | 
|  | rattach(Fid *f) | 
|  | { | 
|  | /* no authentication for the momment */ | 
|  | VacFile *file; | 
|  | char err[80]; | 
|  |  | 
|  | file = vacfsgetroot(fs); | 
|  | if(file == nil) { | 
|  | rerrstr(err, sizeof err); | 
|  | return vtstrdup(err); | 
|  | } | 
|  |  | 
|  | f->busy = 1; | 
|  | f->file = file; | 
|  | f->qid.path = vacfilegetid(f->file); | 
|  | f->qid.vers = 0; | 
|  | f->qid.type = QTDIR; | 
|  | thdr.qid = f->qid; | 
|  | if(rhdr.uname[0]) | 
|  | f->user = vtstrdup(rhdr.uname); | 
|  | else | 
|  | f->user = "none"; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rwalk(Fid *f) | 
|  | { | 
|  | VacFile *file, *nfile; | 
|  | Fid *nf; | 
|  | int nqid, nwname; | 
|  | Qid qid; | 
|  | char *err = nil; | 
|  |  | 
|  | if(f->busy == 0) | 
|  | return Enotexist; | 
|  | nf = nil; | 
|  | if(rhdr.fid != rhdr.newfid){ | 
|  | if(f->open) | 
|  | return vtstrdup(Eisopen); | 
|  | if(f->busy == 0) | 
|  | return vtstrdup(Enotexist); | 
|  | nf = newfid(rhdr.newfid); | 
|  | if(nf->busy) | 
|  | return vtstrdup(Eisopen); | 
|  | nf->busy = 1; | 
|  | nf->open = 0; | 
|  | nf->qid = f->qid; | 
|  | nf->file = vacfileincref(f->file); | 
|  | nf->user = vtstrdup(f->user); | 
|  | f = nf; | 
|  | } | 
|  |  | 
|  | nwname = rhdr.nwname; | 
|  |  | 
|  | /* easy case */ | 
|  | if(nwname == 0) { | 
|  | thdr.nwqid = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | file = f->file; | 
|  | vacfileincref(file); | 
|  | qid = f->qid; | 
|  |  | 
|  | for(nqid = 0; nqid < nwname; nqid++){ | 
|  | if((qid.type & QTDIR) == 0){ | 
|  | err = Enotdir; | 
|  | break; | 
|  | } | 
|  | if(!permf(file, f->user, Pexec)) { | 
|  | err = Eperm; | 
|  | break; | 
|  | } | 
|  | nfile = vacfilewalk(file, rhdr.wname[nqid]); | 
|  | if(nfile == nil) | 
|  | break; | 
|  | vacfiledecref(file); | 
|  | file = nfile; | 
|  | qid.type = QTFILE; | 
|  | if(vacfileisdir(file)) | 
|  | qid.type = QTDIR; | 
|  | #ifdef PLAN9PORT | 
|  | if(vacfilegetmode(file)&ModeLink) | 
|  | qid.type = QTSYMLINK; | 
|  | #endif | 
|  | qid.vers = vacfilegetmcount(file); | 
|  | qid.path = vacfilegetid(file); | 
|  | thdr.wqid[nqid] = qid; | 
|  | } | 
|  |  | 
|  | thdr.nwqid = nqid; | 
|  |  | 
|  | if(nqid == nwname){ | 
|  | /* success */ | 
|  | f->qid = thdr.wqid[nqid-1]; | 
|  | vacfiledecref(f->file); | 
|  | f->file = file; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | vacfiledecref(file); | 
|  | if(nf != nil) | 
|  | rclunk(nf); | 
|  |  | 
|  | /* only error on the first element */ | 
|  | if(nqid == 0) | 
|  | return vtstrdup(err); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char * | 
|  | ropen(Fid *f) | 
|  | { | 
|  | int mode, trunc; | 
|  |  | 
|  | if(f->open) | 
|  | return vtstrdup(Eisopen); | 
|  | if(!f->busy) | 
|  | return vtstrdup(Enotexist); | 
|  |  | 
|  | mode = rhdr.mode; | 
|  | thdr.iounit = messagesize - IOHDRSZ; | 
|  | if(f->qid.type & QTDIR){ | 
|  | if(mode != OREAD) | 
|  | return vtstrdup(Eperm); | 
|  | if(!perm(f, Pread)) | 
|  | return vtstrdup(Eperm); | 
|  | thdr.qid = f->qid; | 
|  | f->vde = nil; | 
|  | f->open = 1; | 
|  | return 0; | 
|  | } | 
|  | if(mode & ORCLOSE) | 
|  | return vtstrdup(Erdonly); | 
|  | trunc = mode & OTRUNC; | 
|  | mode &= OPERM; | 
|  | if(mode==OWRITE || mode==ORDWR || trunc) | 
|  | if(!perm(f, Pwrite)) | 
|  | return vtstrdup(Eperm); | 
|  | if(mode==OREAD || mode==ORDWR) | 
|  | if(!perm(f, Pread)) | 
|  | return vtstrdup(Eperm); | 
|  | if(mode==OEXEC) | 
|  | if(!perm(f, Pexec)) | 
|  | return vtstrdup(Eperm); | 
|  | thdr.qid = f->qid; | 
|  | thdr.iounit = messagesize - IOHDRSZ; | 
|  | f->open = 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rcreate(Fid* fid) | 
|  | { | 
|  | VacFile *vf; | 
|  | ulong mode; | 
|  |  | 
|  | if(fid->open) | 
|  | return vtstrdup(Eisopen); | 
|  | if(!fid->busy) | 
|  | return vtstrdup(Enotexist); | 
|  | if(fs->mode & ModeSnapshot) | 
|  | return vtstrdup(Erdonly); | 
|  | vf = fid->file; | 
|  | if(!vacfileisdir(vf)) | 
|  | return vtstrdup(Enotdir); | 
|  | if(!permf(vf, fid->user, Pwrite)) | 
|  | return vtstrdup(Eperm); | 
|  |  | 
|  | mode = rhdr.perm & 0777; | 
|  |  | 
|  | if(rhdr.perm & DMDIR){ | 
|  | if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND)) | 
|  | return vtstrdup(Emode); | 
|  | switch(rhdr.mode & OPERM){ | 
|  | default: | 
|  | return vtstrdup(Emode); | 
|  | case OEXEC: | 
|  | case OREAD: | 
|  | break; | 
|  | case OWRITE: | 
|  | case ORDWR: | 
|  | return vtstrdup(Eperm); | 
|  | } | 
|  | mode |= ModeDir; | 
|  | } | 
|  | vf = vacfilecreate(vf, rhdr.name, mode); | 
|  | if(vf == nil) { | 
|  | char err[80]; | 
|  | rerrstr(err, sizeof err); | 
|  |  | 
|  | return vtstrdup(err); | 
|  | } | 
|  |  | 
|  | vacfiledecref(fid->file); | 
|  |  | 
|  | fid->file = vf; | 
|  | fid->qid.type = QTFILE; | 
|  | if(vacfileisdir(vf)) | 
|  | fid->qid.type = QTDIR; | 
|  | fid->qid.vers = vacfilegetmcount(vf); | 
|  | fid->qid.path = vacfilegetid(vf); | 
|  |  | 
|  | thdr.qid = fid->qid; | 
|  | thdr.iounit = messagesize - IOHDRSZ; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rread(Fid *f) | 
|  | { | 
|  | char *buf; | 
|  | vlong off; | 
|  | int cnt; | 
|  | VacFile *vf; | 
|  | char err[80]; | 
|  | int n; | 
|  |  | 
|  | if(!f->busy) | 
|  | return vtstrdup(Enotexist); | 
|  | vf = f->file; | 
|  | thdr.count = 0; | 
|  | off = rhdr.offset; | 
|  | buf = thdr.data; | 
|  | cnt = rhdr.count; | 
|  | if(f->qid.type & QTDIR) | 
|  | n = vacdirread(f, buf, off, cnt); | 
|  | else if(vacfilegetmode(f->file)&ModeDevice) | 
|  | return vtstrdup("device"); | 
|  | else if(vacfilegetmode(f->file)&ModeLink) | 
|  | return vtstrdup("symbolic link"); | 
|  | else if(vacfilegetmode(f->file)&ModeNamedPipe) | 
|  | return vtstrdup("named pipe"); | 
|  | else | 
|  | n = vacfileread(vf, buf, cnt, off); | 
|  | if(n < 0) { | 
|  | rerrstr(err, sizeof err); | 
|  | return vtstrdup(err); | 
|  | } | 
|  | thdr.count = n; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* | 
|  | rwrite(Fid *f) | 
|  | { | 
|  | USED(f); | 
|  | return vtstrdup(Erdonly); | 
|  | } | 
|  |  | 
|  | char * | 
|  | rclunk(Fid *f) | 
|  | { | 
|  | f->busy = 0; | 
|  | f->open = 0; | 
|  | vtfree(f->user); | 
|  | f->user = nil; | 
|  | if(f->file) | 
|  | vacfiledecref(f->file); | 
|  | f->file = nil; | 
|  | vdeclose(f->vde); | 
|  | f->vde = nil; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char * | 
|  | rremove(Fid *f) | 
|  | { | 
|  | VacFile *vf, *vfp; | 
|  | char errbuf[80]; | 
|  | char *err = nil; | 
|  |  | 
|  | if(!f->busy) | 
|  | return vtstrdup(Enotexist); | 
|  | vf = f->file; | 
|  | vfp = vacfilegetparent(vf); | 
|  |  | 
|  | if(!permf(vfp, f->user, Pwrite)) { | 
|  | err = Eperm; | 
|  | goto Exit; | 
|  | } | 
|  |  | 
|  | if(!vacfileremove(vf)) { | 
|  | rerrstr(errbuf, sizeof errbuf); | 
|  | err = errbuf; | 
|  | } | 
|  |  | 
|  | Exit: | 
|  | vacfiledecref(vfp); | 
|  | rclunk(f); | 
|  | return vtstrdup(err); | 
|  | } | 
|  |  | 
|  | char * | 
|  | rstat(Fid *f) | 
|  | { | 
|  | VacDir dir; | 
|  | static uchar statbuf[1024]; | 
|  | VacFile *parent; | 
|  |  | 
|  | if(!f->busy) | 
|  | return vtstrdup(Enotexist); | 
|  | parent = vacfilegetparent(f->file); | 
|  | vacfilegetdir(f->file, &dir); | 
|  | thdr.stat = statbuf; | 
|  | thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf); | 
|  | vdcleanup(&dir); | 
|  | vacfiledecref(parent); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char * | 
|  | rwstat(Fid *f) | 
|  | { | 
|  | if(!f->busy) | 
|  | return vtstrdup(Enotexist); | 
|  | return vtstrdup(Erdonly); | 
|  | } | 
|  |  | 
|  | int | 
|  | vacstat(VacFile *parent, VacDir *vd, uchar *p, int np) | 
|  | { | 
|  | int ret; | 
|  | Dir dir; | 
|  | #ifdef PLAN9PORT | 
|  | int n; | 
|  | VacFile *vf; | 
|  | uvlong size; | 
|  | char *ext = nil; | 
|  | #endif | 
|  |  | 
|  | memset(&dir, 0, sizeof(dir)); | 
|  |  | 
|  | dir.qid.path = vd->qid + vacfilegetqidoffset(parent); | 
|  | if(vd->qidspace) | 
|  | dir.qid.path += vd->qidoffset; | 
|  | dir.qid.vers = vd->mcount; | 
|  | dir.mode = vd->mode & 0777; | 
|  | if(vd->mode & ModeAppend){ | 
|  | dir.qid.type |= QTAPPEND; | 
|  | dir.mode |= DMAPPEND; | 
|  | } | 
|  | if(vd->mode & ModeExclusive){ | 
|  | dir.qid.type |= QTEXCL; | 
|  | dir.mode |= DMEXCL; | 
|  | } | 
|  | if(vd->mode & ModeDir){ | 
|  | dir.qid.type |= QTDIR; | 
|  | dir.mode |= DMDIR; | 
|  | } | 
|  |  | 
|  | #ifdef PLAN9PORT | 
|  | if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){ | 
|  | vf = vacfilewalk(parent, vd->elem); | 
|  | if(vf == nil) | 
|  | return 0; | 
|  | vacfilegetsize(vf, &size); | 
|  | ext = malloc(size+1); | 
|  | if(ext == nil) | 
|  | return 0; | 
|  | n = vacfileread(vf, ext, size, 0); | 
|  | USED(n); | 
|  | ext[size] = 0; | 
|  | vacfiledecref(vf); | 
|  | if(vd->mode & ModeLink){ | 
|  | dir.qid.type |= QTSYMLINK; | 
|  | dir.mode |= DMSYMLINK; | 
|  | } | 
|  | if(vd->mode & ModeDevice) | 
|  | dir.mode |= DMDEVICE; | 
|  | if(vd->mode & ModeNamedPipe) | 
|  | dir.mode |= DMNAMEDPIPE; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | dir.atime = vd->atime; | 
|  | dir.mtime = vd->mtime; | 
|  | dir.length = vd->size; | 
|  |  | 
|  | dir.name = vd->elem; | 
|  | dir.uid = vd->uid; | 
|  | dir.gid = vd->gid; | 
|  | dir.muid = vd->mid; | 
|  |  | 
|  | ret = convD2M(&dir, p, np); | 
|  | #ifdef PLAN9PORT | 
|  | free(ext); | 
|  | #endif | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int | 
|  | vacdirread(Fid *f, char *p, long off, long cnt) | 
|  | { | 
|  | int i, n, nb; | 
|  | VacDir vd; | 
|  |  | 
|  | /* | 
|  | * special case of rewinding a directory | 
|  | * otherwise ignore the offset | 
|  | */ | 
|  | if(off == 0 && f->vde){ | 
|  | vdeclose(f->vde); | 
|  | f->vde = nil; | 
|  | } | 
|  |  | 
|  | if(f->vde == nil){ | 
|  | f->vde = vdeopen(f->file); | 
|  | if(f->vde == nil) | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | for(nb = 0; nb < cnt; nb += n) { | 
|  | i = vderead(f->vde, &vd); | 
|  | if(i < 0) | 
|  | return -1; | 
|  | if(i == 0) | 
|  | break; | 
|  | n = vacstat(f->file, &vd, (uchar*)p, cnt-nb); | 
|  | if(n <= BIT16SZ) { | 
|  | vdeunread(f->vde); | 
|  | break; | 
|  | } | 
|  | vdcleanup(&vd); | 
|  | p += n; | 
|  | } | 
|  | return nb; | 
|  | } | 
|  |  | 
|  | Fid * | 
|  | newfid(int fid) | 
|  | { | 
|  | Fid *f, *ff; | 
|  |  | 
|  | ff = 0; | 
|  | for(f = fids; f; f = f->next) | 
|  | if(f->fid == fid) | 
|  | return f; | 
|  | else if(!ff && !f->busy) | 
|  | ff = f; | 
|  | if(ff){ | 
|  | ff->fid = fid; | 
|  | return ff; | 
|  | } | 
|  | f = vtmallocz(sizeof *f); | 
|  | f->fid = fid; | 
|  | f->next = fids; | 
|  | fids = f; | 
|  | return f; | 
|  | } | 
|  |  | 
|  | void | 
|  | io(void) | 
|  | { | 
|  | char *err; | 
|  | int n; | 
|  |  | 
|  | for(;;){ | 
|  | n = read9pmsg(mfd[0], mdata, sizeof mdata); | 
|  | if(n <= 0) | 
|  | break; | 
|  | if(convM2S(mdata, n, &rhdr) != n) | 
|  | sysfatal("convM2S conversion error"); | 
|  |  | 
|  | if(dflag) | 
|  | fprint(2, "vacfs:<-%F\n", &rhdr); | 
|  |  | 
|  | thdr.data = (char*)mdata + IOHDRSZ; | 
|  | if(!fcalls[rhdr.type]) | 
|  | err = "bad fcall type"; | 
|  | else | 
|  | err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); | 
|  | if(err){ | 
|  | thdr.type = Rerror; | 
|  | thdr.ename = err; | 
|  | #ifdef PLAN9PORT | 
|  | thdr.errornum = 0; | 
|  | #endif | 
|  | }else{ | 
|  | thdr.type = rhdr.type + 1; | 
|  | thdr.fid = rhdr.fid; | 
|  | } | 
|  | thdr.tag = rhdr.tag; | 
|  | if(dflag) | 
|  | fprint(2, "vacfs:->%F\n", &thdr); | 
|  | n = convS2M(&thdr, mdata, messagesize); | 
|  | if(n <= BIT16SZ) | 
|  | sysfatal("convS2M conversion error"); | 
|  | if(err) | 
|  | vtfree(err); | 
|  |  | 
|  | if(write(mfd[1], mdata, n) != n) | 
|  | sysfatal("mount write: %r"); | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | permf(VacFile *vf, char *user, int p) | 
|  | { | 
|  | VacDir dir; | 
|  | ulong perm; | 
|  |  | 
|  | if(vacfilegetdir(vf, &dir)) | 
|  | return 0; | 
|  | perm = dir.mode & 0777; | 
|  |  | 
|  | if(noperm) | 
|  | goto Good; | 
|  | if((p*Pother) & perm) | 
|  | goto Good; | 
|  | if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm)) | 
|  | goto Good; | 
|  | if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm)) | 
|  | goto Good; | 
|  | vdcleanup(&dir); | 
|  | return 0; | 
|  | Good: | 
|  | vdcleanup(&dir); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | perm(Fid *f, int p) | 
|  | { | 
|  | return permf(f->file, f->user, p); | 
|  | } | 
|  |  | 
|  | void | 
|  | vacshutdown(void) | 
|  | { | 
|  | Fid *f; | 
|  |  | 
|  | for(f = fids; f; f = f->next) { | 
|  | if(!f->busy) | 
|  | continue; | 
|  | rclunk(f); | 
|  | } | 
|  |  | 
|  | vacfsclose(fs); | 
|  | vthangup(conn); | 
|  | } | 
|  |  |