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