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

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
...@@ -210,9 +210,18 @@ struct cifs_open_info_data { ...@@ -210,9 +210,18 @@ struct cifs_open_info_data {
}; };
}; };
#define cifs_open_data_reparse(d) \ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
((d)->reparse_point || \ {
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE)) 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 { ...@@ -390,8 +399,11 @@ struct smb_version_operations {
int (*rename_pending_delete)(const char *, struct dentry *, int (*rename_pending_delete)(const char *, struct dentry *,
const unsigned int); const unsigned int);
/* send rename request */ /* send rename request */
int (*rename)(const unsigned int, struct cifs_tcon *, const char *, int (*rename)(const unsigned int xid,
const char *, struct cifs_sb_info *); 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 */ /* send create hardlink request */
int (*create_hardlink)(const unsigned int, struct cifs_tcon *, int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
const char *, const char *, const char *, const char *,
......
...@@ -439,9 +439,10 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -439,9 +439,10 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); 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,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb); 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, extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name, int netfid, const char *target_name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
......
...@@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) ...@@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
return rc; return rc;
} }
int int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
int rc = 0; int rc = 0;
RENAME_REQ *pSMB = NULL; RENAME_REQ *pSMB = NULL;
......
...@@ -2244,7 +2244,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, ...@@ -2244,7 +2244,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
return -ENOSYS; return -ENOSYS;
/* try path-based rename first */ /* 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 * Don't bother with rename by filehandle unless file is busy and
......
...@@ -889,11 +889,11 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, ...@@ -889,11 +889,11 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
} }
static int static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, const char *from_name, const char *to_name,
const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb,
struct cifs_sb_info *cifs_sb, __u32 access, int command, __u32 create_options, __u32 access,
struct cifsFileInfo *cfile) int command, struct cifsFileInfo *cfile)
{ {
struct kvec in_iov; struct kvec in_iov;
__le16 *smb2_to_name = NULL; __le16 *smb2_to_name = NULL;
...@@ -907,25 +907,33 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -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_base = smb2_to_name;
in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX); in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 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); &command, 1, cfile, NULL, NULL, NULL, NULL);
smb2_rename_path: smb2_rename_path:
kfree(smb2_to_name); kfree(smb2_to_name);
return rc; return rc;
} }
int int smb2_rename_path(const unsigned int xid,
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb) const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{ {
struct cifsInodeInfo *ci;
struct cifsFileInfo *cfile; 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); drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name, return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
cifs_sb, DELETE, SMB2_OP_RENAME, cfile); co, DELETE, SMB2_OP_RENAME, cfile);
} }
int int
...@@ -933,9 +941,9 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -933,9 +941,9 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, return smb2_set_path_attr(xid, tcon, from_name, to_name,
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK, cifs_sb, 0, FILE_READ_ATTRIBUTES,
NULL); SMB2_OP_HARDLINK, NULL);
} }
int int
......
...@@ -86,9 +86,11 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -86,9 +86,11 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, int smb2_rename_path(const unsigned int xid,
const char *from_name, const char *to_name, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb); 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, extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment