All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ronnie Sahlberg <lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: linux-cifs <linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Cc: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Subject: [PATCH] cifs: fix return code when failing to rename a file onto a directory
Date: Thu,  9 Nov 2017 16:11:57 +1100	[thread overview]
Message-ID: <20171109051157.30814-1-lsahlber@redhat.com> (raw)

Cifs servers return ACCESS_DENIED when trying to rename onto a non-empty
directory. This is different from xfstest where we expect this to return
-EEXIST instead.

As a workaround, if we failed to rename the file and we got -EACCES
then try to open the target file and check the attributes if it is a
directory or not and if so remap the error to -EEXIST.

This makes us pass xfstest  generic/245

Signed-off-by: Ronnie Sahlberg <lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 fs/cifs/smb2ops.c   | 39 +++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.c   | 13 ++++++++++++-
 fs/cifs/smb2proto.h |  2 ++
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index bdb963d0ba32..1c46aab0d015 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -426,6 +426,45 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
+int
+smb2_is_dir(const unsigned int xid, struct cifs_tcon *tcon,
+	    __le16 *target_file)
+{
+	int rc;
+	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+	struct cifs_open_parms oparms;
+	struct cifs_fid fid;
+	struct smb2_file_all_info *smb2_data;
+
+	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
+			    GFP_KERNEL);
+	if (smb2_data == NULL)
+		return -ENOMEM;
+
+	oparms.tcon = tcon;
+	oparms.desired_access = FILE_READ_ATTRIBUTES;
+	oparms.disposition = FILE_OPEN;
+	oparms.create_options = 0;
+	oparms.fid = &fid;
+	oparms.reconnect = false;
+
+	rc = SMB2_open(xid, &oparms, target_file, &oplock, NULL, NULL);
+	if (rc)
+		goto out;
+
+	rc = SMB2_query_info(xid, tcon, fid.persistent_fid, fid.volatile_fid,
+			     smb2_data);
+	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+	if (rc)
+		goto out;
+
+	rc = !!(le32_to_cpu(smb2_data->Attributes) & FILE_ATTRIBUTE_DIRECTORY);
+
+out:
+	kfree(smb2_data);
+	return rc;
+}
+
 #ifdef CONFIG_CIFS_XATTR
 static ssize_t
 move_smb2_ea_to_cifs(char *dst, size_t dst_size,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 553d574940b9..91f0b4a5e749 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -3144,7 +3144,7 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 	struct smb2_file_rename_info info;
 	void **data;
 	unsigned int size[2];
-	int rc;
+	int rc, is_dir;
 	int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
 
 	data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
@@ -3165,6 +3165,17 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
 		current->tgid, FILE_RENAME_INFORMATION, SMB2_O_INFO_FILE,
 		0, 2, data, size);
+
+	/* SMB2 servers responds with ACCESS_DENIED when trying to rename
+	 * and replace onto a non-empty directory. Check for this and remap
+	 * to EEXIST.
+	 */
+	if (rc == -EACCES) {
+		is_dir = smb2_is_dir(xid, tcon, target_file);
+		if (is_dir == 1)
+			rc = -EEXIST;
+	}
+
 	kfree(data);
 	return rc;
 }
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e9ab5227e7a8..35c075364f7e 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -203,4 +203,6 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
 
 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
 					enum securityEnum);
+extern int smb2_is_dir(const unsigned int xid, struct cifs_tcon *tcon,
+		       __le16 *target_file);
 #endif			/* _SMB2PROTO_H */
-- 
2.13.3

             reply	other threads:[~2017-11-09  5:11 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-09  5:11 Ronnie Sahlberg [this message]
     [not found] ` <20171109051157.30814-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-11-09 10:54   ` [PATCH] cifs: fix return code when failing to rename a file onto a directory Aurélien Aptel
2017-11-09 23:52 Ronnie Sahlberg
     [not found] ` <20171109235249.8013-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-11-16 23:31   ` Pavel Shilovsky
     [not found]     ` <CAKywueStf29fgZ-52ONqL+WLSYotaVwMpsqnu2gQdppuw5xtoA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-11-16 23:38       ` Steve French
2017-11-17 15:10       ` Aurélien Aptel
2017-11-20  5:25 Ronnie Sahlberg
     [not found] ` <20171120052549.17909-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-11-20 21:09   ` ronnie sahlberg
     [not found]     ` <CAN05THT53nWN7w161L6CVc0ZjwFbBC+1zcO++z4DdXzQoh=CqQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-11-20 21:17       ` Steve French

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171109051157.30814-1-lsahlber@redhat.com \
    --to=lsahlber-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.