Example #1
0
/* 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);
}
/*
 * 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);
}