#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <nfs/nfs.h>
#include <nfs/export.h>
#include <nfs/nfs4.h>
#include <sys/ddi.h>
#include <sys/door.h>
#include <sys/sdt.h>
#include <nfs/nfssys.h>
void rfs4_init_compound_state(struct compound_state *);
bitmap4 rfs4_supported_attrs;
int MSG_PRT_DEBUG = FALSE;
#ifdef DEBUG
#ifndef RFS4_SUPPORT_MANDATTR_ONLY
#define RFS4_SUPPORT_MANDATTR_ONLY
#endif
#endif
#ifdef RFS4_SUPPORT_MANDATTR_ONLY
#define NFS4_LAST_MANDATTR FATTR4_RDATTR_ERROR
#define RFS4_MANDATTR_ONLY rfs4_mandattr_only
int rfs4_mandattr_only = 0;
#else
#define RFS4_MANDATTR_ONLY 0
#endif
static void rfs4_ntov_init(void);
static int rfs4_fattr4_supported_attrs();
static int rfs4_fattr4_type();
static int rfs4_fattr4_fh_expire_type();
static int rfs4_fattr4_change();
static int rfs4_fattr4_size();
static int rfs4_fattr4_link_support();
static int rfs4_fattr4_symlink_support();
static int rfs4_fattr4_named_attr();
static int rfs4_fattr4_fsid();
static int rfs4_fattr4_unique_handles();
static int rfs4_fattr4_lease_time();
static int rfs4_fattr4_rdattr_error();
static int rfs4_fattr4_acl();
static int rfs4_fattr4_aclsupport();
static int rfs4_fattr4_archive();
static int rfs4_fattr4_cansettime();
static int rfs4_fattr4_case_insensitive();
static int rfs4_fattr4_case_preserving();
static int rfs4_fattr4_chown_restricted();
static int rfs4_fattr4_filehandle();
static int rfs4_fattr4_fileid();
static int rfs4_fattr4_files_avail();
static int rfs4_fattr4_files_free();
static int rfs4_fattr4_files_total();
static int rfs4_fattr4_fs_locations();
static int rfs4_fattr4_hidden();
static int rfs4_fattr4_homogeneous();
static int rfs4_fattr4_maxfilesize();
static int rfs4_fattr4_maxlink();
static int rfs4_fattr4_maxname();
static int rfs4_fattr4_maxread();
static int rfs4_fattr4_maxwrite();
static int rfs4_fattr4_mimetype();
static int rfs4_fattr4_mode();
static int rfs4_fattr4_no_trunc();
static int rfs4_fattr4_numlinks();
static int rfs4_fattr4_owner();
static int rfs4_fattr4_owner_group();
static int rfs4_fattr4_quota_avail_hard();
static int rfs4_fattr4_quota_avail_soft();
static int rfs4_fattr4_quota_used();
static int rfs4_fattr4_rawdev();
static int rfs4_fattr4_space_avail();
static int rfs4_fattr4_space_free();
static int rfs4_fattr4_space_total();
static int rfs4_fattr4_space_used();
static int rfs4_fattr4_system();
static int rfs4_fattr4_time_access();
static int rfs4_fattr4_time_access_set();
static int rfs4_fattr4_time_backup();
static int rfs4_fattr4_time_create();
static int rfs4_fattr4_time_delta();
static int rfs4_fattr4_time_metadata();
static int rfs4_fattr4_time_modify();
static int rfs4_fattr4_time_modify_set();
bitmap4 supported_attrs[3];
static void
init_supported_attrs(void)
{
supported_attrs[0] = supported_attrs[1] = supported_attrs[2] =
rfs4_supported_attrs;
supported_attrs[0] &= ~(FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL |
FATTR4_SEC_LABEL_MASK_LOCAL);
supported_attrs[1] &= ~FATTR4_SEC_LABEL_MASK_LOCAL;
}
void
rfs4_attr_init(void)
{
int i;
struct nfs4_svgetit_arg sarg;
struct compound_state cs;
struct statvfs64 sb;
rfs4_init_compound_state(&cs);
cs.vp = rootvp;
cs.fh.nfs_fh4_val = NULL;
cs.cr = kcred;
cs.minorversion = NFS_PROT_V4_MINORVERSION(NFS_VERS_4_2);
sarg.op = NFS4ATTR_SUPPORTED;
sarg.cs = &cs;
sarg.vap->va_mask = AT_ALL;
sarg.sbp = &sb;
sarg.flag = 0;
sarg.rdattr_error = NFS4_OK;
sarg.rdattr_error_req = FALSE;
sarg.is_referral = B_FALSE;
rfs4_ntov_init();
rfs4_supported_attrs = 0;
for (i = 0; i < NFS4_MAXNUM_ATTRS; i++) {
#ifdef RFS4_SUPPORT_MANDATTR_ONLY
if (rfs4_mandattr_only == TRUE && i > NFS4_LAST_MANDATTR)
continue;
#endif
if ((*nfs4_ntov_map[i].sv_getit)(NFS4ATTR_SUPPORTED,
&sarg, NULL) == 0) {
rfs4_supported_attrs |= nfs4_ntov_map[i].fbit;
}
}
init_supported_attrs();
}
static int
rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
bitmap4 supported = supported_attrs[sarg->cs->minorversion];
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->supported_attrs = supported;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->supported_attrs != supported) {
error = -1;
}
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static nfs_ftype4 vt_to_nf4[] = {
0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0
};
static int
rfs4_fattr4_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_TYPE)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_TYPE);
if (! (sarg->xattr & (FH4_NAMEDATTR | FH4_ATTRDIR)))
na->type = vt_to_nf4[sarg->vap->va_type];
else {
if (sarg->vap->va_type == VDIR)
na->type = NF4ATTRDIR;
else
na->type = NF4NAMEDATTR;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_TYPE);
if (sarg->vap->va_type != nf4_to_vt[na->type])
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
fattr4_get_fh_expire_type(struct exportinfo *exi, uint32_t *fh_expire_typep)
{
#ifdef VOLATILE_FH_TEST
int ex_flags;
if (exi == NULL)
return (ESTALE);
ex_flags = exi->exi_export.ex_flags;
if ((ex_flags & (EX_VOLFH | EX_VOLRNM | EX_VOLMIG | EX_NOEXPOPEN))
== 0) {
*fh_expire_typep = FH4_PERSISTENT;
return (0);
}
*fh_expire_typep = 0;
if (ex_flags & EX_NOEXPOPEN) {
*fh_expire_typep = FH4_NOEXPIRE_WITH_OPEN;
}
if (ex_flags & EX_VOLFH) {
*fh_expire_typep |= FH4_VOLATILE_ANY;
return (0);
}
if (ex_flags & EX_VOLRNM) {
*fh_expire_typep |= FH4_VOL_RENAME;
}
if (ex_flags & EX_VOLMIG) {
*fh_expire_typep |= FH4_VOL_MIGRATION;
}
#else
*fh_expire_typep = FH4_PERSISTENT;
#endif
return (0);
}
static int
rfs4_fattr4_fh_expire_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
uint32_t fh_expire_type;
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
error = fattr4_get_fh_expire_type(sarg->cs->exi,
&na->fh_expire_type);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
error = fattr4_get_fh_expire_type(sarg->cs->exi,
&fh_expire_type);
if (!error && (na->fh_expire_type != fh_expire_type))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep)
{
vattr_t vap2[1], *vap = sarg->vap;
struct compound_state *cs = sarg->cs;
vnode_t *vp = cs->vp;
nfsstat4 status;
timespec_t vis_change;
if ((vap->va_mask & AT_CTIME) == 0) {
if (sarg->rdattr_error && (vp == NULL)) {
return (-1);
}
ASSERT(vp != NULL);
vap = vap2;
vap->va_mask = AT_CTIME;
status = rfs4_vop_getattr(vp, vap, 0, cs->cr);
if (status != NFS4_OK)
return (geterrno4(status));
}
NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime);
if (nfs_visible_change(cs->exi, vp, &vis_change)) {
fattr4_change visch;
NFS4_SET_FATTR4_CHANGE(visch, vis_change);
if (visch > *changep)
*changep = visch;
}
return (0);
}
static int
rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
fattr4_change change;
uint_t mask;
vattr_t *vap = sarg->vap;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
error = fattr4_get_change(sarg, &na->change);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
mask = vap->va_mask;
vap->va_mask &= ~AT_CTIME;
error = fattr4_get_change(sarg, &change);
vap->va_mask = mask;
if (!error && (na->change != change))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_SIZE)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_SIZE);
na->size = sarg->vap->va_size;
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_SIZE);
sarg->vap->va_size = na->size;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_SIZE);
if (sarg->vap->va_size != na->size)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->link_support = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->link_support)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->symlink_support = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->symlink_support)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->cs->vp != NULL);
val = 0;
error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS,
&val, sarg->cs->cr, NULL);
if ((error || val == 0) &&
sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp,
_PC_XATTR_EXISTS, &val, sarg->cs->cr, NULL);
if (error)
break;
}
na->named_attr = (val ? TRUE : FALSE);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS,
&val, sarg->cs->cr, NULL);
if (error || val == 0)
error = VOP_PATHCONF(sarg->cs->vp,
_PC_XATTR_EXISTS, &val,
sarg->cs->cr, NULL);
if (error)
break;
} else
val = 0;
if (na->named_attr != (val ? TRUE : FALSE))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
int *pmaj = (int *)&na->fsid.major;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->is_referral) {
na->fsid.major = 1;
na->fsid.minor = 0;
} else if (sarg->cs->exi->exi_volatile_dev) {
pmaj[0] = sarg->cs->exi->exi_fsid.val[0];
pmaj[1] = sarg->cs->exi->exi_fsid.val[1];
na->fsid.minor = 0;
} else {
na->fsid.major = getmajor(sarg->vap->va_fsid);
na->fsid.minor = getminor(sarg->vap->va_fsid);
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (sarg->is_referral) {
if (na->fsid.major != 1 ||
na->fsid.minor != 0)
error = -1;
} else if (sarg->cs->exi->exi_volatile_dev) {
if (pmaj[0] != sarg->cs->exi->exi_fsid.val[0] ||
pmaj[1] != sarg->cs->exi->exi_fsid.val[1] ||
na->fsid.minor != 0)
error = -1;
} else {
if (na->fsid.major != getmajor(sarg->vap->va_fsid) ||
na->fsid.minor != getminor(sarg->vap->va_fsid))
error = -1;
}
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->unique_handles = FALSE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->unique_handles)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->lease_time = rfs4_lease_time;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->lease_time != rfs4_lease_time)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_rdattr_error(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if ((sarg->op == NFS4ATTR_SETIT) ||
(sarg->op == NFS4ATTR_VERIT))
error = EINVAL;
break;
case NFS4ATTR_GETIT:
ASSERT(sarg->rdattr_error_req);
na->rdattr_error = sarg->rdattr_error;
break;
case NFS4ATTR_SETIT:
case NFS4ATTR_VERIT:
error = EINVAL;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4fhcmp(nfs_fh4 *wirefh, nfs_fh4 *srvfh)
{
nfs_fh4_fmt_t fh;
ASSERT(IS_P2ALIGNED(wirefh->nfs_fh4_val, sizeof (uint32_t)));
bzero(&fh, sizeof (nfs_fh4_fmt_t));
if (!xdr_inline_decode_nfs_fh4((uint32_t *)wirefh->nfs_fh4_val, &fh,
wirefh->nfs_fh4_len))
return (1);
return (bcmp(srvfh->nfs_fh4_val, &fh, srvfh->nfs_fh4_len));
}
static int
rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
nfs_fh4 *fh;
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
return (EINVAL);
return (0);
case NFS4ATTR_GETIT:
fh = &sarg->cs->fh;
if (sarg->cs->fh.nfs_fh4_len == 0) {
if (sarg->rdattr_error && (sarg->cs->vp == NULL))
return (-1);
ASSERT(sarg->cs->vp != NULL);
na->filehandle.nfs_fh4_val =
kmem_alloc(NFS_FH4_LEN, KM_SLEEP);
return (makefh4(&na->filehandle, sarg->cs->vp,
sarg->cs->exi));
}
na->filehandle.nfs_fh4_val =
kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
nfs_fh4_copy(fh, &na->filehandle);
return (0);
case NFS4ATTR_SETIT:
return (EINVAL);
case NFS4ATTR_VERIT:
if (rfs4fhcmp(&na->filehandle, &sarg->cs->fh) == 1)
return (-1);
return (0);
case NFS4ATTR_FREEIT:
if (sarg->op != NFS4ATTR_GETIT)
return (0);
if (na->filehandle.nfs_fh4_val == NULL)
return (0);
kmem_free(na->filehandle.nfs_fh4_val,
na->filehandle.nfs_fh4_len);
na->filehandle.nfs_fh4_val = NULL;
na->filehandle.nfs_fh4_len = 0;
return (0);
}
return (0);
}
static int
rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
vsecattr_t vs_native, vs_ace4;
ulong_t whichacl;
nfsstat4 status;
vattr_t va, *vap = sarg->vap;
vnode_t *vp = sarg->cs->vp;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
break;
case NFS4ATTR_VERIT:
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (vp == NULL)) {
return (-1);
}
ASSERT(vp != NULL);
bzero(&vs_native, sizeof (vs_native));
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
sarg->cs->cr, NULL);
if (error != 0) {
error = 0;
whichacl = _ACL_ACLENT_ENABLED;
}
if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
whichacl = _ACL_ACLENT_ENABLED;
}
if (whichacl & _ACL_ACE_ENABLED)
vs_native.vsa_mask = VSA_ACE | VSA_ACECNT;
else if (whichacl & _ACL_ACLENT_ENABLED)
vs_native.vsa_mask = VSA_ACL | VSA_ACLCNT |
VSA_DFACL | VSA_DFACLCNT;
if (error != 0)
break;
error = VOP_GETSECATTR(vp, &vs_native,
0, sarg->cs->cr, NULL);
if (error != 0)
break;
if (whichacl & _ACL_ACE_ENABLED) {
error = vs_acet_to_ace4(&vs_native, &vs_ace4, TRUE);
vs_acet_destroy(&vs_native);
} else {
error = vs_aent_to_ace4(&vs_native, &vs_ace4,
vp->v_type == VDIR, TRUE);
vs_aent_destroy(&vs_native);
}
if (error != 0)
break;
if (cmd == NFS4ATTR_GETIT) {
na->acl.fattr4_acl_len = vs_ace4.vsa_aclcnt;
na->acl.fattr4_acl_val = vs_ace4.vsa_aclentp;
} else {
if (na->acl.fattr4_acl_len != vs_ace4.vsa_aclcnt)
error = -1;
else if (ln_ace4_cmp(na->acl.fattr4_acl_val,
vs_ace4.vsa_aclentp,
vs_ace4.vsa_aclcnt) != 0)
error = -1;
}
break;
case NFS4ATTR_SETIT:
if (sarg->rdattr_error && (vp == NULL)) {
return (-1);
}
ASSERT(vp != NULL);
bzero(&vs_ace4, sizeof (vs_ace4));
vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
vs_ace4.vsa_aclentsz = vs_ace4.vsa_aclcnt * sizeof (ace_t);
if ((vap->va_mask & (AT_UID | AT_GID)) !=
(AT_UID | AT_GID)) {
vap = &va;
vap->va_mask = AT_UID | AT_GID;
status = rfs4_vop_getattr(vp,
vap, 0, sarg->cs->cr);
if (status != NFS4_OK)
return (geterrno4(status));
}
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
sarg->cs->cr, NULL);
if (error != 0) {
error = 0;
whichacl = _ACL_ACLENT_ENABLED;
}
if (!(whichacl & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED))) {
whichacl = _ACL_ACLENT_ENABLED;
}
if (whichacl & _ACL_ACE_ENABLED) {
error = vs_ace4_to_acet(&vs_ace4, &vs_native,
vap->va_uid, vap->va_gid, TRUE);
if (error != 0)
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_acet_destroy(&vs_native);
} else if (whichacl & _ACL_ACLENT_ENABLED) {
error = vs_ace4_to_aent(&vs_ace4, &vs_native,
vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE);
if (error != 0)
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_aent_destroy(&vs_native);
}
break;
case NFS4ATTR_FREEIT:
if (sarg->op == NFS4ATTR_GETIT) {
vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
vs_ace4_destroy(&vs_ace4);
}
break;
}
return (error);
}
static int
rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->aclsupport = ACL4_SUPPORT_ALLOW_ACL |
ACL4_SUPPORT_DENY_ACL;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL |
ACL4_SUPPORT_DENY_ACL))
error = -1;
break;
}
return (error);
}
static int
rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->cansettime = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->cansettime)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->case_insensitive = FALSE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->case_insensitive)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->case_preserving = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->case_preserving)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
na->chown_restricted = (val == 1);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
if (na->chown_restricted != (val == 1))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_NODEID);
na->fileid = sarg->vap->va_nodeid;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_NODEID);
if (sarg->vap->va_nodeid != na->fileid)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
{
int error = 0;
vattr_t *vap, va;
vnode_t *stubvp = NULL, *vp;
vp = sarg->cs->vp;
sarg->mntdfid_set = FALSE;
if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
VN_HOLD(vp);
stubvp = untraverse(vp, ZONE_ROOTVP());
if (VN_CMP(vp, stubvp)) {
ASSERT(VN_IS_CURZONEROOT(vp));
vap = sarg->vap;
} else {
va.va_mask = AT_NODEID;
vap = &va;
error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr);
}
VN_RELE(stubvp);
} else
vap = sarg->vap;
if (!error && (vap->va_mask & AT_NODEID)) {
sarg->mounted_on_fileid = vap->va_nodeid;
sarg->mntdfid_set = TRUE;
} else if (sarg->rdattr_error)
error = -1;
return (error);
}
static int
rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
case NFS4ATTR_VERIT:
if (!sarg->mntdfid_set)
error = rfs4_get_mntdfileid(cmd, sarg);
if (!error && sarg->mntdfid_set) {
if (cmd == NFS4ATTR_GETIT)
na->mounted_on_fileid = sarg->mounted_on_fileid;
else
if (na->mounted_on_fileid !=
sarg->mounted_on_fileid)
error = -1;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
na->files_avail = sarg->sbp->f_favail;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_favail != na->files_avail)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
na->files_free = sarg->sbp->f_ffree;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_ffree != na->files_free)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
na->files_total = sarg->sbp->f_files;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_files != na->files_total)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static void
rfs4_free_pathname4(pathname4 *pn4)
{
int i, len;
utf8string *utf8s;
if (pn4 == NULL || (len = pn4->pathname4_len) == 0 ||
(utf8s = pn4->pathname4_val) == NULL)
return;
for (i = 0; i < len; i++, utf8s++) {
if (utf8s->utf8string_val == NULL ||
utf8s->utf8string_len == 0)
continue;
kmem_free(utf8s->utf8string_val, utf8s->utf8string_len);
utf8s->utf8string_val = NULL;
}
kmem_free(pn4->pathname4_val,
sizeof (utf8string) * pn4->pathname4_len);
pn4->pathname4_val = 0;
}
static void
rfs4_free_fs_location4(fs_location4 *fsl4)
{
if (fsl4 == NULL)
return;
rfs4_free_pathname4((pathname4 *)&fsl4->server_len);
rfs4_free_pathname4(&fsl4->rootpath);
}
void
rfs4_free_fs_locations4(fs_locations4 *fsls4)
{
int i, len;
fs_location4 *fsl4;
if (fsls4 == NULL)
return;
rfs4_free_pathname4(&fsls4->fs_root);
if ((len = fsls4->locations_len) == 0 ||
(fsl4 = fsls4->locations_val) == NULL)
return;
for (i = 0; i < len; i++) {
rfs4_free_fs_location4(fsl4);
fsl4++;
}
kmem_free(fsls4->locations_val, sizeof (fs_location4) * len);
fsls4->locations_val = NULL;
}
static int
rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
fs_locations4 *fsl;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
{
kstat_named_t *stat =
sarg->cs->exi->exi_ne->ne_globals->svstat[NFS_V4];
fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
if (fsl == NULL)
(void) memset(&(na->fs_locations), 0,
sizeof (fs_locations4));
else {
na->fs_locations = *fsl;
kmem_free(fsl, sizeof (fs_locations4));
}
stat[NFS_REFERRALS].value.ui64++;
break;
}
case NFS4ATTR_FREEIT:
if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
error = EINVAL;
rfs4_free_fs_locations4(&na->fs_locations);
break;
case NFS4ATTR_SETIT:
case NFS4ATTR_VERIT:
error = EINVAL;
break;
}
return (error);
}
static int
rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->homogeneous = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->homogeneous)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
fattr4_maxfilesize maxfilesize;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
sarg->cs->cr, NULL);
if (error)
break;
if (val == (ulong_t)-1) {
na->maxfilesize = MAXOFF32_T;
} else {
if (val >= (sizeof (uint64_t) * 8))
na->maxfilesize = INT64_MAX;
else
na->maxfilesize = ((1LL << (val - 1)) - 1);
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
sarg->cs->cr, NULL);
if (error)
break;
if (val == (ulong_t)-1) {
maxfilesize = MAXOFF32_T;
} else {
if (val >= (sizeof (uint64_t) * 8))
maxfilesize = INT64_MAX;
else
maxfilesize = ((1LL << (val - 1)) - 1);
}
if (na->maxfilesize != maxfilesize)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
sarg->cs->cr, NULL);
if (error == 0) {
na->maxlink = val;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
sarg->cs->cr, NULL);
if (!error && (na->maxlink != (uint32_t)val))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
sarg->cs->cr, NULL);
if (error == 0) {
na->maxname = val;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
sarg->cs->cr, NULL);
if (!error && (na->maxname != val))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->maxread = rfs4_tsize(sarg->cs->req);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->maxread != rfs4_tsize(sarg->cs->req))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->maxwrite = rfs4_tsize(sarg->cs->req);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->maxwrite != rfs4_tsize(sarg->cs->req))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_MODE);
na->mode = sarg->vap->va_mode;
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_MODE);
sarg->vap->va_mode = na->mode;
if (sarg->cs->vp->v_type == VREG &&
(sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
sarg->vap->va_mode &= ~(VSUID | VSGID);
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_MODE);
if (sarg->vap->va_mode != na->mode)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->no_trunc = TRUE;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (!na->no_trunc)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_NLINK);
na->numlinks = sarg->vap->va_nlink;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_NLINK);
if (sarg->vap->va_nlink != na->numlinks)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
uid_t uid;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_UID);
error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
switch (error) {
case ECONNREFUSED:
error = NFS4ERR_DELAY;
break;
default:
break;
}
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_UID);
error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
switch (error) {
case NFS4_OK:
case ENOTSUP:
error = 0;
MSG_PRT_DEBUG = FALSE;
break;
case ECOMM:
case ECONNREFUSED:
if (!MSG_PRT_DEBUG) {
cmn_err(CE_WARN, "!Unable to contact "
"nfsmapid");
MSG_PRT_DEBUG = TRUE;
}
error = NFS4ERR_DELAY;
break;
case EINVAL:
error = NFS4ERR_INVAL;
break;
default:
error = NFS4ERR_BADOWNER;
break;
}
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_UID);
error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
if (error == ENOTSUP)
error = 0;
if (error)
error = -1;
else if (sarg->vap->va_uid != uid)
error = -1;
break;
case NFS4ATTR_FREEIT:
if (sarg->op == NFS4ATTR_GETIT) {
if (na->owner.utf8string_val) {
UTF8STRING_FREE(na->owner)
bzero(&na->owner, sizeof (na->owner));
}
}
break;
}
return (error);
}
static int
rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
gid_t gid;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_GID);
error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
TRUE);
switch (error) {
case ECONNREFUSED:
error = NFS4ERR_DELAY;
break;
default:
break;
}
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_GID);
error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
TRUE);
switch (error) {
case NFS4_OK:
case ENOTSUP:
error = 0;
MSG_PRT_DEBUG = FALSE;
break;
case ECOMM:
case ECONNREFUSED:
if (!MSG_PRT_DEBUG) {
cmn_err(CE_WARN, "!Unable to contact "
"nfsmapid");
MSG_PRT_DEBUG = TRUE;
}
error = NFS4ERR_DELAY;
break;
case EINVAL:
error = NFS4ERR_INVAL;
break;
default:
error = NFS4ERR_BADOWNER;
break;
}
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_GID);
error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
if (error == ENOTSUP)
error = 0;
if (error)
error = -1;
else if (sarg->vap->va_gid != gid)
error = -1;
break;
case NFS4ATTR_FREEIT:
if (sarg->op == NFS4ATTR_GETIT) {
if (na->owner_group.utf8string_val) {
UTF8STRING_FREE(na->owner_group)
bzero(&na->owner_group,
sizeof (na->owner_group));
}
}
break;
}
return (error);
}
static int
rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_RDEV);
na->rawdev.specdata1 = (uint32)getmajor(sarg->vap->va_rdev);
na->rawdev.specdata2 = (uint32)getminor(sarg->vap->va_rdev);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_RDEV);
if ((na->rawdev.specdata1 !=
(uint32)getmajor(sarg->vap->va_rdev)) ||
(na->rawdev.specdata2 !=
(uint32)getminor(sarg->vap->va_rdev)))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
na->space_avail =
(fattr4_space_avail) sarg->sbp->f_frsize *
(fattr4_space_avail) sarg->sbp->f_bavail;
} else {
na->space_avail =
(fattr4_space_avail) sarg->sbp->f_bavail;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_bavail != na->space_avail)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
na->space_free =
(fattr4_space_free) sarg->sbp->f_frsize *
(fattr4_space_free) sarg->sbp->f_bfree;
} else {
na->space_free =
(fattr4_space_free) sarg->sbp->f_bfree;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_bfree != na->space_free)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
error = -1;
break;
}
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
na->space_total =
(fattr4_space_total) sarg->sbp->f_frsize *
(fattr4_space_total) sarg->sbp->f_blocks;
} else {
na->space_total =
(fattr4_space_total) sarg->sbp->f_blocks;
}
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->sbp != NULL);
if (sarg->sbp->f_blocks != na->space_total)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
na->space_used = (fattr4_space_used) DEV_BSIZE *
(fattr4_space_used) sarg->vap->va_nblocks;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
if (sarg->vap->va_nblocks != na->space_used)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
timestruc_t atime;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_ATIME);
error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_ATIME);
error = nfs4_time_ntov(&na->time_access, &atime);
if (error)
break;
if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
settime4 *ta;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if ((sarg->op == NFS4ATTR_GETIT) ||
(sarg->op == NFS4ATTR_VERIT))
error = EINVAL;
break;
case NFS4ATTR_GETIT:
case NFS4ATTR_VERIT:
error = EINVAL;
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_ATIME);
ta = &na->time_access_set;
if (ta->set_it == SET_TO_CLIENT_TIME4) {
error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
} else if (ta->set_it == SET_TO_SERVER_TIME4) {
gethrestime(&sarg->vap->va_atime);
} else {
error = EINVAL;
}
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
return (ENOTSUP);
}
static int
rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->time_delta.seconds = 0;
na->time_delta.nseconds = 1000;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if ((na->time_delta.seconds != 0) ||
(na->time_delta.nseconds != 1000))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
timestruc_t ctime;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_CTIME);
error = nfs4_time_vton(&sarg->vap->va_ctime,
&na->time_metadata);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_CTIME);
error = nfs4_time_ntov(&na->time_metadata, &ctime);
if (error)
break;
if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
timestruc_t mtime;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
error = -1;
break;
}
ASSERT(sarg->vap->va_mask & AT_MTIME);
error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
ASSERT(sarg->vap->va_mask & AT_MTIME);
error = nfs4_time_ntov(&na->time_modify, &mtime);
if (error)
break;
if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
settime4 *tm;
if (RFS4_MANDATTR_ONLY)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if ((sarg->op == NFS4ATTR_GETIT) ||
(sarg->op == NFS4ATTR_VERIT))
error = EINVAL;
break;
case NFS4ATTR_GETIT:
case NFS4ATTR_VERIT:
error = EINVAL;
break;
case NFS4ATTR_SETIT:
ASSERT(sarg->vap->va_mask & AT_MTIME);
tm = &na->time_modify_set;
if (tm->set_it == SET_TO_CLIENT_TIME4) {
error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
sarg->flag = ATTR_UTIME;
} else if (tm->set_it == SET_TO_SERVER_TIME4) {
gethrestime(&sarg->vap->va_mtime);
} else {
error = EINVAL;
}
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static int
rfs4_fattr4_suppattr_exclcreat(nfs4_attr_cmd_t cmd,
struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
{
int error = 0;
if (sarg->cs->minorversion == 0)
return (ENOTSUP);
switch (cmd) {
case NFS4ATTR_SUPPORTED:
if (sarg->op == NFS4ATTR_SETIT)
error = EINVAL;
break;
case NFS4ATTR_GETIT:
na->supp_exclcreat = RFS4_SUPPATTR_EXCLCREAT;
break;
case NFS4ATTR_SETIT:
error = EINVAL;
break;
case NFS4ATTR_VERIT:
if (na->supp_exclcreat != RFS4_SUPPATTR_EXCLCREAT)
error = -1;
break;
case NFS4ATTR_FREEIT:
break;
}
return (error);
}
static void
rfs4_ntov_init(void)
{
nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
nfs4_ntov_map[56].sv_getit = rfs4_fattr4_suppattr_exclcreat;
}