--- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Tue Aug 31 13:02:05 2010
+++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Tue Aug 31 13:02:04 2010
@@ -114,6 +114,7 @@
 static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
 			caller_context_t *);
 static void	smbfs_rele_fid(smbnode_t *, struct smb_cred *);
+static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
 
 /*
  * These are the vnode ops routines which implement the vnode interface to
@@ -838,10 +839,6 @@
 /*
  * Return either cached or remote attributes. If get remote attr
  * use them to check and invalidate caches, then cache the new attributes.
- *
- * XXX
- * This op should eventually support PSARC 2007/315, Extensible Attribute
- * Interfaces, for richer metadata.
  */
 /* ARGSUSED */
 static int
@@ -889,11 +886,6 @@
 
 /* smbfsgetattr() in smbfs_client.c */
 
-/*
- * XXX
- * This op should eventually support PSARC 2007/315, Extensible Attribute
- * Interfaces, for richer metadata.
- */
 /*ARGSUSED4*/
 static int
 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
@@ -979,6 +971,7 @@
 	unsigned short	fid;
 	int have_fid = 0;
 	uint32_t rights = 0;
+	uint32_t dosattr = 0;
 
 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
 
@@ -1009,10 +1002,18 @@
 	smb_credinit(&scred, cr);
 
 	/*
+	 * If the caller has provided extensible attributes,
+	 * map those into DOS attributes supported by SMB.
+	 * Note: zero means "no change".
+	 */
+	if (mask & AT_XVATTR)
+		dosattr = xvattr_to_dosattr(np, vap);
+
+	/*
 	 * Will we need an open handle for this setattr?
 	 * If so, what rights will we need?
 	 */
-	if (mask & (AT_ATIME | AT_MTIME)) {
+	if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
 		rights |=
 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
 	}
@@ -1028,7 +1029,7 @@
 	 * Some servers like NT4 won't set times by path.
 	 * Also, we're usually setting everything anyway.
 	 */
-	if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
+	if (rights != 0) {
 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
 		if (error) {
 			SMBVDEBUG("error %d opening %s\n",
@@ -1085,7 +1086,7 @@
 	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
 	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
 
-	if (mtime || atime) {
+	if (dosattr || mtime || atime) {
 		/*
 		 * Always use the handle-based set attr call now.
 		 * Not trying to set DOS attributes here so pass zero.
@@ -1092,7 +1093,7 @@
 		 */
 		ASSERT(have_fid);
 		error = smbfs_smb_setfattr(np, fid,
-		    0, mtime, atime, &scred);
+		    dosattr, mtime, atime, &scred);
 		if (error) {
 			SMBVDEBUG("set times error %d file %s\n",
 			    error, np->n_rpath);
@@ -1124,6 +1125,64 @@
 }
 
 /*
+ * Helper function for extensible system attributes (PSARC 2007/315)
+ * Compute the DOS attribute word to pass to _setfattr (see above).
+ * This returns zero IFF no change is being made to attributes.
+ * Otherwise return the new attributes or SMB_EFA_NORMAL.
+ */
+static uint32_t
+xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
+{
+	xvattr_t *xvap = (xvattr_t *)vap;
+	xoptattr_t *xoap = NULL;
+	uint32_t attr = np->r_attr.fa_attr;
+	boolean_t anyset = B_FALSE;
+
+	if ((xoap = xva_getxoptattr(xvap)) == NULL)
+		return (0);
+
+	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+		if (xoap->xoa_archive)
+			attr |= SMB_FA_ARCHIVE;
+		else
+			attr &= ~SMB_FA_ARCHIVE;
+		XVA_SET_RTN(xvap, XAT_ARCHIVE);
+		anyset = B_TRUE;
+	}
+	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+		if (xoap->xoa_system)
+			attr |= SMB_FA_SYSTEM;
+		else
+			attr &= ~SMB_FA_SYSTEM;
+		XVA_SET_RTN(xvap, XAT_SYSTEM);
+		anyset = B_TRUE;
+	}
+	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+		if (xoap->xoa_readonly)
+			attr |= SMB_FA_RDONLY;
+		else
+			attr &= ~SMB_FA_RDONLY;
+		XVA_SET_RTN(xvap, XAT_READONLY);
+		anyset = B_TRUE;
+	}
+	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+		if (xoap->xoa_hidden)
+			attr |= SMB_FA_HIDDEN;
+		else
+			attr &= ~SMB_FA_HIDDEN;
+		XVA_SET_RTN(xvap, XAT_HIDDEN);
+		anyset = B_TRUE;
+	}
+
+	if (anyset == B_FALSE)
+		return (0);	/* no change */
+	if (attr == 0)
+		attr = SMB_EFA_NORMAL;
+
+	return (attr);
+}
+
+/*
  * smbfs_access_rwx()
  * Common function for smbfs_access, etc.
  *
@@ -2992,6 +3051,11 @@
 		}
 		return (EINVAL);
 
+	case _PC_SATTR_ENABLED:
+	case _PC_SATTR_EXISTS:
+		*valp = 1;
+		break;
+
 	case _PC_TIMESTAMP_RESOLUTION:
 		/*
 		 * Windows times are tenths of microseconds
