/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/time.h>
#include <sys/systm.h>
#include <nfs/nfs.h>
#include <nfs/nfs4.h>
#include <nfs/rnode4.h>
#include <nfs/nfs4_clnt.h>
#include <sys/cmn_err.h>
static int
timestruc_to_settime4(timestruc_t *tt, settime4 *tt4, int flags)
{
int error = 0;
if (flags & ATTR_UTIME) {
tt4->set_it = SET_TO_CLIENT_TIME4;
error = nfs4_time_vton(tt, &tt4->time);
} else {
tt4->set_it = SET_TO_SERVER_TIME4;
}
return (error);
}
/*
* nfs4_ver_fattr4_attr translates a vattr attribute into a fattr4 attribute
* for use by nfsv4 verify. For setting atime or mtime use the entry for
* time_XX (XX == access or modify).
* Return TRUE if arg was set (even if there was an error) and FALSE
* otherwise. Also set error code. The caller should not continue
* if error was set, whether or not the return is TRUE or FALSE. Returning
* FALSE does not mean there was an error, only that the attr was not set.
*
* Note: For now we only have the options used by setattr. In the future
* the switch statement below should cover all vattr attrs and possibly
* sys attrs as well.
*/
/* ARGSUSED */
static bool_t
nfs4_ver_fattr4_attr(vattr_t *vap, struct nfs4_ntov_map *ntovp,
union nfs4_attr_u *nap, int flags, int *errorp)
{
bool_t retval = TRUE;
/*
* Special case for time set: if setting the
* time, ignore entry for time access/modify set (setattr)
* and instead use that of time access/modify.
*/
*errorp = 0;
/*
* Bit matches the mask
*/
switch (ntovp->vbit & vap->va_mask) {
case AT_SIZE:
nap->size = vap->va_size;
break;
case AT_MODE:
nap->mode = vap->va_mode;
break;
case AT_UID:
/*
* if no mapping, uid could be mapped to a numeric string,
* e.g. 12345->"12345"
*/
if (*errorp = nfs_idmap_uid_str(vap->va_uid, &nap->owner,
FALSE))
retval = FALSE;
break;
case AT_GID:
/*
* if no mapping, gid will be mapped to a number string,
* e.g. "12345"
*/
if (*errorp = nfs_idmap_gid_str(vap->va_gid, &nap->owner_group,
FALSE))
retval = FALSE;
break;
case AT_ATIME:
if ((ntovp->nval != FATTR4_TIME_ACCESS) ||
(*errorp = nfs4_time_vton(&vap->va_ctime,
&nap->time_access))) {
/*
* either asked for FATTR4_TIME_ACCESS_SET -
* not used for setattr
* or system time invalid for otw transfers
*/
retval = FALSE;
}
break;
case AT_MTIME:
if ((ntovp->nval != FATTR4_TIME_MODIFY) ||
(*errorp = nfs4_time_vton(&vap->va_mtime,
&nap->time_modify))) {
/*
* either asked for FATTR4_TIME_MODIFY_SET -
* not used for setattr
* or system time invalid for otw transfers
*/
retval = FALSE;
}
break;
case AT_CTIME:
if (*errorp = nfs4_time_vton(&vap->va_ctime,
&nap->time_metadata)) {
/*
* system time invalid for otw transfers
*/
retval = FALSE;
}
break;
default:
retval = FALSE;
}
return (retval);
}
/*
* nfs4_set_fattr4_attr translates a vattr attribute into a fattr4 attribute
* for use by nfs4_setattr. For setting atime or mtime use the entry for
* time_XX_set rather than time_XX (XX == access or modify).
* Return TRUE if arg was set (even if there was an error) and FALSE
* otherwise. Also set error code. The caller should not continue
* if error was set, whether or not the return is TRUE or FALSE. Returning
* FALSE does not mean there was an error, only that the attr was not set.
*/
static bool_t
nfs4_set_fattr4_attr(vattr_t *vap, vsecattr_t *vsap,
struct nfs4_ntov_map *ntovp, union nfs4_attr_u *nap, int flags,
int *errorp)
{
bool_t retval = TRUE;
/*
* Special case for time set: if setting the
* time, ignore entry for time access/modify
* and instead use that of time access/modify set.
*/
*errorp = 0;
/*
* Bit matches the mask
*/
switch (ntovp->vbit & vap->va_mask) {
case AT_SIZE:
nap->size = vap->va_size;
break;
case AT_MODE:
nap->mode = vap->va_mode;
break;
case AT_UID:
/*
* if no mapping, uid will be mapped to a number string,
* e.g. "12345"
*/
if (*errorp = nfs_idmap_uid_str(vap->va_uid, &nap->owner,
FALSE))
retval = FALSE;
break;
case AT_GID:
/*
* if no mapping, gid will be mapped to a number string,
* e.g. "12345"
*/
if (*errorp = nfs_idmap_gid_str(vap->va_gid, &nap->owner_group,
FALSE))
retval = FALSE;
break;
case AT_ATIME:
if ((ntovp->nval != FATTR4_TIME_ACCESS_SET) ||
(*errorp = timestruc_to_settime4(&vap->va_atime,
&nap->time_access_set, flags))) {
/* FATTR4_TIME_ACCESS - not used for verify */
retval = FALSE;
}
break;
case AT_MTIME:
if ((ntovp->nval != FATTR4_TIME_MODIFY_SET) ||
(*errorp = timestruc_to_settime4(&vap->va_mtime,
&nap->time_modify_set, flags))) {
/* FATTR4_TIME_MODIFY - not used for verify */
retval = FALSE;
}
break;
default:
/*
* If the ntovp->vbit == 0 this is most likely the ACL.
*/
if (ntovp->vbit == 0 && ntovp->fbit == FATTR4_ACL_MASK) {
ASSERT(vsap->vsa_mask == (VSA_ACE | VSA_ACECNT));
nap->acl.fattr4_acl_len = vsap->vsa_aclcnt;
nap->acl.fattr4_acl_val = vsap->vsa_aclentp;
} else
retval = FALSE;
}
return (retval);
}
/*
* XXX - This is a shorter version of vattr_to_fattr4 which only takes care
* of setattr args - size, mode, uid/gid, times. Eventually we should generalize
* by using nfs4_ntov_map and the same functions used by the server.
* Here we just hardcoded the setattr attributes. Note that the order is
* important - it should follow the order of the bits in the mask.
*/
int
vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
enum nfs_opnum4 op, bitmap4 supp)
{
int i, j;
union nfs4_attr_u *na = NULL;
int attrcnt;
int uid_attr = -1;
int gid_attr = -1;
int acl_attr = -1;
XDR xdr;
ulong_t xdr_size;
char *xdr_attrs;
int error = 0;
uint8_t amap[NFS4_MAXNUM_ATTRS];
uint_t va_mask = vap->va_mask;
bool_t (*attrfunc)();
#ifndef lint
/*
* Make sure that maximum attribute number can be expressed as an
* 8 bit quantity.
*/
ASSERT(NFS4_MAXNUM_ATTRS <= (UINT8_MAX + 1));
#endif
fattrp->attrmask = 0;
fattrp->attrlist4_len = 0;
fattrp->attrlist4 = NULL;
na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
KM_SLEEP);
if (op == OP_SETATTR || op == OP_CREATE || op == OP_OPEN) {
/*
* Note we need to set the attrmask for set operations.
* In particular mtime and atime will be set to the
* servers time.
*/
nfs4_vmask_to_nmask_set(va_mask, &fattrp->attrmask);
if (vsap != NULL)
fattrp->attrmask |= FATTR4_ACL_MASK;
attrfunc = nfs4_set_fattr4_attr;
} else { /* verify/nverify */
/*
* Verfy/nverify use the "normal vmask_to_nmask
* this routine knows how to handle all vmask bits
*/
nfs4_vmask_to_nmask(va_mask, &fattrp->attrmask);
/*
* XXX verify/nverify only works for a subset of attrs that
* directly map to vattr_t attrs. So, verify/nverify is
* broken for servers that only support mandatory attrs.
* Mask out change attr for now and fix verify op to
* work with mandonly servers later. nfs4_vmask_to_nmask
* sets change whenever it sees request for ctime/mtime,
* so we must turn off change because nfs4_ver_fattr4_attr
* will not generate args for change. This is a bug
* that will be fixed later.
* XXX
*/
fattrp->attrmask &= ~FATTR4_CHANGE_MASK;
attrfunc = nfs4_ver_fattr4_attr;
}
/* Mask out any rec attrs unsupported by server */
fattrp->attrmask &= supp;
attrcnt = 0;
xdr_size = 0;
for (i = 0; i < nfs4_ntov_map_size; i++) {
/*
* In the case of FATTR4_ACL_MASK, the vbit will be 0 (zero)
* so we must also check if the fbit is FATTR4_ACL_MASK before
* skipping over this attribute.
*/
if (!(nfs4_ntov_map[i].vbit & vap->va_mask)) {
if (nfs4_ntov_map[i].fbit != FATTR4_ACL_MASK)
continue;
if (vsap == NULL)
continue;
}
if (attrfunc == nfs4_set_fattr4_attr) {
if (!(*attrfunc)(vap, vsap, &nfs4_ntov_map[i],
&na[attrcnt], flags, &error))
continue;
} else if (attrfunc == nfs4_ver_fattr4_attr) {
if (!(*attrfunc)(vap, &nfs4_ntov_map[i], &na[attrcnt],
flags, &error))
continue;
}
if (error)
goto done; /* Exit! */
/*
* Calculate XDR size
*/
if (nfs4_ntov_map[i].xdr_size != 0) {
/*
* If we are setting attributes (attrfunc is
* nfs4_set_fattr4_attr) and are setting the
* mtime or atime, adjust the xdr size down by
* 3 words, since we are using the server's
* time as the current time. Exception: if
* ATTR_UTIME is set, the client sends the
* time, so leave the xdr size alone.
*/
xdr_size += nfs4_ntov_map[i].xdr_size;
if ((nfs4_ntov_map[i].nval == FATTR4_TIME_ACCESS_SET ||
nfs4_ntov_map[i].nval == FATTR4_TIME_MODIFY_SET) &&
attrfunc == nfs4_set_fattr4_attr &&
!(flags & ATTR_UTIME)) {
xdr_size -= 3 * BYTES_PER_XDR_UNIT;
}
} else {
/*
* The only zero xdr_sizes we should see
* are AT_UID, AT_GID and FATTR4_ACL_MASK
*/
ASSERT(nfs4_ntov_map[i].vbit == AT_UID ||
nfs4_ntov_map[i].vbit == AT_GID ||
nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK);
if (nfs4_ntov_map[i].vbit == AT_UID) {
uid_attr = attrcnt;
xdr_size += BYTES_PER_XDR_UNIT; /* length */
xdr_size +=
RNDUP(na[attrcnt].owner.utf8string_len);
} else if (nfs4_ntov_map[i].vbit == AT_GID) {
gid_attr = attrcnt;
xdr_size += BYTES_PER_XDR_UNIT; /* length */
xdr_size +=
RNDUP(
na[attrcnt].owner_group.utf8string_len);
} else if (nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK) {
nfsace4 *tmpacl = (nfsace4 *)vsap->vsa_aclentp;
acl_attr = attrcnt;
/* fattr4_acl_len */
xdr_size += BYTES_PER_XDR_UNIT;
/* fattr4_acl_val */
xdr_size += RNDUP((vsap->vsa_aclcnt *
(sizeof (acetype4) + sizeof (aceflag4)
+ sizeof (acemask4))));
for (j = 0; j < vsap->vsa_aclcnt; j++) {
/* who - utf8string_len */
xdr_size += BYTES_PER_XDR_UNIT;
/* who - utf8string_val */
xdr_size +=
RNDUP(tmpacl[j].who.utf8string_len);
}
}
}
/*
* This attr is going otw
*/
amap[attrcnt] = (uint8_t)nfs4_ntov_map[i].nval;
attrcnt++;
/*
* Clear this bit from test mask so we stop
* as soon as all requested attrs are done.
*/
va_mask &= ~nfs4_ntov_map[i].vbit;
if (va_mask == 0 &&
(vsap == NULL || (vsap != NULL && acl_attr != -1)))
break;
}
if (attrcnt == 0) {
goto done;
}
fattrp->attrlist4 = xdr_attrs = kmem_alloc(xdr_size, KM_SLEEP);
fattrp->attrlist4_len = xdr_size;
xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE);
for (i = 0; i < attrcnt; i++) {
if ((*nfs4_ntov_map[amap[i]].xfunc)(&xdr, &na[i]) == FALSE) {
cmn_err(CE_WARN, "vattr_to_fattr4: xdr encode of "
"attribute failed\n");
error = EINVAL;
break;
}
}
done:
/*
* Free any malloc'd attrs, can only be uid or gid
*/
if (uid_attr != -1 && na[uid_attr].owner.utf8string_val != NULL) {
kmem_free(na[uid_attr].owner.utf8string_val,
na[uid_attr].owner.utf8string_len);
}
if (gid_attr != -1 && na[gid_attr].owner_group.utf8string_val != NULL) {
kmem_free(na[gid_attr].owner_group.utf8string_val,
na[gid_attr].owner_group.utf8string_len);
}
/* xdrmem_destroy(&xdrs); */ /* NO-OP */
kmem_free(na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size);
if (error)
nfs4_fattr4_free(fattrp);
return (error);
}
void
nfs4_fattr4_free(fattr4 *attrp)
{
/*
* set attrlist4val/len to 0 because...
*
* op_readdir resfree function could call us again
* for last entry4 if it was able to encode the name
* and cookie but couldn't encode the attrs because
* of maxcount violation (from rddir args). In that
* case, the last/partial entry4's fattr4 has already
* been free'd, but the entry4 remains on the end of
* the list.
*/
attrp->attrmask = 0;
if (attrp->attrlist4) {
kmem_free(attrp->attrlist4, attrp->attrlist4_len);
attrp->attrlist4 = NULL;
attrp->attrlist4_len = 0;
}
}
/*
* Translate a vattr_t mask to a fattr4 type bitmap, caller is
* responsible for zeroing bitsval if needed.
*/
void
nfs4_vmask_to_nmask(uint_t vmask, bitmap4 *bitsval)
{
if (vmask == AT_ALL || vmask == NFS4_VTON_ATTR_MASK) {
*bitsval |= NFS4_NTOV_ATTR_MASK;
return;
}
vmask &= NFS4_VTON_ATTR_MASK;
if (vmask == 0) {
return;
}
if (vmask & AT_TYPE)
*bitsval |= FATTR4_TYPE_MASK;
if (vmask & AT_MODE)
*bitsval |= FATTR4_MODE_MASK;
if (vmask & AT_UID)
*bitsval |= FATTR4_OWNER_MASK;
if (vmask & AT_GID)
*bitsval |= FATTR4_OWNER_GROUP_MASK;
if (vmask & AT_FSID)
*bitsval |= FATTR4_FSID_MASK;
/* set mounted_on_fileid when AT_NODEID requested */
if (vmask & AT_NODEID)
*bitsval |= FATTR4_FILEID_MASK | FATTR4_MOUNTED_ON_FILEID_MASK;
if (vmask & AT_NLINK)
*bitsval |= FATTR4_NUMLINKS_MASK;
if (vmask & AT_SIZE)
*bitsval |= FATTR4_SIZE_MASK;
if (vmask & AT_ATIME)
*bitsval |= FATTR4_TIME_ACCESS_MASK;
if (vmask & AT_MTIME)
*bitsval |= FATTR4_TIME_MODIFY_MASK;
/* also set CHANGE whenever AT_CTIME requested */
if (vmask & AT_CTIME)
*bitsval |= FATTR4_TIME_METADATA_MASK | FATTR4_CHANGE_MASK;
if (vmask & AT_NBLOCKS)
*bitsval |= FATTR4_SPACE_USED_MASK;
if (vmask & AT_RDEV)
*bitsval |= FATTR4_RAWDEV_MASK;
}
/*
* nfs4_vmask_to_nmask_set is used for setattr. A separate function needed
* because of special treatment to timeset.
*/
void
nfs4_vmask_to_nmask_set(uint_t vmask, bitmap4 *bitsval)
{
vmask &= NFS4_VTON_ATTR_MASK_SET;
if (vmask == 0) {
return;
}
if (vmask & AT_MODE)
*bitsval |= FATTR4_MODE_MASK;
if (vmask & AT_UID)
*bitsval |= FATTR4_OWNER_MASK;
if (vmask & AT_GID)
*bitsval |= FATTR4_OWNER_GROUP_MASK;
if (vmask & AT_SIZE)
*bitsval |= FATTR4_SIZE_MASK;
if (vmask & AT_ATIME)
*bitsval |= FATTR4_TIME_ACCESS_SET_MASK;
if (vmask & AT_MTIME)
*bitsval |= FATTR4_TIME_MODIFY_SET_MASK;
}
/*
* Convert NFS Version 4 over the network attributes to the local
* virtual attributes.
*/
vtype_t nf4_to_vt[] = {
VBAD, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VDIR, VREG
};
/*
* { fbit, vbit, vfsstat, mandatory,
* nval, xdr_size, xfunc,
* sv_getit, prtstr },
*/
struct nfs4_ntov_map nfs4_ntov_map[] = {
{ FATTR4_SUPPORTED_ATTRS_MASK, 0, FALSE, TRUE,
FATTR4_SUPPORTED_ATTRS, 2 * BYTES_PER_XDR_UNIT, xdr_bitmap4,
NULL, "fattr4_supported_attrs" },
{ FATTR4_TYPE_MASK, AT_TYPE, FALSE, TRUE,
FATTR4_TYPE, BYTES_PER_XDR_UNIT, xdr_int,
NULL, "fattr4_type" },
{ FATTR4_FH_EXPIRE_TYPE_MASK, 0, FALSE, TRUE,
FATTR4_FH_EXPIRE_TYPE, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_fh_expire_type" },
{ FATTR4_CHANGE_MASK, 0, FALSE, TRUE,
FATTR4_CHANGE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_change" },
{ FATTR4_SIZE_MASK, AT_SIZE, FALSE, TRUE,
FATTR4_SIZE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_size" },
{ FATTR4_LINK_SUPPORT_MASK, 0, FALSE, TRUE,
FATTR4_LINK_SUPPORT, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_link_support" },
{ FATTR4_SYMLINK_SUPPORT_MASK, 0, FALSE, TRUE,
FATTR4_SYMLINK_SUPPORT, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_symlink_support" },
{ FATTR4_NAMED_ATTR_MASK, 0, FALSE, TRUE,
FATTR4_NAMED_ATTR, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_named_attr" },
{ FATTR4_FSID_MASK, AT_FSID, FALSE, TRUE,
FATTR4_FSID, 4 * BYTES_PER_XDR_UNIT, xdr_fattr4_fsid,
NULL, "fattr4_fsid" },
{ FATTR4_UNIQUE_HANDLES_MASK, 0, FALSE, TRUE,
FATTR4_UNIQUE_HANDLES, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_unique_handles" },
{ FATTR4_LEASE_TIME_MASK, 0, FALSE, TRUE,
FATTR4_LEASE_TIME, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_lease_time" },
{ FATTR4_RDATTR_ERROR_MASK, 0, FALSE, TRUE,
FATTR4_RDATTR_ERROR, BYTES_PER_XDR_UNIT, xdr_int,
NULL, "fattr4_rdattr_error" },
{ FATTR4_ACL_MASK, 0, FALSE, FALSE,
FATTR4_ACL, 0, xdr_fattr4_acl,
NULL, "fattr4_acl" },
{ FATTR4_ACLSUPPORT_MASK, 0, FALSE, FALSE,
FATTR4_ACLSUPPORT, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_aclsupport" },
{ FATTR4_ARCHIVE_MASK, 0, FALSE, FALSE,
FATTR4_ARCHIVE, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_archive" },
{ FATTR4_CANSETTIME_MASK, 0, FALSE, FALSE,
FATTR4_CANSETTIME, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_cansettime" },
{ FATTR4_CASE_INSENSITIVE_MASK, 0, FALSE, FALSE,
FATTR4_CASE_INSENSITIVE, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_case_insensitive" },
{ FATTR4_CASE_PRESERVING_MASK, 0, FALSE, FALSE,
FATTR4_CASE_PRESERVING, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_case_preserving" },
{ FATTR4_CHOWN_RESTRICTED_MASK, 0, FALSE, FALSE,
FATTR4_CHOWN_RESTRICTED, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_chown_restricted" },
{ FATTR4_FILEHANDLE_MASK, 0, FALSE, TRUE,
FATTR4_FILEHANDLE, 0, xdr_nfs_fh4,
NULL, "fattr4_filehandle" },
{ FATTR4_FILEID_MASK, AT_NODEID, FALSE, FALSE,
FATTR4_FILEID, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_fileid" },
{ FATTR4_FILES_AVAIL_MASK, 0, TRUE, FALSE,
FATTR4_FILES_AVAIL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_files_avail" },
{ FATTR4_FILES_FREE_MASK, 0, TRUE, FALSE,
FATTR4_FILES_FREE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_files_free" },
{ FATTR4_FILES_TOTAL_MASK, 0, TRUE, FALSE,
FATTR4_FILES_TOTAL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_files_total" },
{ FATTR4_FS_LOCATIONS_MASK, 0, FALSE, FALSE,
FATTR4_FS_LOCATIONS, 0, xdr_fattr4_fs_locations,
NULL, "fattr4_fs_locations" },
{ FATTR4_HIDDEN_MASK, 0, FALSE, FALSE,
FATTR4_HIDDEN, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_hidden" },
{ FATTR4_HOMOGENEOUS_MASK, 0, FALSE, FALSE,
FATTR4_HOMOGENEOUS, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_homogeneous" },
{ FATTR4_MAXFILESIZE_MASK, 0, FALSE, FALSE,
FATTR4_MAXFILESIZE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_maxfilesize" },
{ FATTR4_MAXLINK_MASK, 0, FALSE, FALSE,
FATTR4_MAXLINK, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_maxlink" },
{ FATTR4_MAXNAME_MASK, 0, FALSE, FALSE,
FATTR4_MAXNAME, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_maxname" },
{ FATTR4_MAXREAD_MASK, 0, FALSE, FALSE,
FATTR4_MAXREAD, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_maxread" },
{ FATTR4_MAXWRITE_MASK, 0, FALSE, FALSE,
FATTR4_MAXWRITE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_maxwrite" },
{ FATTR4_MIMETYPE_MASK, 0, FALSE, FALSE,
FATTR4_MIMETYPE, 0, xdr_utf8string,
NULL, "fattr4_mimetype" },
{ FATTR4_MODE_MASK, AT_MODE, FALSE, FALSE,
FATTR4_MODE, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_mode" },
{ FATTR4_NO_TRUNC_MASK, 0, FALSE, FALSE,
FATTR4_NO_TRUNC, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_no_trunc" },
{ FATTR4_NUMLINKS_MASK, AT_NLINK, FALSE, FALSE,
FATTR4_NUMLINKS, BYTES_PER_XDR_UNIT, xdr_u_int,
NULL, "fattr4_numlinks" },
{ FATTR4_OWNER_MASK, AT_UID, FALSE, FALSE,
FATTR4_OWNER, 0, xdr_utf8string,
NULL, "fattr4_owner" },
{ FATTR4_OWNER_GROUP_MASK, AT_GID, FALSE, FALSE,
FATTR4_OWNER_GROUP, 0, xdr_utf8string,
NULL, "fattr4_owner_group" },
{ FATTR4_QUOTA_AVAIL_HARD_MASK, 0, FALSE, FALSE,
FATTR4_QUOTA_AVAIL_HARD, 2 * BYTES_PER_XDR_UNIT,
xdr_u_longlong_t,
NULL, "fattr4_quota_avail_hard" },
{ FATTR4_QUOTA_AVAIL_SOFT_MASK, 0, FALSE, FALSE,
FATTR4_QUOTA_AVAIL_SOFT, 2 * BYTES_PER_XDR_UNIT,
xdr_u_longlong_t,
NULL, "fattr4_quota_avail_soft" },
{ FATTR4_QUOTA_USED_MASK, 0, FALSE, FALSE,
FATTR4_QUOTA_USED, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_quota_used" },
{ FATTR4_RAWDEV_MASK, AT_RDEV, FALSE, FALSE,
FATTR4_RAWDEV, 2 * BYTES_PER_XDR_UNIT, xdr_fattr4_rawdev,
NULL, "fattr4_rawdev" },
{ FATTR4_SPACE_AVAIL_MASK, 0, TRUE, FALSE,
FATTR4_SPACE_AVAIL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_space_avail" },
{ FATTR4_SPACE_FREE_MASK, 0, TRUE, FALSE,
FATTR4_SPACE_FREE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_space_free" },
{ FATTR4_SPACE_TOTAL_MASK, 0, TRUE, FALSE,
FATTR4_SPACE_TOTAL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_space_total" },
{ FATTR4_SPACE_USED_MASK, AT_NBLOCKS, FALSE, FALSE,
FATTR4_SPACE_USED, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
NULL, "fattr4_space_used" },
{ FATTR4_SYSTEM_MASK, 0, FALSE, FALSE,
FATTR4_SYSTEM, BYTES_PER_XDR_UNIT, xdr_bool,
NULL, "fattr4_system" },
{ FATTR4_TIME_ACCESS_MASK, AT_ATIME, FALSE, FALSE,
FATTR4_TIME_ACCESS, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_access" },
{ FATTR4_TIME_ACCESS_SET_MASK, AT_ATIME, FALSE, FALSE,
FATTR4_TIME_ACCESS_SET, 4 * BYTES_PER_XDR_UNIT, xdr_settime4,
NULL, "fattr4_time_access_set" },
{ FATTR4_TIME_BACKUP_MASK, 0, FALSE, FALSE,
FATTR4_TIME_BACKUP, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_backup" },
{ FATTR4_TIME_CREATE_MASK, 0, FALSE, FALSE,
FATTR4_TIME_CREATE, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_create" },
{ FATTR4_TIME_DELTA_MASK, 0, FALSE, FALSE,
FATTR4_TIME_DELTA, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_delta" },
{ FATTR4_TIME_METADATA_MASK, AT_CTIME, FALSE, FALSE,
FATTR4_TIME_METADATA, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_metadata" },
{ FATTR4_TIME_MODIFY_MASK, AT_MTIME, FALSE, FALSE,
FATTR4_TIME_MODIFY, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
NULL, "fattr4_time_modify" },
{ FATTR4_TIME_MODIFY_SET_MASK, AT_MTIME, FALSE, FALSE,
FATTR4_TIME_MODIFY_SET, 4 * BYTES_PER_XDR_UNIT, xdr_settime4,
NULL, "fattr4_time_modify_set" },
{ FATTR4_MOUNTED_ON_FILEID_MASK, AT_NODEID, FALSE, FALSE,
FATTR4_MOUNTED_ON_FILEID, 2 * BYTES_PER_XDR_UNIT,
xdr_u_longlong_t,
NULL, "fattr4_mounted_on_fileid" },
};
uint_t nfs4_ntov_map_size = sizeof (nfs4_ntov_map) /
sizeof (struct nfs4_ntov_map);