1 /* $FreeBSD$ */
2 /* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */
3
4 /*-
5 * copyright (c) 2003
6 * the regents of the university of michigan
7 * all rights reserved
8 *
9 * permission is granted to use, copy, create derivative works and redistribute
10 * this software and such derivative works for any purpose, so long as the name
11 * of the university of michigan is not used in any advertising or publicity
12 * pertaining to the use or distribution of this software without specific,
13 * written prior authorization. if the above copyright notice or any other
14 * identification of the university of michigan is included in any copy of any
15 * portion of this software, then the disclaimer below must also be included.
16 *
17 * this software is provided as is, without representation from the university
18 * of michigan as to its fitness for any purpose, and without warranty by the
19 * university of michigan of any kind, either express or implied, including
20 * without limitation the implied warranties of merchantability and fitness for
21 * a particular purpose. the regents of the university of michigan shall not be
22 * liable for any damages, including special, indirect, incidental, or
23 * consequential damages, with respect to any claim arising out of or in
24 * connection with the use of the software, even if it has been or is hereafter
25 * advised of the possibility of such damages.
26 */
27
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bio.h>
34 #include <sys/buf.h>
35 #include <sys/proc.h>
36 #include <sys/mount.h>
37 #include <sys/vnode.h>
38 #include <sys/namei.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/malloc.h>
43 #include <sys/sysent.h>
44 #include <sys/syscall.h>
45 #include <sys/sysproto.h>
46 #include <sys/fcntl.h>
47
48 #include <machine/stdarg.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_object.h>
52 #include <vm/vm_extern.h>
53 #include <vm/uma.h>
54
55 #include <rpc/rpcclnt.h>
56
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
59 #include <nfsclient/nfs.h>
60 #include <nfs4client/nfs4.h>
61 #include <nfsclient/nfsnode.h>
62 #include <nfsclient/nfsmount.h>
63 #include <nfs/xdr_subs.h>
64 #include <nfsclient/nfsm_subs.h>
65
66 #include <nfs4client/nfs4_dev.h>
67 #include <nfs4client/nfs4_idmap.h>
68 #include <nfs4client/nfs4m_subs.h>
69
70 #include <netinet/in.h>
71
72 #define NFSM_DISSECT(s) do { \
73 tl = nfsm_dissect_xx((s), md, dpos); \
74 if (tl == NULL) { \
75 printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \
76 return (EBADRPC); \
77 } \
78 } while (0)
79
80 #define NFSM_ADV(s) do { \
81 t1 = nfsm_adv_xx((s), md, dpos); \
82 if (t1 != 0) { \
83 printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \
84 return (EBADRPC); \
85 } \
86 } while (0)
87
88 #define NFSM_MTOTIME(t) do { \
89 NFSM_DISSECT(3 * NFSX_UNSIGNED); \
90 (t).tv_sec = fxdr_hyper(tl); \
91 tl += 2; \
92 (t).tv_nsec = fxdr_unsigned(long, *tl++); \
93 } while (0)
94
95 static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2];
96
97 nfsv4bitmap nfsv4_fsinfobm = { 2, __fsinfo_bm };
98 nfsv4bitmap nfsv4_fsattrbm = { 2, __fsattr_bm };
99 nfsv4bitmap nfsv4_getattrbm = { 2, __getattr_bm };
100 nfsv4bitmap nfsv4_readdirbm = { 2, __readdir_bm };
101
102 /* Helper routines */
103 int nfsm_v4build_attrs_xx(struct vattr *, struct mbuf **, caddr_t *);
104 int nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *, struct mbuf **, caddr_t *);
105
106 void
107 nfsm_v4init(void)
108 {
109
110 /* Set up bitmasks */
111 FA4_SET(FA4_FSID, __fsinfo_bm);
112 FA4_SET(FA4_MAXREAD, __fsinfo_bm);
113 FA4_SET(FA4_MAXWRITE, __fsinfo_bm);
114 FA4_SET(FA4_LEASE_TIME, __fsinfo_bm);
115
116 FA4_SET(FA4_FSID, __fsattr_bm);
117 FA4_SET(FA4_FILES_FREE, __fsattr_bm);
118 FA4_SET(FA4_FILES_TOTAL, __fsattr_bm);
119 FA4_SET(FA4_SPACE_AVAIL, __fsattr_bm);
120 FA4_SET(FA4_SPACE_FREE, __fsattr_bm);
121 FA4_SET(FA4_SPACE_TOTAL, __fsattr_bm);
122
123 FA4_SET(FA4_TYPE, __getattr_bm);
124 FA4_SET(FA4_FSID, __getattr_bm);
125 FA4_SET(FA4_SIZE, __getattr_bm);
126 FA4_SET(FA4_MODE, __getattr_bm);
127 FA4_SET(FA4_RAWDEV, __getattr_bm);
128 FA4_SET(FA4_NUMLINKS, __getattr_bm);
129 FA4_SET(FA4_OWNER, __getattr_bm);
130 FA4_SET(FA4_OWNER_GROUP, __getattr_bm);
131 FA4_SET(FA4_FILEID, __getattr_bm);
132 FA4_SET(FA4_TIME_ACCESS, __getattr_bm);
133 FA4_SET(FA4_TIME_CREATE, __getattr_bm);
134 FA4_SET(FA4_TIME_METADATA, __getattr_bm);
135 FA4_SET(FA4_TIME_MODIFY, __getattr_bm);
136
137 FA4_SET(FA4_TYPE, __readdir_bm);
138 FA4_SET(FA4_FSID, __readdir_bm);
139 FA4_SET(FA4_FILEID, __readdir_bm);
140 FA4_SET(FA4_RDATTR_ERROR, __readdir_bm);
141 }
142
143 /*
144 * Util
145 */
146
147 uint32_t
148 nfs_v4fileid4_to_fileid(uint64_t fid)
149 {
150 return ((uint32_t)((fid >> 32) | fid));
151 }
152
153 void
154 nfs_v4initcompound(struct nfs4_compound *cp)
155 {
156 bzero(cp, sizeof(*cp));
157 }
158
159 /*
160 * Build/dissect XDR buffer with a format string.
161 *
162 * u - unsigned
163 * h - hyper
164 * s - stringlength, string
165 * k - skip length (bytes)
166 * a - arraylength, componentlenght, array
167 * o - opaque fix length
168 * O - opaque var length in bytes
169 */
170
171 void
172 nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...)
173 {
174 uint32_t *tl, t1, len, uval;
175 uint64_t hval;
176 va_list args;
177 char *p, *which;
178
179 va_start(args, fmt);
180 for (which = fmt; *which != '\0'; which++)
181 switch (*which) {
182 case 'u': /* Unsigned */
183 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
184 uval = va_arg(args, uint32_t);
185 *tl++ = txdr_unsigned(uval);
186 break;
187 case 'h': /* Hyper */
188 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
189 hval = va_arg(args, uint64_t);
190 txdr_hyper(hval, tl);
191 break;
192 case 'o': /* Fixed-length opaque */
193 len = va_arg(args, uint32_t);
194 p = va_arg(args, char *);
195 tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos);
196 bcopy(p, tl, len);
197 break;
198 case 'O': /* Variable-length opaque */
199 case 's': /* String */
200 len = va_arg(args, uint32_t);
201 p = va_arg(args, char *);
202 t1 = nfsm_strtom_xx(p, len, len, mb, bpos);
203 break;
204 case 'k': /* Skip */
205 len = va_arg(args, uint32_t);
206 nfsm_build_xx(nfsm_rndup(len), mb, bpos);
207 break;
208 default:
209 panic("Invalid buildf string %s[%c]", fmt, *which);
210 break;
211 }
212 va_end(args);
213 }
214
215 int
216 nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...)
217 {
218 uint32_t *tl, t1, len, *uval;
219 uint64_t *hval;
220 va_list args;
221 char *p, *which;
222
223 va_start(args, fmt);
224 for (which = fmt; *which != '\0'; which++)
225 switch (*which) {
226 case 'u': /* Unsigned */
227 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
228 if (tl == NULL)
229 return (EBADRPC);
230 uval = va_arg(args, uint32_t *);
231 *uval = fxdr_unsigned(uint32_t, *tl++);
232 break;
233 case 'h': /* Hyper */
234 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
235 if (tl == NULL)
236 return (EBADRPC);
237 hval = va_arg(args, uint64_t *);
238 *hval = fxdr_hyper(tl);
239 break;
240 case 'o': /* Fixed-length opaque */
241 len = va_arg(args, uint32_t);
242 p = va_arg(args, void *);
243 tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
244 if (tl == NULL)
245 return (EBADRPC);
246 bcopy(tl, p, len);
247 break;
248 case 'O': /* Variable-length opaque */
249 case 's': /* String */
250 len = va_arg(args, uint32_t);
251 p = va_arg(args, char *);
252 tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
253 if (tl == NULL)
254 return (EBADRPC);
255 bcopy(tl, p, len);
256 break;
257 case 'k': /* Skip bytes */
258 len = va_arg(args, uint32_t);
259 t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos);
260 break;
261 default:
262 panic("Invalid dissectf string %s[%c]", fmt, *which);
263 break;
264 }
265 va_end(args);
266
267 return (0);
268 }
269
270 /*
271 * XXX - There are a few problems with the way the postops are places
272 * in the code. Ideally, they should be taken care of immediately, as
273 * to avoid uneceesary waits for mutexes, but then we would be
274 * introducing even more complexity by having to handle two separate
275 * cases. Also, since they are placed at the end of the vnops', there
276 * may be operations which sleep in between, further extending this
277 * wait. It is conceivable that there is a deadlock condition there,
278 * too.
279 *
280 * Also, for vnops that do multiple operations, it's inconvenient
281 * since on error, individual decoding will got nfsmout.
282 */
283
284 int
285 nfs_v4postop(struct nfs4_compound *cp, int status)
286 {
287 struct nfs4_fctx *fcp = cp->fcp;
288
289 /*
290 * XXX does the previous result need to be stores with the
291 * lockowner? ack, spec is unclear ..
292 */
293
294 if (fcp != NULL)
295 if (cp->seqidused < cp->rep_nops ||
296 (cp->seqidused + 1 == cp->rep_nops &&
297 NFS4_SEQIDMUTATINGERROR(status)))
298 fcp->lop->lo_seqid++;
299
300 return (status);
301 }
302
303 int
304 nfs_v4handlestatus(int status, struct nfs4_compound *cp)
305 {
306 return (status);
307 }
308
309 /*
310 * Initial setup of compound.
311 */
312
313 int
314 nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag,
315 struct mbuf **mb, caddr_t *bpos)
316 {
317 uint32_t t1, *tl, siz;
318
319 /* Tag */
320 siz = strlen(tag);
321 t1 = nfsm_rndup(siz) + NFSX_UNSIGNED;
322 if (t1 <= M_TRAILINGSPACE(*mb)) {
323 tl = nfsm_build_xx(t1, mb, bpos);
324 *tl++ = txdr_unsigned(siz);
325 *(tl + ((t1 >> 2) - 2)) = 0;
326 bcopy(tag, tl, siz);
327 } else {
328 t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
329 if (t1 != 0)
330 return (t1);
331 }
332
333 /* Minor version and argarray*/
334 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
335 *tl++ = txdr_unsigned(NFS4_MINOR_VERSION);
336 /* Save for backfill */
337 cp->req_nopsp = tl;
338 *tl = txdr_unsigned(0);
339
340 cp->curvp = NULL;
341 cp->savevp = NULL;
342
343 return (0);
344 }
345
346 /*
347 * XXX
348 * - backfill for stateid, and such
349 */
350 int
351 nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos)
352 {
353 *cp->req_nopsp = txdr_unsigned(cp->req_nops);
354
355 return (0);
356 }
357
358 int
359 nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp,
360 struct mbuf **mb, caddr_t *bpos)
361 {
362 uint32_t t1;
363
364 /* Op */
365 nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH);
366
367 /* FH */
368 t1 = nfsm_fhtom_xx(vp, 1, mb, bpos);
369 if (t1 != 0)
370 return (t1);
371
372 cp->req_nops++;
373 cp->curvp = vp;
374
375 return (0);
376 }
377
378 int
379 nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
380 struct mbuf **mb, caddr_t *bpos)
381 {
382 nfsm_buildf_xx(mb, bpos, "uuo",
383 NFSV4OP_PUTFH,
384 gfh->fh_len,
385 gfh->fh_len,
386 &gfh->fh_val);
387
388 cp->req_nops++;
389
390 return (0);
391 }
392
393 int
394 nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op,
395 struct mbuf **mb, caddr_t *bpos)
396 {
397 nfsm_buildf_xx(mb, bpos, "u", op);
398
399 cp->req_nops++;
400
401 return (0);
402 }
403
404 int
405 nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
406 struct mbuf **mb, caddr_t *bpos)
407 {
408 int i;
409
410 /* Op + bitmap length + bitmap */
411 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen);
412 for (i = 0; i < ga->bm->bmlen; i++)
413 nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]);
414
415 ga->vp = cp->curvp;
416 cp->req_nops++;
417
418 return (0);
419 }
420
421 int
422 nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap,
423 struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos)
424 {
425 int error;
426 static char zero_stateid[NFSX_V4STATEID];
427
428 nfsm_buildf_xx(mb, bpos, "uo",
429 NFSV4OP_SETATTR,
430 NFSX_V4STATEID, fcp ? fcp->stateid : zero_stateid);
431 error = nfsm_v4build_attrs_xx(vap, mb, bpos);
432 if (error == 0)
433 cp->req_nops++;
434
435 return (error);
436 }
437
438 int
439 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
440 struct mbuf **mb, caddr_t *bpos)
441 {
442 nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
443
444 gfh->vp = cp->curvp;
445 cp->req_nops++;
446
447 return (0);
448 }
449
450 int
451 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
452 struct mbuf **mb, caddr_t *bpos)
453 {
454 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
455
456 cp->curvp = l->vp;
457 cp->req_nops++;
458
459 return (0);
460 }
461
462 int
463 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
464 struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
465 {
466 struct timeval tv;
467
468 microtime(&tv);
469
470 nfsm_buildf_xx(mb, bpos, "uuusussu",
471 NFSV4OP_SETCLIENTID,
472 tv.tv_sec, tv.tv_usec,
473 sci->namelen, sci->name,
474 sci->cb_prog,
475 sci->cb_netidlen, sci->cb_netid,
476 sci->cb_univaddrlen, sci->cb_univaddr,
477 0xCA11BACC);
478
479 cp->req_nops++;
480
481 return (0);
482 }
483
484 int
485 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
486 struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
487 {
488 nfsm_buildf_xx(mb, bpos, "uho",
489 NFSV4OP_SETCLIENTID_CONFIRM,
490 sci->clientid,
491 sizeof(sci->verf), sci->verf);
492
493 cp->req_nops++;
494
495 return (0);
496 }
497
498 int
499 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
500 struct mbuf **mb, caddr_t *bpos)
501 {
502 int error = 0;
503 struct nfs4_lowner *lop = op->fcp->lop;
504
505 nfsm_buildf_xx(mb, bpos, "uuuuhuu",
506 NFSV4OP_OPEN,
507 lop->lo_seqid,
508 op->flags & O_ACCMODE,
509 NFSV4OPENSHARE_DENY_NONE,
510 cp->nmp->nm_clientid,
511 4, lop->lo_id);
512
513 if (op->flags & O_CREAT) {
514 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
515 /* openflag4: mode */
516 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
517 /* openflag4: createattrs... */
518 if (op->vap != NULL) {
519 if (op->flags & O_TRUNC)
520 op->vap->va_size = 0;
521 error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
522 if (error != 0)
523 return (error);
524 } else
525 nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
526 } else
527 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
528
529 nfsm_buildf_xx(mb, bpos, "us", op->ctype,
530 op->cnp->cn_namelen, op->cnp->cn_nameptr);
531
532 cp->seqidused = cp->req_nops++;
533 cp->fcp = op->fcp;
534
535 return (error);
536 }
537
538 /*
539 * XXX
540 * - Wait on recovery
541 */
542 int
543 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
544 struct mbuf **mb, caddr_t *bpos)
545 {
546 nfsm_buildf_xx(mb, bpos, "uou",
547 NFSV4OP_OPEN_CONFIRM,
548 NFSX_V4STATEID, op->fcp->stateid,
549 op->fcp->lop->lo_seqid);
550
551 cp->seqidused = cp->req_nops++;
552 cp->fcp = op->fcp;
553
554 return (0);
555 }
556
557 /*
558 * XXX
559 * - Wait on recovery
560 */
561 int
562 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
563 struct mbuf **mb, caddr_t *bpos)
564 {
565 struct nfs4_lowner *lop = fcp->lop;
566
567 nfsm_buildf_xx(mb, bpos, "uuo",
568 NFSV4OP_CLOSE,
569 lop->lo_seqid,
570 NFSX_V4STATEID, fcp->stateid);
571
572 cp->seqidused = cp->req_nops++;
573 cp->fcp = fcp;
574
575 return (0);
576 }
577
578 int
579 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
580 struct mbuf **mb, caddr_t *bpos)
581 {
582 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
583 cp->req_nops++;
584
585 return (0);
586 }
587
588 int
589 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
590 struct mbuf **mb, caddr_t *bpos)
591 {
592 nfsm_buildf_xx(mb, bpos, "uohu",
593 NFSV4OP_READ,
594 NFSX_V4STATEID, r->fcp->stateid,
595 r->off,
596 r->maxcnt);
597 cp->req_nops++;
598
599 return (0);
600 }
601
602 int
603 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
604 struct mbuf **mb, caddr_t *bpos)
605 {
606 nfsm_buildf_xx(mb, bpos, "uohuu",
607 NFSV4OP_WRITE,
608 NFSX_V4STATEID, w->fcp->stateid,
609 w->off,
610 w->stable,
611 w->cnt);
612 cp->req_nops++;
613 return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
614 }
615
616 int
617 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
618 struct mbuf **mb, caddr_t *bpos)
619 {
620 nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
621 cp->req_nops++;
622
623 return (0);
624 }
625
626 int
627 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
628 struct mbuf **mb, caddr_t *bpos)
629 {
630 int i;
631
632 nfsm_buildf_xx(mb, bpos, "uhouuu",
633 NFSV4OP_READDIR,
634 r->cookie,
635 sizeof(r->verf), r->verf,
636 r->cnt >> 4, /* meaningless "dircount" field */
637 r->cnt,
638 r->bm->bmlen);
639
640 for (i = 0; i < r->bm->bmlen; i++)
641 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
642
643 cp->req_nops++;
644
645 return (0);
646 }
647
648 int
649 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
650 struct mbuf **mb, caddr_t *bpos)
651 {
652 nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
653 cp->req_nops++;
654
655 return (0);
656 }
657
658 int
659 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
660 struct mbuf **mb, caddr_t *bpos)
661 {
662 uint32_t t1;
663
664 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
665
666 if (c->type == NFLNK)
667 /* XXX strlen */
668 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
669 else if (c->type == NFCHR || c->type == NFBLK)
670 nfsm_buildf_xx(mb, bpos, "uu",
671 umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
672
673 /* Name */
674 nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);
675
676 /* Attributes */
677 t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
678 if (t1 != 0)
679 return (t1);
680
681 cp->req_nops++;
682
683 return (0);
684 }
685
686 int
687 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
688 struct mbuf **mb, caddr_t *bpos)
689 {
690 nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
691 r->tnamelen, r->tname);
692
693 cp->req_nops++;
694
695 return (0);
696 }
697
698 int
699 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
700 struct mbuf **mb, caddr_t *bpos)
701 {
702 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
703
704 cp->req_nops++;
705
706 return (0);
707 }
708
709 int
710 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
711 struct mbuf **mb, caddr_t *bpos)
712 {
713 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
714
715 cp->req_nops++;
716
717 return (0);
718 }
719
720 int
721 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
722 {
723 uint32_t *tl, *attrlenp, *bmvalp, len;
724 size_t siz;
725
726 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
727
728 *tl++ = txdr_unsigned(2); /* bitmap length */
729 bmvalp = tl;
730 bzero(bmvalp, 8);
731 tl += 2;
732 attrlenp = tl;
733
734 len = 0;
735 if (vap->va_size != VNOVAL) {
736 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
737 FA4_SET(FA4_SIZE, bmvalp);
738 txdr_hyper(vap->va_size, tl); tl += 2;
739 len += 2 * NFSX_UNSIGNED;
740 }
741 if (vap->va_mode != (u_short)VNOVAL) {
742 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
743 FA4_SET(FA4_MODE, bmvalp);
744 *tl++ = txdr_unsigned(vap->va_mode);
745 len += NFSX_UNSIGNED;
746 }
747 if (vap->va_uid != VNOVAL) {
748 int error;
749 char *name;
750 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
751 if (error || name == NULL || siz == 0) {
752 /* XXX */
753 siz = sizeof("nobody") - 1;
754 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
755 bpos);
756 *tl++ = txdr_unsigned(siz);
757 bcopy("nobody", tl, siz);
758 len += NFSX_UNSIGNED + nfsm_rndup(siz);
759 } else {
760 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
761 bpos);
762 *tl++ = txdr_unsigned(siz);
763 bcopy(name, tl, siz);
764 len += NFSX_UNSIGNED + nfsm_rndup(siz);
765 }
766 FA4_SET(FA4_OWNER, bmvalp);
767 }
768 if (vap->va_gid != VNOVAL) {
769 int error;
770 char *name;
771 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
772 if (error || name == NULL || siz == 0) {
773 /* XXX */
774 siz = sizeof("nogroup") - 1;
775 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
776 bpos);
777 *tl++ = txdr_unsigned(siz);
778 bcopy("nogroup", tl, siz);
779 len += NFSX_UNSIGNED + nfsm_rndup(siz);
780 } else {
781 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
782 bpos);
783 *tl++ = txdr_unsigned(siz);
784 bcopy(name, tl, siz);
785 len += NFSX_UNSIGNED + nfsm_rndup(siz);
786 }
787 FA4_SET(FA4_OWNER_GROUP, bmvalp);
788 }
789 if (vap->va_atime.tv_sec != VNOVAL) {
790 uint64_t val = vap->va_atime.tv_sec;
791 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
792 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
793 *tl++ = txdr_unsigned(THCLIENTTIME);
794 txdr_hyper(val, tl); tl += 2;
795 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
796 len += 4 * NFSX_UNSIGNED;
797 }
798 if (vap->va_mtime.tv_sec != VNOVAL) {
799 uint64_t val = vap->va_mtime.tv_sec;
800 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
801 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
802 *tl++ = txdr_unsigned(THCLIENTTIME);
803 txdr_hyper(val, tl); tl += 2;
804 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
805 len += 4 * NFSX_UNSIGNED;
806 }
807
808 bmvalp[0] = txdr_unsigned(bmvalp[0]);
809 bmvalp[1] = txdr_unsigned(bmvalp[1]);
810
811 *attrlenp = txdr_unsigned(len);
812
813 return (0);
814 }
815
816 int
817 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
818 {
819 uint32_t taglen, t1, *tl;
820
821 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
822 if (tl == NULL)
823 return (EBADRPC);
824
825 /* Reply status is handled by the RPC code */
826
827 taglen = fxdr_unsigned(uint32_t, *tl++);
828 t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
829 if (t1 != 0)
830 return (EBADRPC);
831
832 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
833 if (tl == NULL)
834 return (EBADRPC);
835
836 cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
837
838 return (0);
839 }
840
841 int
842 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
843 uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
844 {
845 uint32_t t1, dop, status;
846
847 t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
848 if (t1 != 0)
849 return (t1);
850
851 if (dop != op || status != 0)
852 return (EBADRPC);
853
854 if (skipbytes > 0)
855 NFSM_ADV(nfsm_rndup(skipbytes));
856
857 return (0);
858 }
859
860 int
861 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
862 struct mbuf **md, caddr_t *dpos)
863 {
864 uint32_t *tl;
865
866 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
867 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
868 *tl++ != 0)
869 return (EBADRPC);
870
871 return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
872 }
873
874 int
875 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
876 {
877 uint32_t t1, op, bmlen, status;
878
879 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
880 if (t1 != 0)
881 return (t1);
882
883 if (op != NFSV4OP_SETATTR || status != 0)
884 return (EBADRPC);
885
886 t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
887 if (t1 != 0)
888 return (t1);
889
890 return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
891 }
892
893 int
894 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
895 struct mbuf **md, caddr_t *dpos)
896 {
897 uint32_t *tl, len, xdrlen;
898
899 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
900 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
901 return (EBADRPC);
902
903 if (*tl++ != 0)
904 return (EBADRPC);
905
906 NFSM_DISSECT(NFSX_UNSIGNED);
907 len = fxdr_unsigned(uint32_t, *tl++);
908 if (len > NFSX_V4FH)
909 return (EBADRPC);
910
911 /* XXX integrate this into nfs_mtofh()? */
912
913 gfh->fh_len = len;
914 xdrlen = nfsm_rndup(len);
915
916 NFSM_DISSECT(xdrlen);
917 bcopy(tl, &gfh->fh_val, xdrlen);
918
919 return (0);
920 }
921
922 int
923 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
924 struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
925 {
926 uint32_t *tl;
927
928 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
929 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
930 return (EBADRPC);
931
932 /* Handle NFS4ERR_CLID_INUSE specially */
933 if (*tl++ != 0)
934 return (EBADRPC);
935
936 NFSM_DISSECT(2 * NFSX_UNSIGNED);
937 sci->clientid = fxdr_hyper(tl);
938
939 NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF));
940 bcopy(tl, sci->verf, NFSX_V4VERF);
941
942 return (0);
943 }
944
945 int
946 nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
947 struct mbuf **md, caddr_t *dpos)
948 {
949 uint32_t *tl, t1;
950
951 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
952 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE ||
953 *tl++ != 0)
954 return (EBADRPC);
955
956 /* Copy stateid */
957 t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
958 if (t1 != 0)
959 return (t1);
960
961 return (0);
962 }
963
964 int
965 nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
966 struct mbuf **md, caddr_t *dpos)
967 {
968 uint32_t *tl;
969
970 tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos);
971 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS ||
972 *tl++ != 0)
973 return (EBADRPC);
974
975 acc->supported = fxdr_unsigned(uint32_t, *tl++);
976 acc->rmode = fxdr_unsigned(uint32_t, *tl++);
977
978 return (0);
979 }
980
981 int
982 nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
983 struct mbuf **md, caddr_t *dpos)
984 {
985 uint32_t *tl, t1, bmlen, delegtype = ODNONE;
986 int error = 0;
987 nfsv4changeinfo cinfo;
988 struct nfs4_fctx *fcp = op->fcp;
989
990 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
991 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN ||
992 *tl++ != 0)
993 return (EBADRPC);
994
995 t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
996 if (t1 != 0)
997 return (t1);
998
999 error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos);
1000 if (error != 0)
1001 goto nfsmout;
1002
1003 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1004
1005 op->rflags = fxdr_unsigned(uint32_t, *tl++);
1006 bmlen = fxdr_unsigned(uint32_t, *tl++);
1007 if (bmlen > 2) {
1008 error = EBADRPC;
1009 goto nfsmout;
1010 }
1011
1012 /* Skip */
1013 NFSM_ADV(nfsm_rndup(bmlen << 2));
1014
1015 NFSM_DISSECT(NFSX_UNSIGNED);
1016 delegtype = fxdr_unsigned(uint32_t, *tl++);
1017 switch (delegtype) {
1018 case ODREAD:
1019 case ODWRITE:
1020 printf("nfs4: client delegation not yet supported\n");
1021 error = EOPNOTSUPP;
1022 goto nfsmout;
1023 break;
1024 case ODNONE:
1025 default:
1026 break;
1027 }
1028
1029 nfsmout:
1030 return (error);
1031 }
1032
1033 int
1034 nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
1035 struct mbuf **md, caddr_t *dpos)
1036 {
1037 uint32_t *tl;
1038
1039 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1040 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM ||
1041 *tl++ != 0)
1042 return (EBADRPC);
1043
1044 return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid);
1045 }
1046
1047 int
1048 nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
1049 struct mbuf **md, caddr_t *dpos)
1050 {
1051 uint32_t op, status, t1;
1052
1053 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1054 if (t1 != 0)
1055 return (t1);
1056
1057 if (op != NFSV4OP_READ || status != 0)
1058 return (EBADRPC);
1059
1060 t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen);
1061 if (t1 != 0)
1062 return (t1);
1063
1064 return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos));
1065 }
1066
1067 int
1068 nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
1069 struct mbuf **md, caddr_t *dpos)
1070 {
1071 uint32_t op, status, t1;
1072
1073 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1074 if (t1 != 0)
1075 return (t1);
1076
1077 if (op != NFSV4OP_WRITE || status != 0)
1078 return (EBADRPC);
1079
1080 return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed,
1081 NFSX_V4VERF, w->wverf));
1082 }
1083
1084 int
1085 nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
1086 struct mbuf **md, caddr_t *dpos)
1087 {
1088 uint32_t t1, op, status;
1089
1090 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1091 if (t1 != 0)
1092 return (t1);
1093
1094 if (op != NFSV4OP_COMMIT || status != 0)
1095 return (EBADRPC);
1096
1097 return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf));
1098 }
1099
1100 int
1101 nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
1102 struct mbuf **md, caddr_t *dpos)
1103 {
1104 uint32_t t1, *tl, op, status, bmlen;
1105 nfsv4changeinfo ci;
1106
1107 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1108 if (t1 != 0)
1109 return (t1);
1110
1111 if (op != NFSV4OP_CREATE || status != 0)
1112 return (EBADRPC);
1113
1114 /* Just throw this away for now */
1115 t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos);
1116 if (t1 != 0)
1117 return (t1);
1118
1119 /* Throw this away too */
1120 NFSM_DISSECT(NFSX_UNSIGNED);
1121 bmlen = fxdr_unsigned(uint32_t, *tl++);
1122 NFSM_DISSECT(bmlen * NFSX_UNSIGNED);
1123 tl += bmlen;
1124
1125 return 0;
1126 }
1127
1128 int
1129 nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop,
1130 struct mbuf **md, caddr_t *dpos)
1131 {
1132 uint32_t t1, *tl, op, status, linklen;
1133
1134 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1135 if (t1 != 0)
1136 return (t1);
1137
1138 if (op != NFSV4OP_READLINK || status != 0)
1139 return (EBADRPC);
1140
1141 /* Do this one manually for careful checking of sizes. */
1142 NFSM_DISSECT(NFSX_UNSIGNED);
1143 linklen = fxdr_unsigned(uint32_t, *tl++);
1144 if (linklen <= 0)
1145 return (EBADRPC);
1146
1147 return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos));
1148 }
1149
1150 int
1151 nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci,
1152 struct mbuf **md, caddr_t *dpos)
1153 {
1154 uint32_t *tl;
1155
1156 NFSM_DISSECT(5 * NFSX_UNSIGNED);
1157
1158 ci->ciatomic = fxdr_unsigned(uint32_t, *tl++);
1159 ci->cibefore = fxdr_hyper(tl); tl += 2;
1160 ci->ciafter = fxdr_hyper(tl); tl += 2;
1161
1162 return (0);
1163 }
1164
1165 int
1166 nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos)
1167 {
1168 uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0;
1169
1170 /* Bitmap length + value */
1171 NFSM_DISSECT(NFSX_UNSIGNED);
1172
1173 bmlen = fxdr_unsigned(uint32_t, *tl++);
1174 if (bmlen > 2)
1175 return (EBADRPC);
1176
1177 if (bmlen == 0)
1178 return (0);
1179
1180 NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED);
1181
1182 bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1183 bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1184
1185 /* Attribute length */
1186 attrlen = fxdr_unsigned(uint32_t, *tl++);
1187
1188 /*
1189 * XXX check for correct (<=) attributes mask return from
1190 * server. need to pass this in.
1191 */
1192
1193 if (FA4_ISSET(FA4_TYPE, bmval)) {
1194 /* overflow check */
1195 NFSM_DISSECT(NFSX_UNSIGNED);
1196 fa->fa4_type = fxdr_unsigned(uint32_t, *tl++);
1197 fa->fa4_valid |= FA4V_TYPE;
1198 len += NFSX_UNSIGNED;
1199 }
1200 if (FA4_ISSET(FA4_CHANGE, bmval)) {
1201 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1202 fa->fa4_changeid = fxdr_hyper(tl);
1203 fa->fa4_valid |= FA4V_CHANGEID;
1204 len += 2 * NFSX_UNSIGNED;
1205 }
1206 if (FA4_ISSET(FA4_SIZE, bmval)) {
1207 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1208 fa->fa4_size = fxdr_hyper(tl);
1209 fa->fa4_valid |= FA4V_SIZE;
1210 len += 2 * NFSX_UNSIGNED;
1211 }
1212 if (FA4_ISSET(FA4_FSID, bmval)) {
1213 NFSM_DISSECT(4 * NFSX_UNSIGNED);
1214 fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2;
1215 fa->fa4_fsid_minor = fxdr_hyper(tl);
1216 fa->fa4_valid |= FA4V_SIZE;
1217 len += 4 * NFSX_UNSIGNED;
1218 }
1219 if (FA4_ISSET(FA4_LEASE_TIME, bmval)) {
1220 NFSM_DISSECT(NFSX_UNSIGNED);
1221 fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++);
1222 fa->fa4_valid |= FA4V_LEASE_TIME;
1223 len += NFSX_UNSIGNED;
1224 }
1225 if (FA4_ISSET(FA4_RDATTR_ERROR, bmval)) {
1226 /* ignore for now; we only ask for it so the compound won't fail */
1227 NFSM_DISSECT(NFSX_UNSIGNED);
1228 tl++;
1229 len += NFSX_UNSIGNED;
1230 }
1231 if (FA4_ISSET(FA4_FILEID, bmval)) {
1232 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1233 fa->fa4_fileid = fxdr_hyper(tl);
1234 fa->fa4_valid |= FA4V_FILEID;
1235 len += 2 * NFSX_UNSIGNED;
1236 }
1237 if (FA4_ISSET(FA4_FILES_FREE, bmval)) {
1238 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1239 fa->fa4_ffree = fxdr_hyper(tl);
1240 fa->fa4_valid |= FA4V_FFREE;
1241 len += 2 * NFSX_UNSIGNED;
1242 }
1243 if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) {
1244 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1245 fa->fa4_ftotal = fxdr_hyper(tl);
1246 fa->fa4_valid |= FA4V_FTOTAL;
1247 len += 2 * NFSX_UNSIGNED;
1248 }
1249 if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) {
1250 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1251 fa->fa4_maxfilesize = fxdr_hyper(tl);
1252 fa->fa4_valid |= FA4V_MAXFILESIZE;
1253 len += 2 * NFSX_UNSIGNED;
1254 }
1255 if (FA4_ISSET(FA4_MAXNAME, bmval)) {
1256 NFSM_DISSECT(NFSX_UNSIGNED);
1257 fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++);
1258 fa->fa4_valid |= FA4V_MAXNAME;
1259 len += NFSX_UNSIGNED;
1260 }
1261 if (FA4_ISSET(FA4_MAXREAD, bmval)) {
1262 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1263 fa->fa4_maxread = fxdr_hyper(tl);
1264 fa->fa4_valid |= FA4V_MAXREAD;
1265 len += 2 * NFSX_UNSIGNED;
1266 }
1267 if (FA4_ISSET(FA4_MAXWRITE, bmval)) {
1268 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1269 fa->fa4_maxwrite = fxdr_hyper(tl);
1270 fa->fa4_valid |= FA4V_MAXWRITE;
1271 len += 2 * NFSX_UNSIGNED;
1272 }
1273
1274 if (FA4_ISSET(FA4_MODE, bmval)) {
1275 NFSM_DISSECT(NFSX_UNSIGNED);
1276 fa->fa4_mode = fxdr_unsigned(mode_t, *tl++);
1277 fa->fa4_valid |= FA4V_MODE;
1278 len += NFSX_UNSIGNED;
1279 }
1280 if (FA4_ISSET(FA4_NUMLINKS, bmval)) {
1281 NFSM_DISSECT(NFSX_UNSIGNED);
1282 fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++);
1283 fa->fa4_valid |= FA4V_NLINK;
1284 len += NFSX_UNSIGNED;
1285 }
1286 if (FA4_ISSET(FA4_OWNER, bmval)) {
1287 uint32_t ownerlen;
1288 int error;
1289
1290 NFSM_DISSECT(NFSX_UNSIGNED);
1291
1292 ownerlen = fxdr_unsigned(uint32_t, *tl++);
1293 NFSM_DISSECT(nfsm_rndup(ownerlen));
1294 error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid);
1295 if (error)
1296 fa->fa4_uid = -2;
1297 fa->fa4_valid |= FA4V_UID;
1298 len += NFSX_UNSIGNED + nfsm_rndup(ownerlen);
1299 }
1300 if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) {
1301 uint32_t ownergrouplen;
1302 int error;
1303
1304 NFSM_DISSECT(NFSX_UNSIGNED);
1305 ownergrouplen = fxdr_unsigned(uint32_t, *tl++);
1306 NFSM_DISSECT(nfsm_rndup(ownergrouplen));
1307 error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid);
1308 if (error)
1309 fa->fa4_gid = -2;
1310 fa->fa4_valid |= FA4V_GID;
1311 len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen);
1312 }
1313 if (FA4_ISSET(FA4_RAWDEV, bmval)) {
1314 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1315 fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++);
1316 fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++);
1317 fa->fa4_valid |= FA4V_RDEV;
1318 len += 2 * NFSX_UNSIGNED;
1319 }
1320 if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) {
1321 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1322 fa->fa4_savail = fxdr_hyper(tl);
1323 fa->fa4_valid |= FA4V_SAVAIL;
1324 len += 2 * NFSX_UNSIGNED;
1325 }
1326 if (FA4_ISSET(FA4_SPACE_FREE, bmval)) {
1327 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1328 fa->fa4_sfree = fxdr_hyper(tl);
1329 fa->fa4_valid |= FA4V_SFREE;
1330 len += 2 * NFSX_UNSIGNED;
1331 }
1332 if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) {
1333 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1334 fa->fa4_stotal = fxdr_hyper(tl);
1335 fa->fa4_valid |= FA4V_STOTAL;
1336 len += 2 * NFSX_UNSIGNED;
1337 }
1338 if (FA4_ISSET(FA4_SPACE_USED, bmval)) {
1339 NFSM_ADV(2 * NFSX_UNSIGNED);
1340 len += 2 * NFSX_UNSIGNED;
1341 }
1342 if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) {
1343 NFSM_MTOTIME(fa->fa4_atime);
1344 fa->fa4_valid |= FA4V_ATIME;
1345 len += 3 * NFSX_UNSIGNED;
1346 }
1347 if (FA4_ISSET(FA4_TIME_CREATE, bmval)) {
1348 NFSM_MTOTIME(fa->fa4_btime);
1349 fa->fa4_valid |= FA4V_BTIME;
1350 len += 3 * NFSX_UNSIGNED;
1351 }
1352 if (FA4_ISSET(FA4_TIME_METADATA, bmval)) {
1353 NFSM_MTOTIME(fa->fa4_ctime);
1354 fa->fa4_valid |= FA4V_CTIME;
1355 len += 3 * NFSX_UNSIGNED;
1356 }
1357 if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) {
1358 NFSM_MTOTIME(fa->fa4_mtime);
1359 fa->fa4_valid |= FA4V_MTIME;
1360 len += 3 * NFSX_UNSIGNED;
1361 }
1362
1363 if (len != attrlen)
1364 return (EBADRPC);
1365
1366 return (0);
1367 }
Cache object: fb598cf0555e2380172882de6bcc58df
|