xref: /plan9/sys/src/cmd/9nfs/nfsserver.c (revision 363b328d5e77ac1e503119274823363e6b14b616)
19a747e4fSDavid du Colombier #include "all.h"
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier /*
49a747e4fSDavid du Colombier  *	Cf. /lib/rfc/rfc1094
59a747e4fSDavid du Colombier  */
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier static int	nfsnull(int, Rpccall*, Rpccall*);
89a747e4fSDavid du Colombier static int	nfsgetattr(int, Rpccall*, Rpccall*);
99a747e4fSDavid du Colombier static int	nfssetattr(int, Rpccall*, Rpccall*);
109a747e4fSDavid du Colombier static int	nfsroot(int, Rpccall*, Rpccall*);
119a747e4fSDavid du Colombier static int	nfslookup(int, Rpccall*, Rpccall*);
129a747e4fSDavid du Colombier static int	nfsreadlink(int, Rpccall*, Rpccall*);
139a747e4fSDavid du Colombier static int	nfsread(int, Rpccall*, Rpccall*);
149a747e4fSDavid du Colombier static int	nfswritecache(int, Rpccall*, Rpccall*);
159a747e4fSDavid du Colombier static int	nfswrite(int, Rpccall*, Rpccall*);
169a747e4fSDavid du Colombier static int	nfscreate(int, Rpccall*, Rpccall*);
179a747e4fSDavid du Colombier static int	nfsremove(int, Rpccall*, Rpccall*);
189a747e4fSDavid du Colombier static int	nfsrename(int, Rpccall*, Rpccall*);
199a747e4fSDavid du Colombier static int	nfslink(int, Rpccall*, Rpccall*);
209a747e4fSDavid du Colombier static int	nfssymlink(int, Rpccall*, Rpccall*);
219a747e4fSDavid du Colombier static int	nfsmkdir(int, Rpccall*, Rpccall*);
229a747e4fSDavid du Colombier static int	nfsrmdir(int, Rpccall*, Rpccall*);
239a747e4fSDavid du Colombier static int	nfsreaddir(int, Rpccall*, Rpccall*);
249a747e4fSDavid du Colombier static int	nfsstatfs(int, Rpccall*, Rpccall*);
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier Procmap nfsproc[] = {
279a747e4fSDavid du Colombier 	0, nfsnull,	/* void */
289a747e4fSDavid du Colombier 	1, nfsgetattr,	/* Fhandle */
299a747e4fSDavid du Colombier 	2, nfssetattr,	/* Fhandle, Sattr */
309a747e4fSDavid du Colombier 	3, nfsroot,	/* void */
319a747e4fSDavid du Colombier 	4, nfslookup,	/* Fhandle, String */
329a747e4fSDavid du Colombier 	5, nfsreadlink,	/* Fhandle */
339a747e4fSDavid du Colombier 	6, nfsread,	/* Fhandle, long, long, long */
349a747e4fSDavid du Colombier 	7, nfswritecache,/* void */
359a747e4fSDavid du Colombier 	8, nfswrite,	/* Fhandle, long, long, long, String */
369a747e4fSDavid du Colombier 	9, nfscreate,	/* Fhandle, String, Sattr */
379a747e4fSDavid du Colombier 	10, nfsremove,	/* Fhandle, String */
389a747e4fSDavid du Colombier 	11, nfsrename,	/* Fhandle, String, Fhandle, String */
399a747e4fSDavid du Colombier 	12, nfslink,	/* Fhandle, Fhandle, String */
409a747e4fSDavid du Colombier 	13, nfssymlink,	/* Fhandle, String, String, Sattr */
419a747e4fSDavid du Colombier 	14, nfsmkdir,	/* Fhandle, String, Sattr */
429a747e4fSDavid du Colombier 	15, nfsrmdir,	/* Fhandle, String */
439a747e4fSDavid du Colombier 	16, nfsreaddir,	/* Fhandle, long, long */
449a747e4fSDavid du Colombier 	17, nfsstatfs,	/* Fhandle */
459a747e4fSDavid du Colombier 	0, 0
469a747e4fSDavid du Colombier };
479a747e4fSDavid du Colombier 
489a747e4fSDavid du Colombier void	nfsinit(int, char**);
499a747e4fSDavid du Colombier extern void	mntinit(int, char**);
509a747e4fSDavid du Colombier extern Procmap	mntproc[];
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier Progmap progmap[] = {
539a747e4fSDavid du Colombier 	100005, 1, mntinit, mntproc,
549a747e4fSDavid du Colombier 	100003, 2, nfsinit, nfsproc,
559a747e4fSDavid du Colombier 	0, 0, 0,
569a747e4fSDavid du Colombier };
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier int	myport = 2049;
599a747e4fSDavid du Colombier long	nfstime;
609a747e4fSDavid du Colombier int	conftime;
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier void
main(int argc,char * argv[])639a747e4fSDavid du Colombier main(int argc, char *argv[])
649a747e4fSDavid du Colombier {
659a747e4fSDavid du Colombier 	server(argc, argv, myport, progmap);
669a747e4fSDavid du Colombier }
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier static void
doalarm(void)699a747e4fSDavid du Colombier doalarm(void)
709a747e4fSDavid du Colombier {
719a747e4fSDavid du Colombier 	nfstime = time(0);
729a747e4fSDavid du Colombier 	mnttimer(nfstime);
736ab4d0ffSDavid du Colombier 	if(conftime+5*60 < nfstime){
746ab4d0ffSDavid du Colombier 		conftime = nfstime;
759a747e4fSDavid du Colombier 		readunixidmaps(config);
769a747e4fSDavid du Colombier 	}
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier void
nfsinit(int argc,char ** argv)809a747e4fSDavid du Colombier nfsinit(int argc, char **argv)
819a747e4fSDavid du Colombier {
82*363b328dSDavid du Colombier 	/*
83*363b328dSDavid du Colombier 	 * mntinit will have already parsed our options.
84*363b328dSDavid du Colombier 	 */
859a747e4fSDavid du Colombier 	USED(argc, argv);
869a747e4fSDavid du Colombier 	clog("nfs file server init\n");
879a747e4fSDavid du Colombier 	rpcalarm = doalarm;
889a747e4fSDavid du Colombier 	nfstime = time(0);
899a747e4fSDavid du Colombier }
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier static int
nfsnull(int n,Rpccall * cmd,Rpccall * reply)929a747e4fSDavid du Colombier nfsnull(int n, Rpccall *cmd, Rpccall *reply)
939a747e4fSDavid du Colombier {
949a747e4fSDavid du Colombier 	USED(n, reply);
959a747e4fSDavid du Colombier 	chat("nfsnull...");
969a747e4fSDavid du Colombier 	showauth(&cmd->cred);
979a747e4fSDavid du Colombier 	chat("OK\n");
989a747e4fSDavid du Colombier 	return 0;
999a747e4fSDavid du Colombier }
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier static int
nfsgetattr(int n,Rpccall * cmd,Rpccall * reply)1029a747e4fSDavid du Colombier nfsgetattr(int n, Rpccall *cmd, Rpccall *reply)
1039a747e4fSDavid du Colombier {
1049a747e4fSDavid du Colombier 	Xfid *xf;
1059a747e4fSDavid du Colombier 	Dir dir;
1069a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier 	chat("getattr...");
1099a747e4fSDavid du Colombier 	if(n != FHSIZE)
1109a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
1119a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, &dir);
1129a747e4fSDavid du Colombier 	if(xf == 0)
1139a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
1149a747e4fSDavid du Colombier 	chat("%s...", xf->xp->name);
1159a747e4fSDavid du Colombier 	PLONG(NFS_OK);
1169a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
1179a747e4fSDavid du Colombier 	chat("OK\n");
1189a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
1199a747e4fSDavid du Colombier }
1209a747e4fSDavid du Colombier 
1219a747e4fSDavid du Colombier static int
nfssetattr(int n,Rpccall * cmd,Rpccall * reply)1229a747e4fSDavid du Colombier nfssetattr(int n, Rpccall *cmd, Rpccall *reply)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier 	Xfid *xf;
1256ab4d0ffSDavid du Colombier 	Dir dir, nd;
1269a747e4fSDavid du Colombier 	Sattr sattr;
1279a747e4fSDavid du Colombier 	int r;
1289a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
1299a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	chat("setattr...");
1329a747e4fSDavid du Colombier 	if(n <= FHSIZE)
1339a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
1349a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, &dir);
1359a747e4fSDavid du Colombier 	argptr += FHSIZE;
1369a747e4fSDavid du Colombier 	argptr += convM2sattr(argptr, &sattr);
1379a747e4fSDavid du Colombier 	if(argptr != &((uchar *)cmd->args)[n])
1389a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
1399a747e4fSDavid du Colombier 	chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...",
1409a747e4fSDavid du Colombier 		sattr.mode, sattr.uid, sattr.gid, sattr.size,
1419a747e4fSDavid du Colombier 		sattr.atime, sattr.mtime);
1429a747e4fSDavid du Colombier 	if(xf == 0)
1439a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
1449a747e4fSDavid du Colombier 	if(sattr.uid != NOATTR || sattr.gid != NOATTR)
1459a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
1469a747e4fSDavid du Colombier 	if(sattr.size == 0){
1479a747e4fSDavid du Colombier 		if(xf->xp->s != xf->xp->parent->s){
1489a747e4fSDavid du Colombier 			if(xfauthremove(xf, cmd->user) < 0)
1499a747e4fSDavid du Colombier 				return error(reply, NFSERR_PERM);
1509a747e4fSDavid du Colombier 		}else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0)
1519a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
1529a747e4fSDavid du Colombier 	}else if(sattr.size != NOATTR)
1539a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
1549a747e4fSDavid du Colombier 	r = 0;
1556ab4d0ffSDavid du Colombier 	nulldir(&nd);
1569a747e4fSDavid du Colombier 	if(sattr.mode != NOATTR)
1576ab4d0ffSDavid du Colombier 		++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777);
1589a747e4fSDavid du Colombier 	if(sattr.atime != NOATTR)
1596ab4d0ffSDavid du Colombier 		++r, nd.atime = sattr.atime;
1609a747e4fSDavid du Colombier 	if(sattr.mtime != NOATTR)
1616ab4d0ffSDavid du Colombier 		++r, nd.mtime = sattr.mtime;
1626ab4d0ffSDavid du Colombier 	chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode);
1639a747e4fSDavid du Colombier 	if(r){
1646ab4d0ffSDavid du Colombier 		r = xfwstat(xf, &nd);
1659a747e4fSDavid du Colombier 		if(r < 0)
1669a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
1679a747e4fSDavid du Colombier 	}
1689a747e4fSDavid du Colombier 	if(xfstat(xf, &dir) < 0)
1699a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
1709a747e4fSDavid du Colombier 	PLONG(NFS_OK);
1719a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
1729a747e4fSDavid du Colombier 	chat("OK\n");
1739a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
1749a747e4fSDavid du Colombier }
1759a747e4fSDavid du Colombier 
1769a747e4fSDavid du Colombier static int
nfsroot(int n,Rpccall * cmd,Rpccall * reply)1779a747e4fSDavid du Colombier nfsroot(int n, Rpccall *cmd, Rpccall *reply)
1789a747e4fSDavid du Colombier {
1799a747e4fSDavid du Colombier 	USED(n, reply);
1809a747e4fSDavid du Colombier 	chat("nfsroot...");
1819a747e4fSDavid du Colombier 	showauth(&cmd->cred);
1829a747e4fSDavid du Colombier 	chat("OK\n");
1839a747e4fSDavid du Colombier 	return 0;
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier static int
nfslookup(int n,Rpccall * cmd,Rpccall * reply)1879a747e4fSDavid du Colombier nfslookup(int n, Rpccall *cmd, Rpccall *reply)
1889a747e4fSDavid du Colombier {
1899a747e4fSDavid du Colombier 	Xfile *xp;
1909a747e4fSDavid du Colombier 	Xfid *xf, *newxf;
1919a747e4fSDavid du Colombier 	String elem;
1929a747e4fSDavid du Colombier 	Dir dir;
1939a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
1949a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
1959a747e4fSDavid du Colombier 
1969a747e4fSDavid du Colombier 	chat("lookup...");
1979a747e4fSDavid du Colombier 	if(n <= FHSIZE)
1989a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
1999a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
2009a747e4fSDavid du Colombier 	argptr += FHSIZE;
2019a747e4fSDavid du Colombier 	argptr += string2S(argptr, &elem);
2029a747e4fSDavid du Colombier 	if(argptr != &((uchar *)cmd->args)[n])
2039a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
2049a747e4fSDavid du Colombier 	if(xf == 0)
2059a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
2069a747e4fSDavid du Colombier 	xp = xf->xp;
2079a747e4fSDavid du Colombier 	if(!(xp->qid.type & QTDIR))
2089a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOTDIR);
2099a747e4fSDavid du Colombier 	chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s);
2109a747e4fSDavid du Colombier 	if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
2119a747e4fSDavid du Colombier 		newxf = xfauth(xp, &elem);
2129a747e4fSDavid du Colombier 	else
2139a747e4fSDavid du Colombier 		newxf = xfwalkcr(Twalk, xf, &elem, 0);
2149a747e4fSDavid du Colombier 	if(newxf == 0)
2159a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOENT);
2169a747e4fSDavid du Colombier 	if(xfstat(newxf, &dir) < 0)
2179a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
2189a747e4fSDavid du Colombier 	PLONG(NFS_OK);
2199a747e4fSDavid du Colombier 	dataptr += xp2fhandle(newxf->xp, dataptr);
2209a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
2219a747e4fSDavid du Colombier 	chat("OK\n");
2229a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier 
2259a747e4fSDavid du Colombier static int
nfsreadlink(int n,Rpccall * cmd,Rpccall * reply)2269a747e4fSDavid du Colombier nfsreadlink(int n, Rpccall *cmd, Rpccall *reply)
2279a747e4fSDavid du Colombier {
2289a747e4fSDavid du Colombier 	USED(n, reply);
2299a747e4fSDavid du Colombier 	chat("readlink...");
2309a747e4fSDavid du Colombier 	showauth(&cmd->cred);
2319a747e4fSDavid du Colombier 	return error(reply, NFSERR_NOENT);
2329a747e4fSDavid du Colombier }
2339a747e4fSDavid du Colombier 
2349a747e4fSDavid du Colombier static int
nfsread(int n,Rpccall * cmd,Rpccall * reply)2359a747e4fSDavid du Colombier nfsread(int n, Rpccall *cmd, Rpccall *reply)
2369a747e4fSDavid du Colombier {
2379a747e4fSDavid du Colombier 	Session *s;
2389a747e4fSDavid du Colombier 	Xfid *xf;
2399a747e4fSDavid du Colombier 	Dir dir;
2409a747e4fSDavid du Colombier 	int offset, count;
2419a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
2429a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
2439a747e4fSDavid du Colombier 	uchar *readptr = dataptr + 4 + 17*4 + 4;
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	chat("read...");
2469a747e4fSDavid du Colombier 	if(n != FHSIZE+12)
2479a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
2489a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
2499a747e4fSDavid du Colombier 	argptr += FHSIZE;
2509a747e4fSDavid du Colombier 	offset = GLONG();
2519a747e4fSDavid du Colombier 	count = GLONG();
2529a747e4fSDavid du Colombier 	if(xf == 0)
2539a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
2549a747e4fSDavid du Colombier 	chat("%s %d %d...", xf->xp->name, offset, count);
2559a747e4fSDavid du Colombier 	if(xf->xp->s != xf->xp->parent->s){
2569a747e4fSDavid du Colombier 		count = xfauthread(xf, offset, readptr, count);
2579a747e4fSDavid du Colombier 	}else{
2589a747e4fSDavid du Colombier 		if(xfopen(xf, Oread) < 0)
2599a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
2609a747e4fSDavid du Colombier 		if(count > 8192)
2619a747e4fSDavid du Colombier 			count = 8192;
2629a747e4fSDavid du Colombier 		s = xf->xp->s;
2639a747e4fSDavid du Colombier 		setfid(s, xf->opfid);
2649a747e4fSDavid du Colombier 		xf->opfid->tstale = nfstime + 60;
2659a747e4fSDavid du Colombier 		s->f.offset = offset;
2669a747e4fSDavid du Colombier 		s->f.count = count;
2679a747e4fSDavid du Colombier 		if(xmesg(s, Tread) < 0)
2689a747e4fSDavid du Colombier 			return error(reply, NFSERR_IO);
2699a747e4fSDavid du Colombier 		count = s->f.count;
2709a747e4fSDavid du Colombier 		memmove(readptr, s->f.data, count);
2719a747e4fSDavid du Colombier 	}
2729a747e4fSDavid du Colombier 	if(xfstat(xf, &dir) < 0)
2739a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
2749a747e4fSDavid du Colombier 	PLONG(NFS_OK);
2759a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
2769a747e4fSDavid du Colombier 	PLONG(count);
2779a747e4fSDavid du Colombier 	dataptr += ROUNDUP(count);
2789a747e4fSDavid du Colombier 	chat("%d OK\n", count);
2799a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
2809a747e4fSDavid du Colombier }
2819a747e4fSDavid du Colombier 
2829a747e4fSDavid du Colombier static int
nfswritecache(int n,Rpccall * cmd,Rpccall * reply)2839a747e4fSDavid du Colombier nfswritecache(int n, Rpccall *cmd, Rpccall *reply)
2849a747e4fSDavid du Colombier {
2859a747e4fSDavid du Colombier 	USED(n, reply);
2869a747e4fSDavid du Colombier 	chat("writecache...");
2879a747e4fSDavid du Colombier 	showauth(&cmd->cred);
2889a747e4fSDavid du Colombier 	chat("OK\n");
2899a747e4fSDavid du Colombier 	return 0;
2909a747e4fSDavid du Colombier }
2919a747e4fSDavid du Colombier 
2929a747e4fSDavid du Colombier static int
nfswrite(int n,Rpccall * cmd,Rpccall * reply)2939a747e4fSDavid du Colombier nfswrite(int n, Rpccall *cmd, Rpccall *reply)
2949a747e4fSDavid du Colombier {
2959a747e4fSDavid du Colombier 	Session *s;
2969a747e4fSDavid du Colombier 	Xfid *xf;
2979a747e4fSDavid du Colombier 	Dir dir;
2989a747e4fSDavid du Colombier 	int offset, count;
2999a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
3009a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
3019a747e4fSDavid du Colombier 
3029a747e4fSDavid du Colombier 	chat("write...");
3039a747e4fSDavid du Colombier 	if(n < FHSIZE+16)
3049a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
3059a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
3069a747e4fSDavid du Colombier 	argptr += FHSIZE + 4;
3079a747e4fSDavid du Colombier 	offset = GLONG();
3089a747e4fSDavid du Colombier 	argptr += 4;
3099a747e4fSDavid du Colombier 	count = GLONG();
3109a747e4fSDavid du Colombier 	if(xf == 0)
3119a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
3129a747e4fSDavid du Colombier 	chat("%s %d %d...", xf->xp->name, offset, count);
3139a747e4fSDavid du Colombier 	if(xf->xp->s != xf->xp->parent->s){
3149a747e4fSDavid du Colombier 		if(xfauthwrite(xf, offset, argptr, count) < 0)
3159a747e4fSDavid du Colombier 			return error(reply, NFSERR_IO);
3169a747e4fSDavid du Colombier 	}else{
3179a747e4fSDavid du Colombier 		if(xfopen(xf, Owrite) < 0)
3189a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
3199a747e4fSDavid du Colombier 		s = xf->xp->s;
3209a747e4fSDavid du Colombier 		setfid(s, xf->opfid);
3219a747e4fSDavid du Colombier 		xf->opfid->tstale = nfstime + 60;
3229a747e4fSDavid du Colombier 		s->f.offset = offset;
3239a747e4fSDavid du Colombier 		s->f.count = count;
3249a747e4fSDavid du Colombier 		s->f.data = (char *)argptr;
3259a747e4fSDavid du Colombier 		if(xmesg(s, Twrite) < 0)
3269a747e4fSDavid du Colombier 			return error(reply, NFSERR_IO);
3279a747e4fSDavid du Colombier 	}
3289a747e4fSDavid du Colombier 	if(xfstat(xf, &dir) < 0)
3299a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
3309a747e4fSDavid du Colombier 	PLONG(NFS_OK);
3319a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
3329a747e4fSDavid du Colombier 	chat("OK\n");
3339a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
3349a747e4fSDavid du Colombier }
3359a747e4fSDavid du Colombier 
3369a747e4fSDavid du Colombier static int
creat(int n,Rpccall * cmd,Rpccall * reply,int chdir)3379a747e4fSDavid du Colombier creat(int n, Rpccall *cmd, Rpccall *reply, int chdir)
3389a747e4fSDavid du Colombier {
3399a747e4fSDavid du Colombier 	Xfid *xf, *newxf;
3409a747e4fSDavid du Colombier 	Xfile *xp;
3419a747e4fSDavid du Colombier 	String elem;
3429a747e4fSDavid du Colombier 	Dir dir; Sattr sattr;
3439a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
3449a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
3459a747e4fSDavid du Colombier 	int trunced;
3469a747e4fSDavid du Colombier 
3479a747e4fSDavid du Colombier 	if(n <= FHSIZE)
3489a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
3499a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
3509a747e4fSDavid du Colombier 	argptr += FHSIZE;
3519a747e4fSDavid du Colombier 	argptr += string2S(argptr, &elem);
3529a747e4fSDavid du Colombier 	argptr += convM2sattr(argptr, &sattr);
3539a747e4fSDavid du Colombier 	if(argptr != &((uchar *)cmd->args)[n])
3549a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
3559a747e4fSDavid du Colombier 	if(xf == 0)
3569a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
3579a747e4fSDavid du Colombier 	xp = xf->xp;
3589a747e4fSDavid du Colombier 	if(!(xp->qid.type & QTDIR))
3599a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOTDIR);
3609a747e4fSDavid du Colombier 	chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
3619a747e4fSDavid du Colombier 	trunced = 0;
3629a747e4fSDavid du Colombier 	if(xp->parent == xp && elem.s[0] == '#'){
3639a747e4fSDavid du Colombier 		newxf = xfauth(xp, &elem);
3649a747e4fSDavid du Colombier 		if(newxf == 0)
3659a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
3669a747e4fSDavid du Colombier 		if(xfauthremove(newxf, cmd->user) < 0)
3679a747e4fSDavid du Colombier 			return error(reply, NFSERR_PERM);
3689a747e4fSDavid du Colombier 		trunced = 1;
3699a747e4fSDavid du Colombier 	}else
3709a747e4fSDavid du Colombier 		newxf = xfwalkcr(Twalk, xf, &elem, 0);
3719a747e4fSDavid du Colombier 	if(newxf == 0){
3729a747e4fSDavid du Colombier 		newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777));
3739a747e4fSDavid du Colombier 		if(newxf)
3749a747e4fSDavid du Colombier 			trunced = 1;
3759a747e4fSDavid du Colombier 		else
3769a747e4fSDavid du Colombier 			newxf = xfwalkcr(Twalk, xf, &elem, 0);
3779a747e4fSDavid du Colombier 	}
3789a747e4fSDavid du Colombier 	if(newxf == 0)
3799a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
3809a747e4fSDavid du Colombier 	if(!trunced && chdir)
3819a747e4fSDavid du Colombier 		return error(reply, NFSERR_EXIST);
3829a747e4fSDavid du Colombier 	if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0)
3839a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
3849a747e4fSDavid du Colombier 	if(xfstat(newxf, &dir) < 0)
3859a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
3869a747e4fSDavid du Colombier 
3879a747e4fSDavid du Colombier 	PLONG(NFS_OK);
3889a747e4fSDavid du Colombier 	dataptr += xp2fhandle(newxf->xp, dataptr);
3899a747e4fSDavid du Colombier 	dataptr += dir2fattr(cmd->up, &dir, dataptr);
3909a747e4fSDavid du Colombier 	chat("OK\n");
3919a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier static int
nfscreate(int n,Rpccall * cmd,Rpccall * reply)3959a747e4fSDavid du Colombier nfscreate(int n, Rpccall *cmd, Rpccall *reply)
3969a747e4fSDavid du Colombier {
3979a747e4fSDavid du Colombier 	chat("create...");
3989a747e4fSDavid du Colombier 	return creat(n, cmd, reply, 0);
3999a747e4fSDavid du Colombier }
4009a747e4fSDavid du Colombier 
4019a747e4fSDavid du Colombier static int
remov(int n,Rpccall * cmd,Rpccall * reply)4029a747e4fSDavid du Colombier remov(int n, Rpccall *cmd, Rpccall *reply)
4039a747e4fSDavid du Colombier {
4049a747e4fSDavid du Colombier 	Session *s;
4059a747e4fSDavid du Colombier 	Xfile *xp;
4069a747e4fSDavid du Colombier 	Xfid *xf, *newxf;
4079a747e4fSDavid du Colombier 	String elem;
4089a747e4fSDavid du Colombier 	Fid *nfid;
4099a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
4109a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
4119a747e4fSDavid du Colombier 
4129a747e4fSDavid du Colombier 	if(n <= FHSIZE)
4139a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
4149a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
4159a747e4fSDavid du Colombier 	argptr += FHSIZE;
4169a747e4fSDavid du Colombier 	argptr += string2S(argptr, &elem);
4179a747e4fSDavid du Colombier 	if(argptr != &((uchar *)cmd->args)[n])
4189a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
4199a747e4fSDavid du Colombier 	if(xf == 0)
4209a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
4219a747e4fSDavid du Colombier 	xp = xf->xp;
4229a747e4fSDavid du Colombier 	if(!(xp->qid.type & QTDIR))
4239a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOTDIR);
4249a747e4fSDavid du Colombier 	chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
4259a747e4fSDavid du Colombier 	if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
4269a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
4279a747e4fSDavid du Colombier 	newxf = xfwalkcr(Twalk, xf, &elem, 0);
4289a747e4fSDavid du Colombier 	if(newxf == 0)
4299a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOENT);
4309a747e4fSDavid du Colombier 	s = xp->s;
4319a747e4fSDavid du Colombier 	nfid = newfid(s);
4329a747e4fSDavid du Colombier 	setfid(s, newxf->urfid);
4339a747e4fSDavid du Colombier 	s->f.newfid = nfid - s->fids;
4349a747e4fSDavid du Colombier 	s->f.nwname = 0;
4359a747e4fSDavid du Colombier 	if(xmesg(s, Twalk) < 0){
4369a747e4fSDavid du Colombier 		putfid(s, nfid);
4379a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
4389a747e4fSDavid du Colombier 	}
4399a747e4fSDavid du Colombier 	s->f.fid = nfid - s->fids;
4409a747e4fSDavid du Colombier 	if(xmesg(s, Tremove) < 0){
4419a747e4fSDavid du Colombier 		putfid(s, nfid);
4429a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
4439a747e4fSDavid du Colombier 	}
4449a747e4fSDavid du Colombier 	putfid(s, nfid);
4459a747e4fSDavid du Colombier 	xpclear(newxf->xp);
4469a747e4fSDavid du Colombier 	PLONG(NFS_OK);
4479a747e4fSDavid du Colombier 	chat("OK\n");
4489a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier static int
nfsremove(int n,Rpccall * cmd,Rpccall * reply)4529a747e4fSDavid du Colombier nfsremove(int n, Rpccall *cmd, Rpccall *reply)
4539a747e4fSDavid du Colombier {
4549a747e4fSDavid du Colombier 	chat("remove...");
4559a747e4fSDavid du Colombier 	return remov(n, cmd, reply);
4569a747e4fSDavid du Colombier }
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier static int
nfsrename(int n,Rpccall * cmd,Rpccall * reply)4599a747e4fSDavid du Colombier nfsrename(int n, Rpccall *cmd, Rpccall *reply)
4609a747e4fSDavid du Colombier {
4619a747e4fSDavid du Colombier 	Xfid *xf, *newxf;
4629a747e4fSDavid du Colombier 	Xfile *xp;
4639a747e4fSDavid du Colombier 	uchar *fromdir, *todir;
4649a747e4fSDavid du Colombier 	String fromelem, toelem;
4659a747e4fSDavid du Colombier 	Dir dir;
4669a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
4679a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	chat("rename...");
4709a747e4fSDavid du Colombier 	if(n <= FHSIZE)
4719a747e4fSDavid du Colombier 		return garbage(reply, "count too small");
4729a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
4739a747e4fSDavid du Colombier 	fromdir = argptr;
4749a747e4fSDavid du Colombier 	argptr += FHSIZE;
4759a747e4fSDavid du Colombier 	argptr += string2S(argptr, &fromelem);
4769a747e4fSDavid du Colombier 	todir = argptr;
4779a747e4fSDavid du Colombier 	argptr += FHSIZE;
4789a747e4fSDavid du Colombier 	argptr += string2S(argptr, &toelem);
4799a747e4fSDavid du Colombier 	if(argptr != &((uchar *)cmd->args)[n])
4809a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
4819a747e4fSDavid du Colombier 	if(xf == 0)
4829a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
4839a747e4fSDavid du Colombier 	xp = xf->xp;
4849a747e4fSDavid du Colombier 	if(!(xp->qid.type & QTDIR))
4859a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOTDIR);
4869a747e4fSDavid du Colombier 	if(memcmp(fromdir, todir, FHSIZE) != 0)
4879a747e4fSDavid du Colombier 		return error(reply, NFSERR_NXIO);
4889a747e4fSDavid du Colombier 	newxf = xfwalkcr(Twalk, xf, &fromelem, 0);
4899a747e4fSDavid du Colombier 	if(newxf == 0)
4909a747e4fSDavid du Colombier 		return error(reply, NFSERR_NOENT);
4919a747e4fSDavid du Colombier 	if(xfstat(newxf, &dir) < 0)
4929a747e4fSDavid du Colombier 		return error(reply, NFSERR_IO);
4939a747e4fSDavid du Colombier 
4949a747e4fSDavid du Colombier 	if(xp->parent == xp && toelem.s[0] == '#')
4959a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
496d9306527SDavid du Colombier 	nulldir(&dir);
4979a747e4fSDavid du Colombier 	dir.name = toelem.s;
4989a747e4fSDavid du Colombier 	if(xfwstat(newxf, &dir) < 0)
4999a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
5009a747e4fSDavid du Colombier 	PLONG(NFS_OK);
5019a747e4fSDavid du Colombier 	chat("OK\n");
5029a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier 
5059a747e4fSDavid du Colombier static int
nfslink(int n,Rpccall * cmd,Rpccall * reply)5069a747e4fSDavid du Colombier nfslink(int n, Rpccall *cmd, Rpccall *reply)
5079a747e4fSDavid du Colombier {
5089a747e4fSDavid du Colombier 	USED(n, reply);
5099a747e4fSDavid du Colombier 	chat("link...");
5109a747e4fSDavid du Colombier 	showauth(&cmd->cred);
5119a747e4fSDavid du Colombier 	return error(reply, NFSERR_NOENT);
5129a747e4fSDavid du Colombier }
5139a747e4fSDavid du Colombier 
5149a747e4fSDavid du Colombier static int
nfssymlink(int n,Rpccall * cmd,Rpccall * reply)5159a747e4fSDavid du Colombier nfssymlink(int n, Rpccall *cmd, Rpccall *reply)
5169a747e4fSDavid du Colombier {
5179a747e4fSDavid du Colombier 	USED(n, reply);
5189a747e4fSDavid du Colombier 	chat("symlink...");
5199a747e4fSDavid du Colombier 	showauth(&cmd->cred);
5209a747e4fSDavid du Colombier 	return error(reply, NFSERR_NOENT);
5219a747e4fSDavid du Colombier }
5229a747e4fSDavid du Colombier 
5239a747e4fSDavid du Colombier static int
nfsmkdir(int n,Rpccall * cmd,Rpccall * reply)5249a747e4fSDavid du Colombier nfsmkdir(int n, Rpccall *cmd, Rpccall *reply)
5259a747e4fSDavid du Colombier {
5269a747e4fSDavid du Colombier 	chat("mkdir...");
5279a747e4fSDavid du Colombier 	return creat(n, cmd, reply, DMDIR);
5289a747e4fSDavid du Colombier }
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier static int
nfsrmdir(int n,Rpccall * cmd,Rpccall * reply)5319a747e4fSDavid du Colombier nfsrmdir(int n, Rpccall *cmd, Rpccall *reply)
5329a747e4fSDavid du Colombier {
5339a747e4fSDavid du Colombier 	chat("rmdir...");
5349a747e4fSDavid du Colombier 	return remov(n, cmd, reply);
5359a747e4fSDavid du Colombier }
5369a747e4fSDavid du Colombier 
5379a747e4fSDavid du Colombier static int
nfsreaddir(int n,Rpccall * cmd,Rpccall * reply)5389a747e4fSDavid du Colombier nfsreaddir(int n, Rpccall *cmd, Rpccall *reply)
5399a747e4fSDavid du Colombier {
5409a747e4fSDavid du Colombier 	Session *s;
5419a747e4fSDavid du Colombier 	Xfid *xf;
5429a747e4fSDavid du Colombier 	Dir dir;
5439a747e4fSDavid du Colombier 	char *rdata;
5449a747e4fSDavid du Colombier 	int k, offset, count, sfcount, entries, dsize;
5459a747e4fSDavid du Colombier 	uchar *argptr = cmd->args;
5469a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	chat("readdir...");
5499a747e4fSDavid du Colombier 	if(n != FHSIZE+8)
5509a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
5519a747e4fSDavid du Colombier 	xf = rpc2xfid(cmd, 0);
5529a747e4fSDavid du Colombier 	argptr += FHSIZE;
5539a747e4fSDavid du Colombier 	offset = GLONG();
5549a747e4fSDavid du Colombier 	count = GLONG();
5559a747e4fSDavid du Colombier 	if(xf == 0)
5569a747e4fSDavid du Colombier 		return error(reply, NFSERR_STALE);
5579a747e4fSDavid du Colombier 	chat("%s (%ld) %d %d...", xf->xp->name, xf->offset, offset, count);
5589a747e4fSDavid du Colombier 	s = xf->xp->s;
5599a747e4fSDavid du Colombier 	if((xf->mode & Open) && xf->offset > offset)
5609a747e4fSDavid du Colombier 		xfclose(xf);
5619a747e4fSDavid du Colombier 	if(xfopen(xf, Oread) < 0)
5629a747e4fSDavid du Colombier 		return error(reply, NFSERR_PERM);
5639a747e4fSDavid du Colombier 	while(xf->offset < offset){	/* if we reopened, xf->offset will be zero */
5649a747e4fSDavid du Colombier 		sfcount = offset - xf->offset;
5659a747e4fSDavid du Colombier 		if(sfcount > messagesize-IOHDRSZ)
5669a747e4fSDavid du Colombier 			sfcount = messagesize-IOHDRSZ;
5679a747e4fSDavid du Colombier 		setfid(s, xf->opfid);
5689a747e4fSDavid du Colombier 		s->f.offset = xf->offset;
5699a747e4fSDavid du Colombier 		s->f.count = sfcount;
5709a747e4fSDavid du Colombier 		if(xmesg(s, Tread) < 0){
5719a747e4fSDavid du Colombier 			xfclose(xf);
5729a747e4fSDavid du Colombier 			return error(reply, NFSERR_IO);
5739a747e4fSDavid du Colombier 		}
5749a747e4fSDavid du Colombier 		if(s->f.count <= BIT16SZ)
5759a747e4fSDavid du Colombier 			break;
5769a747e4fSDavid du Colombier 		xf->offset += s->f.count;
5779a747e4fSDavid du Colombier 	}
5789a747e4fSDavid du Colombier 	if(count > messagesize-IOHDRSZ)
5799a747e4fSDavid du Colombier 		count = messagesize-IOHDRSZ;
5809a747e4fSDavid du Colombier 	PLONG(NFS_OK);
5819a747e4fSDavid du Colombier 	entries = 0;
5829a747e4fSDavid du Colombier 	while(count > 16){	/* at least 16 bytes required; we don't know size of name */
5839a747e4fSDavid du Colombier chat("top of loop\n");
5849a747e4fSDavid du Colombier 		setfid(s, xf->opfid);
5859a747e4fSDavid du Colombier 		s->f.offset = xf->offset;
5869a747e4fSDavid du Colombier 		s->f.count = count;	/* as good a guess as any */
5879a747e4fSDavid du Colombier 		if(xmesg(s, Tread) < 0){
5889a747e4fSDavid du Colombier 			xfclose(xf);
5899a747e4fSDavid du Colombier 			return error(reply, NFSERR_IO);
5909a747e4fSDavid du Colombier 		}
5919a747e4fSDavid du Colombier 		sfcount = s->f.count;
5929a747e4fSDavid du Colombier 		if(sfcount <= BIT16SZ)
5939a747e4fSDavid du Colombier 			break;
5949a747e4fSDavid du Colombier 		xf->offset += sfcount;
5959a747e4fSDavid du Colombier chat("count %d data 0x%p\n", s->f.count, s->f.data);
5969a747e4fSDavid du Colombier 		rdata = s->f.data;
5979a747e4fSDavid du Colombier 		/* now have a buffer of Plan 9 directories; unpack into NFS thingies */
5989a747e4fSDavid du Colombier 		while(sfcount >= 0){
5999a747e4fSDavid du Colombier 			dsize = convM2D((uchar*)rdata, sfcount, &dir, (char*)s->statbuf);
6009a747e4fSDavid du Colombier 			if(dsize <= BIT16SZ){
6019a747e4fSDavid du Colombier 				count = 0;	/* force break from outer loop */
6029a747e4fSDavid du Colombier 				break;
6039a747e4fSDavid du Colombier 			}
6049a747e4fSDavid du Colombier 			offset += dsize;
6059a747e4fSDavid du Colombier 			k = strlen(dir.name);
6069a747e4fSDavid du Colombier 			if(count < 16+ROUNDUP(k)){
6079a747e4fSDavid du Colombier 				count = 0;	/* force break from outer loop */
6089a747e4fSDavid du Colombier 				break;
6099a747e4fSDavid du Colombier 			}
6109a747e4fSDavid du Colombier 			PLONG(TRUE);
6119a747e4fSDavid du Colombier 			PLONG(dir.qid.path);
6129a747e4fSDavid du Colombier 			PLONG(k);
6139a747e4fSDavid du Colombier 			PPTR(dir.name, k);
6149a747e4fSDavid du Colombier 			PLONG(offset);
6159a747e4fSDavid du Colombier 			count -= 16+ROUNDUP(k);
6169a747e4fSDavid du Colombier 			rdata += dsize;
6179a747e4fSDavid du Colombier 			sfcount -= dsize;
6189a747e4fSDavid du Colombier 		}
6199a747e4fSDavid du Colombier 	}
6209a747e4fSDavid du Colombier 	PLONG(FALSE);
6219a747e4fSDavid du Colombier 	if(s->f.count <= 0){
6229a747e4fSDavid du Colombier 		xfclose(xf);
6239a747e4fSDavid du Colombier 		chat("eof...");
6249a747e4fSDavid du Colombier 		PLONG(TRUE);
6259a747e4fSDavid du Colombier 	}else
6269a747e4fSDavid du Colombier 		PLONG(FALSE);
6279a747e4fSDavid du Colombier 	chat("%d OK\n", entries);
6289a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
6299a747e4fSDavid du Colombier }
6309a747e4fSDavid du Colombier 
6319a747e4fSDavid du Colombier static int
nfsstatfs(int n,Rpccall * cmd,Rpccall * reply)6329a747e4fSDavid du Colombier nfsstatfs(int n, Rpccall *cmd, Rpccall *reply)
6339a747e4fSDavid du Colombier {
6349a747e4fSDavid du Colombier 	uchar *dataptr = reply->results;
6358cd281c0SDavid du Colombier 	enum {
6368cd281c0SDavid du Colombier 		Xfersize = 2048,
6378cd281c0SDavid du Colombier 		Maxlong = (long)((1ULL<<31) - 1),
6388cd281c0SDavid du Colombier 		Maxfreeblks = Maxlong / Xfersize,
6398cd281c0SDavid du Colombier 	};
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier 	chat("statfs...");
6429a747e4fSDavid du Colombier 	showauth(&cmd->cred);
6439a747e4fSDavid du Colombier 	if(n != FHSIZE)
6449a747e4fSDavid du Colombier 		return garbage(reply, "bad count");
6459a747e4fSDavid du Colombier 	PLONG(NFS_OK);
6468cd281c0SDavid du Colombier 	PLONG(4096);		/* tsize (fs block size) */
6478cd281c0SDavid du Colombier 	PLONG(Xfersize);	/* bsize (optimal transfer size) */
6488cd281c0SDavid du Colombier 	PLONG(Maxfreeblks);	/* blocks in fs */
6498cd281c0SDavid du Colombier 	PLONG(Maxfreeblks);	/* bfree to root*/
6508cd281c0SDavid du Colombier 	PLONG(Maxfreeblks);	/* bavail (free to mortals) */
6519a747e4fSDavid du Colombier 	chat("OK\n");
6529a747e4fSDavid du Colombier 	/*conftime = 0;
6539a747e4fSDavid du Colombier 	readunixidmaps(config);*/
6549a747e4fSDavid du Colombier 	return dataptr - (uchar *)reply->results;
6559a747e4fSDavid du Colombier }
656