summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2017-08-24 11:24:56 +1000
committerSteve French <smfrench@gmail.com>2017-09-04 14:03:45 -0500
commit5517554e43131f542e5f95c94c5cd9a1bb989fab (patch)
tree3e3a16ce06f242c85cf194218227bf57412cbe87 /fs/cifs/smb2ops.c
parent95907fea4fd8ccc736e0a428e52159b4d42b9958 (diff)
cifs: Add support for writing attributes on SMB2+
This adds support for writing extended attributes on SMB2+ shares. Attributes can be written using the setfattr command. RH-bz: 1110709 Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 78516d3a133c..fb2934b9b97c 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -558,6 +558,62 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+
+static int
+smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *path, const char *ea_name, const void *ea_value,
+ const __u16 ea_value_len, const struct nls_table *nls_codepage,
+ struct cifs_sb_info *cifs_sb)
+{
+ int rc;
+ __le16 *utf16_path;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+ struct cifs_open_parms oparms;
+ struct cifs_fid fid;
+ struct smb2_file_full_ea_info *ea;
+ int ea_name_len = strlen(ea_name);
+ int len;
+
+ if (ea_name_len > 255)
+ return -EINVAL;
+
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (!utf16_path)
+ return -ENOMEM;
+
+ oparms.tcon = tcon;
+ oparms.desired_access = FILE_WRITE_EA;
+ oparms.disposition = FILE_OPEN;
+ oparms.create_options = 0;
+ oparms.fid = &fid;
+ oparms.reconnect = false;
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
+ kfree(utf16_path);
+ if (rc) {
+ cifs_dbg(FYI, "open failed rc=%d\n", rc);
+ return rc;
+ }
+
+ len = sizeof(ea) + ea_name_len + ea_value_len + 1;
+ ea = kzalloc(len, GFP_KERNEL);
+ if (ea == NULL) {
+ SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+ return -ENOMEM;
+ }
+
+ ea->ea_name_length = ea_name_len;
+ ea->ea_value_length = cpu_to_le16(ea_value_len);
+ memcpy(ea->ea_data, ea_name, ea_name_len + 1);
+ memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
+
+ rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
+ len);
+ SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+
+ return rc;
+}
+
static bool
smb2_can_echo(struct TCP_Server_Info *server)
{
@@ -2706,6 +2762,7 @@ struct smb_version_operations smb20_operations = {
.select_sectype = smb2_select_sectype,
#ifdef CONFIG_CIFS_XATTR
.query_all_EAs = smb2_query_eas,
+ .set_EA = smb2_set_ea,
#endif /* CIFS_XATTR */
#ifdef CONFIG_CIFS_ACL
.get_acl = get_smb2_acl,
@@ -2799,6 +2856,7 @@ struct smb_version_operations smb21_operations = {
.select_sectype = smb2_select_sectype,
#ifdef CONFIG_CIFS_XATTR
.query_all_EAs = smb2_query_eas,
+ .set_EA = smb2_set_ea,
#endif /* CIFS_XATTR */
#ifdef CONFIG_CIFS_ACL
.get_acl = get_smb2_acl,
@@ -2902,6 +2960,7 @@ struct smb_version_operations smb30_operations = {
.select_sectype = smb2_select_sectype,
#ifdef CONFIG_CIFS_XATTR
.query_all_EAs = smb2_query_eas,
+ .set_EA = smb2_set_ea,
#endif /* CIFS_XATTR */
#ifdef CONFIG_CIFS_ACL
.get_acl = get_smb2_acl,
@@ -3006,6 +3065,7 @@ struct smb_version_operations smb311_operations = {
.select_sectype = smb2_select_sectype,
#ifdef CONFIG_CIFS_XATTR
.query_all_EAs = smb2_query_eas,
+ .set_EA = smb2_set_ea,
#endif /* CIFS_XATTR */
};
#endif /* CIFS_SMB311 */