static int zpl_ioctl_setflags(struct file *filp, void __user *arg) { struct inode *ip = file_inode(filp); uint64_t zfs_flags = ITOZ(ip)->z_pflags; unsigned int ioctl_flags; cred_t *cr = CRED(); xvattr_t xva; xoptattr_t *xoap; int error; fstrans_cookie_t cookie; if (copy_from_user(&ioctl_flags, arg, sizeof (ioctl_flags))) return (-EFAULT); if ((ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL))) return (-EOPNOTSUPP); if ((ioctl_flags & ~(FS_FL_USER_MODIFIABLE))) return (-EACCES); if ((fchange(ioctl_flags, zfs_flags, FS_IMMUTABLE_FL, ZFS_IMMUTABLE) || fchange(ioctl_flags, zfs_flags, FS_APPEND_FL, ZFS_APPENDONLY)) && !capable(CAP_LINUX_IMMUTABLE)) return (-EACCES); if (!zpl_inode_owner_or_capable(ip)) return (-EACCES); xva_init(&xva); xoap = xva_getxoptattr(&xva); XVA_SET_REQ(&xva, XAT_IMMUTABLE); if (ioctl_flags & FS_IMMUTABLE_FL) xoap->xoa_immutable = B_TRUE; XVA_SET_REQ(&xva, XAT_APPENDONLY); if (ioctl_flags & FS_APPEND_FL) xoap->xoa_appendonly = B_TRUE; XVA_SET_REQ(&xva, XAT_NODUMP); if (ioctl_flags & FS_NODUMP_FL) xoap->xoa_nodump = B_TRUE; crhold(cr); cookie = spl_fstrans_mark(); error = -zfs_setattr(ip, (vattr_t *)&xva, 0, cr); spl_fstrans_unmark(cookie); crfree(cr); return (error); }
static int zpl_ioctl_setxattr(struct file *filp, void __user *arg) { struct inode *ip = file_inode(filp); zfsxattr_t fsx; cred_t *cr = CRED(); xvattr_t xva; xoptattr_t *xoap; int err; fstrans_cookie_t cookie; if (copy_from_user(&fsx, arg, sizeof (fsx))) return (-EFAULT); if (!zpl_is_valid_projid(fsx.fsx_projid)) return (-EINVAL); err = __zpl_ioctl_setflags(ip, fsx.fsx_xflags, &xva); if (err) return (err); xoap = xva_getxoptattr(&xva); XVA_SET_REQ(&xva, XAT_PROJID); xoap->xoa_projid = fsx.fsx_projid; crhold(cr); cookie = spl_fstrans_mark(); err = -zfs_setattr(ip, (vattr_t *)&xva, 0, cr); spl_fstrans_unmark(cookie); crfree(cr); return (err); }
static int __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) { uint64_t zfs_flags = ITOZ(ip)->z_pflags; xoptattr_t *xoap; if (ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | ZFS_PROJINHERIT_FL)) return (-EOPNOTSUPP); if (ioctl_flags & ~ZFS_FL_USER_MODIFIABLE) return (-EACCES); if ((fchange(ioctl_flags, zfs_flags, FS_IMMUTABLE_FL, ZFS_IMMUTABLE) || fchange(ioctl_flags, zfs_flags, FS_APPEND_FL, ZFS_APPENDONLY)) && !capable(CAP_LINUX_IMMUTABLE)) return (-EACCES); if (!zpl_inode_owner_or_capable(ip)) return (-EACCES); xva_init(xva); xoap = xva_getxoptattr(xva); XVA_SET_REQ(xva, XAT_IMMUTABLE); if (ioctl_flags & FS_IMMUTABLE_FL) xoap->xoa_immutable = B_TRUE; XVA_SET_REQ(xva, XAT_APPENDONLY); if (ioctl_flags & FS_APPEND_FL) xoap->xoa_appendonly = B_TRUE; XVA_SET_REQ(xva, XAT_NODUMP); if (ioctl_flags & FS_NODUMP_FL) xoap->xoa_nodump = B_TRUE; XVA_SET_REQ(xva, XAT_PROJINHERIT); if (ioctl_flags & ZFS_PROJINHERIT_FL) xoap->xoa_projinherit = B_TRUE; return (0); }
static int xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, caller_context_t *ct) { xvattr_t xvattr; vnode_t *pdvp; int error; /* * Only copy system attrs if the views are the same */ if (strcmp(snm, tnm) != 0) return (EINVAL); xva_init(&xvattr); XVA_SET_REQ(&xvattr, XAT_SYSTEM); XVA_SET_REQ(&xvattr, XAT_READONLY); XVA_SET_REQ(&xvattr, XAT_HIDDEN); XVA_SET_REQ(&xvattr, XAT_ARCHIVE); XVA_SET_REQ(&xvattr, XAT_APPENDONLY); XVA_SET_REQ(&xvattr, XAT_NOUNLINK); XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); XVA_SET_REQ(&xvattr, XAT_NODUMP); XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); XVA_SET_REQ(&xvattr, XAT_CREATETIME); XVA_SET_REQ(&xvattr, XAT_REPARSE); XVA_SET_REQ(&xvattr, XAT_OFFLINE); XVA_SET_REQ(&xvattr, XAT_SPARSE); pdvp = gfs_file_parent(sdvp); error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); if (error) return (error); pdvp = gfs_file_parent(tdvp); error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); return (error); }
/* ARGSUSED */ static int xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { int error = 0; char *buf; char *domain; uint32_t rid; ssize_t size = uiop->uio_resid; nvlist_t *nvp; nvpair_t *pair = NULL; vnode_t *ppvp; xvattr_t xvattr; xoptattr_t *xoap = NULL; /* Pointer to optional attributes */ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) return (EINVAL); /* * Validate file offset and size. */ if (uiop->uio_loffset < (offset_t)0) return (EINVAL); if (size == 0) return (EINVAL); xva_init(&xvattr); if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { return (EINVAL); } /* * Copy and unpack the nvlist */ buf = kmem_alloc(size, KM_SLEEP); if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) { return (EFAULT); } if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) { kmem_free(buf, size); uiop->uio_resid = size; return (EINVAL); } kmem_free(buf, size); /* * Fasttrack empty writes (nvlist with no nvpairs) */ if (nvlist_next_nvpair(nvp, NULL) == 0) return (0); ppvp = gfs_file_parent(gfs_file_parent(vp)); while (pair = nvlist_next_nvpair(nvp, pair)) { data_type_t type; f_attr_t attr; boolean_t value; uint64_t *time, *times; uint_t elem, nelems; nvlist_t *nvp_sid; uint8_t *scanstamp; /* * Validate the name and type of each attribute. * Log any unknown names and continue. This will * help if additional attributes are added later. */ type = nvpair_type(pair); if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) { cmn_err(CE_WARN, "Unknown attribute %s", nvpair_name(pair)); continue; } /* * Verify nvlist type matches required type and view is OK */ if (type != attr_to_data_type(attr) || (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) { nvlist_free(nvp); return (EINVAL); } /* * For OWNERSID/GROUPSID make sure the target * file system support ephemeral ID's */ if ((attr == F_OWNERSID || attr == F_GROUPSID) && (!(vp->v_vfsp->vfs_flag & VFS_XID))) { nvlist_free(nvp); return (EINVAL); } /* * Retrieve data from nvpair */ switch (type) { case DATA_TYPE_BOOLEAN_VALUE: if (nvpair_value_boolean_value(pair, &value)) { nvlist_free(nvp); return (EINVAL); } break; case DATA_TYPE_UINT64_ARRAY: if (nvpair_value_uint64_array(pair, ×, &nelems)) { nvlist_free(nvp); return (EINVAL); } break; case DATA_TYPE_NVLIST: if (nvpair_value_nvlist(pair, &nvp_sid)) { nvlist_free(nvp); return (EINVAL); } break; case DATA_TYPE_UINT8_ARRAY: if (nvpair_value_uint8_array(pair, &scanstamp, &nelems)) { nvlist_free(nvp); return (EINVAL); } break; default: nvlist_free(nvp); return (EINVAL); } switch (attr) { /* * If we have several similar optional attributes to * process then we should do it all together here so that * xoap and the requested bitmap can be set in one place. */ case F_READONLY: XVA_SET_REQ(&xvattr, XAT_READONLY); xoap->xoa_readonly = value; break; case F_HIDDEN: XVA_SET_REQ(&xvattr, XAT_HIDDEN); xoap->xoa_hidden = value; break; case F_SYSTEM: XVA_SET_REQ(&xvattr, XAT_SYSTEM); xoap->xoa_system = value; break; case F_ARCHIVE: XVA_SET_REQ(&xvattr, XAT_ARCHIVE); xoap->xoa_archive = value; break; case F_IMMUTABLE: XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); xoap->xoa_immutable = value; break; case F_NOUNLINK: XVA_SET_REQ(&xvattr, XAT_NOUNLINK); xoap->xoa_nounlink = value; break; case F_APPENDONLY: XVA_SET_REQ(&xvattr, XAT_APPENDONLY); xoap->xoa_appendonly = value; break; case F_NODUMP: XVA_SET_REQ(&xvattr, XAT_NODUMP); xoap->xoa_nodump = value; break; case F_AV_QUARANTINED: XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); xoap->xoa_av_quarantined = value; break; case F_AV_MODIFIED: XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); xoap->xoa_av_modified = value; break; case F_CRTIME: XVA_SET_REQ(&xvattr, XAT_CREATETIME); time = (uint64_t *)&(xoap->xoa_createtime); for (elem = 0; elem < nelems; elem++) *time++ = times[elem]; break; case F_OWNERSID: case F_GROUPSID: if (nvlist_lookup_string(nvp_sid, SID_DOMAIN, &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID, &rid)) { nvlist_free(nvp); return (EINVAL); } /* * Now map domain+rid to ephemeral id's * * If mapping fails, then the uid/gid will * be set to UID_NOBODY by Winchester. */ if (attr == F_OWNERSID) { (void) kidmap_getuidbysid(crgetzone(cr), domain, rid, &xvattr.xva_vattr.va_uid); xvattr.xva_vattr.va_mask |= AT_UID; } else { (void) kidmap_getgidbysid(crgetzone(cr), domain, rid, &xvattr.xva_vattr.va_gid); xvattr.xva_vattr.va_mask |= AT_GID; } break; case F_AV_SCANSTAMP: if (ppvp->v_type == VREG) { XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); (void) memcpy(xoap->xoa_av_scanstamp, scanstamp, nelems); } else { nvlist_free(nvp); return (EINVAL); } break; case F_REPARSE: XVA_SET_REQ(&xvattr, XAT_REPARSE); xoap->xoa_reparse = value; break; case F_OFFLINE: XVA_SET_REQ(&xvattr, XAT_OFFLINE); xoap->xoa_offline = value; break; case F_SPARSE: XVA_SET_REQ(&xvattr, XAT_SPARSE); xoap->xoa_sparse = value; break; default: break; } } ppvp = gfs_file_parent(gfs_file_parent(vp)); error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); if (error) uiop->uio_resid = size; nvlist_free(nvp); return (error); }
/* ARGSUSED */ static int xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp, cred_t *cr, caller_context_t *ct) { int error; f_attr_t attr; uint64_t fsid; xvattr_t xvattr; xoptattr_t *xoap; /* Pointer to optional attributes */ vnode_t *ppvp; const char *domain; uint32_t rid; xva_init(&xvattr); if ((xoap = xva_getxoptattr(&xvattr)) == NULL) return (EINVAL); /* * For detecting ephemeral uid/gid */ xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID); /* * We need to access the real fs object. * vp points to a GFS file; ppvp points to the real object. */ ppvp = gfs_file_parent(gfs_file_parent(vp)); /* * Iterate through the attrs associated with this view */ for (attr = 0; attr < F_ATTR_ALL; attr++) { if (xattr_view != attr_to_xattr_view(attr)) { continue; } switch (attr) { case F_SYSTEM: XVA_SET_REQ(&xvattr, XAT_SYSTEM); break; case F_READONLY: XVA_SET_REQ(&xvattr, XAT_READONLY); break; case F_HIDDEN: XVA_SET_REQ(&xvattr, XAT_HIDDEN); break; case F_ARCHIVE: XVA_SET_REQ(&xvattr, XAT_ARCHIVE); break; case F_IMMUTABLE: XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); break; case F_APPENDONLY: XVA_SET_REQ(&xvattr, XAT_APPENDONLY); break; case F_NOUNLINK: XVA_SET_REQ(&xvattr, XAT_NOUNLINK); break; case F_OPAQUE: XVA_SET_REQ(&xvattr, XAT_OPAQUE); break; case F_NODUMP: XVA_SET_REQ(&xvattr, XAT_NODUMP); break; case F_AV_QUARANTINED: XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); break; case F_AV_MODIFIED: XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); break; case F_AV_SCANSTAMP: if (ppvp->v_type == VREG) XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); break; case F_CRTIME: XVA_SET_REQ(&xvattr, XAT_CREATETIME); break; case F_FSID: fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) | (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] & 0xffffffff)); VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), fsid) == 0); break; case F_REPARSE: XVA_SET_REQ(&xvattr, XAT_REPARSE); break; case F_GEN: XVA_SET_REQ(&xvattr, XAT_GEN); break; case F_OFFLINE: XVA_SET_REQ(&xvattr, XAT_OFFLINE); break; case F_SPARSE: XVA_SET_REQ(&xvattr, XAT_SPARSE); break; default: break; } } error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); if (error) return (error); /* * Process all the optional attributes together here. Notice that * xoap was set when the optional attribute bits were set above. */ if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) { if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_READONLY), xoap->xoa_readonly) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_HIDDEN), xoap->xoa_hidden) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_SYSTEM), xoap->xoa_system) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_ARCHIVE), xoap->xoa_archive) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_IMMUTABLE), xoap->xoa_immutable) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_NOUNLINK), xoap->xoa_nounlink) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_APPENDONLY), xoap->xoa_appendonly) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_NODUMP), xoap->xoa_nodump) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_OPAQUE), xoap->xoa_opaque) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_AV_QUARANTINED), xoap->xoa_av_quarantined) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_AV_MODIFIED), xoap->xoa_av_modified) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) { VERIFY(nvlist_add_uint8_array(nvlp, attr_to_name(F_AV_SCANSTAMP), xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp)) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { VERIFY(nvlist_add_uint64_array(nvlp, attr_to_name(F_CRTIME), (uint64_t *)&(xoap->xoa_createtime), sizeof (xoap->xoa_createtime) / sizeof (uint64_t)) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_REPARSE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_REPARSE), xoap->xoa_reparse) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_GEN)) { VERIFY(nvlist_add_uint64(nvlp, attr_to_name(F_GEN), xoap->xoa_generation) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_OFFLINE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_OFFLINE), xoap->xoa_offline) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_SPARSE)) { VERIFY(nvlist_add_boolean_value(nvlp, attr_to_name(F_SPARSE), xoap->xoa_sparse) == 0); } } /* * Check for optional ownersid/groupsid */ if (xvattr.xva_vattr.va_uid > MAXUID) { nvlist_t *nvl_sid; if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) return (ENOMEM); if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid, &domain, &rid) == 0) { VERIFY(nvlist_add_string(nvl_sid, SID_DOMAIN, domain) == 0); VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID), nvl_sid) == 0); } nvlist_free(nvl_sid); } if (xvattr.xva_vattr.va_gid > MAXUID) { nvlist_t *nvl_sid; if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) return (ENOMEM); if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid, &domain, &rid) == 0) { VERIFY(nvlist_add_string(nvl_sid, SID_DOMAIN, domain) == 0); VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID), nvl_sid) == 0); } nvlist_free(nvl_sid); } return (0); }
static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) { xoptattr_t *xoap = NULL; uint_t xva_mask; /* * Initialize xvattr, including bzero */ xva_init(xvattr); xoap = xva_getxoptattr(xvattr); ASSERT(xoap); /* * Copy caller-specified classic attributes to xvattr. * First save xvattr's mask (set in xva_init()), which * contains AT_XVATTR. This is |'d in later if needed. */ xva_mask = xvattr->xva_vattr.va_mask; xvattr->xva_vattr = smb_attr->sa_vattr; smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); /* * Do not set ctime (only the file system can do it) */ xvattr->xva_vattr.va_mask &= ~AT_CTIME; if (smb_attr->sa_mask & SMB_AT_DOSATTR) { /* * "|" in the original xva_mask, which contains * AT_XVATTR */ xvattr->xva_vattr.va_mask |= xva_mask; XVA_SET_REQ(xvattr, XAT_ARCHIVE); XVA_SET_REQ(xvattr, XAT_SYSTEM); XVA_SET_REQ(xvattr, XAT_READONLY); XVA_SET_REQ(xvattr, XAT_HIDDEN); /* * smb_attr->sa_dosattr: If a given bit is not set, * that indicates that the corresponding field needs * to be updated with a "0" value. This is done * implicitly as the xoap->xoa_* fields were bzero'd. */ if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) xoap->xoa_archive = 1; if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) xoap->xoa_system = 1; if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) xoap->xoa_readonly = 1; if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) xoap->xoa_hidden = 1; } if (smb_attr->sa_mask & SMB_AT_CRTIME) { /* * "|" in the original xva_mask, which contains * AT_XVATTR */ xvattr->xva_vattr.va_mask |= xva_mask; XVA_SET_REQ(xvattr, XAT_CREATETIME); xoap->xoa_createtime = smb_attr->sa_crtime; } }
/* * smb_vop_getattr() * * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS * service (instead of calling VOP_GETATTR directly) to retrieve attributes * due to special processing needed for streams files. * * All attributes are retrieved. * * When vp denotes a named stream, then unnamed_vp should be passed in (denoting * the corresponding unnamed stream). * A named stream's attributes (as far as CIFS is concerned) are those of the * unnamed stream (minus the size attribute, and the type), plus the size of * the named stream, and a type value of VREG. * Although the file system may store other attributes with the named stream, * these should not be used by CIFS for any purpose. * * File systems without VFSFT_XVATTR do not support DOS attributes or create * time (crtime). In this case the mtime is used as the crtime. * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr * is 0 and the mtime is used as the crtime. */ int smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, int flags, cred_t *cr) { int error; vnode_t *use_vp; smb_attr_t tmp_attr; xvattr_t tmp_xvattr; xoptattr_t *xoap = NULL; if (unnamed_vp) use_vp = unnamed_vp; else use_vp = vp; if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { xva_init(&tmp_xvattr); xoap = xva_getxoptattr(&tmp_xvattr); ASSERT(xoap); smb_sa_to_va_mask(ret_attr->sa_mask, &tmp_xvattr.xva_vattr.va_mask); XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags, cr, &smb_ct); if (error != 0) return (error); ret_attr->sa_vattr = tmp_xvattr.xva_vattr; ret_attr->sa_dosattr = 0; if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) { xoap = xva_getxoptattr(&tmp_xvattr); ASSERT(xoap); if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) && (xoap->xoa_readonly)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; } if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) && (xoap->xoa_hidden)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; } if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) && (xoap->xoa_system)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; } if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) && (xoap->xoa_archive)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; } ret_attr->sa_crtime = xoap->xoa_createtime; } else { ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; } } else { /* * Support for file systems without VFSFT_XVATTR */ smb_sa_to_va_mask(ret_attr->sa_mask, &ret_attr->sa_vattr.va_mask); error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); if (error != 0) return (error); ret_attr->sa_dosattr = 0; ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; } if (unnamed_vp) { ret_attr->sa_vattr.va_type = VREG; if (ret_attr->sa_mask & (SMB_AT_SIZE | SMB_AT_NBLOCKS)) { tmp_attr.sa_vattr.va_mask = AT_SIZE | AT_NBLOCKS; error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); if (error != 0) return (error); ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; ret_attr->sa_vattr.va_nblocks = tmp_attr.sa_vattr.va_nblocks; } } if (ret_attr->sa_vattr.va_type == VDIR) ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; return (error); }