xref: /plan9/sys/src/cmd/rio/fsys.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include "dat.h"
117dd7cddfSDavid du Colombier #include "fns.h"
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier char Eperm[] = "permission denied";
147dd7cddfSDavid du Colombier char Eexist[] = "file does not exist";
157dd7cddfSDavid du Colombier char Enotdir[] = "not a directory";
167dd7cddfSDavid du Colombier char	Ebadfcall[] = "bad fcall type";
177dd7cddfSDavid du Colombier char	Eoffset[] = "illegal offset";
187dd7cddfSDavid du Colombier 
19*9a747e4fSDavid du Colombier int	messagesize = 8192+IOHDRSZ;	/* good start */
20*9a747e4fSDavid du Colombier 
21*9a747e4fSDavid du Colombier enum{
22*9a747e4fSDavid du Colombier 	DEBUG = 0
23*9a747e4fSDavid du Colombier };
24*9a747e4fSDavid du Colombier 
257dd7cddfSDavid du Colombier Dirtab dirtab[]=
267dd7cddfSDavid du Colombier {
27*9a747e4fSDavid du Colombier 	{ ".",			QTDIR,	Qdir,			0500|DMDIR },
28*9a747e4fSDavid du Colombier 	{ "cons",		QTFILE,	Qcons,		0600 },
29*9a747e4fSDavid du Colombier 	{ "cursor",		QTFILE,	Qcursor,		0600 },
30*9a747e4fSDavid du Colombier 	{ "consctl",	QTFILE,	Qconsctl,		0200 },
31*9a747e4fSDavid du Colombier 	{ "winid",		QTFILE,	Qwinid,		0400 },
32*9a747e4fSDavid du Colombier 	{ "winname",	QTFILE,	Qwinname,	0400 },
33*9a747e4fSDavid du Colombier 	{ "kbdin",		QTFILE,	Qkbdin,		0200 },
34*9a747e4fSDavid du Colombier 	{ "label",		QTFILE,	Qlabel,		0600 },
35*9a747e4fSDavid du Colombier 	{ "mouse",	QTFILE,	Qmouse,		0600 },
36*9a747e4fSDavid du Colombier 	{ "screen",		QTFILE,	Qscreen,		0400 },
37*9a747e4fSDavid du Colombier 	{ "snarf",		QTFILE,	Qsnarf,		0600 },
38*9a747e4fSDavid du Colombier 	{ "text",		QTFILE,	Qtext,		0400 },
39*9a747e4fSDavid du Colombier 	{ "wdir",		QTFILE,	Qwdir,		0600 },
40*9a747e4fSDavid du Colombier 	{ "wctl",		QTFILE,	Qwctl,		0600 },
41*9a747e4fSDavid du Colombier 	{ "window",	QTFILE,	Qwindow,		0400 },
42*9a747e4fSDavid du Colombier 	{ "wsys",		QTDIR,	Qwsys,		0500|DMDIR },
437dd7cddfSDavid du Colombier 	{ nil, }
447dd7cddfSDavid du Colombier };
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier static uint		getclock(void);
477dd7cddfSDavid du Colombier static void		filsysproc(void*);
487dd7cddfSDavid du Colombier static Fid*		newfid(Filsys*, int);
49*9a747e4fSDavid du Colombier static int		dostat(Filsys*, int, Dirtab*, uchar*, int, uint);
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier int	clockfd;
52*9a747e4fSDavid du Colombier int	firstmessage = 1;
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier char	srvpipe[64];
557dd7cddfSDavid du Colombier char	srvwctl[64];
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier static	Xfid*	filsysflush(Filsys*, Xfid*, Fid*);
58*9a747e4fSDavid du Colombier static	Xfid*	filsysversion(Filsys*, Xfid*, Fid*);
59*9a747e4fSDavid du Colombier static	Xfid*	filsysauth(Filsys*, Xfid*, Fid*);
607dd7cddfSDavid du Colombier static	Xfid*	filsysnop(Filsys*, Xfid*, Fid*);
617dd7cddfSDavid du Colombier static	Xfid*	filsysattach(Filsys*, Xfid*, Fid*);
627dd7cddfSDavid du Colombier static	Xfid*	filsyswalk(Filsys*, Xfid*, Fid*);
637dd7cddfSDavid du Colombier static	Xfid*	filsysopen(Filsys*, Xfid*, Fid*);
647dd7cddfSDavid du Colombier static	Xfid*	filsyscreate(Filsys*, Xfid*, Fid*);
657dd7cddfSDavid du Colombier static	Xfid*	filsysread(Filsys*, Xfid*, Fid*);
667dd7cddfSDavid du Colombier static	Xfid*	filsyswrite(Filsys*, Xfid*, Fid*);
677dd7cddfSDavid du Colombier static	Xfid*	filsysclunk(Filsys*, Xfid*, Fid*);
687dd7cddfSDavid du Colombier static	Xfid*	filsysremove(Filsys*, Xfid*, Fid*);
697dd7cddfSDavid du Colombier static	Xfid*	filsysstat(Filsys*, Xfid*, Fid*);
707dd7cddfSDavid du Colombier static	Xfid*	filsyswstat(Filsys*, Xfid*, Fid*);
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier Xfid* 	(*fcall[Tmax])(Filsys*, Xfid*, Fid*) =
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier 	[Tflush]	= filsysflush,
75*9a747e4fSDavid du Colombier 	[Tversion]	= filsysversion,
76*9a747e4fSDavid du Colombier 	[Tauth]	= filsysauth,
777dd7cddfSDavid du Colombier 	[Tattach]	= filsysattach,
787dd7cddfSDavid du Colombier 	[Twalk]	= filsyswalk,
797dd7cddfSDavid du Colombier 	[Topen]	= filsysopen,
807dd7cddfSDavid du Colombier 	[Tcreate]	= filsyscreate,
817dd7cddfSDavid du Colombier 	[Tread]	= filsysread,
827dd7cddfSDavid du Colombier 	[Twrite]	= filsyswrite,
837dd7cddfSDavid du Colombier 	[Tclunk]	= filsysclunk,
847dd7cddfSDavid du Colombier 	[Tremove]= filsysremove,
857dd7cddfSDavid du Colombier 	[Tstat]	= filsysstat,
867dd7cddfSDavid du Colombier 	[Twstat]	= filsyswstat,
877dd7cddfSDavid du Colombier };
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier void
post(char * name,char * envname,int srvfd)907dd7cddfSDavid du Colombier post(char *name, char *envname, int srvfd)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	int fd;
937dd7cddfSDavid du Colombier 	char buf[32];
947dd7cddfSDavid du Colombier 
95*9a747e4fSDavid du Colombier 	fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);
967dd7cddfSDavid du Colombier 	if(fd < 0)
977dd7cddfSDavid du Colombier 		error(name);
987dd7cddfSDavid du Colombier 	sprint(buf, "%d",srvfd);
997dd7cddfSDavid du Colombier 	if(write(fd, buf, strlen(buf)) != strlen(buf))
1007dd7cddfSDavid du Colombier 		error("srv write");
1017dd7cddfSDavid du Colombier 	putenv(envname, name);
1027dd7cddfSDavid du Colombier }
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier /*
1057dd7cddfSDavid du Colombier  * Build pipe with OCEXEC set on second fd.
1067dd7cddfSDavid du Colombier  * Can't put it on both because we want to post one in /srv.
1077dd7cddfSDavid du Colombier  */
1087dd7cddfSDavid du Colombier int
cexecpipe(int * p0,int * p1)1097dd7cddfSDavid du Colombier cexecpipe(int *p0, int *p1)
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier 	/* pipe the hard way to get close on exec */
112*9a747e4fSDavid du Colombier 	if(bind("#|", "/mnt/temp", MREPL) < 0)
1137dd7cddfSDavid du Colombier 		return -1;
114*9a747e4fSDavid du Colombier 	*p0 = open("/mnt/temp/data", ORDWR);
115*9a747e4fSDavid du Colombier 	*p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);
116*9a747e4fSDavid du Colombier 	unmount(nil, "/mnt/temp");
1177dd7cddfSDavid du Colombier 	if(*p0<0 || *p1<0)
1187dd7cddfSDavid du Colombier 		return -1;
1197dd7cddfSDavid du Colombier 	return 0;
1207dd7cddfSDavid du Colombier }
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier Filsys*
filsysinit(Channel * cxfidalloc)1237dd7cddfSDavid du Colombier filsysinit(Channel *cxfidalloc)
1247dd7cddfSDavid du Colombier {
1257dd7cddfSDavid du Colombier 	int n, fd, pid, p0;
1267dd7cddfSDavid du Colombier 	Filsys *fs;
1277dd7cddfSDavid du Colombier 	Channel *c;
128*9a747e4fSDavid du Colombier 	char buf[128];
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	fs = emalloc(sizeof(Filsys));
1317dd7cddfSDavid du Colombier 	if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
1327dd7cddfSDavid du Colombier 		goto Rescue;
133*9a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
1347dd7cddfSDavid du Colombier 	clockfd = open("/dev/time", OREAD|OCEXEC);
1357dd7cddfSDavid du Colombier 	fd = open("/dev/user", OREAD);
136*9a747e4fSDavid du Colombier 	strcpy(buf, "Jean-Paul_Belmondo");
1377dd7cddfSDavid du Colombier 	if(fd >= 0){
138*9a747e4fSDavid du Colombier 		n = read(fd, buf, sizeof buf-1);
1397dd7cddfSDavid du Colombier 		if(n > 0)
140*9a747e4fSDavid du Colombier 			buf[n] = 0;
1417dd7cddfSDavid du Colombier 		close(fd);
1427dd7cddfSDavid du Colombier 	}
143*9a747e4fSDavid du Colombier 	fs->user = estrdup(buf);
1447dd7cddfSDavid du Colombier 	fs->cxfidalloc = cxfidalloc;
1457dd7cddfSDavid du Colombier 	pid = getpid();
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	/*
1487dd7cddfSDavid du Colombier 	 * Create and post wctl pipe
1497dd7cddfSDavid du Colombier 	 */
1507dd7cddfSDavid du Colombier 	if(cexecpipe(&p0, &wctlfd) < 0)
1517dd7cddfSDavid du Colombier 		goto Rescue;
1527dd7cddfSDavid du Colombier 	sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);
1537dd7cddfSDavid du Colombier 	post(srvwctl, "wctl", p0);
1547dd7cddfSDavid du Colombier 	close(p0);
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	/*
1577dd7cddfSDavid du Colombier 	 * Start server processes
1587dd7cddfSDavid du Colombier 	 */
1597dd7cddfSDavid du Colombier 	c = chancreate(sizeof(char*), 0);
1607dd7cddfSDavid du Colombier 	if(c == nil)
1617dd7cddfSDavid du Colombier 		error("wctl channel");
1627dd7cddfSDavid du Colombier 	proccreate(wctlproc, c, 4096);
1637dd7cddfSDavid du Colombier 	threadcreate(wctlthread, c, 4096);
1647dd7cddfSDavid du Colombier 	proccreate(filsysproc, fs, 10000);
1657dd7cddfSDavid du Colombier 
166*9a747e4fSDavid du Colombier 	/*
167*9a747e4fSDavid du Colombier 	 * Post srv pipe
168*9a747e4fSDavid du Colombier 	 */
169*9a747e4fSDavid du Colombier 	sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);
170*9a747e4fSDavid du Colombier 	post(srvpipe, "wsys", fs->cfd);
171*9a747e4fSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	return fs;
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier Rescue:
1757dd7cddfSDavid du Colombier 	free(fs);
1767dd7cddfSDavid du Colombier 	return nil;
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier static
1807dd7cddfSDavid du Colombier void
filsysproc(void * arg)1817dd7cddfSDavid du Colombier filsysproc(void *arg)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier 	int n;
1847dd7cddfSDavid du Colombier 	Xfid *x;
1857dd7cddfSDavid du Colombier 	Fid *f;
1867dd7cddfSDavid du Colombier 	Fcall t;
187*9a747e4fSDavid du Colombier 	uchar *buf;
1887dd7cddfSDavid du Colombier 	Filsys *fs;
1897dd7cddfSDavid du Colombier 
19059cc4ca5SDavid du Colombier 	threadsetname("FILSYSPROC");
1917dd7cddfSDavid du Colombier 	fs = arg;
1927dd7cddfSDavid du Colombier 	fs->pid = getpid();
1937dd7cddfSDavid du Colombier 	x = nil;
1947dd7cddfSDavid du Colombier 	for(;;){
195*9a747e4fSDavid du Colombier 		buf = emalloc(messagesize+UTFmax);	/* UTFmax for appending partial rune in xfidwrite */
196*9a747e4fSDavid du Colombier 		n = read9pmsg(fs->sfd, buf, messagesize);
19759cc4ca5SDavid du Colombier 		if(n <= 0){
198*9a747e4fSDavid du Colombier 			yield();	/* if threadexitsall'ing, will not return */
199*9a747e4fSDavid du Colombier 			fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
20059cc4ca5SDavid du Colombier 			errorshouldabort = 0;
20159cc4ca5SDavid du Colombier 			error("eof or i/o error on server channel");
20259cc4ca5SDavid du Colombier 		}
2037dd7cddfSDavid du Colombier 		if(x == nil){
2047dd7cddfSDavid du Colombier 			send(fs->cxfidalloc, nil);
2057dd7cddfSDavid du Colombier 			recv(fs->cxfidalloc, &x);
2067dd7cddfSDavid du Colombier 			x->fs = fs;
2077dd7cddfSDavid du Colombier 		}
2087dd7cddfSDavid du Colombier 		x->buf = buf;
209*9a747e4fSDavid du Colombier 		if(convM2S(buf, n, x) != n)
2107dd7cddfSDavid du Colombier 			error("convert error in convM2S");
211*9a747e4fSDavid du Colombier 		if(DEBUG)
212*9a747e4fSDavid du Colombier 			fprint(2, "rio:<-%F\n", &x->Fcall);
2137dd7cddfSDavid du Colombier 		if(fcall[x->type] == nil)
2147dd7cddfSDavid du Colombier 			x = filsysrespond(fs, x, &t, Ebadfcall);
2157dd7cddfSDavid du Colombier 		else{
216*9a747e4fSDavid du Colombier 			if(x->type==Tversion || x->type==Tauth)
2177dd7cddfSDavid du Colombier 				f = nil;
2187dd7cddfSDavid du Colombier 			else
2197dd7cddfSDavid du Colombier 				f = newfid(fs, x->fid);
2207dd7cddfSDavid du Colombier 			x->f = f;
2217dd7cddfSDavid du Colombier 			x  = (*fcall[x->type])(fs, x, f);
2227dd7cddfSDavid du Colombier 		}
223*9a747e4fSDavid du Colombier 		firstmessage = 0;
2247dd7cddfSDavid du Colombier 	}
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier /*
2287dd7cddfSDavid du Colombier  * Called only from a different FD group
2297dd7cddfSDavid du Colombier  */
2307dd7cddfSDavid du Colombier int
filsysmount(Filsys * fs,int id)2317dd7cddfSDavid du Colombier filsysmount(Filsys *fs, int id)
2327dd7cddfSDavid du Colombier {
233*9a747e4fSDavid du Colombier 	char buf[32];
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier 	close(fs->sfd);	/* close server end so mount won't hang if exiting */
2367dd7cddfSDavid du Colombier 	sprint(buf, "%d", id);
237*9a747e4fSDavid du Colombier 	if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){
238*9a747e4fSDavid du Colombier 		fprint(2, "mount failed: %r\n");
2397dd7cddfSDavid du Colombier 		return -1;
2407dd7cddfSDavid du Colombier 	}
2417dd7cddfSDavid du Colombier 	if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
242*9a747e4fSDavid du Colombier 		fprint(2, "bind failed: %r\n");
2437dd7cddfSDavid du Colombier 		return -1;
2447dd7cddfSDavid du Colombier 	}
2457dd7cddfSDavid du Colombier 	return 0;
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier 
2487dd7cddfSDavid du Colombier Xfid*
filsysrespond(Filsys * fs,Xfid * x,Fcall * t,char * err)2497dd7cddfSDavid du Colombier filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err)
2507dd7cddfSDavid du Colombier {
2517dd7cddfSDavid du Colombier 	int n;
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	if(err){
2547dd7cddfSDavid du Colombier 		t->type = Rerror;
255*9a747e4fSDavid du Colombier 		t->ename = err;
2567dd7cddfSDavid du Colombier 	}else
2577dd7cddfSDavid du Colombier 		t->type = x->type+1;
2587dd7cddfSDavid du Colombier 	t->fid = x->fid;
2597dd7cddfSDavid du Colombier 	t->tag = x->tag;
2607dd7cddfSDavid du Colombier 	if(x->buf == nil)
261*9a747e4fSDavid du Colombier 		x->buf = malloc(messagesize);
262*9a747e4fSDavid du Colombier 	n = convS2M(t, x->buf, messagesize);
263*9a747e4fSDavid du Colombier 	if(n <= 0)
2647dd7cddfSDavid du Colombier 		error("convert error in convS2M");
2657dd7cddfSDavid du Colombier 	if(write(fs->sfd, x->buf, n) != n)
2667dd7cddfSDavid du Colombier 		error("write error in respond");
267*9a747e4fSDavid du Colombier 	if(DEBUG)
268*9a747e4fSDavid du Colombier 		fprint(2, "rio:->%F\n", t);
2697dd7cddfSDavid du Colombier 	free(x->buf);
2707dd7cddfSDavid du Colombier 	x->buf = nil;
2717dd7cddfSDavid du Colombier 	return x;
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier void
filsyscancel(Xfid * x)2757dd7cddfSDavid du Colombier filsyscancel(Xfid *x)
2767dd7cddfSDavid du Colombier {
2777dd7cddfSDavid du Colombier 	if(x->buf){
2787dd7cddfSDavid du Colombier 		free(x->buf);
2797dd7cddfSDavid du Colombier 		x->buf = nil;
2807dd7cddfSDavid du Colombier 	}
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier static
2847dd7cddfSDavid du Colombier Xfid*
filsysversion(Filsys * fs,Xfid * x,Fid *)285*9a747e4fSDavid du Colombier filsysversion(Filsys *fs, Xfid *x, Fid*)
2867dd7cddfSDavid du Colombier {
2877dd7cddfSDavid du Colombier 	Fcall t;
2887dd7cddfSDavid du Colombier 
289*9a747e4fSDavid du Colombier 	if(!firstmessage)
290*9a747e4fSDavid du Colombier 		return filsysrespond(x->fs, x, &t, "version request not first message");
291*9a747e4fSDavid du Colombier 	if(x->msize < 256)
292*9a747e4fSDavid du Colombier 		return filsysrespond(x->fs, x, &t, "version: message size too small");
293*9a747e4fSDavid du Colombier 	messagesize = x->msize;
294*9a747e4fSDavid du Colombier 	t.msize = messagesize;
295*9a747e4fSDavid du Colombier 	if(strncmp(x->version, "9P2000", 6) != 0)
296*9a747e4fSDavid du Colombier 		return filsysrespond(x->fs, x, &t, "unrecognized 9P version");
297*9a747e4fSDavid du Colombier 	t.version = "9P2000";
2987dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, nil);
2997dd7cddfSDavid du Colombier }
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier static
3027dd7cddfSDavid du Colombier Xfid*
filsysauth(Filsys * fs,Xfid * x,Fid *)303*9a747e4fSDavid du Colombier filsysauth(Filsys *fs, Xfid *x, Fid*)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier 	Fcall t;
3067dd7cddfSDavid du Colombier 
307*9a747e4fSDavid du Colombier 		return filsysrespond(fs, x, &t, "rio: authentication not required");
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier static
3117dd7cddfSDavid du Colombier Xfid*
filsysflush(Filsys *,Xfid * x,Fid *)3127dd7cddfSDavid du Colombier filsysflush(Filsys*, Xfid *x, Fid*)
3137dd7cddfSDavid du Colombier {
3147dd7cddfSDavid du Colombier 	sendp(x->c, xfidflush);
3157dd7cddfSDavid du Colombier 	return nil;
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier static
3197dd7cddfSDavid du Colombier Xfid*
filsysattach(Filsys *,Xfid * x,Fid * f)3207dd7cddfSDavid du Colombier filsysattach(Filsys *, Xfid *x, Fid *f)
3217dd7cddfSDavid du Colombier {
3227dd7cddfSDavid du Colombier 	Fcall t;
3237dd7cddfSDavid du Colombier 
3247dd7cddfSDavid du Colombier 	if(strcmp(x->uname, x->fs->user) != 0)
3257dd7cddfSDavid du Colombier 		return filsysrespond(x->fs, x, &t, Eperm);
3267dd7cddfSDavid du Colombier 	f->busy = TRUE;
3277dd7cddfSDavid du Colombier 	f->open = FALSE;
328*9a747e4fSDavid du Colombier 	f->qid.path = Qdir;
329*9a747e4fSDavid du Colombier 	f->qid.type = QTDIR;
330*9a747e4fSDavid du Colombier 	f->qid.vers = 0;
3317dd7cddfSDavid du Colombier 	f->dir = dirtab;
3327dd7cddfSDavid du Colombier 	f->nrpart = 0;
3337dd7cddfSDavid du Colombier 	sendp(x->c, xfidattach);
3347dd7cddfSDavid du Colombier 	return nil;
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier static
338*9a747e4fSDavid du Colombier int
numeric(char * s)339*9a747e4fSDavid du Colombier numeric(char *s)
3407dd7cddfSDavid du Colombier {
341*9a747e4fSDavid du Colombier 	for(; *s!='\0'; s++)
342*9a747e4fSDavid du Colombier 		if(*s<'0' || '9'<*s)
343*9a747e4fSDavid du Colombier 			return 0;
344*9a747e4fSDavid du Colombier 	return 1;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier static
3487dd7cddfSDavid du Colombier Xfid*
filsyswalk(Filsys * fs,Xfid * x,Fid * f)3497dd7cddfSDavid du Colombier filsyswalk(Filsys *fs, Xfid *x, Fid *f)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier 	Fcall t;
352*9a747e4fSDavid du Colombier 	Fid *nf;
353*9a747e4fSDavid du Colombier 	int i, id;
354*9a747e4fSDavid du Colombier 	uchar type;
355*9a747e4fSDavid du Colombier 	ulong path;
356*9a747e4fSDavid du Colombier 	Dirtab *d, *dir;
3577dd7cddfSDavid du Colombier 	Window *w;
358*9a747e4fSDavid du Colombier 	char *err;
359*9a747e4fSDavid du Colombier 	Qid qid;
3607dd7cddfSDavid du Colombier 
361*9a747e4fSDavid du Colombier 	if(f->open)
362*9a747e4fSDavid du Colombier 		return filsysrespond(fs, x, &t, "walk of open file");
363*9a747e4fSDavid du Colombier 	nf = nil;
364*9a747e4fSDavid du Colombier 	if(x->fid  != x->newfid){
365*9a747e4fSDavid du Colombier 		/* BUG: check exists */
366*9a747e4fSDavid du Colombier 		nf = newfid(fs, x->newfid);
367*9a747e4fSDavid du Colombier 		if(nf->busy)
368*9a747e4fSDavid du Colombier 			return filsysrespond(fs, x, &t, "clone to busy fid");
369*9a747e4fSDavid du Colombier 		nf->busy = TRUE;
370*9a747e4fSDavid du Colombier 		nf->open = FALSE;
371*9a747e4fSDavid du Colombier 		nf->dir = f->dir;
372*9a747e4fSDavid du Colombier 		nf->qid = f->qid;
373*9a747e4fSDavid du Colombier 		nf->w = f->w;
374*9a747e4fSDavid du Colombier 		incref(f->w);
375*9a747e4fSDavid du Colombier 		nf->nrpart = 0;	/* not open, so must be zero */
376*9a747e4fSDavid du Colombier 		f = nf;	/* walk f */
3777dd7cddfSDavid du Colombier 	}
378*9a747e4fSDavid du Colombier 
379*9a747e4fSDavid du Colombier 	t.nwqid = 0;
380*9a747e4fSDavid du Colombier 	err = nil;
381*9a747e4fSDavid du Colombier 
382*9a747e4fSDavid du Colombier 	/* update f->qid, f->dir only if walk completes */
383*9a747e4fSDavid du Colombier 	qid = f->qid;
384*9a747e4fSDavid du Colombier 	dir = f->dir;
385*9a747e4fSDavid du Colombier 
386*9a747e4fSDavid du Colombier 	if(x->nwname > 0){
387*9a747e4fSDavid du Colombier 		for(i=0; i<x->nwname; i++){
388*9a747e4fSDavid du Colombier 			if((qid.type & QTDIR) == 0){
389*9a747e4fSDavid du Colombier 				err = Enotdir;
390*9a747e4fSDavid du Colombier 				break;
391*9a747e4fSDavid du Colombier 			}
392*9a747e4fSDavid du Colombier 			if(strcmp(x->wname[i], "..") == 0){
393*9a747e4fSDavid du Colombier 				type = QTDIR;
394*9a747e4fSDavid du Colombier 				path = Qdir;
395*9a747e4fSDavid du Colombier 				dir = dirtab;
396*9a747e4fSDavid du Colombier 				if(FILE(qid) == Qwsysdir)
397*9a747e4fSDavid du Colombier 					path = Qwsys;
398*9a747e4fSDavid du Colombier 				id = 0;
399*9a747e4fSDavid du Colombier     Accept:
400*9a747e4fSDavid du Colombier 				if(i == MAXWELEM){
401*9a747e4fSDavid du Colombier 					err = "name too long";
402*9a747e4fSDavid du Colombier 					break;
403*9a747e4fSDavid du Colombier 				}
404*9a747e4fSDavid du Colombier 				qid.type = type;
405*9a747e4fSDavid du Colombier 				qid.vers = 0;
406*9a747e4fSDavid du Colombier 				qid.path = QID(id, path);
407*9a747e4fSDavid du Colombier 				t.wqid[t.nwqid++] = qid;
408*9a747e4fSDavid du Colombier 				continue;
409*9a747e4fSDavid du Colombier 			}
410*9a747e4fSDavid du Colombier 
411*9a747e4fSDavid du Colombier 			if(qid.path == Qwsys){
4127dd7cddfSDavid du Colombier 				/* is it a numeric name? */
413*9a747e4fSDavid du Colombier 				if(!numeric(x->wname[i]))
414*9a747e4fSDavid du Colombier 					break;
4157dd7cddfSDavid du Colombier 				/* yes: it's a directory */
416*9a747e4fSDavid du Colombier 				id = atoi(x->wname[i]);
4177dd7cddfSDavid du Colombier 				qlock(&all);
4187dd7cddfSDavid du Colombier 				w = wlookid(id);
4197dd7cddfSDavid du Colombier 				if(w == nil){
4207dd7cddfSDavid du Colombier 					qunlock(&all);
421*9a747e4fSDavid du Colombier 					break;
4227dd7cddfSDavid du Colombier 				}
423*9a747e4fSDavid du Colombier 				path = Qwsysdir;
424*9a747e4fSDavid du Colombier 				type = QTDIR;
4257dd7cddfSDavid du Colombier 				qunlock(&all);
4267dd7cddfSDavid du Colombier 				incref(w);
4277dd7cddfSDavid du Colombier 				sendp(winclosechan, f->w);
4287dd7cddfSDavid du Colombier 				f->w = w;
429*9a747e4fSDavid du Colombier 				dir = dirtab;
430*9a747e4fSDavid du Colombier 				goto Accept;
4317dd7cddfSDavid du Colombier 			}
4327dd7cddfSDavid du Colombier 
433*9a747e4fSDavid du Colombier 			if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0)
434*9a747e4fSDavid du Colombier 				break;	/* don't serve /dev/snarf if it's provided in the environment */
4357dd7cddfSDavid du Colombier 			id = WIN(f->qid);
4367dd7cddfSDavid du Colombier 			d = dirtab;
4377dd7cddfSDavid du Colombier 			d++;	/* skip '.' */
4387dd7cddfSDavid du Colombier 			for(; d->name; d++)
439*9a747e4fSDavid du Colombier 				if(strcmp(x->wname[i], d->name) == 0){
440*9a747e4fSDavid du Colombier 					path = d->qid;
441*9a747e4fSDavid du Colombier 					type = d->type;
442*9a747e4fSDavid du Colombier 					dir = d;
443*9a747e4fSDavid du Colombier 					goto Accept;
4447dd7cddfSDavid du Colombier 				}
4457dd7cddfSDavid du Colombier 
446*9a747e4fSDavid du Colombier 			break;	/* file not found */
4477dd7cddfSDavid du Colombier 		}
4487dd7cddfSDavid du Colombier 
449*9a747e4fSDavid du Colombier 		if(i==0 && err==nil)
450*9a747e4fSDavid du Colombier 			err = Eexist;
451*9a747e4fSDavid du Colombier 	}
4527dd7cddfSDavid du Colombier 
453*9a747e4fSDavid du Colombier 	if(err!=nil || t.nwqid<x->nwname){
454*9a747e4fSDavid du Colombier 		if(nf){
455*9a747e4fSDavid du Colombier 			if(nf->w)
456*9a747e4fSDavid du Colombier 				sendp(winclosechan, nf->w);
457*9a747e4fSDavid du Colombier 			nf->open = FALSE;
458*9a747e4fSDavid du Colombier 			nf->busy = FALSE;
459*9a747e4fSDavid du Colombier 		}
460*9a747e4fSDavid du Colombier 	}else if(t.nwqid == x->nwname){
461*9a747e4fSDavid du Colombier 		f->dir = dir;
462*9a747e4fSDavid du Colombier 		f->qid = qid;
463*9a747e4fSDavid du Colombier 	}
464*9a747e4fSDavid du Colombier 
465*9a747e4fSDavid du Colombier 	return filsysrespond(fs, x, &t, err);
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier static
4697dd7cddfSDavid du Colombier Xfid*
filsysopen(Filsys * fs,Xfid * x,Fid * f)4707dd7cddfSDavid du Colombier filsysopen(Filsys *fs, Xfid *x, Fid *f)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier 	Fcall t;
4737dd7cddfSDavid du Colombier 	int m;
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier 	/* can't truncate anything, so just disregard */
4767dd7cddfSDavid du Colombier 	x->mode &= ~(OTRUNC|OCEXEC);
4777dd7cddfSDavid du Colombier 	/* can't execute or remove anything */
4787dd7cddfSDavid du Colombier 	if(x->mode==OEXEC || (x->mode&ORCLOSE))
4797dd7cddfSDavid du Colombier 		goto Deny;
4807dd7cddfSDavid du Colombier 	switch(x->mode){
4817dd7cddfSDavid du Colombier 	default:
4827dd7cddfSDavid du Colombier 		goto Deny;
4837dd7cddfSDavid du Colombier 	case OREAD:
4847dd7cddfSDavid du Colombier 		m = 0400;
4857dd7cddfSDavid du Colombier 		break;
4867dd7cddfSDavid du Colombier 	case OWRITE:
4877dd7cddfSDavid du Colombier 		m = 0200;
4887dd7cddfSDavid du Colombier 		break;
4897dd7cddfSDavid du Colombier 	case ORDWR:
4907dd7cddfSDavid du Colombier 		m = 0600;
4917dd7cddfSDavid du Colombier 		break;
4927dd7cddfSDavid du Colombier 	}
493*9a747e4fSDavid du Colombier 	if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
4947dd7cddfSDavid du Colombier 		goto Deny;
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	sendp(x->c, xfidopen);
4977dd7cddfSDavid du Colombier 	return nil;
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier     Deny:
5007dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, Eperm);
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier static
5047dd7cddfSDavid du Colombier Xfid*
filsyscreate(Filsys * fs,Xfid * x,Fid *)5057dd7cddfSDavid du Colombier filsyscreate(Filsys *fs, Xfid *x, Fid*)
5067dd7cddfSDavid du Colombier {
5077dd7cddfSDavid du Colombier 	Fcall t;
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, Eperm);
5107dd7cddfSDavid du Colombier }
5117dd7cddfSDavid du Colombier 
5127dd7cddfSDavid du Colombier static
5137dd7cddfSDavid du Colombier int
idcmp(void * a,void * b)5147dd7cddfSDavid du Colombier idcmp(void *a, void *b)
5157dd7cddfSDavid du Colombier {
5167dd7cddfSDavid du Colombier 	return *(int*)a - *(int*)b;
5177dd7cddfSDavid du Colombier }
5187dd7cddfSDavid du Colombier 
5197dd7cddfSDavid du Colombier static
5207dd7cddfSDavid du Colombier Xfid*
filsysread(Filsys * fs,Xfid * x,Fid * f)5217dd7cddfSDavid du Colombier filsysread(Filsys *fs, Xfid *x, Fid *f)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier 	Fcall t;
524*9a747e4fSDavid du Colombier 	uchar *b;
525*9a747e4fSDavid du Colombier 	int i, n, o, e, len, j, k, *ids;
5267dd7cddfSDavid du Colombier 	Dirtab *d, dt;
5277dd7cddfSDavid du Colombier 	uint clock;
5287dd7cddfSDavid du Colombier 	char buf[16];
5297dd7cddfSDavid du Colombier 
530*9a747e4fSDavid du Colombier 	if((f->qid.type & QTDIR) == 0){
5317dd7cddfSDavid du Colombier 		sendp(x->c, xfidread);
5327dd7cddfSDavid du Colombier 		return nil;
5337dd7cddfSDavid du Colombier 	}
5347dd7cddfSDavid du Colombier 	o = x->offset;
5357dd7cddfSDavid du Colombier 	e = x->offset+x->count;
5367dd7cddfSDavid du Colombier 	clock = getclock();
537*9a747e4fSDavid du Colombier 	b = malloc(messagesize-IOHDRSZ);	/* avoid memset of emalloc */
538*9a747e4fSDavid du Colombier 	if(b == nil)
539*9a747e4fSDavid du Colombier 		return filsysrespond(fs, x, &t, "out of memory");
5407dd7cddfSDavid du Colombier 	n = 0;
5417dd7cddfSDavid du Colombier 	switch(FILE(f->qid)){
5427dd7cddfSDavid du Colombier 	case Qdir:
5437dd7cddfSDavid du Colombier 	case Qwsysdir:
5447dd7cddfSDavid du Colombier 		d = dirtab;
5457dd7cddfSDavid du Colombier 		d++;	/* first entry is '.' */
546*9a747e4fSDavid du Colombier 		for(i=0; d->name!=nil && i<e; i+=len){
547*9a747e4fSDavid du Colombier 			len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);
548*9a747e4fSDavid du Colombier 			if(len <= BIT16SZ)
549*9a747e4fSDavid du Colombier 				break;
550*9a747e4fSDavid du Colombier 			if(i >= o)
551*9a747e4fSDavid du Colombier 				n += len;
5527dd7cddfSDavid du Colombier 			d++;
5537dd7cddfSDavid du Colombier 		}
5547dd7cddfSDavid du Colombier 		break;
5557dd7cddfSDavid du Colombier 	case Qwsys:
5567dd7cddfSDavid du Colombier 		qlock(&all);
5577dd7cddfSDavid du Colombier 		ids = emalloc(nwindow*sizeof(int));
5587dd7cddfSDavid du Colombier 		for(j=0; j<nwindow; j++)
5597dd7cddfSDavid du Colombier 			ids[j] = window[j]->id;
5607dd7cddfSDavid du Colombier 		qunlock(&all);
5617dd7cddfSDavid du Colombier 		qsort(ids, nwindow, sizeof ids[0], idcmp);
5627dd7cddfSDavid du Colombier 		dt.name = buf;
563*9a747e4fSDavid du Colombier 		for(i=0, j=0; j<nwindow && i<e; i+=len){
5647dd7cddfSDavid du Colombier 			k = ids[j];
5657dd7cddfSDavid du Colombier 			sprint(dt.name, "%d", k);
566*9a747e4fSDavid du Colombier 			dt.qid = QID(k, Qdir);
567*9a747e4fSDavid du Colombier 			dt.type = QTDIR;
568*9a747e4fSDavid du Colombier 			dt.perm = DMDIR|0700;
569*9a747e4fSDavid du Colombier 			len = dostat(fs, k, &dt, b+n, x->count-n, clock);
570*9a747e4fSDavid du Colombier 			if(len == 0)
571*9a747e4fSDavid du Colombier 				break;
572*9a747e4fSDavid du Colombier 			if(i >= o)
573*9a747e4fSDavid du Colombier 				n += len;
5747dd7cddfSDavid du Colombier 			j++;
5757dd7cddfSDavid du Colombier 		}
5767dd7cddfSDavid du Colombier 		free(ids);
5777dd7cddfSDavid du Colombier 		break;
5787dd7cddfSDavid du Colombier 	}
579*9a747e4fSDavid du Colombier 	t.data = (char*)b;
5807dd7cddfSDavid du Colombier 	t.count = n;
5817dd7cddfSDavid du Colombier 	filsysrespond(fs, x, &t, nil);
5827dd7cddfSDavid du Colombier 	free(b);
5837dd7cddfSDavid du Colombier 	return x;
5847dd7cddfSDavid du Colombier }
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier static
5877dd7cddfSDavid du Colombier Xfid*
filsyswrite(Filsys *,Xfid * x,Fid *)5887dd7cddfSDavid du Colombier filsyswrite(Filsys*, Xfid *x, Fid*)
5897dd7cddfSDavid du Colombier {
5907dd7cddfSDavid du Colombier 	sendp(x->c, xfidwrite);
5917dd7cddfSDavid du Colombier 	return nil;
5927dd7cddfSDavid du Colombier }
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier static
5957dd7cddfSDavid du Colombier Xfid*
filsysclunk(Filsys * fs,Xfid * x,Fid * f)5967dd7cddfSDavid du Colombier filsysclunk(Filsys *fs, Xfid *x, Fid *f)
5977dd7cddfSDavid du Colombier {
5987dd7cddfSDavid du Colombier 	Fcall t;
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier 	if(f->open){
6017dd7cddfSDavid du Colombier 		f->busy = FALSE;
6027dd7cddfSDavid du Colombier 		f->open = FALSE;
6037dd7cddfSDavid du Colombier 		sendp(x->c, xfidclose);
6047dd7cddfSDavid du Colombier 		return nil;
6057dd7cddfSDavid du Colombier 	}
6067dd7cddfSDavid du Colombier 	if(f->w)
6077dd7cddfSDavid du Colombier 		sendp(winclosechan, f->w);
6087dd7cddfSDavid du Colombier 	f->busy = FALSE;
6097dd7cddfSDavid du Colombier 	f->open = FALSE;
6107dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, nil);
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier static
6147dd7cddfSDavid du Colombier Xfid*
filsysremove(Filsys * fs,Xfid * x,Fid *)6157dd7cddfSDavid du Colombier filsysremove(Filsys *fs, Xfid *x, Fid*)
6167dd7cddfSDavid du Colombier {
6177dd7cddfSDavid du Colombier 	Fcall t;
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, Eperm);
6207dd7cddfSDavid du Colombier }
6217dd7cddfSDavid du Colombier 
6227dd7cddfSDavid du Colombier static
6237dd7cddfSDavid du Colombier Xfid*
filsysstat(Filsys * fs,Xfid * x,Fid * f)6247dd7cddfSDavid du Colombier filsysstat(Filsys *fs, Xfid *x, Fid *f)
6257dd7cddfSDavid du Colombier {
6267dd7cddfSDavid du Colombier 	Fcall t;
6277dd7cddfSDavid du Colombier 
628*9a747e4fSDavid du Colombier 	t.stat = emalloc(messagesize-IOHDRSZ);
629*9a747e4fSDavid du Colombier 	t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
630*9a747e4fSDavid du Colombier 	x = filsysrespond(fs, x, &t, nil);
631*9a747e4fSDavid du Colombier 	free(t.stat);
632*9a747e4fSDavid du Colombier 	return x;
6337dd7cddfSDavid du Colombier }
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier static
6367dd7cddfSDavid du Colombier Xfid*
filsyswstat(Filsys * fs,Xfid * x,Fid *)6377dd7cddfSDavid du Colombier filsyswstat(Filsys *fs, Xfid *x, Fid*)
6387dd7cddfSDavid du Colombier {
6397dd7cddfSDavid du Colombier 	Fcall t;
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier 	return filsysrespond(fs, x, &t, Eperm);
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier static
6457dd7cddfSDavid du Colombier Fid*
newfid(Filsys * fs,int fid)6467dd7cddfSDavid du Colombier newfid(Filsys *fs, int fid)
6477dd7cddfSDavid du Colombier {
6487dd7cddfSDavid du Colombier 	Fid *f, *ff, **fh;
6497dd7cddfSDavid du Colombier 
6507dd7cddfSDavid du Colombier 	ff = nil;
6517dd7cddfSDavid du Colombier 	fh = &fs->fids[fid&(Nhash-1)];
6527dd7cddfSDavid du Colombier 	for(f=*fh; f; f=f->next)
6537dd7cddfSDavid du Colombier 		if(f->fid == fid)
6547dd7cddfSDavid du Colombier 			return f;
6557dd7cddfSDavid du Colombier 		else if(ff==nil && f->busy==FALSE)
6567dd7cddfSDavid du Colombier 			ff = f;
6577dd7cddfSDavid du Colombier 	if(ff){
6587dd7cddfSDavid du Colombier 		ff->fid = fid;
6597dd7cddfSDavid du Colombier 		return ff;
6607dd7cddfSDavid du Colombier 	}
6617dd7cddfSDavid du Colombier 	f = emalloc(sizeof *f);
6627dd7cddfSDavid du Colombier 	f->fid = fid;
6637dd7cddfSDavid du Colombier 	f->next = *fh;
6647dd7cddfSDavid du Colombier 	*fh = f;
6657dd7cddfSDavid du Colombier 	return f;
6667dd7cddfSDavid du Colombier }
6677dd7cddfSDavid du Colombier 
6687dd7cddfSDavid du Colombier static
6697dd7cddfSDavid du Colombier uint
getclock(void)6707dd7cddfSDavid du Colombier getclock(void)
6717dd7cddfSDavid du Colombier {
6727dd7cddfSDavid du Colombier 	char buf[32];
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	seek(clockfd, 0, 0);
6757dd7cddfSDavid du Colombier 	read(clockfd, buf, sizeof buf);
6767dd7cddfSDavid du Colombier 	return atoi(buf);
6777dd7cddfSDavid du Colombier }
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier static
680*9a747e4fSDavid du Colombier int
dostat(Filsys * fs,int id,Dirtab * dir,uchar * buf,int nbuf,uint clock)681*9a747e4fSDavid du Colombier dostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
6827dd7cddfSDavid du Colombier {
6837dd7cddfSDavid du Colombier 	Dir d;
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	d.qid.path = QID(id, dir->qid);
68680ee5cbfSDavid du Colombier 	if(dir->qid == Qsnarf)
68780ee5cbfSDavid du Colombier 		d.qid.vers = snarfversion;
68880ee5cbfSDavid du Colombier 	else
6897dd7cddfSDavid du Colombier 		d.qid.vers = 0;
690*9a747e4fSDavid du Colombier 	d.qid.type = dir->type;
6917dd7cddfSDavid du Colombier 	d.mode = dir->perm;
6927dd7cddfSDavid du Colombier 	d.length = 0;	/* would be nice to do better */
693*9a747e4fSDavid du Colombier 	d.name = dir->name;
694*9a747e4fSDavid du Colombier 	d.uid = fs->user;
695*9a747e4fSDavid du Colombier 	d.gid = fs->user;
696*9a747e4fSDavid du Colombier 	d.muid = fs->user;
6977dd7cddfSDavid du Colombier 	d.atime = clock;
6987dd7cddfSDavid du Colombier 	d.mtime = clock;
699*9a747e4fSDavid du Colombier 	return convD2M(&d, buf, nbuf);
7007dd7cddfSDavid du Colombier }
701