1 /*
2  * linux/fs/nfsd/nfs3xdr.c
3  *
4  * XDR support for nfsd/protocol version 3.
5  *
6  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
7  */
8 
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs3.h>
12 
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/nfsd/nfsd.h>
16 #include <linux/nfsd/xdr3.h>
17 
18 #define NFSDDBG_FACILITY		NFSDDBG_XDR
19 
20 #ifdef NFSD_OPTIMIZE_SPACE
21 # define inline
22 #endif
23 
24 
25 /*
26  * Mapping of S_IF* types to NFS file types
27  */
28 static u32	nfs3_ftypes[] = {
29 	NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
30 	NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
31 	NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
32 	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
33 };
34 
35 /*
36  * XDR functions for basic NFS types
37  */
38 static inline u32 *
encode_time3(u32 * p,time_t secs)39 encode_time3(u32 *p, time_t secs)
40 {
41 	*p++ = htonl((u32) secs); *p++ = 0;
42 	return p;
43 }
44 
45 static inline u32 *
decode_time3(u32 * p,time_t * secp)46 decode_time3(u32 *p, time_t *secp)
47 {
48 	*secp = ntohl(*p++);
49 	return p + 1;
50 }
51 
52 static inline u32 *
decode_fh(u32 * p,struct svc_fh * fhp)53 decode_fh(u32 *p, struct svc_fh *fhp)
54 {
55 	unsigned int size;
56 	fh_init(fhp, NFS3_FHSIZE);
57 	size = ntohl(*p++);
58 	if (size > NFS3_FHSIZE)
59 		return NULL;
60 
61 	memcpy(&fhp->fh_handle.fh_base, p, size);
62 	fhp->fh_handle.fh_size = size;
63 	return p + XDR_QUADLEN(size);
64 }
65 
66 static inline u32 *
encode_fh(u32 * p,struct svc_fh * fhp)67 encode_fh(u32 *p, struct svc_fh *fhp)
68 {
69 	int size = fhp->fh_handle.fh_size;
70 	*p++ = htonl(size);
71 	if (size) p[XDR_QUADLEN(size)-1]=0;
72 	memcpy(p, &fhp->fh_handle.fh_base, size);
73 	return p + XDR_QUADLEN(size);
74 }
75 
76 /*
77  * Decode a file name and make sure that the path contains
78  * no slashes or null bytes.
79  */
80 static inline u32 *
decode_filename(u32 * p,char ** namp,int * lenp)81 decode_filename(u32 *p, char **namp, int *lenp)
82 {
83 	char		*name;
84 	int		i;
85 
86 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
87 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
88 			if (*name == '\0' || *name == '/')
89 				return NULL;
90 		}
91 	}
92 
93 	return p;
94 }
95 
96 static inline u32 *
decode_pathname(u32 * p,char ** namp,int * lenp)97 decode_pathname(u32 *p, char **namp, int *lenp)
98 {
99 	char		*name;
100 	int		i;
101 
102 	if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
103 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
104 			if (*name == '\0')
105 				return NULL;
106 		}
107 	}
108 
109 	return p;
110 }
111 
112 static inline u32 *
decode_sattr3(u32 * p,struct iattr * iap)113 decode_sattr3(u32 *p, struct iattr *iap)
114 {
115 	u32	tmp;
116 
117 	iap->ia_valid = 0;
118 
119 	if (*p++) {
120 		iap->ia_valid |= ATTR_MODE;
121 		iap->ia_mode = ntohl(*p++);
122 	}
123 	if (*p++) {
124 		iap->ia_valid |= ATTR_UID;
125 		iap->ia_uid = ntohl(*p++);
126 	}
127 	if (*p++) {
128 		iap->ia_valid |= ATTR_GID;
129 		iap->ia_gid = ntohl(*p++);
130 	}
131 	if (*p++) {
132 		u64	newsize;
133 
134 		iap->ia_valid |= ATTR_SIZE;
135 		p = xdr_decode_hyper(p, &newsize);
136 		if (newsize <= NFS_OFFSET_MAX)
137 			iap->ia_size = newsize;
138 		else
139 			iap->ia_size = NFS_OFFSET_MAX;
140 	}
141 	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
142 		iap->ia_valid |= ATTR_ATIME;
143 	} else if (tmp == 2) {		/* set to client time */
144 		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
145 		iap->ia_atime = ntohl(*p++), p++;
146 	}
147 	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
148 		iap->ia_valid |= ATTR_MTIME;
149 	} else if (tmp == 2) {		/* set to client time */
150 		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
151 		iap->ia_mtime = ntohl(*p++), p++;
152 	}
153 	return p;
154 }
155 
156 static inline u32 *
encode_fattr3(struct svc_rqst * rqstp,u32 * p,struct svc_fh * fhp)157 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
158 {
159 	struct inode	*inode = fhp->fh_dentry->d_inode;
160 
161 	*p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
162 	*p++ = htonl((u32) inode->i_mode);
163 	*p++ = htonl((u32) inode->i_nlink);
164 	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
165 	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
166 	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
167 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
168 	} else {
169 		p = xdr_encode_hyper(p, (u64) inode->i_size);
170 	}
171 	if (inode->i_blksize == 0 && inode->i_blocks == 0)
172 		/* Minix file system(?) i_size is (hopefully) close enough */
173 		p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
174 	else
175 		p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
176 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
177 	*p++ = htonl((u32) MINOR(inode->i_rdev));
178 	if (rqstp->rq_reffh->fh_version == 1
179 	    && rqstp->rq_reffh->fh_fsid_type == 1
180 	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
181 		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
182 	else
183 		p = xdr_encode_hyper(p, (u64) inode->i_dev);
184 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
185 	p = encode_time3(p, inode->i_atime);
186 	p = encode_time3(p, lease_get_mtime(inode));
187 	p = encode_time3(p, inode->i_ctime);
188 
189 	return p;
190 }
191 
192 static inline u32 *
encode_saved_post_attr(struct svc_rqst * rqstp,u32 * p,struct svc_fh * fhp)193 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
194 {
195 	struct inode	*inode = fhp->fh_dentry->d_inode;
196 
197 	/* Attributes to follow */
198 	*p++ = xdr_one;
199 
200 	*p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
201 	*p++ = htonl((u32) fhp->fh_post_mode);
202 	*p++ = htonl((u32) fhp->fh_post_nlink);
203 	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
204 	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
205 	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
206 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
207 	} else {
208 		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
209 	}
210 	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
211 	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
212 	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
213 	if (rqstp->rq_reffh->fh_version == 1
214 	    && rqstp->rq_reffh->fh_fsid_type == 1
215 	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
216 		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
217 	else
218 		p = xdr_encode_hyper(p, (u64) inode->i_dev);
219 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
220 	p = encode_time3(p, fhp->fh_post_atime);
221 	p = encode_time3(p, fhp->fh_post_mtime);
222 	p = encode_time3(p, fhp->fh_post_ctime);
223 
224 	return p;
225 }
226 
227 /*
228  * Encode post-operation attributes.
229  * The inode may be NULL if the call failed because of a stale file
230  * handle. In this case, no attributes are returned.
231  */
232 static u32 *
encode_post_op_attr(struct svc_rqst * rqstp,u32 * p,struct svc_fh * fhp)233 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
234 {
235 	struct dentry *dentry = fhp->fh_dentry;
236 	if (dentry && dentry->d_inode != NULL) {
237 		*p++ = xdr_one;		/* attributes follow */
238 		return encode_fattr3(rqstp, p, fhp);
239 	}
240 	*p++ = xdr_zero;
241 	return p;
242 }
243 
244 /*
245  * Enocde weak cache consistency data
246  */
247 static u32 *
encode_wcc_data(struct svc_rqst * rqstp,u32 * p,struct svc_fh * fhp)248 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
249 {
250 	struct dentry	*dentry = fhp->fh_dentry;
251 
252 	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
253 		if (fhp->fh_pre_saved) {
254 			*p++ = xdr_one;
255 			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
256 			p = encode_time3(p, fhp->fh_pre_mtime);
257 			p = encode_time3(p, fhp->fh_pre_ctime);
258 		} else {
259 			*p++ = xdr_zero;
260 		}
261 		return encode_saved_post_attr(rqstp, p, fhp);
262 	}
263 	/* no pre- or post-attrs */
264 	*p++ = xdr_zero;
265 	return encode_post_op_attr(rqstp, p, fhp);
266 }
267 
268 /*
269  * Check buffer bounds after decoding arguments
270  */
271 static inline int
xdr_argsize_check(struct svc_rqst * rqstp,u32 * p)272 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
273 {
274 	struct svc_buf	*buf = &rqstp->rq_argbuf;
275 
276 	return p >= buf->base && p <= buf->base + buf->buflen ;
277 }
278 
279 static inline int
xdr_ressize_check(struct svc_rqst * rqstp,u32 * p)280 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
281 {
282 	struct svc_buf	*buf = &rqstp->rq_resbuf;
283 
284 	buf->len = p - buf->base;
285 	dprintk("nfsd: ressize_check p %p base %p len %d\n",
286 			p, buf->base, buf->buflen);
287 	return (buf->len <= buf->buflen);
288 }
289 
290 /*
291  * XDR decode functions
292  */
293 int
nfs3svc_decode_fhandle(struct svc_rqst * rqstp,u32 * p,struct svc_fh * fhp)294 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
295 {
296 	if (!(p = decode_fh(p, fhp)))
297 		return 0;
298 	return xdr_argsize_check(rqstp, p);
299 }
300 
301 int
nfs3svc_decode_sattrargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_sattrargs * args)302 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
303 					struct nfsd3_sattrargs *args)
304 {
305 	if (!(p = decode_fh(p, &args->fh))
306 	 || !(p = decode_sattr3(p, &args->attrs)))
307 		return 0;
308 
309 	if ((args->check_guard = ntohl(*p++)) != 0)
310 		p = decode_time3(p, &args->guardtime);
311 
312 	return xdr_argsize_check(rqstp, p);
313 }
314 
315 int
nfs3svc_decode_diropargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_diropargs * args)316 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
317 					struct nfsd3_diropargs *args)
318 {
319 	if (!(p = decode_fh(p, &args->fh))
320 	 || !(p = decode_filename(p, &args->name, &args->len)))
321 		return 0;
322 
323 	return xdr_argsize_check(rqstp, p);
324 }
325 
326 int
nfs3svc_decode_accessargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_accessargs * args)327 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
328 					struct nfsd3_accessargs *args)
329 {
330 	if (!(p = decode_fh(p, &args->fh)))
331 		return 0;
332 	args->access = ntohl(*p++);
333 
334 	return xdr_argsize_check(rqstp, p);
335 }
336 
337 int
nfs3svc_decode_readargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readargs * args)338 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
339 					struct nfsd3_readargs *args)
340 {
341 	if (!(p = decode_fh(p, &args->fh))
342 	 || !(p = xdr_decode_hyper(p, &args->offset)))
343 		return 0;
344 
345 	args->count = ntohl(*p++);
346 	return xdr_argsize_check(rqstp, p);
347 }
348 
349 int
nfs3svc_decode_writeargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_writeargs * args)350 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
351 					struct nfsd3_writeargs *args)
352 {
353 	if (!(p = decode_fh(p, &args->fh))
354 	 || !(p = xdr_decode_hyper(p, &args->offset)))
355 		return 0;
356 
357 	args->count = ntohl(*p++);
358 	args->stable = ntohl(*p++);
359 	args->len = ntohl(*p++);
360 	args->data = (char *) p;
361 	p += XDR_QUADLEN(args->len);
362 
363 	return xdr_argsize_check(rqstp, p);
364 }
365 
366 int
nfs3svc_decode_createargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_createargs * args)367 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
368 					struct nfsd3_createargs *args)
369 {
370 	if (!(p = decode_fh(p, &args->fh))
371 	 || !(p = decode_filename(p, &args->name, &args->len)))
372 		return 0;
373 
374 	switch (args->createmode = ntohl(*p++)) {
375 	case NFS3_CREATE_UNCHECKED:
376 	case NFS3_CREATE_GUARDED:
377 		if (!(p = decode_sattr3(p, &args->attrs)))
378 			return 0;
379 		break;
380 	case NFS3_CREATE_EXCLUSIVE:
381 		args->verf = p;
382 		p += 2;
383 		break;
384 	default:
385 		return 0;
386 	}
387 
388 	return xdr_argsize_check(rqstp, p);
389 }
390 int
nfs3svc_decode_mkdirargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_createargs * args)391 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
392 					struct nfsd3_createargs *args)
393 {
394 	if (!(p = decode_fh(p, &args->fh))
395 	 || !(p = decode_filename(p, &args->name, &args->len))
396 	 || !(p = decode_sattr3(p, &args->attrs)))
397 		return 0;
398 
399 	return xdr_argsize_check(rqstp, p);
400 }
401 
402 int
nfs3svc_decode_symlinkargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_symlinkargs * args)403 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
404 					struct nfsd3_symlinkargs *args)
405 {
406 	if (!(p = decode_fh(p, &args->ffh))
407 	 || !(p = decode_filename(p, &args->fname, &args->flen))
408 	 || !(p = decode_sattr3(p, &args->attrs))
409 	 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
410 		return 0;
411 
412 	return xdr_argsize_check(rqstp, p);
413 }
414 
415 int
nfs3svc_decode_mknodargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_mknodargs * args)416 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
417 					struct nfsd3_mknodargs *args)
418 {
419 	if (!(p = decode_fh(p, &args->fh))
420 	 || !(p = decode_filename(p, &args->name, &args->len)))
421 		return 0;
422 
423 	args->ftype = ntohl(*p++);
424 
425 	if (args->ftype == NF3BLK  || args->ftype == NF3CHR
426 	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
427 		if (!(p = decode_sattr3(p, &args->attrs)))
428 			return 0;
429 	}
430 
431 	if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
432 		args->major = ntohl(*p++);
433 		args->minor = ntohl(*p++);
434 	}
435 
436 	return xdr_argsize_check(rqstp, p);
437 }
438 
439 int
nfs3svc_decode_renameargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_renameargs * args)440 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
441 					struct nfsd3_renameargs *args)
442 {
443 	if (!(p = decode_fh(p, &args->ffh))
444 	 || !(p = decode_filename(p, &args->fname, &args->flen))
445 	 || !(p = decode_fh(p, &args->tfh))
446 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
447 		return 0;
448 
449 	return xdr_argsize_check(rqstp, p);
450 }
451 
452 int
nfs3svc_decode_linkargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_linkargs * args)453 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
454 					struct nfsd3_linkargs *args)
455 {
456 	if (!(p = decode_fh(p, &args->ffh))
457 	 || !(p = decode_fh(p, &args->tfh))
458 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
459 		return 0;
460 
461 	return xdr_argsize_check(rqstp, p);
462 }
463 
464 int
nfs3svc_decode_readdirargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readdirargs * args)465 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
466 					struct nfsd3_readdirargs *args)
467 {
468 	if (!(p = decode_fh(p, &args->fh)))
469 		return 0;
470 	p = xdr_decode_hyper(p, &args->cookie);
471 	args->verf   = p; p += 2;
472 	args->dircount = ~0;
473 	args->count  = ntohl(*p++);
474 
475 	return xdr_argsize_check(rqstp, p);
476 }
477 
478 int
nfs3svc_decode_readdirplusargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readdirargs * args)479 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
480 					struct nfsd3_readdirargs *args)
481 {
482 	if (!(p = decode_fh(p, &args->fh)))
483 		return 0;
484 	p = xdr_decode_hyper(p, &args->cookie);
485 	args->verf     = p; p += 2;
486 	args->dircount = ntohl(*p++);
487 	args->count    = ntohl(*p++);
488 
489 	return xdr_argsize_check(rqstp, p);
490 }
491 
492 int
nfs3svc_decode_commitargs(struct svc_rqst * rqstp,u32 * p,struct nfsd3_commitargs * args)493 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
494 					struct nfsd3_commitargs *args)
495 {
496 	if (!(p = decode_fh(p, &args->fh)))
497 		return 0;
498 	p = xdr_decode_hyper(p, &args->offset);
499 	args->count = ntohl(*p++);
500 
501 	return xdr_argsize_check(rqstp, p);
502 }
503 
504 /*
505  * XDR encode functions
506  */
507 /*
508  * There must be an encoding function for void results so svc_process
509  * will work properly.
510  */
511 int
nfs3svc_encode_voidres(struct svc_rqst * rqstp,u32 * p,void * dummy)512 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
513 {
514 	return xdr_ressize_check(rqstp, p);
515 }
516 
517 /* GETATTR */
518 int
nfs3svc_encode_attrstat(struct svc_rqst * rqstp,u32 * p,struct nfsd3_attrstat * resp)519 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
520 					struct nfsd3_attrstat *resp)
521 {
522 	if (resp->status == 0)
523 		p = encode_fattr3(rqstp, p, &resp->fh);
524 	return xdr_ressize_check(rqstp, p);
525 }
526 
527 /* SETATTR, REMOVE, RMDIR */
528 int
nfs3svc_encode_wccstat(struct svc_rqst * rqstp,u32 * p,struct nfsd3_attrstat * resp)529 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
530 					struct nfsd3_attrstat *resp)
531 {
532 	p = encode_wcc_data(rqstp, p, &resp->fh);
533 	return xdr_ressize_check(rqstp, p);
534 }
535 
536 /* LOOKUP */
537 int
nfs3svc_encode_diropres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_diropres * resp)538 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
539 					struct nfsd3_diropres *resp)
540 {
541 	if (resp->status == 0) {
542 		p = encode_fh(p, &resp->fh);
543 		p = encode_post_op_attr(rqstp, p, &resp->fh);
544 	}
545 	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
546 	return xdr_ressize_check(rqstp, p);
547 }
548 
549 /* ACCESS */
550 int
nfs3svc_encode_accessres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_accessres * resp)551 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
552 					struct nfsd3_accessres *resp)
553 {
554 	p = encode_post_op_attr(rqstp, p, &resp->fh);
555 	if (resp->status == 0)
556 		*p++ = htonl(resp->access);
557 	return xdr_ressize_check(rqstp, p);
558 }
559 
560 /* READLINK */
561 int
nfs3svc_encode_readlinkres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readlinkres * resp)562 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
563 					struct nfsd3_readlinkres *resp)
564 {
565 	p = encode_post_op_attr(rqstp, p, &resp->fh);
566 	if (resp->status == 0) {
567 		*p++ = htonl(resp->len);
568 		p += XDR_QUADLEN(resp->len);
569 	}
570 	return xdr_ressize_check(rqstp, p);
571 }
572 
573 /* READ */
574 int
nfs3svc_encode_readres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readres * resp)575 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
576 					struct nfsd3_readres *resp)
577 {
578 	p = encode_post_op_attr(rqstp, p, &resp->fh);
579 	if (resp->status == 0) {
580 		*p++ = htonl(resp->count);
581 		*p++ = htonl(resp->eof);
582 		*p++ = htonl(resp->count);	/* xdr opaque count */
583 		p += XDR_QUADLEN(resp->count);
584 	}
585 	return xdr_ressize_check(rqstp, p);
586 }
587 
588 /* WRITE */
589 int
nfs3svc_encode_writeres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_writeres * resp)590 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
591 					struct nfsd3_writeres *resp)
592 {
593 	p = encode_wcc_data(rqstp, p, &resp->fh);
594 	if (resp->status == 0) {
595 		*p++ = htonl(resp->count);
596 		*p++ = htonl(resp->committed);
597 		*p++ = htonl(nfssvc_boot.tv_sec);
598 		*p++ = htonl(nfssvc_boot.tv_usec);
599 	}
600 	return xdr_ressize_check(rqstp, p);
601 }
602 
603 /* CREATE, MKDIR, SYMLINK, MKNOD */
604 int
nfs3svc_encode_createres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_diropres * resp)605 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
606 					struct nfsd3_diropres *resp)
607 {
608 	if (resp->status == 0) {
609 		*p++ = xdr_one;
610 		p = encode_fh(p, &resp->fh);
611 		p = encode_post_op_attr(rqstp, p, &resp->fh);
612 	}
613 	p = encode_wcc_data(rqstp, p, &resp->dirfh);
614 	return xdr_ressize_check(rqstp, p);
615 }
616 
617 /* RENAME */
618 int
nfs3svc_encode_renameres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_renameres * resp)619 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
620 					struct nfsd3_renameres *resp)
621 {
622 	p = encode_wcc_data(rqstp, p, &resp->ffh);
623 	p = encode_wcc_data(rqstp, p, &resp->tfh);
624 	return xdr_ressize_check(rqstp, p);
625 }
626 
627 /* LINK */
628 int
nfs3svc_encode_linkres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_linkres * resp)629 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
630 					struct nfsd3_linkres *resp)
631 {
632 	p = encode_post_op_attr(rqstp, p, &resp->fh);
633 	p = encode_wcc_data(rqstp, p, &resp->tfh);
634 	return xdr_ressize_check(rqstp, p);
635 }
636 
637 /* READDIR */
638 int
nfs3svc_encode_readdirres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_readdirres * resp)639 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
640 					struct nfsd3_readdirres *resp)
641 {
642 	p = encode_post_op_attr(rqstp, p, &resp->fh);
643 	if (resp->status == 0) {
644 		/* stupid readdir cookie */
645 		memcpy(p, resp->verf, 8); p += 2;
646 		p += XDR_QUADLEN(resp->count);
647 	}
648 
649 	return xdr_ressize_check(rqstp, p);
650 }
651 
652 /*
653  * Encode a directory entry. This one works for both normal readdir
654  * and readdirplus.
655  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
656  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
657  *
658  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
659  * file handle.
660  */
661 
662 #define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
663 #define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
664 static int
encode_entry(struct readdir_cd * cd,const char * name,int namlen,off_t offset,ino_t ino,unsigned int d_type,int plus)665 encode_entry(struct readdir_cd *cd, const char *name,
666 	     int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
667 {
668 	u32		*p = cd->buffer;
669 	int		buflen, slen, elen;
670 
671 	if (cd->offset)
672 		xdr_encode_hyper(cd->offset, (u64) offset);
673 
674 	/* nfsd_readdir calls us with name == 0 when it wants us to
675 	 * set the last offset entry. */
676 	if (name == 0)
677 		return 0;
678 
679 	/*
680 	dprintk("encode_entry(%.*s @%ld%s)\n",
681 		namlen, name, (long) offset, plus? " plus" : "");
682 	 */
683 
684 	/* truncate filename if too long */
685 	if (namlen > NFS3_MAXNAMLEN)
686 		namlen = NFS3_MAXNAMLEN;
687 
688 	slen = XDR_QUADLEN(namlen);
689 	elen = slen + NFS3_ENTRY_BAGGAGE
690 		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
691 	if ((buflen = cd->buflen - elen) < 0) {
692 		cd->eob = 1;
693 		return -EINVAL;
694 	}
695 	*p++ = xdr_one;				 /* mark entry present */
696 	p    = xdr_encode_hyper(p, ino);	 /* file id */
697 	p    = xdr_encode_array(p, name, namlen);/* name length & name */
698 
699 	cd->offset = p;			/* remember pointer */
700 	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);	/* offset of next entry */
701 
702 	/* throw in readdirplus baggage */
703 	if (plus) {
704 		struct svc_fh	fh;
705 		struct svc_export	*exp;
706 		struct dentry		*dparent, *dchild;
707 
708 		dparent = cd->dirfh->fh_dentry;
709 		exp  = cd->dirfh->fh_export;
710 
711 		fh_init(&fh, NFS3_FHSIZE);
712 		if (isdotent(name, namlen)) {
713 			dchild = dparent;
714 			if (namlen == 2)
715 				dchild = dchild->d_parent;
716 			dchild = dget(dchild);
717 		} else
718 			dchild = lookup_one_len(name, dparent,namlen);
719 		if (IS_ERR(dchild))
720 			goto noexec;
721 		if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
722 			goto noexec;
723 		p = encode_post_op_attr(cd->rqstp, p, &fh);
724 		*p++ = xdr_one; /* yes, a file handle follows */
725 		p = encode_fh(p, &fh);
726 		fh_put(&fh);
727 	}
728 
729 out:
730 	cd->buflen = buflen;
731 	cd->buffer = p;
732 	return 0;
733 
734 noexec:
735 	*p++ = 0;
736 	*p++ = 0;
737 	goto out;
738 }
739 
740 int
nfs3svc_encode_entry(struct readdir_cd * cd,const char * name,int namlen,loff_t offset,ino_t ino,unsigned int d_type)741 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
742 		     int namlen, loff_t offset, ino_t ino, unsigned int d_type)
743 {
744 	return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
745 }
746 
747 int
nfs3svc_encode_entry_plus(struct readdir_cd * cd,const char * name,int namlen,loff_t offset,ino_t ino,unsigned int d_type)748 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
749 			  int namlen, loff_t offset, ino_t ino, unsigned int d_type)
750 {
751 	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
752 }
753 
754 /* FSSTAT */
755 int
nfs3svc_encode_fsstatres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_fsstatres * resp)756 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
757 					struct nfsd3_fsstatres *resp)
758 {
759 	struct statfs	*s = &resp->stats;
760 	u64		bs = s->f_bsize;
761 
762 	*p++ = xdr_zero;	/* no post_op_attr */
763 
764 	if (resp->status == 0) {
765 		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
766 		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
767 		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
768 		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
769 		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
770 		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
771 		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
772 	}
773 	return xdr_ressize_check(rqstp, p);
774 }
775 
776 /* FSINFO */
777 int
nfs3svc_encode_fsinfores(struct svc_rqst * rqstp,u32 * p,struct nfsd3_fsinfores * resp)778 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
779 					struct nfsd3_fsinfores *resp)
780 {
781 	*p++ = xdr_zero;	/* no post_op_attr */
782 
783 	if (resp->status == 0) {
784 		*p++ = htonl(resp->f_rtmax);
785 		*p++ = htonl(resp->f_rtpref);
786 		*p++ = htonl(resp->f_rtmult);
787 		*p++ = htonl(resp->f_wtmax);
788 		*p++ = htonl(resp->f_wtpref);
789 		*p++ = htonl(resp->f_wtmult);
790 		*p++ = htonl(resp->f_dtpref);
791 		p = xdr_encode_hyper(p, resp->f_maxfilesize);
792 		*p++ = xdr_one;
793 		*p++ = xdr_zero;
794 		*p++ = htonl(resp->f_properties);
795 	}
796 
797 	return xdr_ressize_check(rqstp, p);
798 }
799 
800 /* PATHCONF */
801 int
nfs3svc_encode_pathconfres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_pathconfres * resp)802 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
803 					struct nfsd3_pathconfres *resp)
804 {
805 	*p++ = xdr_zero;	/* no post_op_attr */
806 
807 	if (resp->status == 0) {
808 		*p++ = htonl(resp->p_link_max);
809 		*p++ = htonl(resp->p_name_max);
810 		*p++ = htonl(resp->p_no_trunc);
811 		*p++ = htonl(resp->p_chown_restricted);
812 		*p++ = htonl(resp->p_case_insensitive);
813 		*p++ = htonl(resp->p_case_preserving);
814 	}
815 
816 	return xdr_ressize_check(rqstp, p);
817 }
818 
819 /* COMMIT */
820 int
nfs3svc_encode_commitres(struct svc_rqst * rqstp,u32 * p,struct nfsd3_commitres * resp)821 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
822 					struct nfsd3_commitres *resp)
823 {
824 	p = encode_wcc_data(rqstp, p, &resp->fh);
825 	/* Write verifier */
826 	if (resp->status == 0) {
827 		*p++ = htonl(nfssvc_boot.tv_sec);
828 		*p++ = htonl(nfssvc_boot.tv_usec);
829 	}
830 	return xdr_ressize_check(rqstp, p);
831 }
832 
833 /*
834  * XDR release functions
835  */
836 int
nfs3svc_release_fhandle(struct svc_rqst * rqstp,u32 * p,struct nfsd3_attrstat * resp)837 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
838 					struct nfsd3_attrstat *resp)
839 {
840 	fh_put(&resp->fh);
841 	return 1;
842 }
843 
844 int
nfs3svc_release_fhandle2(struct svc_rqst * rqstp,u32 * p,struct nfsd3_fhandle_pair * resp)845 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
846 					struct nfsd3_fhandle_pair *resp)
847 {
848 	fh_put(&resp->fh1);
849 	fh_put(&resp->fh2);
850 	return 1;
851 }
852