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 *
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 *
46 decode_time3(u32 *p, time_t *secp)
47 {
48 *secp = ntohl(*p++);
49 return p + 1;
50 }
51
52 static inline u32 *
53 decode_fh(u32 *p, struct svc_fh *fhp)
54 {
55 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 *
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 *
81 decode_filename(u32 *p, char **namp, int *lenp)
82 {
83 char *name;
84 int i;
85
86 if ((p = xdr_decode_string(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 *name = '\0';
92 }
93
94 return p;
95 }
96
97 static inline u32 *
98 decode_pathname(u32 *p, char **namp, int *lenp)
99 {
100 char *name;
101 int i;
102
103 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
104 for (i = 0, name = *namp; i < *lenp; i++, name++) {
105 if (*name == '\0')
106 return NULL;
107 }
108 *name = '\0';
109 }
110
111 return p;
112 }
113
114 static inline u32 *
115 decode_sattr3(u32 *p, struct iattr *iap)
116 {
117 u32 tmp;
118
119 iap->ia_valid = 0;
120
121 if (*p++) {
122 iap->ia_valid |= ATTR_MODE;
123 iap->ia_mode = ntohl(*p++);
124 }
125 if (*p++) {
126 iap->ia_valid |= ATTR_UID;
127 iap->ia_uid = ntohl(*p++);
128 }
129 if (*p++) {
130 iap->ia_valid |= ATTR_GID;
131 iap->ia_gid = ntohl(*p++);
132 }
133 if (*p++) {
134 u64 newsize;
135
136 iap->ia_valid |= ATTR_SIZE;
137 p = xdr_decode_hyper(p, &newsize);
138 if (newsize <= NFS_OFFSET_MAX)
139 iap->ia_size = newsize;
140 else
141 iap->ia_size = NFS_OFFSET_MAX;
142 }
143 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
144 iap->ia_valid |= ATTR_ATIME;
145 } else if (tmp == 2) { /* set to client time */
146 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
147 iap->ia_atime = ntohl(*p++), p++;
148 }
149 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
150 iap->ia_valid |= ATTR_MTIME;
151 } else if (tmp == 2) { /* set to client time */
152 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
153 iap->ia_mtime = ntohl(*p++), p++;
154 }
155 return p;
156 }
157
158 static inline u32 *
159 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
160 {
161 struct inode *inode = dentry->d_inode;
162
163 if (!inode) {
164 printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
165 return NULL;
166 }
167
168 *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
169 *p++ = htonl((u32) inode->i_mode);
170 *p++ = htonl((u32) inode->i_nlink);
171 *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
172 *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
173 if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
174 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
175 } else {
176 p = xdr_encode_hyper(p, (u64) inode->i_size);
177 }
178 if (inode->i_blksize == 0 && inode->i_blocks == 0)
179 /* Minix file system(?) i_size is (hopefully) close enough */
180 p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
181 else
182 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
183 *p++ = htonl((u32) MAJOR(inode->i_rdev));
184 *p++ = htonl((u32) MINOR(inode->i_rdev));
185 p = xdr_encode_hyper(p, (u64) inode->i_dev);
186 p = xdr_encode_hyper(p, (u64) inode->i_ino);
187 p = encode_time3(p, inode->i_atime);
188 p = encode_time3(p, lease_get_mtime(inode));
189 p = encode_time3(p, inode->i_ctime);
190
191 return p;
192 }
193
194 static inline u32 *
195 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
196 {
197 struct inode *inode = fhp->fh_dentry->d_inode;
198
199 /* Attributes to follow */
200 *p++ = xdr_one;
201
202 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
203 *p++ = htonl((u32) fhp->fh_post_mode);
204 *p++ = htonl((u32) fhp->fh_post_nlink);
205 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
206 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
207 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
208 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
209 } else {
210 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
211 }
212 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
213 *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
214 *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
215 p = xdr_encode_hyper(p, (u64) inode->i_dev);
216 p = xdr_encode_hyper(p, (u64) inode->i_ino);
217 p = encode_time3(p, fhp->fh_post_atime);
218 p = encode_time3(p, fhp->fh_post_mtime);
219 p = encode_time3(p, fhp->fh_post_ctime);
220
221 return p;
222 }
223
224 /*
225 * Encode post-operation attributes.
226 * The inode may be NULL if the call failed because of a stale file
227 * handle. In this case, no attributes are returned.
228 */
229 static u32 *
230 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
231 {
232 if (dentry && dentry->d_inode != NULL) {
233 *p++ = xdr_one; /* attributes follow */
234 return encode_fattr3(rqstp, p, dentry);
235 }
236 *p++ = xdr_zero;
237 return p;
238 }
239
240 /*
241 * Enocde weak cache consistency data
242 */
243 static u32 *
244 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
245 {
246 struct dentry *dentry = fhp->fh_dentry;
247
248 if (dentry && dentry->d_inode && fhp->fh_post_saved) {
249 if (fhp->fh_pre_saved) {
250 *p++ = xdr_one;
251 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
252 p = encode_time3(p, fhp->fh_pre_mtime);
253 p = encode_time3(p, fhp->fh_pre_ctime);
254 } else {
255 *p++ = xdr_zero;
256 }
257 return encode_saved_post_attr(rqstp, p, fhp);
258 }
259 /* no pre- or post-attrs */
260 *p++ = xdr_zero;
261 return encode_post_op_attr(rqstp, p, dentry);
262 }
263
264 /*
265 * Check buffer bounds after decoding arguments
266 */
267 static inline int
268 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
269 {
270 struct svc_buf *buf = &rqstp->rq_argbuf;
271
272 return p - buf->base <= buf->buflen;
273 }
274
275 static inline int
276 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
277 {
278 struct svc_buf *buf = &rqstp->rq_resbuf;
279
280 buf->len = p - buf->base;
281 dprintk("nfsd: ressize_check p %p base %p len %d\n",
282 p, buf->base, buf->buflen);
283 return (buf->len <= buf->buflen);
284 }
285
286 /*
287 * XDR decode functions
288 */
289 int
290 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
291 {
292 if (!(p = decode_fh(p, fhp)))
293 return 0;
294 return xdr_argsize_check(rqstp, p);
295 }
296
297 int
298 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
299 struct nfsd3_sattrargs *args)
300 {
301 if (!(p = decode_fh(p, &args->fh))
302 || !(p = decode_sattr3(p, &args->attrs)))
303 return 0;
304
305 if ((args->check_guard = ntohl(*p++)) != 0)
306 p = decode_time3(p, &args->guardtime);
307
308 return xdr_argsize_check(rqstp, p);
309 }
310
311 int
312 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
313 struct nfsd3_diropargs *args)
314 {
315 if (!(p = decode_fh(p, &args->fh))
316 || !(p = decode_filename(p, &args->name, &args->len)))
317 return 0;
318
319 return xdr_argsize_check(rqstp, p);
320 }
321
322 int
323 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
324 struct nfsd3_accessargs *args)
325 {
326 if (!(p = decode_fh(p, &args->fh)))
327 return 0;
328 args->access = ntohl(*p++);
329
330 return xdr_argsize_check(rqstp, p);
331 }
332
333 int
334 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
335 struct nfsd3_readargs *args)
336 {
337 if (!(p = decode_fh(p, &args->fh))
338 || !(p = xdr_decode_hyper(p, &args->offset)))
339 return 0;
340
341 args->count = ntohl(*p++);
342 return xdr_argsize_check(rqstp, p);
343 }
344
345 int
346 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
347 struct nfsd3_writeargs *args)
348 {
349 if (!(p = decode_fh(p, &args->fh))
350 || !(p = xdr_decode_hyper(p, &args->offset)))
351 return 0;
352
353 args->count = ntohl(*p++);
354 args->stable = ntohl(*p++);
355 args->len = ntohl(*p++);
356 args->data = (char *) p;
357 p += XDR_QUADLEN(args->len);
358
359 return xdr_argsize_check(rqstp, p);
360 }
361
362 int
363 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
364 struct nfsd3_createargs *args)
365 {
366 if (!(p = decode_fh(p, &args->fh))
367 || !(p = decode_filename(p, &args->name, &args->len)))
368 return 0;
369
370 switch (args->createmode = ntohl(*p++)) {
371 case NFS3_CREATE_UNCHECKED:
372 case NFS3_CREATE_GUARDED:
373 if (!(p = decode_sattr3(p, &args->attrs)))
374 return 0;
375 break;
376 case NFS3_CREATE_EXCLUSIVE:
377 args->verf = p;
378 p += 2;
379 break;
380 default:
381 return 0;
382 }
383
384 return xdr_argsize_check(rqstp, p);
385 }
386 int
387 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
388 struct nfsd3_createargs *args)
389 {
390 if (!(p = decode_fh(p, &args->fh))
391 || !(p = decode_filename(p, &args->name, &args->len))
392 || !(p = decode_sattr3(p, &args->attrs)))
393 return 0;
394
395 return xdr_argsize_check(rqstp, p);
396 }
397
398 int
399 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
400 struct nfsd3_symlinkargs *args)
401 {
402 if (!(p = decode_fh(p, &args->ffh))
403 || !(p = decode_filename(p, &args->fname, &args->flen))
404 || !(p = decode_sattr3(p, &args->attrs))
405 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
406 return 0;
407
408 return xdr_argsize_check(rqstp, p);
409 }
410
411 int
412 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
413 struct nfsd3_mknodargs *args)
414 {
415 if (!(p = decode_fh(p, &args->fh))
416 || !(p = decode_filename(p, &args->name, &args->len)))
417 return 0;
418
419 args->ftype = ntohl(*p++);
420
421 if (args->ftype == NF3BLK || args->ftype == NF3CHR
422 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
423 if (!(p = decode_sattr3(p, &args->attrs)))
424 return 0;
425 }
426
427 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
428 args->major = ntohl(*p++);
429 args->minor = ntohl(*p++);
430 }
431
432 return xdr_argsize_check(rqstp, p);
433 }
434
435 int
436 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
437 struct nfsd3_renameargs *args)
438 {
439 if (!(p = decode_fh(p, &args->ffh))
440 || !(p = decode_filename(p, &args->fname, &args->flen))
441 || !(p = decode_fh(p, &args->tfh))
442 || !(p = decode_filename(p, &args->tname, &args->tlen)))
443 return 0;
444
445 return xdr_argsize_check(rqstp, p);
446 }
447
448 int
449 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
450 struct nfsd3_linkargs *args)
451 {
452 if (!(p = decode_fh(p, &args->ffh))
453 || !(p = decode_fh(p, &args->tfh))
454 || !(p = decode_filename(p, &args->tname, &args->tlen)))
455 return 0;
456
457 return xdr_argsize_check(rqstp, p);
458 }
459
460 int
461 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
462 struct nfsd3_readdirargs *args)
463 {
464 if (!(p = decode_fh(p, &args->fh)))
465 return 0;
466 p = xdr_decode_hyper(p, &args->cookie);
467 args->verf = p; p += 2;
468 args->dircount = ~0;
469 args->count = ntohl(*p++);
470
471 return xdr_argsize_check(rqstp, p);
472 }
473
474 int
475 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
476 struct nfsd3_readdirargs *args)
477 {
478 if (!(p = decode_fh(p, &args->fh)))
479 return 0;
480 p = xdr_decode_hyper(p, &args->cookie);
481 args->verf = p; p += 2;
482 args->dircount = ntohl(*p++);
483 args->count = ntohl(*p++);
484
485 return xdr_argsize_check(rqstp, p);
486 }
487
488 int
489 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
490 struct nfsd3_commitargs *args)
491 {
492 if (!(p = decode_fh(p, &args->fh)))
493 return 0;
494 p = xdr_decode_hyper(p, &args->offset);
495 args->count = ntohl(*p++);
496
497 return xdr_argsize_check(rqstp, p);
498 }
499
500 /*
501 * XDR encode functions
502 */
503 /*
504 * There must be an encoding function for void results so svc_process
505 * will work properly.
506 */
507 int
508 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
509 {
510 return xdr_ressize_check(rqstp, p);
511 }
512
513 /* GETATTR */
514 int
515 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
516 struct nfsd3_attrstat *resp)
517 {
518 if (resp->status == 0
519 && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
520 return 0;
521 return xdr_ressize_check(rqstp, p);
522 }
523
524 /* SETATTR, REMOVE, RMDIR */
525 int
526 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
527 struct nfsd3_attrstat *resp)
528 {
529 if (!(p = encode_wcc_data(rqstp, p, &resp->fh)))
530 return 0;
531 return xdr_ressize_check(rqstp, p);
532 }
533
534 /* LOOKUP */
535 int
536 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
537 struct nfsd3_diropres *resp)
538 {
539 if (resp->status == 0) {
540 p = encode_fh(p, &resp->fh);
541 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
542 }
543 p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
544 return xdr_ressize_check(rqstp, p);
545 }
546
547 /* ACCESS */
548 int
549 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
550 struct nfsd3_accessres *resp)
551 {
552 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
553 if (resp->status == 0)
554 *p++ = htonl(resp->access);
555 return xdr_ressize_check(rqstp, p);
556 }
557
558 /* READLINK */
559 int
560 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
561 struct nfsd3_readlinkres *resp)
562 {
563 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
564 if (resp->status == 0) {
565 *p++ = htonl(resp->len);
566 p += XDR_QUADLEN(resp->len);
567 }
568 return xdr_ressize_check(rqstp, p);
569 }
570
571 /* READ */
572 int
573 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
574 struct nfsd3_readres *resp)
575 {
576 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
577 if (resp->status == 0) {
578 *p++ = htonl(resp->count);
579 *p++ = htonl(resp->eof);
580 *p++ = htonl(resp->count); /* xdr opaque count */
581 p += XDR_QUADLEN(resp->count);
582 }
583 return xdr_ressize_check(rqstp, p);
584 }
585
586 /* WRITE */
587 int
588 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
589 struct nfsd3_writeres *resp)
590 {
591 p = encode_wcc_data(rqstp, p, &resp->fh);
592 if (resp->status == 0) {
593 *p++ = htonl(resp->count);
594 *p++ = htonl(resp->committed);
595 *p++ = htonl(nfssvc_boot.tv_sec);
596 *p++ = htonl(nfssvc_boot.tv_usec);
597 }
598 return xdr_ressize_check(rqstp, p);
599 }
600
601 /* CREATE, MKDIR, SYMLINK, MKNOD */
602 int
603 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
604 struct nfsd3_diropres *resp)
605 {
606 if (resp->status == 0) {
607 *p++ = xdr_one;
608 p = encode_fh(p, &resp->fh);
609 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
610 }
611 p = encode_wcc_data(rqstp, p, &resp->dirfh);
612 return xdr_ressize_check(rqstp, p);
613 }
614
615 /* RENAME */
616 int
617 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
618 struct nfsd3_renameres *resp)
619 {
620 p = encode_wcc_data(rqstp, p, &resp->ffh);
621 p = encode_wcc_data(rqstp, p, &resp->tfh);
622 return xdr_ressize_check(rqstp, p);
623 }
624
625 /* LINK */
626 int
627 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
628 struct nfsd3_linkres *resp)
629 {
630 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
631 p = encode_wcc_data(rqstp, p, &resp->tfh);
632 return xdr_ressize_check(rqstp, p);
633 }
634
635 /* READDIR */
636 int
637 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
638 struct nfsd3_readdirres *resp)
639 {
640 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
641 if (resp->status == 0) {
642 /* stupid readdir cookie */
643 memcpy(p, resp->verf, 8); p += 2;
644 p += XDR_QUADLEN(resp->count);
645 }
646
647 return xdr_ressize_check(rqstp, p);
648 }
649
650 /*
651 * Encode a directory entry. This one works for both normal readdir
652 * and readdirplus.
653 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
654 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
655 *
656 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
657 * file handle.
658 */
659
660 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
661 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
662 static int
663 encode_entry(struct readdir_cd *cd, const char *name,
664 int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
665 {
666 u32 *p = cd->buffer;
667 int buflen, slen, elen;
668
669 if (cd->offset)
670 xdr_encode_hyper(cd->offset, (u64) offset);
671
672 /* nfsd_readdir calls us with name == 0 when it wants us to
673 * set the last offset entry. */
674 if (name == 0)
675 return 0;
676
677 /*
678 dprintk("encode_entry(%.*s @%ld%s)\n",
679 namlen, name, (long) offset, plus? " plus" : "");
680 */
681
682 /* truncate filename if too long */
683 if (namlen > NFS3_MAXNAMLEN)
684 namlen = NFS3_MAXNAMLEN;
685
686 slen = XDR_QUADLEN(namlen);
687 elen = slen + NFS3_ENTRY_BAGGAGE
688 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
689 if ((buflen = cd->buflen - elen) < 0) {
690 cd->eob = 1;
691 return -EINVAL;
692 }
693 *p++ = xdr_one; /* mark entry present */
694 p = xdr_encode_hyper(p, ino); /* file id */
695 p = xdr_encode_array(p, name, namlen);/* name length & name */
696
697 cd->offset = p; /* remember pointer */
698 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
699
700 /* throw in readdirplus baggage */
701 if (plus) {
702 struct svc_fh fh;
703 struct svc_export *exp;
704 struct dentry *dparent, *dchild;
705
706 dparent = cd->dirfh->fh_dentry;
707 exp = cd->dirfh->fh_export;
708
709 fh_init(&fh, NFS3_FHSIZE);
710 if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0)
711 goto noexec;
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(name, dparent);
719 if (IS_ERR(dchild))
720 goto noexec;
721 if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
722 goto noexec;
723 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
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
741 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
742 int namlen, off_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
748 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
749 int namlen, off_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
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
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
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
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
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
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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.