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