smb: client: fix renaming of reparse points
[ Upstream commit 7435d51b7ea2ab7801279c43ecd72063e9d5c92f ] 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: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
d91ecb894a
commit
c586b0c746
|
@ -205,9 +205,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;
|
||||
}
|
||||
|
||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||
{
|
||||
|
@ -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 *,
|
||||
|
|
|
@ -435,9 +435,10 @@ 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,
|
||||
const char *from_name, const char *to_name,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
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,
|
||||
int netfid, const char *target_name,
|
||||
const struct nls_table *nls_codepage,
|
||||
|
|
|
@ -2149,10 +2149,10 @@ 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,
|
||||
const char *from_name, const char *to_name,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
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)
|
||||
{
|
||||
int rc = 0;
|
||||
RENAME_REQ *pSMB = NULL;
|
||||
|
|
|
@ -2219,7 +2219,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
|
||||
|
|
|
@ -781,11 +781,11 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|||
ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
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)
|
||||
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 create_options, __u32 access,
|
||||
int command, struct cifsFileInfo *cfile)
|
||||
{
|
||||
__le16 *smb2_to_name = NULL;
|
||||
int rc;
|
||||
|
@ -796,25 +796,33 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto smb2_rename_path;
|
||||
}
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||
FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
|
||||
FILE_OPEN, create_options, ACL_NO_MODE, smb2_to_name,
|
||||
command, 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,
|
||||
const char *from_name, const char *to_name,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
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
|
||||
|
@ -822,9 +830,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
|
||||
|
|
|
@ -80,9 +80,11 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
const char *name, struct cifs_sb_info *cifs_sb);
|
||||
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *name, struct cifs_sb_info *cifs_sb);
|
||||
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *from_name, const char *to_name,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
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);
|
||||
extern int 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);
|
||||
|
|
Loading…
Reference in New Issue