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, ZONE_ROOTVP());
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 {
1613 kstat_named_t *stat =
1614 sarg->cs->exi->exi_ne->ne_globals->svstat[NFS_V4];
1615
1616 fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
1617 if (fsl == NULL)
1618 (void) memset(&(na->fs_locations), 0,
1619 sizeof (fs_locations4));
1620 else {
1621 na->fs_locations = *fsl;
1622 kmem_free(fsl, sizeof (fs_locations4));
1623 }
1624 stat[NFS_REFERRALS].value.ui64++;
1625 break;
1626 }
1627 case NFS4ATTR_FREEIT:
1628 if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
1629 error = EINVAL;
1630 rfs4_free_fs_locations4(&na->fs_locations);
1631 break;
1632
1633 case NFS4ATTR_SETIT:
1634 case NFS4ATTR_VERIT:
1635 /*
1636 * read-only attr
1637 */
1638 error = EINVAL;
1639 break;
1640 }
1641 return (error);
1642 }
1643
1644 /* ARGSUSED */
1645 static int
1646 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1647 union nfs4_attr_u *na)
1648 {
1649 return (ENOTSUP);
1650 }
1651
1652 /* ARGSUSED */
1653 static int
1654 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1655 union nfs4_attr_u *na)
1656 {
1657 int error = 0;
1658
1659 if (RFS4_MANDATTR_ONLY)
1660 return (ENOTSUP);
1661
1662 switch (cmd) {
1663 case NFS4ATTR_SUPPORTED:
1664 if (sarg->op == NFS4ATTR_SETIT)
1665 error = EINVAL;
1666 break; /* this attr is supported */
1667 case NFS4ATTR_GETIT:
1668 na->homogeneous = TRUE; /* XXX - need a VOP extension */
1669 break;
1670 case NFS4ATTR_SETIT:
1671 /*
1672 * read-only attr
1673 */
1674 error = EINVAL;
1675 break;
1676 case NFS4ATTR_VERIT:
1677 if (!na->homogeneous)
1678 error = -1; /* no match */
1679 break;
1680 case NFS4ATTR_FREEIT:
1681 break;
1682 }
1683 return (error);
1684 }
1685
1686 /* ARGSUSED */
1687 static int
1688 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1689 union nfs4_attr_u *na)
1690 {
1691 int error = 0;
1692 ulong_t val;
1693 fattr4_maxfilesize maxfilesize;
1694
1695 if (RFS4_MANDATTR_ONLY)
1696 return (ENOTSUP);
1697
1698 switch (cmd) {
1699 case NFS4ATTR_SUPPORTED:
1700 if (sarg->op == NFS4ATTR_SETIT)
1701 error = EINVAL;
1702 break; /* this attr is supported */
1703 case NFS4ATTR_GETIT:
1704 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1705 error = -1; /* may be okay if rdattr_error */
1706 break;
1707 }
1708 ASSERT(sarg->cs->vp != NULL);
1709 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1710 sarg->cs->cr, NULL);
1711 if (error)
1712 break;
1713
1714 /*
1715 * If the underlying file system does not support
1716 * _PC_FILESIZEBITS, return a reasonable default. Note that
1717 * error code on VOP_PATHCONF will be 0, even if the underlying
1718 * file system does not support _PC_FILESIZEBITS.
1719 */
1720 if (val == (ulong_t)-1) {
1721 na->maxfilesize = MAXOFF32_T;
1722 } else {
1723 if (val >= (sizeof (uint64_t) * 8))
1724 na->maxfilesize = INT64_MAX;
1725 else
1726 na->maxfilesize = ((1LL << (val - 1)) - 1);
1727 }
1728 break;
1729 case NFS4ATTR_SETIT:
1730 /*
1731 * read-only attr
1732 */
1733 error = EINVAL;
1734 break;
1735 case NFS4ATTR_VERIT:
1736 ASSERT(sarg->cs->vp != NULL);
1737 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1738 sarg->cs->cr, NULL);
1739 if (error)
1740 break;
1741 /*
1742 * If the underlying file system does not support
1743 * _PC_FILESIZEBITS, return a reasonable default. Note that
1744 * error code on VOP_PATHCONF will be 0, even if the underlying
1745 * file system does not support _PC_FILESIZEBITS.
1746 */
1747 if (val == (ulong_t)-1) {
1748 maxfilesize = MAXOFF32_T;
1749 } else {
1750 if (val >= (sizeof (uint64_t) * 8))
1751 maxfilesize = INT64_MAX;
1752 else
1753 maxfilesize = ((1LL << (val - 1)) - 1);
1754 }
1755 if (na->maxfilesize != maxfilesize)
1756 error = -1; /* no match */
1757 break;
1758 case NFS4ATTR_FREEIT:
1759 break;
1760 }
1761 return (error);
1762 }
1763
1764 /* ARGSUSED */
1765 static int
1766 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1767 union nfs4_attr_u *na)
1768 {
1769 int error = 0;
1770 ulong_t val;
1771
1772 if (RFS4_MANDATTR_ONLY)
1773 return (ENOTSUP);
1774
1775 switch (cmd) {
1776 case NFS4ATTR_SUPPORTED:
1777 if (sarg->op == NFS4ATTR_SETIT)
1778 error = EINVAL;
1779 break; /* this attr is supported */
1780 case NFS4ATTR_GETIT:
1781 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1782 error = -1; /* may be okay if rdattr_error */
1783 break;
1784 }
1785 ASSERT(sarg->cs->vp != NULL);
1786 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1787 sarg->cs->cr, NULL);
1788 if (error == 0) {
1789 na->maxlink = val;
1790 }
1791 break;
1792 case NFS4ATTR_SETIT:
1793 /*
1794 * read-only attr
1795 */
1796 error = EINVAL;
1797 break;
1798 case NFS4ATTR_VERIT:
1799 ASSERT(sarg->cs->vp != NULL);
1800 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1801 sarg->cs->cr, NULL);
1802 if (!error && (na->maxlink != (uint32_t)val))
1803 error = -1; /* no match */
1804 break;
1805 case NFS4ATTR_FREEIT:
1806 break;
1807 }
1808 return (error);
1809 }
1810
1811 /* ARGSUSED */
1812 static int
1813 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1814 union nfs4_attr_u *na)
1815 {
1816 int error = 0;
1817 ulong_t val;
1818
1819 if (RFS4_MANDATTR_ONLY)
1820 return (ENOTSUP);
1821
1822 switch (cmd) {
1823 case NFS4ATTR_SUPPORTED:
1824 if (sarg->op == NFS4ATTR_SETIT)
1825 error = EINVAL;
1826 break; /* this attr is supported */
1827 case NFS4ATTR_GETIT:
1828 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1829 error = -1; /* may be okay if rdattr_error */
1830 break;
1831 }
1832 ASSERT(sarg->cs->vp != NULL);
1833 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1834 sarg->cs->cr, NULL);
1835 if (error == 0) {
1836 na->maxname = val;
1837 }
1838 break;
1839 case NFS4ATTR_SETIT:
1840 /*
1841 * read-only attr
1842 */
1843 error = EINVAL;
1844 break;
1845 case NFS4ATTR_VERIT:
1846 ASSERT(sarg->cs->vp != NULL);
1847 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1848 sarg->cs->cr, NULL);
1849 if (!error && (na->maxname != val))
1850 error = -1; /* no match */
1851 break;
1852 case NFS4ATTR_FREEIT:
1853 break;
1854 }
1855 return (error);
1856 }
1857
1858 /* ARGSUSED */
1859 static int
1860 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1861 union nfs4_attr_u *na)
1862 {
1863 int error = 0;
1864
1865 if (RFS4_MANDATTR_ONLY)
1866 return (ENOTSUP);
1867
1868 switch (cmd) {
1869 case NFS4ATTR_SUPPORTED:
1870 if (sarg->op == NFS4ATTR_SETIT)
1871 error = EINVAL;
1872 break; /* this attr is supported */
1873 case NFS4ATTR_GETIT:
1874 na->maxread = rfs4_tsize(sarg->cs->req);
1875 break;
1876 case NFS4ATTR_SETIT:
1877 /*
1878 * read-only attr
1879 */
1880 error = EINVAL;
1881 break;
1882 case NFS4ATTR_VERIT:
1883 if (na->maxread != rfs4_tsize(sarg->cs->req))
1884 error = -1; /* no match */
1885 break;
1886 case NFS4ATTR_FREEIT:
1887 break;
1888 }
1889 return (error);
1890 }
1891
1892 /* ARGSUSED */
1893 static int
1894 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1895 union nfs4_attr_u *na)
1896 {
1897 int error = 0;
1898
1899 if (RFS4_MANDATTR_ONLY)
1900 return (ENOTSUP);
1901
1902 switch (cmd) {
1903 case NFS4ATTR_SUPPORTED:
1904 if (sarg->op == NFS4ATTR_SETIT)
1905 error = EINVAL;
1906 break; /* this attr is supported */
1907 case NFS4ATTR_GETIT:
1908 na->maxwrite = rfs4_tsize(sarg->cs->req);
1909 break;
1910 case NFS4ATTR_SETIT:
1911 /*
1912 * read-only attr
1913 */
1914 error = EINVAL;
1915 break;
1916 case NFS4ATTR_VERIT:
1917 if (na->maxwrite != rfs4_tsize(sarg->cs->req))
1918 error = -1; /* no match */
1919 break;
1920 case NFS4ATTR_FREEIT:
1921 break;
1922 }
1923 return (error);
1924 }
1925
1926 /* ARGSUSED */
1927 static int
1928 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1929 union nfs4_attr_u *na)
1930 {
1931 return (ENOTSUP);
1932 }
1933
1934 /* ARGSUSED */
1935 static int
1936 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1937 union nfs4_attr_u *na)
1938 {
1939 int error = 0;
1940
1941 if (RFS4_MANDATTR_ONLY)
1942 return (ENOTSUP);
1943
1944 switch (cmd) {
1945 case NFS4ATTR_SUPPORTED:
1946 break; /* this attr is supported */
1947 case NFS4ATTR_GETIT:
1948 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
1949 error = -1; /* may be okay if rdattr_error */
1950 break;
1951 }
1952 ASSERT(sarg->vap->va_mask & AT_MODE);
1953 na->mode = sarg->vap->va_mode;
1954 break;
1955 case NFS4ATTR_SETIT:
1956 ASSERT(sarg->vap->va_mask & AT_MODE);
1957 sarg->vap->va_mode = na->mode;
1958 /*
1959 * If the filesystem is exported with nosuid, then mask off
1960 * the setuid and setgid bits.
1961 */
1962 if (sarg->cs->vp->v_type == VREG &&
1963 (sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
1964 sarg->vap->va_mode &= ~(VSUID | VSGID);
1965 break;
1966 case NFS4ATTR_VERIT:
1967 ASSERT(sarg->vap->va_mask & AT_MODE);
1968 if (sarg->vap->va_mode != na->mode)
1969 error = -1; /* no match */
1970 break;
1971 case NFS4ATTR_FREEIT:
1972 break;
1973 }
1974 return (error);
1975 }
1976
1977 /* ARGSUSED */
1978 static int
1979 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1980 union nfs4_attr_u *na)
1981 {
1982 int error = 0;
1983
1984 if (RFS4_MANDATTR_ONLY)
1985 return (ENOTSUP);
1986
1987 switch (cmd) {
1988 case NFS4ATTR_SUPPORTED:
1989 if (sarg->op == NFS4ATTR_SETIT)
1990 error = EINVAL;
1991 break; /* this attr is supported */
1992 case NFS4ATTR_GETIT:
1993 na->no_trunc = TRUE;
1994 break;
1995 case NFS4ATTR_SETIT:
1996 /*
1997 * read-only attr
1998 */
1999 error = EINVAL;
2000 break;
2001 case NFS4ATTR_VERIT:
2002 if (!na->no_trunc)
2003 error = -1; /* no match */
2004 break;
2005 case NFS4ATTR_FREEIT:
2006 break;
2007 }
2008 return (error);
2009 }
2010
2011 /* ARGSUSED */
2012 static int
2013 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2014 union nfs4_attr_u *na)
2015 {
2016 int error = 0;
2017
2018 if (RFS4_MANDATTR_ONLY)
2019 return (ENOTSUP);
2020
2021 switch (cmd) {
2022 case NFS4ATTR_SUPPORTED:
2023 if (sarg->op == NFS4ATTR_SETIT)
2024 error = EINVAL;
2025 break; /* this attr is supported */
2026 case NFS4ATTR_GETIT:
2027 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
2028 error = -1; /* may be okay if rdattr_error */
2029 break;
2030 }
2031 ASSERT(sarg->vap->va_mask & AT_NLINK);
2032 na->numlinks = sarg->vap->va_nlink;
2033 break;
2034 case NFS4ATTR_SETIT:
2035 /*
2036 * read-only attr
2037 */
2038 error = EINVAL;
2039 break;
2040 case NFS4ATTR_VERIT:
2041 ASSERT(sarg->vap->va_mask & AT_NLINK);
2042 if (sarg->vap->va_nlink != na->numlinks)
2043 error = -1; /* no match */
2044 break;
2045 case NFS4ATTR_FREEIT:
2046 break;
2047 }
2048 return (error);
2049 }
2050
2051 /* ARGSUSED */
2052 static int
2053 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2054 union nfs4_attr_u *na)
2055 {
2056 int error = 0;
2057 uid_t uid;
2058
2059 if (RFS4_MANDATTR_ONLY)
2060 return (ENOTSUP);
2061
2062 switch (cmd) {
2063 case NFS4ATTR_SUPPORTED:
2064 break; /* this attr is supported */
2065 case NFS4ATTR_GETIT:
2066 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
2067 error = -1; /* may be okay if rdattr_error */
2068 break;
2069 }
2070 ASSERT(sarg->vap->va_mask & AT_UID);
2071
2072 /*
2073 * There are well defined polices for what happens on server-
2074 * side GETATTR when uid to attribute string conversion cannot
2075 * occur. Please refer to nfs4_idmap.c for details.
2076 */
2077 error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
2078 switch (error) {
2079 case ECONNREFUSED:
2080 error = NFS4ERR_DELAY;
2081 break;
2082 default:
2083 break;
2084 }
2085 break;
2086
2087 case NFS4ATTR_SETIT:
2088 ASSERT(sarg->vap->va_mask & AT_UID);
2089
2090 /*
2091 * There are well defined policies for what happens on server-
2092 * side SETATTR of 'owner' when a "user@domain" mapping cannot
2093 * occur. Please refer to nfs4_idmap.c for details.
2094 *
2095 * Any other errors, such as the mapping not being found by
2096 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2097 * in NFS4ERR_BADOWNER.
2098 *
2099 * XXX need to return consistent errors, perhaps all
2100 * server side attribute routines should return NFS4ERR*.
2101 */
2102 error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
2103 switch (error) {
2104 case NFS4_OK:
2105 case ENOTSUP:
2106 /*
2107 * Ignore warning that we are the
2108 * nfsmapid (can't happen on srv)
2109 */
2110 error = 0;
2111 MSG_PRT_DEBUG = FALSE;
2112 break;
2113
2114 case ECOMM:
2115 case ECONNREFUSED:
2116 if (!MSG_PRT_DEBUG) {
2117 /*
2118 * printed just once per daemon death,
2119 * inform the user and then stay silent
2120 */
2121 cmn_err(CE_WARN, "!Unable to contact "
2122 "nfsmapid");
2123 MSG_PRT_DEBUG = TRUE;
2124 }
2125 error = NFS4ERR_DELAY;
2126 break;
2127
2128 case EINVAL:
2129 error = NFS4ERR_INVAL;
2130 break;
2131
2132 default:
2133 error = NFS4ERR_BADOWNER;
2134 break;
2135 }
2136 break;
2137
2138 case NFS4ATTR_VERIT:
2139 ASSERT(sarg->vap->va_mask & AT_UID);
2140 error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
2141 /*
2142 * Ignore warning that we are the nfsmapid (can't happen on srv)
2143 */
2144 if (error == ENOTSUP)
2145 error = 0;
2146 if (error)
2147 error = -1; /* no match */
2148 else if (sarg->vap->va_uid != uid)
2149 error = -1; /* no match */
2150 break;
2151 case NFS4ATTR_FREEIT:
2152 if (sarg->op == NFS4ATTR_GETIT) {
2153 if (na->owner.utf8string_val) {
2154 UTF8STRING_FREE(na->owner)
2155 bzero(&na->owner, sizeof (na->owner));
2156 }
2157 }
2158 break;
2159 }
2160 return (error);
2161 }
2162
2163 /* ARGSUSED */
2164 static int
2165 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2166 union nfs4_attr_u *na)
2167 {
2168 int error = 0;
2169 gid_t gid;
2170
2171 if (RFS4_MANDATTR_ONLY)
2172 return (ENOTSUP);
2173
2174 switch (cmd) {
2175 case NFS4ATTR_SUPPORTED:
2176 break; /* this attr is supported */
2177 case NFS4ATTR_GETIT:
2178 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
2179 error = -1; /* may be okay if rdattr_error */
2180 break;
2181 }
2182 ASSERT(sarg->vap->va_mask & AT_GID);
2183
2184 /*
2185 * There are well defined polices for what happens on server-
2186 * side GETATTR when gid to attribute string conversion cannot
2187 * occur. Please refer to nfs4_idmap.c for details.
2188 */
2189 error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
2190 TRUE);
2191 switch (error) {
2192 case ECONNREFUSED:
2193 error = NFS4ERR_DELAY;
2194 break;
2195 default:
2196 break;
2197 }
2198 break;
2199
2200 case NFS4ATTR_SETIT:
2201 ASSERT(sarg->vap->va_mask & AT_GID);
2202
2203 /*
2204 * There are well defined policies for what happens on server-
2205 * side SETATTR of 'owner_group' when a "group@domain" mapping
2206 * cannot occur. Please refer to nfs4_idmap.c for details.
2207 *
2208 * Any other errors, such as the mapping not being found by
2209 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2210 * in NFS4ERR_BADOWNER.
2211 *
2212 * XXX need to return consistent errors, perhaps all
2213 * server side attribute routines should return NFS4ERR*.
2214 */
2215 error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
2216 TRUE);
2217 switch (error) {
2218 case NFS4_OK:
2219 case ENOTSUP:
2220 /*
2221 * Ignore warning that we are the
2222 * nfsmapid (can't happen on srv)
2223 */
2224 error = 0;
2225 MSG_PRT_DEBUG = FALSE;
2226 break;
2227
2228 case ECOMM:
2229 case ECONNREFUSED:
2230 if (!MSG_PRT_DEBUG) {
2231 /*
2232 * printed just once per daemon death,
2233 * inform the user and then stay silent
2234 */
2235 cmn_err(CE_WARN, "!Unable to contact "
2236 "nfsmapid");
2237 MSG_PRT_DEBUG = TRUE;
2238 }
2239 error = NFS4ERR_DELAY;
2240 break;
2241
2242 case EINVAL:
2243 error = NFS4ERR_INVAL;
2244 break;
2245
2246 default:
2247 error = NFS4ERR_BADOWNER;
2248 break;
2249 }
2250 break;
2251
2252 case NFS4ATTR_VERIT:
2253 ASSERT(sarg->vap->va_mask & AT_GID);
2254 error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
2255 /*
2256 * Ignore warning that we are the nfsmapid (can't happen on srv)
2257 */
2258 if (error == ENOTSUP)
2259 error = 0;
2260 if (error)
2261 error = -1; /* no match */
2262 else if (sarg->vap->va_gid != gid)
2263 error = -1; /* no match */
2264 break;
2265 case NFS4ATTR_FREEIT:
2266 if (sarg->op == NFS4ATTR_GETIT) {
2267 if (na->owner_group.utf8string_val) {
2268 UTF8STRING_FREE(na->owner_group)
2269 bzero(&na->owner_group,
2270 sizeof (na->owner_group));
2271 }
2272 }
2273 break;
2274 }
2275 return (error);
2276 }
2277
2278 /* XXX - quota attributes should be supportable on Solaris 2 */
2279 /* ARGSUSED */
2280 static int
2281 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2282 union nfs4_attr_u *na)
2283 {
2284 return (ENOTSUP);
2285 }
2286
2287 /* ARGSUSED */
2288 static int
2289 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2290 union nfs4_attr_u *na)
2291 {
2292 return (ENOTSUP);
2293 }
2294
2295 /* ARGSUSED */
2296 static int
2297 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2298 union nfs4_attr_u *na)
2299 {
2300 return (ENOTSUP);
2301 }
2302
2303 /* ARGSUSED */
2304 static int
2305 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2306 union nfs4_attr_u *na)
2307 {
2308 int error = 0;
2309
2310 if (RFS4_MANDATTR_ONLY)
2311 return (ENOTSUP);
2312
2313 switch (cmd) {
2314 case NFS4ATTR_SUPPORTED:
2315 if (sarg->op == NFS4ATTR_SETIT)
2316 error = EINVAL;
2317 break; /* this attr is supported */
2318 case NFS4ATTR_GETIT:
2319 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
2320 error = -1; /* may be okay if rdattr_error */
2321 break;
2322 }
2323 ASSERT(sarg->vap->va_mask & AT_RDEV);
2324 na->rawdev.specdata1 = (uint32)getmajor(sarg->vap->va_rdev);
2325 na->rawdev.specdata2 = (uint32)getminor(sarg->vap->va_rdev);
2326 break;
2327 case NFS4ATTR_SETIT:
2328 /*
2329 * read-only attr
2330 */
2331 error = EINVAL;
2332 break;
2333 case NFS4ATTR_VERIT:
2334 ASSERT(sarg->vap->va_mask & AT_RDEV);
2335 if ((na->rawdev.specdata1 !=
2336 (uint32)getmajor(sarg->vap->va_rdev)) ||
2337 (na->rawdev.specdata2 !=
2338 (uint32)getminor(sarg->vap->va_rdev)))
2339 error = -1; /* no match */
2340 break;
2341 case NFS4ATTR_FREEIT:
2342 break;
2343 }
2344 return (error);
2345 }
2346
2347 /* ARGSUSED */
2348 static int
2349 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2350 union nfs4_attr_u *na)
2351 {
2352 int error = 0;
2353
2354 if (RFS4_MANDATTR_ONLY)
2355 return (ENOTSUP);
2356
2357 switch (cmd) {
2358 case NFS4ATTR_SUPPORTED:
2359 if (sarg->op == NFS4ATTR_SETIT)
2360 error = EINVAL;
2361 break; /* this attr is supported */
2362 case NFS4ATTR_GETIT:
2363 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2364 error = -1; /* may be okay if rdattr_error */
2365 break;
2366 }
2367 ASSERT(sarg->sbp != NULL);
2368 if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
2369 na->space_avail =
2370 (fattr4_space_avail) sarg->sbp->f_frsize *
2371 (fattr4_space_avail) sarg->sbp->f_bavail;
2372 } else {
2373 na->space_avail =
2374 (fattr4_space_avail) sarg->sbp->f_bavail;
2375 }
2376 break;
2377 case NFS4ATTR_SETIT:
2378 /*
2379 * read-only attr
2380 */
2381 error = EINVAL;
2382 break;
2383 case NFS4ATTR_VERIT:
2384 ASSERT(sarg->sbp != NULL);
2385 if (sarg->sbp->f_bavail != na->space_avail)
2386 error = -1; /* no match */
2387 break;
2388 case NFS4ATTR_FREEIT:
2389 break;
2390 }
2391 return (error);
2392 }
2393
2394 /* ARGSUSED */
2395 static int
2396 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2397 union nfs4_attr_u *na)
2398 {
2399 int error = 0;
2400
2401 if (RFS4_MANDATTR_ONLY)
2402 return (ENOTSUP);
2403
2404 switch (cmd) {
2405 case NFS4ATTR_SUPPORTED:
2406 if (sarg->op == NFS4ATTR_SETIT)
2407 error = EINVAL;
2408 break; /* this attr is supported */
2409 case NFS4ATTR_GETIT:
2410 if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2411 error = -1; /* may be okay if rdattr_error */
2412 break;
2413 }
2414 ASSERT(sarg->sbp != NULL);
2415 if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
2416 na->space_free =
2417 (fattr4_space_free) sarg->sbp->f_frsize *
2418 (fattr4_space_free) sarg->sbp->f_bfree;
2419 } else {
2420 na->space_free =
2421 (fattr4_space_free) sarg->sbp->f_bfree;
2422 }
2423 break;
2424 case NFS4ATTR_SETIT:
2425 /*
2426 * read-only attr
2427 */
2428 error = EINVAL;
2429 break;
2430 case NFS4ATTR_VERIT:
2431 ASSERT(sarg->sbp != NULL);
2432 if (sarg->sbp->f_bfree != na->space_free)
2433 error = -1; /* no match */
2434 break;
2435 case NFS4ATTR_FREEIT:
2436 break;
2437 }
2438 return (error);
2439 }
2440
2441 /* ARGSUSED */
2442 static int
2443 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2444 union nfs4_attr_u *na)
2445 {
2446 int error = 0;
2447
2448 if (RFS4_MANDATTR_ONLY)
2449 return (ENOTSUP);
2450
2451 switch (cmd) {
2452 case NFS4ATTR_SUPPORTED:
2453 if (sarg->op == NFS4ATTR_SETIT)
2454 error = EINVAL;
2455 break; /* this attr is supported */
2456 case NFS4ATTR_GETIT:
2457 if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
2458 error = -1; /* may be okay if rdattr_error */
2459 break;
2460 }
2461 ASSERT(sarg->sbp != NULL);
2462 if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
2463 na->space_total =
2464 (fattr4_space_total) sarg->sbp->f_frsize *
2465 (fattr4_space_total) sarg->sbp->f_blocks;
2466 } else {
2467 na->space_total =
2468 (fattr4_space_total) sarg->sbp->f_blocks;
2469 }
2470 break;
2471 case NFS4ATTR_SETIT:
2472 /*
2473 * read-only attr
2474 */
2475 error = EINVAL;
2476 break;
2477 case NFS4ATTR_VERIT:
2478 ASSERT(sarg->sbp != NULL);
2479 if (sarg->sbp->f_blocks != na->space_total)
2480 error = -1; /* no match */
2481 break;
2482 case NFS4ATTR_FREEIT:
2483 break;
2484 }
2485 return (error);
2486 }
2487
2488 /* ARGSUSED */
2489 static int
2490 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2491 union nfs4_attr_u *na)
2492 {
2493 int error = 0;
2494
2495 if (RFS4_MANDATTR_ONLY)
2496 return (ENOTSUP);
2497
2498 switch (cmd) {
2499 case NFS4ATTR_SUPPORTED:
2500 if (sarg->op == NFS4ATTR_SETIT)
2501 error = EINVAL;
2502 break; /* this attr is supported */
2503 case NFS4ATTR_GETIT:
2504 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
2505 error = -1; /* may be okay if rdattr_error */
2506 break;
2507 }
2508 ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2509 na->space_used = (fattr4_space_used) DEV_BSIZE *
2510 (fattr4_space_used) sarg->vap->va_nblocks;
2511 break;
2512 case NFS4ATTR_SETIT:
2513 /*
2514 * read-only attr
2515 */
2516 error = EINVAL;
2517 break;
2518 case NFS4ATTR_VERIT:
2519 ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2520 if (sarg->vap->va_nblocks != na->space_used)
2521 error = -1; /* no match */
2522 break;
2523 case NFS4ATTR_FREEIT:
2524 break;
2525 }
2526 return (error);
2527 }
2528
2529 /* ARGSUSED */
2530 static int
2531 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2532 union nfs4_attr_u *na)
2533 {
2534 return (ENOTSUP);
2535 }
2536
2537 /* ARGSUSED */
2538 static int
2539 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2540 union nfs4_attr_u *na)
2541 {
2542 int error = 0;
2543 timestruc_t atime;
2544
2545 if (RFS4_MANDATTR_ONLY)
2546 return (ENOTSUP);
2547
2548 switch (cmd) {
2549 case NFS4ATTR_SUPPORTED:
2550 if (sarg->op == NFS4ATTR_SETIT)
2551 error = EINVAL;
2552 break; /* this attr is supported */
2553 case NFS4ATTR_GETIT:
2554 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
2555 error = -1; /* may be okay if rdattr_error */
2556 break;
2557 }
2558 ASSERT(sarg->vap->va_mask & AT_ATIME);
2559 error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
2560 break;
2561 case NFS4ATTR_SETIT:
2562 /*
2563 * read-only attr
2564 */
2565 error = EINVAL;
2566 break;
2567 case NFS4ATTR_VERIT:
2568 ASSERT(sarg->vap->va_mask & AT_ATIME);
2569 error = nfs4_time_ntov(&na->time_access, &atime);
2570 if (error)
2571 break;
2572 if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
2573 error = -1; /* no match */
2574 break;
2575 case NFS4ATTR_FREEIT:
2576 break;
2577 }
2578 return (error);
2579 }
2580
2581 /*
2582 * XXX - need to support the setting of access time
2583 */
2584 /* ARGSUSED */
2585 static int
2586 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2587 union nfs4_attr_u *na)
2588 {
2589 int error = 0;
2590 settime4 *ta;
2591
2592 if (RFS4_MANDATTR_ONLY)
2593 return (ENOTSUP);
2594
2595 switch (cmd) {
2596 case NFS4ATTR_SUPPORTED:
2597 if ((sarg->op == NFS4ATTR_GETIT) ||
2598 (sarg->op == NFS4ATTR_VERIT))
2599 error = EINVAL;
2600 break; /* this attr is supported */
2601 case NFS4ATTR_GETIT:
2602 case NFS4ATTR_VERIT:
2603 /*
2604 * write only attr
2605 */
2606 error = EINVAL;
2607 break;
2608 case NFS4ATTR_SETIT:
2609 ASSERT(sarg->vap->va_mask & AT_ATIME);
2610 /*
2611 * Set access time (by server or by client)
2612 */
2613 ta = &na->time_access_set;
2614 if (ta->set_it == SET_TO_CLIENT_TIME4) {
2615 error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
2616 } else if (ta->set_it == SET_TO_SERVER_TIME4) {
2617 gethrestime(&sarg->vap->va_atime);
2618 } else {
2619 error = EINVAL;
2620 }
2621 break;
2622 case NFS4ATTR_FREEIT:
2623 break;
2624 }
2625 return (error);
2626 }
2627
2628 /* ARGSUSED */
2629 static int
2630 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2631 union nfs4_attr_u *na)
2632 {
2633 return (ENOTSUP);
2634 }
2635
2636 /* ARGSUSED */
2637 static int
2638 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2639 union nfs4_attr_u *na)
2640 {
2641 return (ENOTSUP);
2642 }
2643
2644 /* ARGSUSED */
2645 static int
2646 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2647 union nfs4_attr_u *na)
2648 {
2649 int error = 0;
2650
2651 if (RFS4_MANDATTR_ONLY)
2652 return (ENOTSUP);
2653
2654 switch (cmd) {
2655 case NFS4ATTR_SUPPORTED:
2656 if (sarg->op == NFS4ATTR_SETIT)
2657 error = EINVAL;
2658 break; /* this attr is supported */
2659 case NFS4ATTR_GETIT:
2660 na->time_delta.seconds = 0;
2661 na->time_delta.nseconds = 1000;
2662 break;
2663 case NFS4ATTR_SETIT:
2664 /*
2665 * write only attr
2666 */
2667 error = EINVAL;
2668 break;
2669 case NFS4ATTR_VERIT:
2670 if ((na->time_delta.seconds != 0) ||
2671 (na->time_delta.nseconds != 1000))
2672 error = -1; /* no match */
2673 break;
2674 case NFS4ATTR_FREEIT:
2675 break;
2676 }
2677 return (error);
2678 }
2679
2680 /* ARGSUSED */
2681 static int
2682 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2683 union nfs4_attr_u *na)
2684 {
2685 int error = 0;
2686 timestruc_t ctime;
2687
2688 if (RFS4_MANDATTR_ONLY)
2689 return (ENOTSUP);
2690
2691 switch (cmd) {
2692 case NFS4ATTR_SUPPORTED:
2693 if (sarg->op == NFS4ATTR_SETIT)
2694 error = EINVAL;
2695 break; /* this attr is supported */
2696 case NFS4ATTR_GETIT:
2697 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
2698 error = -1; /* may be okay if rdattr_error */
2699 break;
2700 }
2701 ASSERT(sarg->vap->va_mask & AT_CTIME);
2702 error = nfs4_time_vton(&sarg->vap->va_ctime,
2703 &na->time_metadata);
2704 break;
2705 case NFS4ATTR_SETIT:
2706 /*
2707 * read-only attr
2708 */
2709 error = EINVAL;
2710 break;
2711 case NFS4ATTR_VERIT:
2712 ASSERT(sarg->vap->va_mask & AT_CTIME);
2713 error = nfs4_time_ntov(&na->time_metadata, &ctime);
2714 if (error)
2715 break;
2716 if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
2717 error = -1; /* no match */
2718 break;
2719 case NFS4ATTR_FREEIT:
2720 break;
2721 }
2722 return (error);
2723 }
2724
2725 /* ARGSUSED */
2726 static int
2727 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2728 union nfs4_attr_u *na)
2729 {
2730 int error = 0;
2731 timestruc_t mtime;
2732
2733 if (RFS4_MANDATTR_ONLY)
2734 return (ENOTSUP);
2735
2736 switch (cmd) {
2737 case NFS4ATTR_SUPPORTED:
2738 if (sarg->op == NFS4ATTR_SETIT)
2739 error = EINVAL;
2740 break; /* this attr is supported */
2741 case NFS4ATTR_GETIT:
2742 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
2743 error = -1; /* may be okay if rdattr_error */
2744 break;
2745 }
2746 ASSERT(sarg->vap->va_mask & AT_MTIME);
2747 error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
2748 break;
2749 case NFS4ATTR_SETIT:
2750 /*
2751 * read-only attr
2752 */
2753 error = EINVAL;
2754 break;
2755 case NFS4ATTR_VERIT:
2756 ASSERT(sarg->vap->va_mask & AT_MTIME);
2757 error = nfs4_time_ntov(&na->time_modify, &mtime);
2758 if (error)
2759 break;
2760 if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
2761 error = -1; /* no match */
2762 break;
2763 case NFS4ATTR_FREEIT:
2764 break;
2765 }
2766 return (error);
2767 }
2768
2769 /*
2770 * XXX - need to add support for setting modify time
2771 */
2772 /* ARGSUSED */
2773 static int
2774 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2775 union nfs4_attr_u *na)
2776 {
2777 int error = 0;
2778 settime4 *tm;
2779
2780 if (RFS4_MANDATTR_ONLY)
2781 return (ENOTSUP);
2782
2783 switch (cmd) {
2784 case NFS4ATTR_SUPPORTED:
2785 if ((sarg->op == NFS4ATTR_GETIT) ||
2786 (sarg->op == NFS4ATTR_VERIT))
2787 error = EINVAL;
2788 break; /* this attr is supported */
2789 case NFS4ATTR_GETIT:
2790 case NFS4ATTR_VERIT:
2791 /*
2792 * write only attr
2793 */
2794 error = EINVAL;
2795 break;
2796 case NFS4ATTR_SETIT:
2797 ASSERT(sarg->vap->va_mask & AT_MTIME);
2798 /*
2799 * Set modify time (by server or by client)
2800 */
2801 tm = &na->time_modify_set;
2802 if (tm->set_it == SET_TO_CLIENT_TIME4) {
2803 error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
2804 sarg->flag = ATTR_UTIME;
2805 } else if (tm->set_it == SET_TO_SERVER_TIME4) {
2806 gethrestime(&sarg->vap->va_mtime);
2807 } else {
2808 error = EINVAL;
2809 }
2810 break;
2811 case NFS4ATTR_FREEIT:
2812 break;
2813 }
2814 return (error);
2815 }
2816
2817
2818 static void
2819 rfs4_ntov_init(void)
2820 {
2821 /* index must be same as corresponding FATTR4_* define */
2822 nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
2823 nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
2824 nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
2825 nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
2826 nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
2827 nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
2828 nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
2829 nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
2830 nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
2831 nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
2832 nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
2833 nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
2834 nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
2835 nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
2836 nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
2837 nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
2838 nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
2839 nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
2840 nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
2841 nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
2842 nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
2843 nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
2844 nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
2845 nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
2846 nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
2847 nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
2848 nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
2849 nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
2850 nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
2851 nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
2852 nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
2853 nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
2854 nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
2855 nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
2856 nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
2857 nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
2858 nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
2859 nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
2860 nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
2861 nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
2862 nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
2863 nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
2864 nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
2865 nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
2866 nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
2867 nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
2868 nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
2869 nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
2870 nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
2871 nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
2872 nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
2873 nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
2874 nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
2875 nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
2876 nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
2877 nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
2878 }