Commit 7435d51b authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: fix renaming of reparse points



The client was sending an SMB2_CREATE request without setting
OPEN_REPARSE_POINT flag thus failing the entire rename operation.

Fix this by setting OPEN_REPARSE_POINT in create options for
SMB2_CREATE request when the source inode is a repase point.

Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 67ec9949
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -210,9 +210,18 @@ struct cifs_open_info_data {
	};
};

#define cifs_open_data_reparse(d) \
	((d)->reparse_point || \
	 (le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
{
	struct smb2_file_all_info *fi = &data->fi;
	u32 attrs = le32_to_cpu(fi->Attributes);
	bool ret;

	ret = data->reparse_point || (attrs & ATTR_REPARSE);
	if (ret)
		attrs |= ATTR_REPARSE;
	fi->Attributes = cpu_to_le32(attrs);
	return ret;
}

/*
 *****************************************************************
@@ -390,8 +399,11 @@ struct smb_version_operations {
	int (*rename_pending_delete)(const char *, struct dentry *,
				     const unsigned int);
	/* send rename request */
	int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
		      const char *, struct cifs_sb_info *);
	int (*rename)(const unsigned int xid,
		      struct cifs_tcon *tcon,
		      struct dentry *source_dentry,
		      const char *from_name, const char *to_name,
		      struct cifs_sb_info *cifs_sb);
	/* send create hardlink request */
	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
			       const char *, const char *,
+4 −3
Original line number Diff line number Diff line
@@ -439,7 +439,8 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
			int remap_special_chars);
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
			  const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
		  struct dentry *source_dentry,
		  const char *from_name, const char *to_name,
		  struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
+4 −4
Original line number Diff line number Diff line
@@ -2149,8 +2149,8 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
	return rc;
}

int
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
		  struct dentry *source_dentry,
		  const char *from_name, const char *to_name,
		  struct cifs_sb_info *cifs_sb)
{
+2 −1
Original line number Diff line number Diff line
@@ -2244,7 +2244,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
		return -ENOSYS;

	/* try path-based rename first */
	rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
	rc = server->ops->rename(xid, tcon, from_dentry,
				 from_path, to_path, cifs_sb);

	/*
	 * Don't bother with rename by filehandle unless file is busy and
+23 −15
Original line number Diff line number Diff line
@@ -889,11 +889,11 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
				NULL, NULL, NULL, NULL, NULL);
}

static int
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
			      const char *from_name, const char *to_name,
		   struct cifs_sb_info *cifs_sb, __u32 access, int command,
		   struct cifsFileInfo *cfile)
			      struct cifs_sb_info *cifs_sb,
			      __u32 create_options, __u32 access,
			      int command, struct cifsFileInfo *cfile)
{
	struct kvec in_iov;
	__le16 *smb2_to_name = NULL;
@@ -907,25 +907,33 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
	in_iov.iov_base = smb2_to_name;
	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
			      FILE_OPEN, 0, ACL_NO_MODE, &in_iov,
			      FILE_OPEN, create_options, ACL_NO_MODE, &in_iov,
			      &command, 1, cfile, NULL, NULL, NULL, NULL);
smb2_rename_path:
	kfree(smb2_to_name);
	return rc;
}

int
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
int smb2_rename_path(const unsigned int xid,
		     struct cifs_tcon *tcon,
		     struct dentry *source_dentry,
		     const char *from_name, const char *to_name,
		     struct cifs_sb_info *cifs_sb)
{
	struct cifsInodeInfo *ci;
	struct cifsFileInfo *cfile;
	__u32 co = 0;

	if (source_dentry) {
		ci = CIFS_I(d_inode(source_dentry));
		if (ci->cifsAttrs & ATTR_REPARSE)
			co |= OPEN_REPARSE_POINT;
	}
	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);

	return smb2_set_path_attr(xid, tcon, from_name, to_name,
				  cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
				  co, DELETE, SMB2_OP_RENAME, cfile);
}

int
@@ -933,9 +941,9 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
		     const char *from_name, const char *to_name,
		     struct cifs_sb_info *cifs_sb)
{
	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
				  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
				  NULL);
	return smb2_set_path_attr(xid, tcon, from_name, to_name,
				  cifs_sb, 0, FILE_READ_ATTRIBUTES,
				  SMB2_OP_HARDLINK, NULL);
}

int
Loading