1 #include "stdinc.h"
2 #include <fcall.h>
3 #include "vac.h"
4 
5 typedef struct Fid Fid;
6 
7 enum
8 {
9 	OPERM	= 0x3		/* mask of all permission types in open mode */
10 };
11 
12 struct Fid
13 {
14 	short busy;
15 	short open;
16 	int fid;
17 	char *user;
18 	Qid qid;
19 	VacFile *file;
20 	VacDirEnum *vde;
21 	Fid	*next;
22 };
23 
24 enum
25 {
26 	Pexec =		1,
27 	Pwrite = 	2,
28 	Pread = 	4,
29 	Pother = 	1,
30 	Pgroup = 	8,
31 	Powner =	64
32 };
33 
34 Fid	*fids;
35 uchar	*data;
36 int	mfd[2];
37 int	srvfd = -1;
38 char	*user;
39 uchar	mdata[8192+IOHDRSZ];
40 int messagesize = sizeof mdata;
41 Fcall	rhdr;
42 Fcall	thdr;
43 VacFs	*fs;
44 VtConn  *conn;
45 int	noperm;
46 char *defmnt;
47 
48 Fid *	newfid(int);
49 void	error(char*);
50 void	io(void);
51 void	vacshutdown(void);
52 void	usage(void);
53 int	perm(Fid*, int);
54 int	permf(VacFile*, char*, int);
55 ulong	getl(void *p);
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);
59 void 	srv(void* a);
60 
61 
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*);
67 
68 char 	*(*fcalls[Tmax])(Fid*);
69 
70 void
initfcalls(void)71 initfcalls(void)
72 {
73 	fcalls[Tflush]=	rflush;
74 	fcalls[Tversion]=	rversion;
75 	fcalls[Tattach]=	rattach;
76 	fcalls[Tauth]=		rauth;
77 	fcalls[Twalk]=		rwalk;
78 	fcalls[Topen]=		ropen;
79 	fcalls[Tcreate]=	rcreate;
80 	fcalls[Tread]=		rread;
81 	fcalls[Twrite]=	rwrite;
82 	fcalls[Tclunk]=	rclunk;
83 	fcalls[Tremove]=	rremove;
84 	fcalls[Tstat]=		rstat;
85 	fcalls[Twstat]=	rwstat;
86 }
87 
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";
101 
102 int dflag;
103 
104 void
notifyf(void * a,char * s)105 notifyf(void *a, char *s)
106 {
107 	USED(a);
108 	if(strncmp(s, "interrupt", 9) == 0)
109 		noted(NCONT);
110 	noted(NDFLT);
111 }
112 
113 #define TWID64 ~(u64int)0
114 static u64int
unittoull(char * s)115 unittoull(char *s)
116 {
117 	char *es;
118 	u64int n;
119 
120 	if(s == nil)
121 		return TWID64;
122 	n = strtoul(s, &es, 0);
123 	if(*es == 'k' || *es == 'K'){
124 		n *= 1024;
125 		es++;
126 	}else if(*es == 'm' || *es == 'M'){
127 		n *= 1024*1024;
128 		es++;
129 	}else if(*es == 'g' || *es == 'G'){
130 		n *= 1024*1024*1024;
131 		es++;
132 	}
133 	if(*es != '\0')
134 		return TWID64;
135 	return n;
136 }
137 
138 void
threadmain(int argc,char * argv[])139 threadmain(int argc, char *argv[])
140 {
141 	char *defsrv, *srvname;
142 	int p[2], fd;
143 	int stdio;
144 	char *host = nil;
145 	ulong mem;
146 
147 	mem = 16<<20;
148 	stdio = 0;
149 	fmtinstall('H', encodefmt);
150 	fmtinstall('V', vtscorefmt);
151 	fmtinstall('F', vtfcallfmt);
152 
153 	defmnt = nil;
154 	defsrv = nil;
155 	ARGBEGIN{
156 	case 'd':
157 		fmtinstall('F', fcallfmt);
158 		dflag = 1;
159 		break;
160 	case 'i':
161 		defmnt = nil;
162 		stdio = 1;
163 		mfd[0] = 0;
164 		mfd[1] = 1;
165 		break;
166 	case 'h':
167 		host = EARGF(usage());
168 		break;
169 	case 'S':
170 		defsrv = EARGF(usage());
171 		break;
172 	case 's':
173 		defsrv = "vacfs";
174 		break;
175 	case 'M':
176 		mem = unittoull(EARGF(usage()));
177 		break;
178 	case 'm':
179 		defmnt = EARGF(usage());
180 		break;
181 	case 'p':
182 		noperm = 1;
183 		break;
184 	case 'V':
185 		chattyventi = 1;
186 		break;
187 	default:
188 		usage();
189 	}ARGEND
190 
191 	if(argc != 1)
192 		usage();
193 
194 #ifdef PLAN9PORT
195 	if(defsrv == nil && defmnt == nil && !stdio){
196 		srvname = strchr(argv[0], '/');
197 		if(srvname)
198 			srvname++;
199 		else
200 			srvname = 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;
206 	}
207 #else
208 	if(defsrv == nil && defmnt == nil && !stdio)
209 		defmnt = "/n/vac";
210 #endif
211 	if(stdio && defmnt)
212 		sysfatal("cannot use -m with -i");
213 
214 	initfcalls();
215 
216 	notify(notifyf);
217 	user = getuser();
218 
219 	conn = vtdial(host);
220 	if(conn == nil)
221 		sysfatal("could not connect to server: %r");
222 
223 	if(vtconnect(conn) < 0)
224 		sysfatal("vtconnect: %r");
225 
226 	fs = vacfsopen(conn, argv[0], VtOREAD, mem);
227 	if(fs == nil)
228 		sysfatal("vacfsopen: %r");
229 
230 	if(!stdio){
231 		if(pipe(p) < 0)
232 			sysfatal("pipe failed: %r");
233 		mfd[0] = p[0];
234 		mfd[1] = p[0];
235 		srvfd = p[1];
236 #ifndef PLAN9PORT
237 		if(defsrv){
238 			srvname = smprint("/srv/%s", defsrv);
239 			fd = create(srvname, OWRITE|ORCLOSE, 0666);
240 			if(fd < 0)
241 				sysfatal("create %s: %r", srvname);
242 			if(fprint(fd, "%d", srvfd) < 0)
243 				sysfatal("write %s: %r", srvname);
244 			free(srvname);
245 		}
246 #endif
247 	}
248 
249 #ifdef PLAN9PORT
250 	USED(fd);
251 	proccreate(srv, 0, 32 * 1024);
252 	if(!stdio && post9pservice(p[1], defsrv, defmnt) < 0)
253 		sysfatal("post9pservice");
254 #else
255 	procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
256 
257 	if(!stdio){
258 		close(p[0]);
259 		if(defmnt){
260 			if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
261 				sysfatal("mount %s: %r", defmnt);
262 		}
263 	}
264 #endif
265 	threadexits(0);
266 }
267 
268 void
srv(void * a)269 srv(void *a)
270 {
271 	USED(a);
272 	io();
273 	vacshutdown();
274 }
275 
276 void
usage(void)277 usage(void)
278 {
279 	fprint(2, "usage: %s [-sd] [-h host] [-m mountpoint] [-M mem] vacfile\n", argv0);
280 	threadexitsall("usage");
281 }
282 
283 char*
rversion(Fid * unused)284 rversion(Fid *unused)
285 {
286 	Fid *f;
287 
288 	USED(unused);
289 
290 	for(f = fids; f; f = f->next)
291 		if(f->busy)
292 			rclunk(f);
293 
294 	if(rhdr.msize < 256)
295 		return vtstrdup("version: message size too small");
296 	messagesize = rhdr.msize;
297 	if(messagesize > sizeof mdata)
298 		messagesize = sizeof mdata;
299 	thdr.msize = messagesize;
300 	if(strncmp(rhdr.version, "9P2000", 6) != 0)
301 		return vtstrdup("unrecognized 9P version");
302 	thdr.version = "9P2000";
303 	return nil;
304 }
305 
306 char*
rflush(Fid * f)307 rflush(Fid *f)
308 {
309 	USED(f);
310 	return 0;
311 }
312 
313 char*
rauth(Fid * f)314 rauth(Fid *f)
315 {
316 	USED(f);
317 	return vtstrdup("vacfs: authentication not required");
318 }
319 
320 char*
rattach(Fid * f)321 rattach(Fid *f)
322 {
323 	/* no authentication for the momment */
324 	VacFile *file;
325 	char err[80];
326 
327 	file = vacfsgetroot(fs);
328 	if(file == nil) {
329 		rerrstr(err, sizeof err);
330 		return vtstrdup(err);
331 	}
332 
333 	f->busy = 1;
334 	f->file = file;
335 	f->qid.path = vacfilegetid(f->file);
336 	f->qid.vers = 0;
337 	f->qid.type = QTDIR;
338 	thdr.qid = f->qid;
339 	if(rhdr.uname[0])
340 		f->user = vtstrdup(rhdr.uname);
341 	else
342 		f->user = "none";
343 	return 0;
344 }
345 
346 char*
rwalk(Fid * f)347 rwalk(Fid *f)
348 {
349 	VacFile *file, *nfile;
350 	Fid *nf;
351 	int nqid, nwname;
352 	Qid qid;
353 	char *err = nil;
354 
355 	if(f->busy == 0)
356 		return Enotexist;
357 	nf = nil;
358 	if(rhdr.fid != rhdr.newfid){
359 		if(f->open)
360 			return vtstrdup(Eisopen);
361 		if(f->busy == 0)
362 			return vtstrdup(Enotexist);
363 		nf = newfid(rhdr.newfid);
364 		if(nf->busy)
365 			return vtstrdup(Eisopen);
366 		nf->busy = 1;
367 		nf->open = 0;
368 		nf->qid = f->qid;
369 		nf->file = vacfileincref(f->file);
370 		nf->user = vtstrdup(f->user);
371 		f = nf;
372 	}
373 
374 	nwname = rhdr.nwname;
375 
376 	/* easy case */
377 	if(nwname == 0) {
378 		thdr.nwqid = 0;
379 		return 0;
380 	}
381 
382 	file = f->file;
383 	vacfileincref(file);
384 	qid = f->qid;
385 
386 	for(nqid = 0; nqid < nwname; nqid++){
387 		if((qid.type & QTDIR) == 0){
388 			err = Enotdir;
389 			break;
390 		}
391 		if(!permf(file, f->user, Pexec)) {
392 			err = Eperm;
393 			break;
394 		}
395 		nfile = vacfilewalk(file, rhdr.wname[nqid]);
396 		if(nfile == nil)
397 			break;
398 		vacfiledecref(file);
399 		file = nfile;
400 		qid.type = QTFILE;
401 		if(vacfileisdir(file))
402 			qid.type = QTDIR;
403 #ifdef PLAN9PORT
404 		if(vacfilegetmode(file)&ModeLink)
405 			qid.type = QTSYMLINK;
406 #endif
407 		qid.vers = vacfilegetmcount(file);
408 		qid.path = vacfilegetid(file);
409 		thdr.wqid[nqid] = qid;
410 	}
411 
412 	thdr.nwqid = nqid;
413 
414 	if(nqid == nwname){
415 		/* success */
416 		f->qid = thdr.wqid[nqid-1];
417 		vacfiledecref(f->file);
418 		f->file = file;
419 		return 0;
420 	}
421 
422 	vacfiledecref(file);
423 	if(nf != nil)
424 		rclunk(nf);
425 
426 	/* only error on the first element */
427 	if(nqid == 0)
428 		return vtstrdup(err);
429 
430 	return 0;
431 }
432 
433 char *
ropen(Fid * f)434 ropen(Fid *f)
435 {
436 	int mode, trunc;
437 
438 	if(f->open)
439 		return vtstrdup(Eisopen);
440 	if(!f->busy)
441 		return vtstrdup(Enotexist);
442 
443 	mode = rhdr.mode;
444 	thdr.iounit = messagesize - IOHDRSZ;
445 	if(f->qid.type & QTDIR){
446 		if(mode != OREAD)
447 			return vtstrdup(Eperm);
448 		if(!perm(f, Pread))
449 			return vtstrdup(Eperm);
450 		thdr.qid = f->qid;
451 		f->vde = nil;
452 		f->open = 1;
453 		return 0;
454 	}
455 	if(mode & ORCLOSE)
456 		return vtstrdup(Erdonly);
457 	trunc = mode & OTRUNC;
458 	mode &= OPERM;
459 	if(mode==OWRITE || mode==ORDWR || trunc)
460 		if(!perm(f, Pwrite))
461 			return vtstrdup(Eperm);
462 	if(mode==OREAD || mode==ORDWR)
463 		if(!perm(f, Pread))
464 			return vtstrdup(Eperm);
465 	if(mode==OEXEC)
466 		if(!perm(f, Pexec))
467 			return vtstrdup(Eperm);
468 	thdr.qid = f->qid;
469 	thdr.iounit = messagesize - IOHDRSZ;
470 	f->open = 1;
471 	return 0;
472 }
473 
474 char*
rcreate(Fid * fid)475 rcreate(Fid* fid)
476 {
477 	VacFile *vf;
478 	ulong mode;
479 
480 	if(fid->open)
481 		return vtstrdup(Eisopen);
482 	if(!fid->busy)
483 		return vtstrdup(Enotexist);
484 	if(fs->mode & ModeSnapshot)
485 		return vtstrdup(Erdonly);
486 	vf = fid->file;
487 	if(!vacfileisdir(vf))
488 		return vtstrdup(Enotdir);
489 	if(!permf(vf, fid->user, Pwrite))
490 		return vtstrdup(Eperm);
491 
492 	mode = rhdr.perm & 0777;
493 
494 	if(rhdr.perm & DMDIR){
495 		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
496 			return vtstrdup(Emode);
497 		switch(rhdr.mode & OPERM){
498 		default:
499 			return vtstrdup(Emode);
500 		case OEXEC:
501 		case OREAD:
502 			break;
503 		case OWRITE:
504 		case ORDWR:
505 			return vtstrdup(Eperm);
506 		}
507 		mode |= ModeDir;
508 	}
509 	vf = vacfilecreate(vf, rhdr.name, mode);
510 	if(vf == nil) {
511 		char err[80];
512 		rerrstr(err, sizeof err);
513 
514 		return vtstrdup(err);
515 	}
516 
517 	vacfiledecref(fid->file);
518 
519 	fid->file = vf;
520 	fid->qid.type = QTFILE;
521 	if(vacfileisdir(vf))
522 		fid->qid.type = QTDIR;
523 	fid->qid.vers = vacfilegetmcount(vf);
524 	fid->qid.path = vacfilegetid(vf);
525 
526 	thdr.qid = fid->qid;
527 	thdr.iounit = messagesize - IOHDRSZ;
528 
529 	return 0;
530 }
531 
532 char*
rread(Fid * f)533 rread(Fid *f)
534 {
535 	char *buf;
536 	vlong off;
537 	int cnt;
538 	VacFile *vf;
539 	char err[80];
540 	int n;
541 
542 	if(!f->busy)
543 		return vtstrdup(Enotexist);
544 	vf = f->file;
545 	thdr.count = 0;
546 	off = rhdr.offset;
547 	buf = thdr.data;
548 	cnt = rhdr.count;
549 	if(f->qid.type & QTDIR)
550 		n = vacdirread(f, buf, off, cnt);
551 	else if(vacfilegetmode(f->file)&ModeDevice)
552 		return vtstrdup("device");
553 	else if(vacfilegetmode(f->file)&ModeLink)
554 		return vtstrdup("symbolic link");
555 	else if(vacfilegetmode(f->file)&ModeNamedPipe)
556 		return vtstrdup("named pipe");
557 	else
558 		n = vacfileread(vf, buf, cnt, off);
559 	if(n < 0) {
560 		rerrstr(err, sizeof err);
561 		return vtstrdup(err);
562 	}
563 	thdr.count = n;
564 	return 0;
565 }
566 
567 char*
rwrite(Fid * f)568 rwrite(Fid *f)
569 {
570 	USED(f);
571 	return vtstrdup(Erdonly);
572 }
573 
574 char *
rclunk(Fid * f)575 rclunk(Fid *f)
576 {
577 	f->busy = 0;
578 	f->open = 0;
579 	vtfree(f->user);
580 	f->user = nil;
581 	if(f->file)
582 		vacfiledecref(f->file);
583 	f->file = nil;
584 	vdeclose(f->vde);
585 	f->vde = nil;
586 	return 0;
587 }
588 
589 char *
rremove(Fid * f)590 rremove(Fid *f)
591 {
592 	VacFile *vf, *vfp;
593 	char errbuf[80];
594 	char *err = nil;
595 
596 	if(!f->busy)
597 		return vtstrdup(Enotexist);
598 	vf = f->file;
599 	vfp = vacfilegetparent(vf);
600 
601 	if(!permf(vfp, f->user, Pwrite)) {
602 		err = Eperm;
603 		goto Exit;
604 	}
605 
606 	if(!vacfileremove(vf)) {
607 		rerrstr(errbuf, sizeof errbuf);
608 		err = errbuf;
609 	}
610 
611 Exit:
612 	vacfiledecref(vfp);
613 	rclunk(f);
614 	return vtstrdup(err);
615 }
616 
617 char *
rstat(Fid * f)618 rstat(Fid *f)
619 {
620 	VacDir dir;
621 	static uchar statbuf[1024];
622 	VacFile *parent;
623 
624 	if(!f->busy)
625 		return vtstrdup(Enotexist);
626 	parent = vacfilegetparent(f->file);
627 	vacfilegetdir(f->file, &dir);
628 	thdr.stat = statbuf;
629 	thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
630 	vdcleanup(&dir);
631 	vacfiledecref(parent);
632 	return 0;
633 }
634 
635 char *
rwstat(Fid * f)636 rwstat(Fid *f)
637 {
638 	if(!f->busy)
639 		return vtstrdup(Enotexist);
640 	return vtstrdup(Erdonly);
641 }
642 
643 int
vacstat(VacFile * parent,VacDir * vd,uchar * p,int np)644 vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
645 {
646 	int ret;
647 	Dir dir;
648 #ifdef PLAN9PORT
649 	int n;
650 	VacFile *vf;
651 	uvlong size;
652 	char *ext = nil;
653 #endif
654 
655 	memset(&dir, 0, sizeof(dir));
656 
657 	dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
658 	if(vd->qidspace)
659 		dir.qid.path += vd->qidoffset;
660 	dir.qid.vers = vd->mcount;
661 	dir.mode = vd->mode & 0777;
662 	if(vd->mode & ModeAppend){
663 		dir.qid.type |= QTAPPEND;
664 		dir.mode |= DMAPPEND;
665 	}
666 	if(vd->mode & ModeExclusive){
667 		dir.qid.type |= QTEXCL;
668 		dir.mode |= DMEXCL;
669 	}
670 	if(vd->mode & ModeDir){
671 		dir.qid.type |= QTDIR;
672 		dir.mode |= DMDIR;
673 	}
674 
675 #ifdef PLAN9PORT
676 	if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
677 		vf = vacfilewalk(parent, vd->elem);
678 		if(vf == nil)
679 			return 0;
680 		vacfilegetsize(vf, &size);
681 		ext = malloc(size+1);
682 		if(ext == nil)
683 			return 0;
684 		n = vacfileread(vf, ext, size, 0);
685 		USED(n);
686 		ext[size] = 0;
687 		vacfiledecref(vf);
688 		if(vd->mode & ModeLink){
689 			dir.qid.type |= QTSYMLINK;
690 			dir.mode |= DMSYMLINK;
691 		}
692 		if(vd->mode & ModeDevice)
693 			dir.mode |= DMDEVICE;
694 		if(vd->mode & ModeNamedPipe)
695 			dir.mode |= DMNAMEDPIPE;
696 	}
697 #endif
698 
699 	dir.atime = vd->atime;
700 	dir.mtime = vd->mtime;
701 	dir.length = vd->size;
702 
703 	dir.name = vd->elem;
704 	dir.uid = vd->uid;
705 	dir.gid = vd->gid;
706 	dir.muid = vd->mid;
707 
708 	ret = convD2M(&dir, p, np);
709 #ifdef PLAN9PORT
710 	free(ext);
711 #endif
712 	return ret;
713 }
714 
715 int
vacdirread(Fid * f,char * p,long off,long cnt)716 vacdirread(Fid *f, char *p, long off, long cnt)
717 {
718 	int i, n, nb;
719 	VacDir vd;
720 
721 	/*
722 	 * special case of rewinding a directory
723 	 * otherwise ignore the offset
724 	 */
725 	if(off == 0 && f->vde){
726 		vdeclose(f->vde);
727 		f->vde = nil;
728 	}
729 
730 	if(f->vde == nil){
731 		f->vde = vdeopen(f->file);
732 		if(f->vde == nil)
733 			return -1;
734 	}
735 
736 	for(nb = 0; nb < cnt; nb += n) {
737 		i = vderead(f->vde, &vd);
738 		if(i < 0)
739 			return -1;
740 		if(i == 0)
741 			break;
742 		n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
743 		if(n <= BIT16SZ) {
744 			vdeunread(f->vde);
745 			break;
746 		}
747 		vdcleanup(&vd);
748 		p += n;
749 	}
750 	return nb;
751 }
752 
753 Fid *
newfid(int fid)754 newfid(int fid)
755 {
756 	Fid *f, *ff;
757 
758 	ff = 0;
759 	for(f = fids; f; f = f->next)
760 		if(f->fid == fid)
761 			return f;
762 		else if(!ff && !f->busy)
763 			ff = f;
764 	if(ff){
765 		ff->fid = fid;
766 		return ff;
767 	}
768 	f = vtmallocz(sizeof *f);
769 	f->fid = fid;
770 	f->next = fids;
771 	fids = f;
772 	return f;
773 }
774 
775 void
io(void)776 io(void)
777 {
778 	char *err;
779 	int n;
780 
781 	for(;;){
782 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
783 		if(n <= 0)
784 			break;
785 		if(convM2S(mdata, n, &rhdr) != n)
786 			sysfatal("convM2S conversion error");
787 
788 		if(dflag)
789 			fprint(2, "vacfs:<-%F\n", &rhdr);
790 
791 		thdr.data = (char*)mdata + IOHDRSZ;
792 		if(!fcalls[rhdr.type])
793 			err = "bad fcall type";
794 		else
795 			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
796 		if(err){
797 			thdr.type = Rerror;
798 			thdr.ename = err;
799 #ifdef PLAN9PORT
800 			thdr.errornum = 0;
801 #endif
802 		}else{
803 			thdr.type = rhdr.type + 1;
804 			thdr.fid = rhdr.fid;
805 		}
806 		thdr.tag = rhdr.tag;
807 		if(dflag)
808 			fprint(2, "vacfs:->%F\n", &thdr);
809 		n = convS2M(&thdr, mdata, messagesize);
810 		if(n <= BIT16SZ)
811 			sysfatal("convS2M conversion error");
812 		if(err)
813 			vtfree(err);
814 
815 		if(write(mfd[1], mdata, n) != n)
816 			sysfatal("mount write: %r");
817 	}
818 }
819 
820 int
permf(VacFile * vf,char * user,int p)821 permf(VacFile *vf, char *user, int p)
822 {
823 	VacDir dir;
824 	ulong perm;
825 
826 	if(vacfilegetdir(vf, &dir))
827 		return 0;
828 	perm = dir.mode & 0777;
829 
830 	if(noperm)
831 		goto Good;
832 	if((p*Pother) & perm)
833 		goto Good;
834 	if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
835 		goto Good;
836 	if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
837 		goto Good;
838 	vdcleanup(&dir);
839 	return 0;
840 Good:
841 	vdcleanup(&dir);
842 	return 1;
843 }
844 
845 int
perm(Fid * f,int p)846 perm(Fid *f, int p)
847 {
848 	return permf(f->file, f->user, p);
849 }
850 
851 void
vacshutdown(void)852 vacshutdown(void)
853 {
854 	Fid *f;
855 
856 	for(f = fids; f; f = f->next) {
857 		if(!f->busy)
858 			continue;
859 		rclunk(f);
860 	}
861 
862 	vacfsclose(fs);
863 	vthangup(conn);
864 }
865