1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2018 Nexenta Systems, Inc.
29 */
30
31 #include <sys/systm.h>
32 #include <sys/cmn_err.h>
33 #include <nfs/nfs.h>
34 #include <nfs/export.h>
35 #include <nfs/nfs4.h>
36 #include <sys/ddi.h>
37 #include <sys/door.h>
38 #include <sys/sdt.h>
39 #include <nfs/nfssys.h>
40
41 void rfs4_init_compound_state(struct compound_state *);
42
43 bitmap4 rfs4_supported_attrs;
44 int MSG_PRT_DEBUG = FALSE;
45
46 /* If building with DEBUG enabled, enable mandattr tunable by default */
47 #ifdef DEBUG
48 #ifndef RFS4_SUPPORT_MANDATTR_ONLY
49 #define RFS4_SUPPORT_MANDATTR_ONLY
50 #endif
51 #endif
52
53 /*
54 * If building with mandattr only code, disable it by default.
55 * To enable, set rfs4_mandattr_only in /etc/system and reboot.
56 * When building without mandattr ifdef, the compiler should
57 * optimize away the the comparisons because RFS4_MANDATTR_ONLY
58 * is defined to be 0.
59 */
60 #ifdef RFS4_SUPPORT_MANDATTR_ONLY
61 #define NFS4_LAST_MANDATTR FATTR4_RDATTR_ERROR
62 #define RFS4_MANDATTR_ONLY rfs4_mandattr_only
63 int rfs4_mandattr_only = 0;
64 #else
65 #define RFS4_MANDATTR_ONLY 0
66 #endif
67
68
69 static void rfs4_ntov_init(void);
70 static int rfs4_fattr4_supported_attrs();
71 static int rfs4_fattr4_type();
72 static int rfs4_fattr4_fh_expire_type();
73 static int rfs4_fattr4_change();
74 static int rfs4_fattr4_size();
75 static int rfs4_fattr4_link_support();
76 static int rfs4_fattr4_symlink_support();
77 static int rfs4_fattr4_named_attr();
78 static int rfs4_fattr4_fsid();
79 static int rfs4_fattr4_unique_handles();
80 static int rfs4_fattr4_lease_time();
81 static int rfs4_fattr4_rdattr_error();
82 static int rfs4_fattr4_acl();
83 static int rfs4_fattr4_aclsupport();
84 static int rfs4_fattr4_archive();
85 static int rfs4_fattr4_cansettime();
86 static int rfs4_fattr4_case_insensitive();
87 static int rfs4_fattr4_case_preserving();
88 static int rfs4_fattr4_chown_restricted();
89 static int rfs4_fattr4_filehandle();
90 static int rfs4_fattr4_fileid();
91 static int rfs4_fattr4_files_avail();
92 static int rfs4_fattr4_files_free();
93 static int rfs4_fattr4_files_total();
94 static int rfs4_fattr4_fs_locations();
95 static int rfs4_fattr4_hidden();
96 static int rfs4_fattr4_homogeneous();
97 static int rfs4_fattr4_maxfilesize();
98 static int rfs4_fattr4_maxlink();
99 static int rfs4_fattr4_maxname();
100 static int rfs4_fattr4_maxread();
101 static int rfs4_fattr4_maxwrite();
102 static int rfs4_fattr4_mimetype();
103 static int rfs4_fattr4_mode();
104 static int rfs4_fattr4_no_trunc();
105 static int rfs4_fattr4_numlinks();
106 static int rfs4_fattr4_owner();
107 static int rfs4_fattr4_owner_group();
108 static int rfs4_fattr4_quota_avail_hard();
109 static int rfs4_fattr4_quota_avail_soft();
110 static int rfs4_fattr4_quota_used();
111 static int rfs4_fattr4_rawdev();
112 static int rfs4_fattr4_space_avail();
113 static int rfs4_fattr4_space_free();
114 static int rfs4_fattr4_space_total();
115 static int rfs4_fattr4_space_used();
116 static int rfs4_fattr4_system();
117 static int rfs4_fattr4_time_access();
118 static int rfs4_fattr4_time_access_set();
119 static int rfs4_fattr4_time_backup();
120 static int rfs4_fattr4_time_create();
121 static int rfs4_fattr4_time_delta();
122 static int rfs4_fattr4_time_metadata();
123 static int rfs4_fattr4_time_modify();
124 static int rfs4_fattr4_time_modify_set();
125
126 /*
127 * Initialize the supported attributes
128 */
129 void
130 rfs4_attr_init()
131 {
132 int i;
133 struct nfs4_svgetit_arg sarg;
134 struct compound_state cs;
135 struct statvfs64 sb;
136
137 rfs4_init_compound_state(&cs);
138 /*
139 * This is global state checking, called once. We might be in
140 * non-global-zone context here (say a modload happens from a zone
141 * process) so in this case, we want the global-zone root vnode.
142 */
143 cs.vp = rootvp;
144 cs.fh.nfs_fh4_val = NULL;
145 cs.cr = kcred;
146
147 /*
148 * Get all the supported attributes
149 */
150 sarg.op = NFS4ATTR_SUPPORTED;
151 sarg.cs = &cs;
152 sarg.vap->va_mask = AT_ALL;
153 sarg.sbp = &sb;
154 sarg.flag = 0;
155 sarg.rdattr_error = NFS4_OK;
156 sarg.rdattr_error_req = FALSE;
157 sarg.is_referral = B_FALSE;
158
159 rfs4_ntov_init();
160
161 rfs4_supported_attrs = 0;
162 for (i = 0; i < NFS4_MAXNUM_ATTRS; i++) {
163 #ifdef RFS4_SUPPORT_MANDATTR_ONLY
164 if (rfs4_mandattr_only == TRUE && i > NFS4_LAST_MANDATTR)
165 continue;
166 #endif
167 if ((*nfs4_ntov_map[i].sv_getit)(NFS4ATTR_SUPPORTED,
168 &sarg, NULL) == 0) {
169 rfs4_supported_attrs |= nfs4_ntov_map[i].fbit;
170 }
171 }
172 }
173
174 /*
175 * The following rfs4_fattr4_* functions convert between the fattr4
176 * arguments/attributes and the system (e.g. vattr) values. The following
177 * commands are currently in use:
178 *
179 * NFS4ATTR_SUPPORTED: checks if the attribute in question is supported:
180 * sarg.op = SUPPORTED - all supported attrs
181 * sarg.op = GETIT - only supported readable attrs
182 * sarg.op = SETIT - only supported writable attrs
183 *
184 * NFS4ATTR_GETIT: getattr type conversion - convert system values
185 * (e.g. vattr struct) to fattr4 type values to be returned to the
186 * user - usually in response to nfsv4 getattr request.
187 *
188 * NFS4ATTR_SETIT: convert fattr4 type values to system values to use by
189 * setattr. Allows only read/write and write attributes,
190 * even if not supported by the filesystem. Note that ufs only allows setattr
191 * of owner/group, mode, size, atime/mtime.
192 *
193 * NFS4ATTR_VERIT: convert fattr4 type values to system values to use by
194 * verify/nverify. Implemented to allow
195 * almost everything that can be returned by getattr into known structs
196 * (like vfsstat64 or vattr_t), that is, both read only and read/write attrs.
197 * The function will return -1 if it found that the arguments don't match.
198 * This applies to system-wide values that don't require a VOP_GETATTR
199 * or other further checks to verify. It will return no error if they
200 * either match or were retrieved successfully for later checking.
201 *
202 * NFS4ATTR_FREEIT: free up any space allocated by either of the above.
203 * The sargp->op should be either NFS4ATTR_GETIT or NFS4ATTR_SETIT
204 * to indicate which op was used to allocate the space.
205 *
206 * XXX Note: these functions are currently used by the server only. A
207 * XXX different method of conversion is used on the client side.
208 * XXX Eventually combining the two (possibly by adding NFS4ATTR_CLNT_GETIT
209 * XXX and SETIT) may be a cleaner approach.
210 */
211
212 /*
213 * Mandatory attributes
214 */
215
216 /* ARGSUSED */
217 static int
218 rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
219 union nfs4_attr_u *na)
220 {
221 int error = 0;
222
223 switch (cmd) {
224 case NFS4ATTR_SUPPORTED:
225 if (sarg->op == NFS4ATTR_SETIT)
226 error = EINVAL;
227 break; /* this attr is supported */
228 case NFS4ATTR_GETIT:
229 na->supported_attrs = rfs4_supported_attrs;
230 break;
231 case NFS4ATTR_SETIT:
232 /*
233 * read-only attr
234 */
235 error = EINVAL;
236 break;
237 case NFS4ATTR_VERIT:
238 /*
239 * Compare the input bitmap to the server's bitmap
240 */
241 if (na->supported_attrs != rfs4_supported_attrs) {
242 error = -1; /* no match */
243 }
244 break;
245 case NFS4ATTR_FREEIT:
246 break;
247 }
248 return (error);
249 }
250
251 /*
252 * Translate vnode vtype to nfsv4_ftype.
253 */
254 static nfs_ftype4 vt_to_nf4[] = {
255 0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0
256 };
257
258 /* ARGSUSED */
259 static int
260 rfs4_fattr4_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
261 union nfs4_attr_u *na)
262 {
263 int error = 0;
264
265 switch (cmd) {
266 case NFS4ATTR_SUPPORTED:
267 if (sarg->op == NFS4ATTR_SETIT)
268 error = EINVAL;
269 break; /* this attr is supported */
270 case NFS4ATTR_GETIT:
271 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_TYPE)) {
272 error = -1; /* may be okay if rdattr_error */
273 break;
274 }
275 ASSERT(sarg->vap->va_mask & AT_TYPE);
276
277 /*
278 * if xattr flag not set, use v4_to_nf4 mapping;
279 * otherwise verify xattr flag is in sync with va_type
280 * and set xattr types.
281 */
282 if (! (sarg->xattr & (FH4_NAMEDATTR | FH4_ATTRDIR)))
283 na->type = vt_to_nf4[sarg->vap->va_type];
284 else {
285 /*
286 * FH4 flag was set. Dir type maps to attrdir,
287 * and all other types map to namedattr.
288 */
289 if (sarg->vap->va_type == VDIR)
290 na->type = NF4ATTRDIR;
291 else
292 na->type = NF4NAMEDATTR;
293 }
294 break;
295 case NFS4ATTR_SETIT:
296 /*
297 * read-only attr
298 */
299 error = EINVAL;
300 break;
301 case NFS4ATTR_VERIT:
302 /*
303 * Compare the input type to the object type on server
304 */
305 ASSERT(sarg->vap->va_mask & AT_TYPE);
306 if (sarg->vap->va_type != nf4_to_vt[na->type])
307 error = -1; /* no match */
308 break;
309 case NFS4ATTR_FREEIT:
310 break;
311 }
312 return (error);
313 }
314
315 /* ARGSUSED */
316 static int
317 fattr4_get_fh_expire_type(struct exportinfo *exi, uint32_t *fh_expire_typep)
318 {
319 #ifdef VOLATILE_FH_TEST
320 int ex_flags;
321
322 if (exi == NULL)
323 return (ESTALE);
324 ex_flags = exi->exi_export.ex_flags;
325 if ((ex_flags & (EX_VOLFH | EX_VOLRNM | EX_VOLMIG | EX_NOEXPOPEN))
326 == 0) {
327 *fh_expire_typep = FH4_PERSISTENT;
328 return (0);
329 }
330 *fh_expire_typep = 0;
331
332 if (ex_flags & EX_NOEXPOPEN) {
333 /* file handles should not expire with open - not used */
334 *fh_expire_typep = FH4_NOEXPIRE_WITH_OPEN;
335 }
336 if (ex_flags & EX_VOLFH) {
337 /*
338 * file handles may expire any time - on share here.
339 * If volatile any, no need to check other flags.
340 */
341 *fh_expire_typep |= FH4_VOLATILE_ANY;
342 return (0);
343 }
344 if (ex_flags & EX_VOLRNM) {
345 /* file handles may expire on rename */
346 *fh_expire_typep |= FH4_VOL_RENAME;
347 }
348 if (ex_flags & EX_VOLMIG) {
349 /* file handles may expire on migration - not used */
350 *fh_expire_typep |= FH4_VOL_MIGRATION;
351 }
352 #else /* not VOLATILE_FH_TEST */
353 *fh_expire_typep = FH4_PERSISTENT;
354 #endif /* VOLATILE_FH_TEST */
355
356 return (0);
357 }
358
359 /*
360 * At this point the only volatile filehandles we allow (for test purposes
361 * only) are either fh's that expire when the filesystem is shared (reshared),
362 * fh's that expire on a rename and persistent ones.
363 */
364 /* ARGSUSED */
365 static int
366 rfs4_fattr4_fh_expire_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
367 union nfs4_attr_u *na)
368 {
369 uint32_t fh_expire_type;
370 int error = 0;
371
372 switch (cmd) {
373 case NFS4ATTR_SUPPORTED:
374 if (sarg->op == NFS4ATTR_SETIT)
375 error = EINVAL;
376 break; /* this attr is supported */
377 case NFS4ATTR_GETIT:
378 error = fattr4_get_fh_expire_type(sarg->cs->exi,
379 &na->fh_expire_type);
380 break;
381 case NFS4ATTR_SETIT:
382 /*
383 * read-only attr
384 */
385 error = EINVAL;
386 break;
387 case NFS4ATTR_VERIT:
388 error = fattr4_get_fh_expire_type(sarg->cs->exi,
389 &fh_expire_type);
390 if (!error && (na->fh_expire_type != fh_expire_type))
391 error = -1; /* no match */
392 break;
393 case NFS4ATTR_FREEIT:
394 break;
395 }
396 return (error);
397 }
398
399 static int
400 fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep)
401 {
402 vattr_t vap2[1], *vap = sarg->vap;
403 struct compound_state *cs = sarg->cs;
404 vnode_t *vp = cs->vp;
405 nfsstat4 status;
406 timespec_t vis_change;
407
408 if ((vap->va_mask & AT_CTIME) == 0) {
409 if (sarg->rdattr_error && (vp == NULL)) {
410 return (-1); /* may be okay if rdattr_error */
411 }
412 ASSERT(vp != NULL);
413 vap = vap2;
414 vap->va_mask = AT_CTIME;
415 status = rfs4_vop_getattr(vp, vap, 0, cs->cr);
416 if (status != NFS4_OK)
417 return (geterrno4(status));
418 }
419 NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime);
420
421 if (nfs_visible_change(cs->exi, vp, &vis_change)) {
422 fattr4_change visch;
423 NFS4_SET_FATTR4_CHANGE(visch, vis_change);
424 if (visch > *changep)
425 *changep = visch;
426 }
427
428 return (0);
429 }
430
431 /* ARGSUSED */
432 static int
433 rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
434 union nfs4_attr_u *na)
435 {
436 int error = 0;
437 fattr4_change change;
438 uint_t mask;
439 vattr_t *vap = sarg->vap;
440
441 switch (cmd) {
442 case NFS4ATTR_SUPPORTED:
443 if (sarg->op == NFS4ATTR_SETIT)
444 error = EINVAL;
445 break; /* this attr is supported */
446 case NFS4ATTR_GETIT:
447 error = fattr4_get_change(sarg, &na->change);
448 break;
449 case NFS4ATTR_SETIT:
450 /*
451 * read-only attr
452 */
453 error = EINVAL;
454 break;
455 case NFS4ATTR_VERIT:
456 mask = vap->va_mask;
457 vap->va_mask &= ~AT_CTIME; /* force a VOP_GETATTR */
458 error = fattr4_get_change(sarg, &change);
459 vap->va_mask = mask;
460 if (!error && (na->change != change))
461 error = -1;
462 break;
463 case NFS4ATTR_FREEIT:
464 break;
465 }
466 return (error);
467 }
468
469 /* ARGSUSED */
470 static int
471 rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
472 union nfs4_attr_u *na)
473 {
474 int error = 0;
475
476 switch (cmd) {
477 case NFS4ATTR_SUPPORTED:
478 break; /* this attr is supported */
479 case NFS4ATTR_GETIT:
480 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_SIZE)) {
481 error = -1; /* may be okay if rdattr_error */
482 break;
483 }
484 ASSERT(sarg->vap->va_mask & AT_SIZE);
485 na->size = sarg->vap->va_size;
486 break;
487 case NFS4ATTR_SETIT:
488 ASSERT(sarg->vap->va_mask & AT_SIZE);
489 sarg->vap->va_size = na->size;
490 break;
491 case NFS4ATTR_VERIT:
492 ASSERT(sarg->vap->va_mask & AT_SIZE);
493 if (sarg->vap->va_size != na->size)
494 error = -1; /* no match */
495 break;
496 case NFS4ATTR_FREEIT:
497 break;
498 }
499 return (error);
500 }
501
502 /*
503 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
504 * hard links.
505 */
506 /* ARGSUSED */
507 static int
508 rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
509 union nfs4_attr_u *na)
510 {
511 int error = 0;
512
513 switch (cmd) {
514 case NFS4ATTR_SUPPORTED:
515 if (sarg->op == NFS4ATTR_SETIT)
516 error = EINVAL;
517 break; /* this attr is supported */
518 case NFS4ATTR_GETIT:
519 na->link_support = TRUE;
520 break;
521 case NFS4ATTR_SETIT:
522 /*
523 * read-only attr
524 */
525 error = EINVAL;
526 break;
527 case NFS4ATTR_VERIT:
528 if (!na->link_support)
529 error = -1; /* no match */
530 break;
531 case NFS4ATTR_FREEIT:
532 break;
533 }
534 return (error);
535 }
536
537 /*
538 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
539 * sym links.
540 */
541 /* ARGSUSED */
542 static int
543 rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
544 union nfs4_attr_u *na)
545 {
546 int error = 0;
547
548 switch (cmd) {
549 case NFS4ATTR_SUPPORTED:
550 if (sarg->op == NFS4ATTR_SETIT)
551 error = EINVAL;
552 break; /* this attr is supported */
553 case NFS4ATTR_GETIT:
554 na->symlink_support = TRUE;
555 break;
556 case NFS4ATTR_SETIT:
557 /*
558 * read-only attr
559 */
560 error = EINVAL;
561 break;
562 case NFS4ATTR_VERIT:
563 if (!na->symlink_support)
564 error = -1; /* no match */
565 break;
566 case NFS4ATTR_FREEIT:
567 break;
568 }
569 return (error);
570 }
571
572 /* ARGSUSED */
573 static int
574 rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
575 union nfs4_attr_u *na)
576 {
577 int error = 0;
578 ulong_t val;
579
580 switch (cmd) {
581 case NFS4ATTR_SUPPORTED:
582 if (sarg->op == NFS4ATTR_SETIT)
583 error = EINVAL;
584 break; /* this attr is supported */
585 case NFS4ATTR_GETIT:
586 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
587 error = -1; /* may be okay if rdattr_error */
588 break;
589 }
590 ASSERT(sarg->cs->vp != NULL);
591
592 /*
593 * Solaris xattr model requires that VFS_XATTR is set
594 * in file systems enabled for generic xattr. If VFS_XATTR
595 * not set, no need to call pathconf for _PC_XATTR_EXISTS..
596 *
597 * However the VFS_XATTR flag doesn't indicate sysattr support
598 * so always check for sysattrs and then only do the
599 * _PC_XATTR_EXISTS pathconf if needed.
600 */
601
602 val = 0;
603 error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS,
604 &val, sarg->cs->cr, NULL);
605 if ((error || val == 0) &&
606 sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
607 error = VOP_PATHCONF(sarg->cs->vp,
608 _PC_XATTR_EXISTS, &val, sarg->cs->cr, NULL);
609 if (error)
610 break;
611 }
612 na->named_attr = (val ? TRUE : FALSE);
613 break;
614 case NFS4ATTR_SETIT:
615 /*
616 * read-only attr
617 */
618 error = EINVAL;
619 break;
620 case NFS4ATTR_VERIT:
621 ASSERT(sarg->cs->vp != NULL);
622 if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
623 error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS,
624 &val, sarg->cs->cr, NULL);
625 if (error || val == 0)
626 error = VOP_PATHCONF(sarg->cs->vp,
627 _PC_XATTR_EXISTS, &val,
628 sarg->cs->cr, NULL);
629 if (error)
630 break;
631 } else
632 val = 0;
633 if (na->named_attr != (val ? TRUE : FALSE))
634 error = -1; /* no match */
635 break;
636 case NFS4ATTR_FREEIT:
637 break;
638 }
639 return (error);
640 }
641
642 /* ARGSUSED */
643 static int
644 rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
645 union nfs4_attr_u *na)
646 {
647 int error = 0;
648 int *pmaj = (int *)&na->fsid.major;
649
650 /*
651 * fsid_t is 64bits so it fits completely in fattr4_fsid.major.
652 * fattr4_fsid.minor is always set to 0 since it isn't needed (yet).
653 */
654 switch (cmd) {
655 case NFS4ATTR_SUPPORTED:
656 if (sarg->op == NFS4ATTR_SETIT)
657 error = EINVAL;
658 break; /* this attr is supported */
659 case NFS4ATTR_GETIT:
660 if (sarg->is_referral) {
661 na->fsid.major = 1;
662 na->fsid.minor = 0;
663 } else if (sarg->cs->exi->exi_volatile_dev) {
664 pmaj[0] = sarg->cs->exi->exi_fsid.val[0];
665 pmaj[1] = sarg->cs->exi->exi_fsid.val[1];
666 na->fsid.minor = 0;
667 } else {
668 na->fsid.major = getmajor(sarg->vap->va_fsid);
669 na->fsid.minor = getminor(sarg->vap->va_fsid);
670 }
671 break;
672 case NFS4ATTR_SETIT:
673 error = EINVAL;
674 break;
675 case NFS4ATTR_VERIT:
676 if (sarg->is_referral) {
677 if (na->fsid.major != 1 ||
678 na->fsid.minor != 0)
679 error = -1;
680 } else if (sarg->cs->exi->exi_volatile_dev) {
681 if (pmaj[0] != sarg->cs->exi->exi_fsid.val[0] ||
682 pmaj[1] != sarg->cs->exi->exi_fsid.val[1] ||
683 na->fsid.minor != 0)
684 error = -1;
685 } else {
686 if (na->fsid.major != getmajor(sarg->vap->va_fsid) ||
687 na->fsid.minor != getminor(sarg->vap->va_fsid))
688 error = -1;
689 }
690 break;
691 case NFS4ATTR_FREEIT:
692 break;
693 }
694 return (error);
695 }
696
697 /* ARGSUSED */
698 static int
699 rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
700 union nfs4_attr_u *na)
701 {
702 /*
703 * XXX
704 * For now, we can't support this. Problem of /export, beinging
705 * a file system, /export/a and /export/b shared separately,
706 * and /export/a/l and /export/b/l are ahrd links of each other.
707 */
708 int error = 0;
709
710 switch (cmd) {
711 case NFS4ATTR_SUPPORTED:
712 if (sarg->op == NFS4ATTR_SETIT)
713 error = EINVAL;
714 break; /* this attr is supported */
715 case NFS4ATTR_GETIT:
716 na->unique_handles = FALSE;
717 break;
718 case NFS4ATTR_SETIT:
719 /*
720 * read-only attr
721 */
722 error = EINVAL;
723 break;
724 case NFS4ATTR_VERIT:
725 if (na->unique_handles)
726 error = -1; /* no match */
727 break;
728 case NFS4ATTR_FREEIT:
729 break;
730 }
731 return (error);
732 }
733
734 /* ARGSUSED */
735 static int
736 rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
737 union nfs4_attr_u *na)
738 {
739 int error = 0;
740
741 switch (cmd) {
742 case NFS4ATTR_SUPPORTED:
743 if (sarg->op == NFS4ATTR_SETIT)
744 error = EINVAL;
745 break; /* this attr is supported */
746 case NFS4ATTR_GETIT:
747 na->lease_time = rfs4_lease_time;
748 break;
749 case NFS4ATTR_SETIT:
750 /*
751 * read-only attr
752 */
753 error = EINVAL;
754 break;
755 case NFS4ATTR_VERIT:
756 if (na->lease_time != rfs4_lease_time)
757 error = -1; /* no match */
758 break;
759 case NFS4ATTR_FREEIT:
760 break;
761 }
762 return (error);
763 }
764
765 /* ARGSUSED */
766 static int
767 rfs4_fattr4_rdattr_error(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
768 union nfs4_attr_u *na)
769 {
770 int error = 0;
771
772 switch (cmd) {
773 case NFS4ATTR_SUPPORTED:
774 if ((sarg->op == NFS4ATTR_SETIT) ||
775 (sarg->op == NFS4ATTR_VERIT))
776 error = EINVAL;
777 break; /* this attr is supported */
778 case NFS4ATTR_GETIT:
779 ASSERT(sarg->rdattr_error_req);
780 na->rdattr_error = sarg->rdattr_error;
781 break;
782 case NFS4ATTR_SETIT:
783 case NFS4ATTR_VERIT:
784 /*
785 * read-only attr
786 */
787 error = EINVAL;
788 break;
789 case NFS4ATTR_FREEIT:
790 break;
791 }
792 return (error);
793 }
794
795 /*
796 * Server side compare of a filehandle from the wire to a native
797 * server filehandle.
798 */
799 static int
800 rfs4fhcmp(nfs_fh4 *wirefh, nfs_fh4 *srvfh)
801 {
802 nfs_fh4_fmt_t fh;
803
804 ASSERT(IS_P2ALIGNED(wirefh->nfs_fh4_val, sizeof (uint32_t)));
805
806 bzero(&fh, sizeof (nfs_fh4_fmt_t));
807 if (!xdr_inline_decode_nfs_fh4((uint32_t *)wirefh->nfs_fh4_val, &fh,
808 wirefh->nfs_fh4_len))
809 return (1);
810
811 return (bcmp(srvfh->nfs_fh4_val, &fh, srvfh->nfs_fh4_len));
812 }
813
814 /* ARGSUSED */
815 static int
816 rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
817 union nfs4_attr_u *na)
818 {
819 nfs_fh4 *fh;
820
821 switch (cmd) {
822 case NFS4ATTR_SUPPORTED:
823 if (sarg->op == NFS4ATTR_SETIT)
824 return (EINVAL);
825 return (0); /* this attr is supported */
826 case NFS4ATTR_GETIT:
827 /*
828 * If sarg->cs->fh is all zeros then should makefh a new
829 * one, otherwise, copy that one over.
830 */
831 fh = &sarg->cs->fh;
832 if (sarg->cs->fh.nfs_fh4_len == 0) {
833 if (sarg->rdattr_error && (sarg->cs->vp == NULL))
834 return (-1); /* okay if rdattr_error */
835 ASSERT(sarg->cs->vp != NULL);
836 na->filehandle.nfs_fh4_val =
837 kmem_alloc(NFS_FH4_LEN, KM_SLEEP);
838 return (makefh4(&na->filehandle, sarg->cs->vp,
839 sarg->cs->exi));
840 }
841 na->filehandle.nfs_fh4_val =
842 kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
843 nfs_fh4_copy(fh, &na->filehandle);
844 return (0);
845 case NFS4ATTR_SETIT:
846 /*
847 * read-only attr
848 */
849 return (EINVAL);
850 case NFS4ATTR_VERIT:
851 /*
852 * A verify of a filehandle will have the client sending
853 * the raw format which needs to be compared to the
854 * native format.
855 */
856 if (rfs4fhcmp(&na->filehandle, &sarg->cs->fh) == 1)
857 return (-1); /* no match */
858 return (0);
859 case NFS4ATTR_FREEIT:
860 if (sarg->op != NFS4ATTR_GETIT)
861 return (0);
862 if (na->filehandle.nfs_fh4_val == NULL)
863 return (0);
864 kmem_free(na->filehandle.nfs_fh4_val,
865 na->filehandle.nfs_fh4_len);
866 na->filehandle.nfs_fh4_val = NULL;
867 na->filehandle.nfs_fh4_len = 0;
868 return (0);
869 }
870 return (0);
871 }
872
873 /*
874 * Recommended attributes
875 */
876
877 /* ARGSUSED */
878 static int
879 rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
880 union nfs4_attr_u *na)
881 {
882 int error = 0;
883 vsecattr_t vs_native, vs_ace4;
884 ulong_t whichacl;
885 nfsstat4 status;
886 vattr_t va, *vap = sarg->vap;
887 vnode_t *vp = sarg->cs->vp;
888
889 if (RFS4_MANDATTR_ONLY)
890 return (ENOTSUP);
891
892 switch (cmd) {
893 case NFS4ATTR_SUPPORTED:
894 break;
895
896 case NFS4ATTR_VERIT:
897 case NFS4ATTR_GETIT:
898 if (sarg->rdattr_error && (vp == NULL)) {
899 return (-1);
900 }
901 ASSERT(vp != NULL);
902 bzero(&vs_native, sizeof (vs_native));
903
904 /* see which ACLs fs supports */
905 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
906 sarg->cs->cr, NULL);
907 if (error != 0) {
908 /*
909 * If we got an error, then the filesystem
910 * likely does not understand the _PC_ACL_ENABLED
911 * pathconf. In this case, we fall back to trying
912 * POSIX-draft (aka UFS-style) ACLs, since that's
913 * the behavior used by earlier version of NFS.
914 */
915 error = 0;
916 whichacl = _ACL_ACLENT_ENABLED;
917 }
918
919 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
920 /*
921 * If the file system supports neither ACE nor
922 * ACLENT ACLs we will fall back to UFS-style ACLs
923 * like we did above if there was an error upon
924 * calling VOP_PATHCONF.
925 *
926 * ACE and ACLENT type ACLs are the only interfaces
927 * supported thus far. If any other bits are set on
928 * 'whichacl' upon return from VOP_PATHCONF, we will
929 * ignore them.
930 */
931 whichacl = _ACL_ACLENT_ENABLED;
932 }
933
934 if (whichacl & _ACL_ACE_ENABLED)
935 vs_native.vsa_mask = VSA_ACE | VSA_ACECNT;
936 else if (whichacl & _ACL_ACLENT_ENABLED)
937 vs_native.vsa_mask = VSA_ACL | VSA_ACLCNT |
938 VSA_DFACL | VSA_DFACLCNT;
939
940 if (error != 0)
941 break;
942
943 /* get the ACL, and translate it into nfsace4 style */
944 error = VOP_GETSECATTR(vp, &vs_native,
945 0, sarg->cs->cr, NULL);
946 if (error != 0)
947 break;
948 if (whichacl & _ACL_ACE_ENABLED) {
949 error = vs_acet_to_ace4(&vs_native, &vs_ace4, TRUE);
950 vs_acet_destroy(&vs_native);
951 } else {
952 error = vs_aent_to_ace4(&vs_native, &vs_ace4,
953 vp->v_type == VDIR, TRUE);
954 vs_aent_destroy(&vs_native);
955 }
956 if (error != 0)
957 break;
958
959 if (cmd == NFS4ATTR_GETIT) {
960 na->acl.fattr4_acl_len = vs_ace4.vsa_aclcnt;
961 /* see case NFS4ATTR_FREEIT for this being freed */
962 na->acl.fattr4_acl_val = vs_ace4.vsa_aclentp;
963 } else {
964 if (na->acl.fattr4_acl_len != vs_ace4.vsa_aclcnt)
965 error = -1; /* no match */
966 else if (ln_ace4_cmp(na->acl.fattr4_acl_val,
967 vs_ace4.vsa_aclentp,
968 vs_ace4.vsa_aclcnt) != 0)
969 error = -1; /* no match */
970 }
971
972 break;
973
974 case NFS4ATTR_SETIT:
975 if (sarg->rdattr_error && (vp == NULL)) {
976 return (-1);
977 }
978 ASSERT(vp != NULL);
979
980 /* prepare vs_ace4 from fattr4 data */
981 bzero(&vs_ace4, sizeof (vs_ace4));
982 vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
983 vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
984 vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
985 vs_ace4.vsa_aclentsz = vs_ace4.vsa_aclcnt * sizeof (ace_t);
986 /* make sure we have correct owner/group */
987 if ((vap->va_mask & (AT_UID | AT_GID)) !=
988 (AT_UID | AT_GID)) {
989 vap = &va;
990 vap->va_mask = AT_UID | AT_GID;
991 status = rfs4_vop_getattr(vp,
992 vap, 0, sarg->cs->cr);
993 if (status != NFS4_OK)
994 return (geterrno4(status));
995 }
996
997 /* see which ACLs the fs supports */
998 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
999 sarg->cs->cr, NULL);
1000 if (error != 0) {
1001 /*
1002 * If we got an error, then the filesystem
1003 * likely does not understand the _PC_ACL_ENABLED
1004 * pathconf. In this case, we fall back to trying
1005 * POSIX-draft (aka UFS-style) ACLs, since that's
1006 * the behavior used by earlier version of NFS.
1007 */
1008 error = 0;
1009 whichacl = _ACL_ACLENT_ENABLED;
1010 }
1011
1012 if (!(whichacl & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED))) {
1013 /*
1014 * If the file system supports neither ACE nor
1015 * ACLENT ACLs we will fall back to UFS-style ACLs
1016 * like we did above if there was an error upon
1017 * calling VOP_PATHCONF.
1018 *
1019 * ACE and ACLENT type ACLs are the only interfaces
1020 * supported thus far. If any other bits are set on
1021 * 'whichacl' upon return from VOP_PATHCONF, we will
1022 * ignore them.
1023 */
1024 whichacl = _ACL_ACLENT_ENABLED;
1025 }
1026
1027 if (whichacl & _ACL_ACE_ENABLED) {
1028 error = vs_ace4_to_acet(&vs_ace4, &vs_native,
1029 vap->va_uid, vap->va_gid, TRUE);
1030 if (error != 0)
1031 break;
1032 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
1033 error = VOP_SETSECATTR(vp, &vs_native,
1034 0, sarg->cs->cr, NULL);
1035 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
1036 vs_acet_destroy(&vs_native);
1037 } else if (whichacl & _ACL_ACLENT_ENABLED) {
1038 error = vs_ace4_to_aent(&vs_ace4, &vs_native,
1039 vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE);
1040 if (error != 0)
1041 break;
1042 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
1043 error = VOP_SETSECATTR(vp, &vs_native,
1044 0, sarg->cs->cr, NULL);
1045 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
1046 vs_aent_destroy(&vs_native);
1047 }
1048 break;
1049
1050 case NFS4ATTR_FREEIT:
1051 if (sarg->op == NFS4ATTR_GETIT) {
1052 vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
1053 vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
1054 vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
1055 vs_ace4_destroy(&vs_ace4);
1056 }
1057 break;
1058 }
1059
1060 return (error);
1061 }
1062
1063 /* ARGSUSED */
1064 static int
1065 rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1066 union nfs4_attr_u *na)
1067 {
1068 int error = 0;
1069
1070 if (RFS4_MANDATTR_ONLY)
1071 return (ENOTSUP);
1072
1073 switch (cmd) {
1074 case NFS4ATTR_SUPPORTED:
1075 if (sarg->op == NFS4ATTR_SETIT)
1076 error = EINVAL;
1077 break; /* supported */
1078 case NFS4ATTR_GETIT:
1079 na->aclsupport = ACL4_SUPPORT_ALLOW_ACL |
1080 ACL4_SUPPORT_DENY_ACL;
1081 break;
1082 case NFS4ATTR_SETIT:
1083 error = EINVAL;
1084 break;
1085 case NFS4ATTR_VERIT:
1086 if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL |
1087 ACL4_SUPPORT_DENY_ACL))
1088 error = -1; /* no match */
1089 break;
1090 }
1091
1092 return (error);
1093 }
1094
1095 /* ARGSUSED */
1096 static int
1097 rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1098 union nfs4_attr_u *na)
1099 {
1100 return (ENOTSUP);
1101 }
1102
1103 /* ARGSUSED */
1104 static int
1105 rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1106 union nfs4_attr_u *na)
1107 {
1108 int error = 0;
1109
1110 if (RFS4_MANDATTR_ONLY)
1111 return (ENOTSUP);
1112
1113 switch (cmd) {
1114 case NFS4ATTR_SUPPORTED:
1115 if (sarg->op == NFS4ATTR_SETIT)
1116 error = EINVAL;
1117 break; /* this attr is supported */
1118 case NFS4ATTR_GETIT:
1119 na->cansettime = TRUE;
1120 break;
1121 case NFS4ATTR_SETIT:
1122 /*
1123 * read-only attr
1124 */
1125 error = EINVAL;
1126 break;
1127 case NFS4ATTR_VERIT:
1128 if (!na->cansettime)
1129 error = -1; /* no match */
1130 break;
1131 case NFS4ATTR_FREEIT:
1132 break;
1133 }
1134 return (error);
1135 }
1136
1137 /*
1138 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
1139 * case insensitive.
1140 */
1141 /* ARGSUSED */
1142 static int
1143 rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1144 union nfs4_attr_u *na)
1145 {
1146 int error = 0;
1147
1148 if (RFS4_MANDATTR_ONLY)
1149 return (ENOTSUP);
1150
1151 switch (cmd) {
1152 case NFS4ATTR_SUPPORTED:
1153 if (sarg->op == NFS4ATTR_SETIT)
1154 error = EINVAL;
1155 break; /* this attr is supported */
1156 case NFS4ATTR_GETIT:
1157 na->case_insensitive = FALSE;
1158 break;
1159 case NFS4ATTR_SETIT:
1160 /*
1161 * read-only attr
1162 */
1163 error = EINVAL;
1164 break;
1165 case NFS4ATTR_VERIT:
1166 if (!na->case_insensitive)
1167 error = -1; /* no match */
1168 break;
1169 case NFS4ATTR_FREEIT:
1170 break;
1171 }
1172 return (error);
1173 }
1174
1175 /* ARGSUSED */
1176 static int
1177 rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1178 union nfs4_attr_u *na)
1179 {
1180 int error = 0;
1181
1182 if (RFS4_MANDATTR_ONLY)
1183 return (ENOTSUP);
1184
1185 switch (cmd) {
1186 case NFS4ATTR_SUPPORTED:
1187 if (sarg->op == NFS4ATTR_SETIT)
1188 error = EINVAL;
1189 break; /* this attr is supported */
1190 case NFS4ATTR_GETIT:
1191 na->case_preserving = TRUE;
1192 break;
1193 case NFS4ATTR_SETIT:
1194 /*
1195 * read-only attr
1196 */
1197 error = EINVAL;
1198 break;
1199 case NFS4ATTR_VERIT:
1200 if (!na->case_preserving)
1201 error = -1; /* no match */
1202 break;
1203 case NFS4ATTR_FREEIT:
1204 break;
1205 }
1206 return (error);
1207 }
1208
1209 /* fattr4_chown_restricted should reall be fattr4_chown_allowed */
1210 /* ARGSUSED */
1211 static int
1212 rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1213 union nfs4_attr_u *na)
1214 {
1215 int error = 0;
1216 ulong_t val;
1217
1218 if (RFS4_MANDATTR_ONLY)
1219 return (ENOTSUP);
1220
1221 switch (cmd) {
1222 case NFS4ATTR_SUPPORTED:
1223 if (sarg->op == NFS4ATTR_SETIT)
1224 error = EINVAL;
1225 break; /* this attr is supported */
1226 case NFS4ATTR_GETIT:
1227 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1228 error = -1; /* may be okay if rdattr_error */
1229 break;
1230 }
1231 ASSERT(sarg->cs->vp != NULL);
1232 error = VOP_PATHCONF(sarg->cs->vp,
1233 _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
1234 if (error)
1235 break;
1236
1237 na->chown_restricted = (val == 1);
1238 break;
1239 case NFS4ATTR_SETIT:
1240 /*
1241 * read-only attr
1242 */
1243 error = EINVAL;
1244 break;
1245 case NFS4ATTR_VERIT:
1246 ASSERT(sarg->cs->vp != NULL);
1247 error = VOP_PATHCONF(sarg->cs->vp,
1248 _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
1249 if (error)
1250 break;
1251 if (na->chown_restricted != (val == 1))
1252 error = -1; /* no match */
1253 break;
1254 case NFS4ATTR_FREEIT:
1255 break;
1256 }
1257 return (error);
1258 }
1259
1260 /* ARGSUSED */
1261 static int
1262 rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1263 union nfs4_attr_u *na)
1264 {
1265 int error = 0;
1266
1267 if (RFS4_MANDATTR_ONLY)
1268 return (ENOTSUP);
1269
1270 switch (cmd) {
1271 case NFS4ATTR_SUPPORTED:
1272 if (sarg->op == NFS4ATTR_SETIT)
1273 error = EINVAL;
1274 break; /* this attr is supported */
1275 case NFS4ATTR_GETIT:
1276 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) {
1277 error = -1; /* may be okay if rdattr_error */
1278 break;
1279 }
1280 ASSERT(sarg->vap->va_mask & AT_NODEID);
1281 na->fileid = sarg->vap->va_nodeid;
1282 break;
1283 case NFS4ATTR_SETIT:
1284 /*
1285 * read-only attr
1286 */
1287 error = EINVAL;
1288 break;
1289 case NFS4ATTR_VERIT:
1290 ASSERT(sarg->vap->va_mask & AT_NODEID);
1291 if (sarg->vap->va_nodeid != na->fileid)
1292 error = -1; /* no match */
1293 break;
1294 case NFS4ATTR_FREEIT:
1295 break;
1296 }
1297 return (error);
1298 }
1299
1300 /* ARGSUSED */
1301 static int
1302 rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
1303 {
1304 int error = 0;
1305 vattr_t *vap, va;
1306 vnode_t *stubvp = NULL, *vp;
1307
1308 vp = sarg->cs->vp;
1309 sarg->mntdfid_set = FALSE;
1310
1311 /*
1312 * VROOT object or zone's root, must untraverse.
1313 *
1314 * NOTE: Not doing reality checks on curzone vs. compound
1315 * state vnode because it will mismatch once at initialization
1316 * if a non-global-zone triggers the module load, BUT in that case
1317 * the vp is literally "/" which has VROOT set.
1318 */
1319 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
1320
1321 /* extra hold for vp since untraverse might rele */
1322 VN_HOLD(vp);
1323 stubvp = untraverse(vp);
1324
1325 /*
1326 * If vp/stubvp are same, we must be at system-or-zone
1327 * root because untraverse returned same vp
1328 * for a VROOT object. sarg->vap was setup
1329 * before we got here, so there's no need to do
1330 * another getattr -- just use the one in sarg.
1331 */
1332 if (VN_CMP(vp, stubvp)) {
1333 ASSERT(VN_IS_CURZONEROOT(vp));
1334 vap = sarg->vap;
1335 } else {
1336 va.va_mask = AT_NODEID;
1337 vap = &va;
1338 error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr);
1339 }
1340
1341 /*
1342 * Done with stub, time to rele. If vp and stubvp
1343 * were the same, then we need to rele either vp or
1344 * stubvp. If they weren't the same, then untraverse()
1345 * already took case of the extra hold on vp, and only
1346 * the stub needs to be rele'd. Both cases are handled
1347 * by unconditionally rele'ing the stub.
1348 */
1349 VN_RELE(stubvp);
1350 } else
1351 vap = sarg->vap;
1352
1353 /*
1354 * At this point, vap should contain "correct" AT_NODEID --
1355 * (for V_ROOT case, nodeid of stub, for non-VROOT case,
1356 * nodeid of vp). If error or AT_NODEID not available, then
1357 * make the obligatory (yet mysterious) rdattr_error
1358 * check that is so common in the attr code.
1359 */
1360 if (!error && (vap->va_mask & AT_NODEID)) {
1361 sarg->mounted_on_fileid = vap->va_nodeid;
1362 sarg->mntdfid_set = TRUE;
1363 } else if (sarg->rdattr_error)
1364 error = -1;
1365
1366 /*
1367 * error describes these cases:
1368 * 0 : success
1369 * -1: failure due to previous attr processing error (rddir only).
1370 * * : new attr failure (if rddir, caller will set rdattr_error)
1371 */
1372 return (error);
1373 }
1374
1375 /* ARGSUSED */
1376 static int
1377 rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
1378 struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
1379 {
1380 int error = 0;
1381
1382 if (RFS4_MANDATTR_ONLY)
1383 return (ENOTSUP);
1384
1385 switch (cmd) {
1386 case NFS4ATTR_SUPPORTED:
1387 if (sarg->op == NFS4ATTR_SETIT)
1388 error = EINVAL;
1389 break; /* this attr is supported */
1390 case NFS4ATTR_GETIT:
1391 case NFS4ATTR_VERIT:
1392 if (!sarg->mntdfid_set)
1393 error = rfs4_get_mntdfileid(cmd, sarg);
1394
1395 if (!error && sarg->mntdfid_set) {
1396 if (cmd == NFS4ATTR_GETIT)
1397 na->mounted_on_fileid = sarg->mounted_on_fileid;
1398 else
1399 if (na->mounted_on_fileid !=
1400 sarg->mounted_on_fileid)
1401 error = -1;
1402 }
1403 break;
1404 case NFS4ATTR_SETIT:
1405 /* read-only attr */
1406 error = EINVAL;
1407 break;
1408 case NFS4ATTR_FREEIT:
1409 break;
1410 }
1411 return (error);
1412 }
1413
1414 /* ARGSUSED */
1415 static int
1416 rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1417 union nfs4_attr_u *na)
1418 {
1419 int error = 0;
1420
1421 if (RFS4_MANDATTR_ONLY)
1422 return (ENOTSUP);
1423
1424 switch (cmd) {
1425 case NFS4ATTR_SUPPORTED:
1426 if (sarg->op == NFS4ATTR_SETIT)
1427 error = EINVAL;
1428 break; /* this attr is supported */
1429 case NFS4ATTR_GETIT:
1430 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1431 error = -1; /* may be okay if rdattr_error */
1432 break;
1433 }
1434 ASSERT(sarg->sbp != NULL);
1435 na->files_avail = sarg->sbp->f_favail;
1436 break;
1437 case NFS4ATTR_SETIT:
1438 /*
1439 * read-only attr
1440 */
1441 error = EINVAL;
1442 break;
1443 case NFS4ATTR_VERIT:
1444 ASSERT(sarg->sbp != NULL);
1445 if (sarg->sbp->f_favail != na->files_avail)
1446 error = -1; /* no match */
1447 break;
1448 case NFS4ATTR_FREEIT:
1449 break;
1450 }
1451 return (error);
1452 }
1453
1454 /* ARGSUSED */
1455 static int
1456 rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1457 union nfs4_attr_u *na)
1458 {
1459 int error = 0;
1460
1461 if (RFS4_MANDATTR_ONLY)
1462 return (ENOTSUP);
1463
1464 switch (cmd) {
1465 case NFS4ATTR_SUPPORTED:
1466 if (sarg->op == NFS4ATTR_SETIT)
1467 error = EINVAL;
1468 break; /* this attr is supported */
1469 case NFS4ATTR_GETIT:
1470 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1471 error = -1; /* may be okay if rdattr_error */
1472 break;
1473 }
1474 ASSERT(sarg->sbp != NULL);
1475 na->files_free = sarg->sbp->f_ffree;
1476 break;
1477 case NFS4ATTR_SETIT:
1478 /*
1479 * read-only attr
1480 */
1481 error = EINVAL;
1482 break;
1483 case NFS4ATTR_VERIT:
1484 ASSERT(sarg->sbp != NULL);
1485 if (sarg->sbp->f_ffree != na->files_free)
1486 error = -1; /* no match */
1487 break;
1488 case NFS4ATTR_FREEIT:
1489 break;
1490 }
1491 return (error);
1492 }
1493
1494 /* ARGSUSED */
1495 static int
1496 rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1497 union nfs4_attr_u *na)
1498 {
1499 int error = 0;
1500
1501 if (RFS4_MANDATTR_ONLY)
1502 return (ENOTSUP);
1503
1504 switch (cmd) {
1505 case NFS4ATTR_SUPPORTED:
1506 if (sarg->op == NFS4ATTR_SETIT)
1507 error = EINVAL;
1508 break; /* this attr is supported */
1509 case NFS4ATTR_GETIT:
1510 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1511 error = -1; /* may be okay if rdattr_error */
1512 break;
1513 }
1514 ASSERT(sarg->sbp != NULL);
1515 na->files_total = sarg->sbp->f_files;
1516 break;
1517 case NFS4ATTR_SETIT:
1518 /*
1519 * read-only attr
1520 */
1521 error = EINVAL;
1522 break;
1523 case NFS4ATTR_VERIT:
1524 ASSERT(sarg->sbp != NULL);
1525 if (sarg->sbp->f_files != na->files_total)
1526 error = -1; /* no match */
1527 break;
1528 case NFS4ATTR_FREEIT:
1529 break;
1530 }
1531 return (error);
1532 }
1533
1534 static void
1535 rfs4_free_pathname4(pathname4 *pn4)
1536 {
1537 int i, len;
1538 utf8string *utf8s;
1539
1540 if (pn4 == NULL || (len = pn4->pathname4_len) == 0 ||
1541 (utf8s = pn4->pathname4_val) == NULL)
1542 return;
1543
1544 for (i = 0; i < len; i++, utf8s++) {
1545 if (utf8s->utf8string_val == NULL ||
1546 utf8s->utf8string_len == 0)
1547 continue;
1548
1549 kmem_free(utf8s->utf8string_val, utf8s->utf8string_len);
1550 utf8s->utf8string_val = NULL;
1551 }
1552
1553 kmem_free(pn4->pathname4_val,
1554 sizeof (utf8string) * pn4->pathname4_len);
1555 pn4->pathname4_val = 0;
1556 }
1557
1558 static void
1559 rfs4_free_fs_location4(fs_location4 *fsl4)
1560 {
1561 if (fsl4 == NULL)
1562 return;
1563
1564 rfs4_free_pathname4((pathname4 *)&fsl4->server_len);
1565 rfs4_free_pathname4(&fsl4->rootpath);
1566 }
1567
1568 void
1569 rfs4_free_fs_locations4(fs_locations4 *fsls4)
1570 {
1571 int i, len;
1572 fs_location4 *fsl4;
1573
1574 if (fsls4 == NULL)
1575 return;
1576
1577 /* free fs_root */
1578 rfs4_free_pathname4(&fsls4->fs_root);
1579
1580 if ((len = fsls4->locations_len) == 0 ||
1581 (fsl4 = fsls4->locations_val) == NULL)
1582 return;
1583
1584 /* free fs_location4 */
1585 for (i = 0; i < len; i++) {
1586 rfs4_free_fs_location4(fsl4);
1587 fsl4++;
1588 }
1589
1590 kmem_free(fsls4->locations_val, sizeof (fs_location4) * len);
1591 fsls4->locations_val = NULL;
1592 }
1593
1594 /* ARGSUSED */
1595 static int
1596 rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1597 union nfs4_attr_u *na)
1598 {
1599 int error = 0;
1600 fs_locations4 *fsl;
1601
1602 if (RFS4_MANDATTR_ONLY)
1603 return (ENOTSUP);
1604
1605 switch (cmd) {
1606 case NFS4ATTR_SUPPORTED:
1607 if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
1608 error = EINVAL;
1609 break; /* this attr is supported */
1610
1611 case NFS4ATTR_GETIT:
1612 fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
1613 if (fsl == NULL)
1614 (void) memset(&(na->fs_locations), 0,
1615 sizeof (fs_locations4));
1616 else {
1617 na->fs_locations = *fsl;
1618 kmem_free(fsl, sizeof (fs_locations4));
1619 }
1620 global_svstat_ptr[4][NFS_REFERRALS].value.ui64++;
1621 break;
1622
1623 case NFS4ATTR_FREEIT:
1624 if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
1625 error = EINVAL;
1626 rfs4_free_fs_locations4(&na->fs_locations);
1627 break;
1628
1629 case NFS4ATTR_SETIT:
1630 case NFS4ATTR_VERIT:
1631 /*
1632 * read-only attr
1633 */
1634 error = EINVAL;
1635 break;
1636 }
1637 return (error);
1638 }
1639
1640 /* ARGSUSED */
1641 static int
1642 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1643 union nfs4_attr_u *na)
1644 {
1645 return (ENOTSUP);
1646 }
1647
1648 /* ARGSUSED */
1649 static int
1650 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1651 union nfs4_attr_u *na)
1652 {
1653 int error = 0;
1654
1655 if (RFS4_MANDATTR_ONLY)
1656 return (ENOTSUP);
1657
1658 switch (cmd) {
1659 case NFS4ATTR_SUPPORTED:
1660 if (sarg->op == NFS4ATTR_SETIT)
1661 error = EINVAL;
1662 break; /* this attr is supported */
1663 case NFS4ATTR_GETIT:
1664 na->homogeneous = TRUE; /* XXX - need a VOP extension */
1665 break;
1666 case NFS4ATTR_SETIT:
1667 /*
1668 * read-only attr
1669 */
1670 error = EINVAL;
1671 break;
1672 case NFS4ATTR_VERIT:
1673 if (!na->homogeneous)
1674 error = -1; /* no match */
1675 break;
1676 case NFS4ATTR_FREEIT:
1677 break;
1678 }
1679 return (error);
1680 }
1681
1682 /* ARGSUSED */
1683 static int
1684 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1685 union nfs4_attr_u *na)
1686 {
1687 int error = 0;
1688 ulong_t val;
1689 fattr4_maxfilesize maxfilesize;
1690
1691 if (RFS4_MANDATTR_ONLY)
1692 return (ENOTSUP);
1693
1694 switch (cmd) {
1695 case NFS4ATTR_SUPPORTED:
1696 if (sarg->op == NFS4ATTR_SETIT)
1697 error = EINVAL;
1698 break; /* this attr is supported */
1699 case NFS4ATTR_GETIT:
1700 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1701 error = -1; /* may be okay if rdattr_error */
1702 break;
1703 }
1704 ASSERT(sarg->cs->vp != NULL);
1705 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1706 sarg->cs->cr, NULL);
1707 if (error)
1708 break;
1709
1710 /*
1711 * If the underlying file system does not support
1712 * _PC_FILESIZEBITS, return a reasonable default. Note that
1713 * error code on VOP_PATHCONF will be 0, even if the underlying
1714 * file system does not support _PC_FILESIZEBITS.
1715 */
1716 if (val == (ulong_t)-1) {
1717 na->maxfilesize = MAXOFF32_T;
1718 } else {
1719 if (val >= (sizeof (uint64_t) * 8))
1720 na->maxfilesize = INT64_MAX;
1721 else
1722 na->maxfilesize = ((1LL << (val - 1)) - 1);
1723 }
1724 break;
1725 case NFS4ATTR_SETIT:
1726 /*
1727 * read-only attr
1728 */
1729 error = EINVAL;
1730 break;
1731 case NFS4ATTR_VERIT:
1732 ASSERT(sarg->cs->vp != NULL);
1733 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1734 sarg->cs->cr, NULL);
1735 if (error)
1736 break;
1737 /*
1738 * If the underlying file system does not support
1739 * _PC_FILESIZEBITS, return a reasonable default. Note that
1740 * error code on VOP_PATHCONF will be 0, even if the underlying
1741 * file system does not support _PC_FILESIZEBITS.
1742 */
1743 if (val == (ulong_t)-1) {
1744 maxfilesize = MAXOFF32_T;
1745 } else {
1746 if (val >= (sizeof (uint64_t) * 8))
1747 maxfilesize = INT64_MAX;
1748 else
1749 maxfilesize = ((1LL << (val - 1)) - 1);
1750 }
1751 if (na->maxfilesize != maxfilesize)
1752 error = -1; /* no match */
1753 break;
1754 case NFS4ATTR_FREEIT:
1755 break;
1756 }
1757 return (error);
1758 }
1759
1760 /* ARGSUSED */
1761 static int
1762 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1763 union nfs4_attr_u *na)
1764 {
1765 int error = 0;
1766 ulong_t val;
1767
1768 if (RFS4_MANDATTR_ONLY)
1769 return (ENOTSUP);
1770
1771 switch (cmd) {
1772 case NFS4ATTR_SUPPORTED:
1773 if (sarg->op == NFS4ATTR_SETIT)
1774 error = EINVAL;
1775 break; /* this attr is supported */
1776 case NFS4ATTR_GETIT:
1777 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1778 error = -1; /* may be okay if rdattr_error */
1779 break;
1780 }
1781 ASSERT(sarg->cs->vp != NULL);
1782 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1783 sarg->cs->cr, NULL);
1784 if (error == 0) {
1785 na->maxlink = val;
1786 }
1787 break;
1788 case NFS4ATTR_SETIT:
1789 /*
1790 * read-only attr
1791 */
1792 error = EINVAL;
1793 break;
1794 case NFS4ATTR_VERIT:
1795 ASSERT(sarg->cs->vp != NULL);
1796 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1797 sarg->cs->cr, NULL);
1798 if (!error && (na->maxlink != (uint32_t)val))
1799 error = -1; /* no match */
1800 break;
1801 case NFS4ATTR_FREEIT:
1802 break;
1803 }
1804 return (error);
1805 }
1806
1807 /* ARGSUSED */
1808 static int
1809 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1810 union nfs4_attr_u *na)
1811 {
1812 int error = 0;
1813 ulong_t val;
1814
1815 if (RFS4_MANDATTR_ONLY)
1816 return (ENOTSUP);
1817
1818 switch (cmd) {
1819 case NFS4ATTR_SUPPORTED:
1820 if (sarg->op == NFS4ATTR_SETIT)
1821 error = EINVAL;
1822 break; /* this attr is supported */
1823 case NFS4ATTR_GETIT:
1824 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1825 error = -1; /* may be okay if rdattr_error */
1826 break;
1827 }
1828 ASSERT(sarg->cs->vp != NULL);
1829 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1830 sarg->cs->cr, NULL);
1831 if (error == 0) {
1832 na->maxname = val;
1833 }
1834 break;
1835 case NFS4ATTR_SETIT:
1836 /*
1837 * read-only attr
1838 */
1839 error = EINVAL;
1840 break;
1841 case NFS4ATTR_VERIT:
1842 ASSERT(sarg->cs->vp != NULL);
1843 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1844 sarg->cs->cr, NULL);
1845 if (!error && (na->maxname != val))
1846 error = -1; /* no match */
1847 break;
1848 case NFS4ATTR_FREEIT:
1849 break;
1850 }
1851 return (error);
1852 }
1853
1854 /* ARGSUSED */
1855 static int
1856 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1857 union nfs4_attr_u *na)
1858 {
1859 int error = 0;
1860
1861 if (RFS4_MANDATTR_ONLY)
1862 return (ENOTSUP);
1863
1864 switch (cmd) {
1865 case NFS4ATTR_SUPPORTED:
1866 if (sarg->op == NFS4ATTR_SETIT)
1867 error = EINVAL;
1868 break; /* this attr is supported */
1869 case NFS4ATTR_GETIT:
1870 na->maxread = rfs4_tsize(sarg->cs->req);
1871 break;
1872 case NFS4ATTR_SETIT:
1873 /*
1874 * read-only attr
1875 */
1876 error = EINVAL;
1877 break;
1878 case NFS4ATTR_VERIT:
1879 if (na->maxread != rfs4_tsize(sarg->cs->req))
1880 error = -1; /* no match */
1881 break;
1882 case NFS4ATTR_FREEIT:
1883 break;
1884 }
1885 return (error);
1886 }
1887
1888 /* ARGSUSED */
1889 static int
1890 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1891 union nfs4_attr_u *na)
1892 {
1893 int error = 0;
1894
1895 if (RFS4_MANDATTR_ONLY)
1896 return (ENOTSUP);
1897
1898 switch (cmd) {
1899 case NFS4ATTR_SUPPORTED:
1900 if (sarg->op == NFS4ATTR_SETIT)
1901 error = EINVAL;
1902 break; /* this attr is supported */
1903 case NFS4ATTR_GETIT:
1904 na->maxwrite = rfs4_tsize(sarg->cs->req);
1905 break;
1906 case NFS4ATTR_SETIT:
1907 /*
1908 * read-only attr
1909 */
1910 error = EINVAL;
1911 break;
1912 case NFS4ATTR_VERIT:
1913 if (na->maxwrite != rfs4_tsize(sarg->cs->req))
1914 error = -1; /* no match */
1915 break;
1916 case NFS4ATTR_FREEIT:
1917 break;
1918 }
1919 return (error);
1920 }
1921
1922 /* ARGSUSED */
1923 static int
1924 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1925 union nfs4_attr_u *na)
1926 {
1927 return (ENOTSUP);
1928 }
1929
1930 /* ARGSUSED */
1931 static int
1932 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1933 union nfs4_attr_u *na)
1934 {
1935 int error = 0;
1936
1937 if (RFS4_MANDATTR_ONLY)
1938 return (ENOTSUP);
1939
1940 switch (cmd) {
1941 case NFS4ATTR_SUPPORTED:
1942 break; /* this attr is supported */
1943 case NFS4ATTR_GETIT:
1944 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
1945 error = -1; /* may be okay if rdattr_error */
1946 break;
1947 }
1948 ASSERT(sarg->vap->va_mask & AT_MODE);
1949 na->mode = sarg->vap->va_mode;
1950 break;
1951 case NFS4ATTR_SETIT:
1952 ASSERT(sarg->vap->va_mask & AT_MODE);
1953 sarg->vap->va_mode = na->mode;
1954 /*
1955 * If the filesystem is exported with nosuid, then mask off
1956 * the setuid and setgid bits.
1957 */
1958 if (sarg->cs->vp->v_type == VREG &&
1959 (sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
1960 sarg->vap->va_mode &= ~(VSUID | VSGID);
1961 break;
1962 case NFS4ATTR_VERIT:
1963 ASSERT(sarg->vap->va_mask & AT_MODE);
1964 if (sarg->vap->va_mode != na->mode)
1965 error = -1; /* no match */
1966 break;
1967 case NFS4ATTR_FREEIT:
1968 break;
1969 }
1970 return (error);
1971 }
1972
1973 /* ARGSUSED */
1974 static int
1975 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1976 union nfs4_attr_u *na)
1977 {
1978 int error = 0;
1979
1980 if (RFS4_MANDATTR_ONLY)
1981 return (ENOTSUP);
1982
1983 switch (cmd) {
1984 case NFS4ATTR_SUPPORTED:
1985 if (sarg->op == NFS4ATTR_SETIT)
1986 error = EINVAL;
1987 break; /* this attr is supported */
1988 case NFS4ATTR_GETIT:
1989 na->no_trunc = TRUE;
1990 break;
1991 case NFS4ATTR_SETIT:
1992 /*
1993 * read-only attr
1994 */
1995 error = EINVAL;
1996 break;
1997 case NFS4ATTR_VERIT:
1998 if (!na->no_trunc)
1999 error = -1; /* no match */
2000 break;
2001 case NFS4ATTR_FREEIT:
2002 break;
2003 }
2004 return (error);
2005 }
2006
2007 /* ARGSUSED */
2008 static int
2009 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2010 union nfs4_attr_u *na)
2011 {
2012 int error = 0;
2013
2014 if (RFS4_MANDATTR_ONLY)
2015 return (ENOTSUP);
2016
2017 switch (cmd) {
2018 case NFS4ATTR_SUPPORTED:
2019 if (sarg->op == NFS4ATTR_SETIT)
2020 error = EINVAL;
2021 break; /* this attr is supported */
2022 case NFS4ATTR_GETIT:
2023 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
2024 error = -1; /* may be okay if rdattr_error */
2025 break;
2026 }
2027 ASSERT(sarg->vap->va_mask & AT_NLINK);
2028 na->numlinks = sarg->vap->va_nlink;
2029 break;
2030 case NFS4ATTR_SETIT:
2031 /*
2032 * read-only attr
2033 */
2034 error = EINVAL;
2035 break;
2036 case NFS4ATTR_VERIT:
2037 ASSERT(sarg->vap->va_mask & AT_NLINK);
2038 if (sarg->vap->va_nlink != na->numlinks)
2039 error = -1; /* no match */
2040 break;
2041 case NFS4ATTR_FREEIT:
2042 break;
2043 }
2044 return (error);
2045 }
2046
2047 /* ARGSUSED */
2048 static int
2049 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2050 union nfs4_attr_u *na)
2051 {
2052 int error = 0;
2053 uid_t uid;
2054
2055 if (RFS4_MANDATTR_ONLY)
2056 return (ENOTSUP);
2057
2058 switch (cmd) {
2059 case NFS4ATTR_SUPPORTED:
2060 break; /* this attr is supported */
2061 case NFS4ATTR_GETIT:
2062 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
2063 error = -1; /* may be okay if rdattr_error */
2064 break;
2065 }
2066 ASSERT(sarg->vap->va_mask & AT_UID);
2067
2068 /*
2069 * There are well defined polices for what happens on server-
2070 * side GETATTR when uid to attribute string conversion cannot
2071 * occur. Please refer to nfs4_idmap.c for details.
2072 */
2073 error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
2074 switch (error) {
2075 case ECONNREFUSED:
2076 error = NFS4ERR_DELAY;
2077 break;
2078 default:
2079 break;
2080 }
2081 break;
2082
2083 case NFS4ATTR_SETIT:
2084 ASSERT(sarg->vap->va_mask & AT_UID);
2085
2086 /*
2087 * There are well defined policies for what happens on server-
2088 * side SETATTR of 'owner' when a "user@domain" mapping cannot
2089 * occur. Please refer to nfs4_idmap.c for details.
2090 *
2091 * Any other errors, such as the mapping not being found by
2092 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2093 * in NFS4ERR_BADOWNER.
2094 *
2095 * XXX need to return consistent errors, perhaps all
2096 * server side attribute routines should return NFS4ERR*.
2097 */
2098 error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
2099 switch (error) {
2100 case NFS4_OK:
2101 case ENOTSUP:
2102 /*
2103 * Ignore warning that we are the
2104 * nfsmapid (can't happen on srv)
2105 */
2106 error = 0;
2107 MSG_PRT_DEBUG = FALSE;
2108 break;
2109
2110 case ECOMM:
2111 case ECONNREFUSED:
2112 if (!MSG_PRT_DEBUG) {
2113 /*
2114 * printed just once per daemon death,
2115 * inform the user and then stay silent
2116 */
2117 cmn_err(CE_WARN, "!Unable to contact "
2118 "nfsmapid");
2119 MSG_PRT_DEBUG = TRUE;
2120 }
2121 error = NFS4ERR_DELAY;
2122 break;
2123
2124 case EINVAL:
2125 error = NFS4ERR_INVAL;
2126 break;
2127
2128 default:
2129 error = NFS4ERR_BADOWNER;
2130 break;
2131 }
2132 break;
2133
2134 case NFS4ATTR_VERIT:
2135 ASSERT(sarg->vap->va_mask & AT_UID);
2136 error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
2137 /*
2138 * Ignore warning that we are the nfsmapid (can't happen on srv)
2139 */
2140 if (error == ENOTSUP)
2141 error = 0;
2142 if (error)
2143 error = -1; /* no match */
2144 else if (sarg->vap->va_uid != uid)
2145 error = -1; /* no match */
2146 break;
2147 case NFS4ATTR_FREEIT:
2148 if (sarg->op == NFS4ATTR_GETIT) {
2149 if (na->owner.utf8string_val) {
2150 UTF8STRING_FREE(na->owner)
2151 bzero(&na->owner, sizeof (na->owner));
2152 }
2153 }
2154 break;
2155 }
2156 return (error);
2157 }
2158
2159 /* ARGSUSED */
2160 static int
2161 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2162 union nfs4_attr_u *na)
2163 {
2164 int error = 0;
2165 gid_t gid;
2166
2167 if (RFS4_MANDATTR_ONLY)
2168 return (ENOTSUP);
2169
2170 switch (cmd) {
2171 case NFS4ATTR_SUPPORTED:
2172 break; /* this attr is supported */
2173 case NFS4ATTR_GETIT:
2174 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
2175 error = -1; /* may be okay if rdattr_error */
2176 break;
2177 }
2178 ASSERT(sarg->vap->va_mask & AT_GID);
2179
2180 /*
2181 * There are well defined polices for what happens on server-
2182 * side GETATTR when gid to attribute string conversion cannot
2183 * occur. Please refer to nfs4_idmap.c for details.
2184 */
2185 error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
2186 TRUE);
2187 switch (error) {
2188 case ECONNREFUSED:
2189 error = NFS4ERR_DELAY;
2190 break;
2191 default:
2192 break;
2193 }
2194 break;
2195
2196 case NFS4ATTR_SETIT:
2197 ASSERT(sarg->vap->va_mask & AT_GID);
2198
2199 /*
2200 * There are well defined policies for what happens on server-
2201 * side SETATTR of 'owner_group' when a "group@domain" mapping
2202 * cannot occur. Please refer to nfs4_idmap.c for details.
2203 *
2204 * Any other errors, such as the mapping not being found by
2205 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2206 * in NFS4ERR_BADOWNER.
2207 *
2208 * XXX need to return consistent errors, perhaps all
2209 * server side attribute routines should return NFS4ERR*.
2210 */
2211 error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
2212 TRUE);
2213 switch (error) {
2214 case NFS4_OK:
2215 case ENOTSUP:
2216 /*
2217 * Ignore warning that we are the
2218 * nfsmapid (can't happen on srv)
2219 */
2220 error = 0;
2221 MSG_PRT_DEBUG = FALSE;
2222 break;
2223
2224 case ECOMM:
2225 case ECONNREFUSED:
2226 if (!MSG_PRT_DEBUG) {
2227 /*
2228 * printed just once per daemon death,
2229 * inform the user and then stay silent
2230 */
2231 cmn_err(CE_WARN, "!Unable to contact "
2232 "nfsmapid");
2233 MSG_PRT_DEBUG = TRUE;
2234 }
2235 error = NFS4ERR_DELAY;
2236 break;
2237
2238 case EINVAL:
2239 error = NFS4ERR_INVAL;
2240 break;
2241
2242 default:
2243 error = NFS4ERR_BADOWNER;
2244 break;
2245 }
2246 break;
2247
2248 case NFS4ATTR_VERIT:
2249 ASSERT(sarg->vap->va_mask & AT_GID);
2250 error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
2251 /*
2252 * Ignore warning that we are the nfsmapid (can't happen on srv)
2253 */
2254 if (error == ENOTSUP)
2255 error = 0;
2256 if (error)
2257 error = -1; /* no match */
2258 else if (sarg->vap->va_gid != gid)
2259 error = -1; /* no match */
2260 break;
2261 case NFS4ATTR_FREEIT:
2262 if (sarg->op == NFS4ATTR_GETIT) {
2263 if (na->owner_group.utf8string_val) {
2264 UTF8STRING_FREE(na->owner_group)
2265 bzero(&na->owner_group,
2266 sizeof (na->owner_group));
2267 }
2268 }
2269 break;
2270 }
2271 return (error);
2272 }
2273
2274 /* XXX - quota attributes should be supportable on Solaris 2 */
2275 /* ARGSUSED */
2276 static int
2277 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2278 union nfs4_attr_u *na)
2279 {
2280 return (ENOTSUP);
2281 }
2282
2283 /* ARGSUSED */
2284 static int
2285 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2286 union nfs4_attr_u *na)
2287 {
2288 return (ENOTSUP);
2289 }
2290
2291 /* ARGSUSED */
2292 static int
2293 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2294 union nfs4_attr_u *na)
2295 {
2296 return (ENOTSUP);
2297 }
2298
2299 /* ARGSUSED */
2300 static int
2301 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2302 union nfs4_attr_u *na)
2303 {
2304 int error = 0;
2305
2306 if (RFS4_MANDATTR_ONLY)
2307 return (ENOTSUP);
2308
2309 switch (cmd) {
2310 case NFS4ATTR_SUPPORTED:
2311 if (sarg->op == NFS4ATTR_SETIT)
2312 error = EINVAL;
2313 break; /* this attr is supported */
2314 case NFS4ATTR_GETIT:
2315 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
2316 error = -1; /* may be okay if rdattr_error */
2317 break;
2318 }
2319 ASSERT(sarg->vap->va_mask & AT_RDEV);
2320 na->rawdev.specdata1 = (uint32)getmajor(sarg->vap->va_rdev);
2321 na->rawdev.specdata2 = (uint32)getminor(sarg->vap->va_rdev);
2322 break;
2323 case NFS4ATTR_SETIT:
2324 /*
2325 * read-only attr
2326 */
2327 error = EINVAL;
2328 break;
2329 case NFS4ATTR_VERIT:
2330 ASSERT(sarg->vap->va_mask & AT_RDEV);
2331 if ((na->rawdev.specdata1 !=
2332 (uint32)getmajor(sarg->vap->va_rdev)) ||
2333 (na->rawdev.specdata2 !=
2334 (uint32)getminor(sarg->vap->va_rdev)))
2335 error = -1; /* no match */
2336 break;
2337 case NFS4ATTR_FREEIT:
2338 break;
2339 }
2340 return (error);
2341 }
2342
2343 /* ARGSUSED */
2344 static int
2345 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2346 union nfs4_attr_u *na)
2347 {
2348 int error = 0;
2349
2350 if (RFS4_MANDATTR_ONLY)
2351 return (ENOTSUP);
2352
2353 switch (cmd) {
2354 case NFS4ATTR_SUPPORTED:
2355 if (sarg->op == NFS4ATTR_SETIT)
2356 error = EINVAL;
2357 break; /* this attr is supported */
2358 case NFS4ATTR_GETIT:
2359 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2360 error = -1; /* may be okay if rdattr_error */
2361 break;
2362 }
2363 ASSERT(sarg->sbp != NULL);
2364 if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
2365 na->space_avail =
2366 (fattr4_space_avail) sarg->sbp->f_frsize *
2367 (fattr4_space_avail) sarg->sbp->f_bavail;
2368 } else {
2369 na->space_avail =
2370 (fattr4_space_avail) sarg->sbp->f_bavail;
2371 }
2372 break;
2373 case NFS4ATTR_SETIT:
2374 /*
2375 * read-only attr
2376 */
2377 error = EINVAL;
2378 break;
2379 case NFS4ATTR_VERIT:
2380 ASSERT(sarg->sbp != NULL);
2381 if (sarg->sbp->f_bavail != na->space_avail)
2382 error = -1; /* no match */
2383 break;
2384 case NFS4ATTR_FREEIT:
2385 break;
2386 }
2387 return (error);
2388 }
2389
2390 /* ARGSUSED */
2391 static int
2392 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2393 union nfs4_attr_u *na)
2394 {
2395 int error = 0;
2396
2397 if (RFS4_MANDATTR_ONLY)
2398 return (ENOTSUP);
2399
2400 switch (cmd) {
2401 case NFS4ATTR_SUPPORTED:
2402 if (sarg->op == NFS4ATTR_SETIT)
2403 error = EINVAL;
2404 break; /* this attr is supported */
2405 case NFS4ATTR_GETIT:
2406 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2407 error = -1; /* may be okay if rdattr_error */
2408 break;
2409 }
2410 ASSERT(sarg->sbp != NULL);
2411 if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
2412 na->space_free =
2413 (fattr4_space_free) sarg->sbp->f_frsize *
2414 (fattr4_space_free) sarg->sbp->f_bfree;
2415 } else {
2416 na->space_free =
2417 (fattr4_space_free) sarg->sbp->f_bfree;
2418 }
2419 break;
2420 case NFS4ATTR_SETIT:
2421 /*
2422 * read-only attr
2423 */
2424 error = EINVAL;
2425 break;
2426 case NFS4ATTR_VERIT:
2427 ASSERT(sarg->sbp != NULL);
2428 if (sarg->sbp->f_bfree != na->space_free)
2429 error = -1; /* no match */
2430 break;
2431 case NFS4ATTR_FREEIT:
2432 break;
2433 }
2434 return (error);
2435 }
2436
2437 /* ARGSUSED */
2438 static int
2439 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2440 union nfs4_attr_u *na)
2441 {
2442 int error = 0;
2443
2444 if (RFS4_MANDATTR_ONLY)
2445 return (ENOTSUP);
2446
2447 switch (cmd) {
2448 case NFS4ATTR_SUPPORTED:
2449 if (sarg->op == NFS4ATTR_SETIT)
2450 error = EINVAL;
2451 break; /* this attr is supported */
2452 case NFS4ATTR_GETIT:
2453 if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
2454 error = -1; /* may be okay if rdattr_error */
2455 break;
2456 }
2457 ASSERT(sarg->sbp != NULL);
2458 if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
2459 na->space_total =
2460 (fattr4_space_total) sarg->sbp->f_frsize *
2461 (fattr4_space_total) sarg->sbp->f_blocks;
2462 } else {
2463 na->space_total =
2464 (fattr4_space_total) sarg->sbp->f_blocks;
2465 }
2466 break;
2467 case NFS4ATTR_SETIT:
2468 /*
2469 * read-only attr
2470 */
2471 error = EINVAL;
2472 break;
2473 case NFS4ATTR_VERIT:
2474 ASSERT(sarg->sbp != NULL);
2475 if (sarg->sbp->f_blocks != na->space_total)
2476 error = -1; /* no match */
2477 break;
2478 case NFS4ATTR_FREEIT:
2479 break;
2480 }
2481 return (error);
2482 }
2483
2484 /* ARGSUSED */
2485 static int
2486 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2487 union nfs4_attr_u *na)
2488 {
2489 int error = 0;
2490
2491 if (RFS4_MANDATTR_ONLY)
2492 return (ENOTSUP);
2493
2494 switch (cmd) {
2495 case NFS4ATTR_SUPPORTED:
2496 if (sarg->op == NFS4ATTR_SETIT)
2497 error = EINVAL;
2498 break; /* this attr is supported */
2499 case NFS4ATTR_GETIT:
2500 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
2501 error = -1; /* may be okay if rdattr_error */
2502 break;
2503 }
2504 ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2505 na->space_used = (fattr4_space_used) DEV_BSIZE *
2506 (fattr4_space_used) sarg->vap->va_nblocks;
2507 break;
2508 case NFS4ATTR_SETIT:
2509 /*
2510 * read-only attr
2511 */
2512 error = EINVAL;
2513 break;
2514 case NFS4ATTR_VERIT:
2515 ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2516 if (sarg->vap->va_nblocks != na->space_used)
2517 error = -1; /* no match */
2518 break;
2519 case NFS4ATTR_FREEIT:
2520 break;
2521 }
2522 return (error);
2523 }
2524
2525 /* ARGSUSED */
2526 static int
2527 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2528 union nfs4_attr_u *na)
2529 {
2530 return (ENOTSUP);
2531 }
2532
2533 /* ARGSUSED */
2534 static int
2535 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2536 union nfs4_attr_u *na)
2537 {
2538 int error = 0;
2539 timestruc_t atime;
2540
2541 if (RFS4_MANDATTR_ONLY)
2542 return (ENOTSUP);
2543
2544 switch (cmd) {
2545 case NFS4ATTR_SUPPORTED:
2546 if (sarg->op == NFS4ATTR_SETIT)
2547 error = EINVAL;
2548 break; /* this attr is supported */
2549 case NFS4ATTR_GETIT:
2550 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
2551 error = -1; /* may be okay if rdattr_error */
2552 break;
2553 }
2554 ASSERT(sarg->vap->va_mask & AT_ATIME);
2555 error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
2556 break;
2557 case NFS4ATTR_SETIT:
2558 /*
2559 * read-only attr
2560 */
2561 error = EINVAL;
2562 break;
2563 case NFS4ATTR_VERIT:
2564 ASSERT(sarg->vap->va_mask & AT_ATIME);
2565 error = nfs4_time_ntov(&na->time_access, &atime);
2566 if (error)
2567 break;
2568 if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
2569 error = -1; /* no match */
2570 break;
2571 case NFS4ATTR_FREEIT:
2572 break;
2573 }
2574 return (error);
2575 }
2576
2577 /*
2578 * XXX - need to support the setting of access time
2579 */
2580 /* ARGSUSED */
2581 static int
2582 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2583 union nfs4_attr_u *na)
2584 {
2585 int error = 0;
2586 settime4 *ta;
2587
2588 if (RFS4_MANDATTR_ONLY)
2589 return (ENOTSUP);
2590
2591 switch (cmd) {
2592 case NFS4ATTR_SUPPORTED:
2593 if ((sarg->op == NFS4ATTR_GETIT) ||
2594 (sarg->op == NFS4ATTR_VERIT))
2595 error = EINVAL;
2596 break; /* this attr is supported */
2597 case NFS4ATTR_GETIT:
2598 case NFS4ATTR_VERIT:
2599 /*
2600 * write only attr
2601 */
2602 error = EINVAL;
2603 break;
2604 case NFS4ATTR_SETIT:
2605 ASSERT(sarg->vap->va_mask & AT_ATIME);
2606 /*
2607 * Set access time (by server or by client)
2608 */
2609 ta = &na->time_access_set;
2610 if (ta->set_it == SET_TO_CLIENT_TIME4) {
2611 error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
2612 } else if (ta->set_it == SET_TO_SERVER_TIME4) {
2613 gethrestime(&sarg->vap->va_atime);
2614 } else {
2615 error = EINVAL;
2616 }
2617 break;
2618 case NFS4ATTR_FREEIT:
2619 break;
2620 }
2621 return (error);
2622 }
2623
2624 /* ARGSUSED */
2625 static int
2626 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2627 union nfs4_attr_u *na)
2628 {
2629 return (ENOTSUP);
2630 }
2631
2632 /* ARGSUSED */
2633 static int
2634 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2635 union nfs4_attr_u *na)
2636 {
2637 return (ENOTSUP);
2638 }
2639
2640 /* ARGSUSED */
2641 static int
2642 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2643 union nfs4_attr_u *na)
2644 {
2645 int error = 0;
2646
2647 if (RFS4_MANDATTR_ONLY)
2648 return (ENOTSUP);
2649
2650 switch (cmd) {
2651 case NFS4ATTR_SUPPORTED:
2652 if (sarg->op == NFS4ATTR_SETIT)
2653 error = EINVAL;
2654 break; /* this attr is supported */
2655 case NFS4ATTR_GETIT:
2656 na->time_delta.seconds = 0;
2657 na->time_delta.nseconds = 1000;
2658 break;
2659 case NFS4ATTR_SETIT:
2660 /*
2661 * write only attr
2662 */
2663 error = EINVAL;
2664 break;
2665 case NFS4ATTR_VERIT:
2666 if ((na->time_delta.seconds != 0) ||
2667 (na->time_delta.nseconds != 1000))
2668 error = -1; /* no match */
2669 break;
2670 case NFS4ATTR_FREEIT:
2671 break;
2672 }
2673 return (error);
2674 }
2675
2676 /* ARGSUSED */
2677 static int
2678 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2679 union nfs4_attr_u *na)
2680 {
2681 int error = 0;
2682 timestruc_t ctime;
2683
2684 if (RFS4_MANDATTR_ONLY)
2685 return (ENOTSUP);
2686
2687 switch (cmd) {
2688 case NFS4ATTR_SUPPORTED:
2689 if (sarg->op == NFS4ATTR_SETIT)
2690 error = EINVAL;
2691 break; /* this attr is supported */
2692 case NFS4ATTR_GETIT:
2693 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
2694 error = -1; /* may be okay if rdattr_error */
2695 break;
2696 }
2697 ASSERT(sarg->vap->va_mask & AT_CTIME);
2698 error = nfs4_time_vton(&sarg->vap->va_ctime,
2699 &na->time_metadata);
2700 break;
2701 case NFS4ATTR_SETIT:
2702 /*
2703 * read-only attr
2704 */
2705 error = EINVAL;
2706 break;
2707 case NFS4ATTR_VERIT:
2708 ASSERT(sarg->vap->va_mask & AT_CTIME);
2709 error = nfs4_time_ntov(&na->time_metadata, &ctime);
2710 if (error)
2711 break;
2712 if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
2713 error = -1; /* no match */
2714 break;
2715 case NFS4ATTR_FREEIT:
2716 break;
2717 }
2718 return (error);
2719 }
2720
2721 /* ARGSUSED */
2722 static int
2723 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2724 union nfs4_attr_u *na)
2725 {
2726 int error = 0;
2727 timestruc_t mtime;
2728
2729 if (RFS4_MANDATTR_ONLY)
2730 return (ENOTSUP);
2731
2732 switch (cmd) {
2733 case NFS4ATTR_SUPPORTED:
2734 if (sarg->op == NFS4ATTR_SETIT)
2735 error = EINVAL;
2736 break; /* this attr is supported */
2737 case NFS4ATTR_GETIT:
2738 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
2739 error = -1; /* may be okay if rdattr_error */
2740 break;
2741 }
2742 ASSERT(sarg->vap->va_mask & AT_MTIME);
2743 error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
2744 break;
2745 case NFS4ATTR_SETIT:
2746 /*
2747 * read-only attr
2748 */
2749 error = EINVAL;
2750 break;
2751 case NFS4ATTR_VERIT:
2752 ASSERT(sarg->vap->va_mask & AT_MTIME);
2753 error = nfs4_time_ntov(&na->time_modify, &mtime);
2754 if (error)
2755 break;
2756 if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
2757 error = -1; /* no match */
2758 break;
2759 case NFS4ATTR_FREEIT:
2760 break;
2761 }
2762 return (error);
2763 }
2764
2765 /*
2766 * XXX - need to add support for setting modify time
2767 */
2768 /* ARGSUSED */
2769 static int
2770 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2771 union nfs4_attr_u *na)
2772 {
2773 int error = 0;
2774 settime4 *tm;
2775
2776 if (RFS4_MANDATTR_ONLY)
2777 return (ENOTSUP);
2778
2779 switch (cmd) {
2780 case NFS4ATTR_SUPPORTED:
2781 if ((sarg->op == NFS4ATTR_GETIT) ||
2782 (sarg->op == NFS4ATTR_VERIT))
2783 error = EINVAL;
2784 break; /* this attr is supported */
2785 case NFS4ATTR_GETIT:
2786 case NFS4ATTR_VERIT:
2787 /*
2788 * write only attr
2789 */
2790 error = EINVAL;
2791 break;
2792 case NFS4ATTR_SETIT:
2793 ASSERT(sarg->vap->va_mask & AT_MTIME);
2794 /*
2795 * Set modify time (by server or by client)
2796 */
2797 tm = &na->time_modify_set;
2798 if (tm->set_it == SET_TO_CLIENT_TIME4) {
2799 error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
2800 sarg->flag = ATTR_UTIME;
2801 } else if (tm->set_it == SET_TO_SERVER_TIME4) {
2802 gethrestime(&sarg->vap->va_mtime);
2803 } else {
2804 error = EINVAL;
2805 }
2806 break;
2807 case NFS4ATTR_FREEIT:
2808 break;
2809 }
2810 return (error);
2811 }
2812
2813
2814 static void
2815 rfs4_ntov_init(void)
2816 {
2817 /* index must be same as corresponding FATTR4_* define */
2818 nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
2819 nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
2820 nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
2821 nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
2822 nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
2823 nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
2824 nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
2825 nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
2826 nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
2827 nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
2828 nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
2829 nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
2830 nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
2831 nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
2832 nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
2833 nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
2834 nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
2835 nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
2836 nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
2837 nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
2838 nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
2839 nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
2840 nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
2841 nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
2842 nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
2843 nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
2844 nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
2845 nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
2846 nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
2847 nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
2848 nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
2849 nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
2850 nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
2851 nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
2852 nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
2853 nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
2854 nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
2855 nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
2856 nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
2857 nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
2858 nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
2859 nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
2860 nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
2861 nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
2862 nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
2863 nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
2864 nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
2865 nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
2866 nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
2867 nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
2868 nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
2869 nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
2870 nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
2871 nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
2872 nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
2873 nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
2874 }