diff options
Diffstat (limited to 'fs/smb/client/smb2inode.c')
-rw-r--r-- | fs/smb/client/smb2inode.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 9f5bc41433c1..e49d0c25eb03 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -24,7 +24,7 @@ #include "smb2pdu.h" #include "smb2proto.h" #include "cached_dir.h" -#include "smb2status.h" +#include "../common/smb2status.h" static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov) { @@ -315,7 +315,7 @@ replay_again: SMB2_O_INFO_FILE, 0, sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + - (sizeof(struct cifs_sid) * 2), 0, NULL); + (sizeof(struct smb_sid) * 2), 0, NULL); } else { rc = SMB2_query_info_init(tcon, server, &rqst[num_rqst], @@ -325,7 +325,7 @@ replay_again: SMB2_O_INFO_FILE, 0, sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + - (sizeof(struct cifs_sid) * 2), 0, NULL); + (sizeof(struct smb_sid) * 2), 0, NULL); } if (!rc && (!cfile || num_rqst > 1)) { smb2_set_next_command(tcon, &rqst[num_rqst]); @@ -1106,6 +1106,8 @@ int smb2_rename_path(const unsigned int xid, co, DELETE, SMB2_OP_RENAME, cfile, source_dentry); if (rc == -EINVAL) { cifs_dbg(FYI, "invalid lease key, resending request without lease"); + cifs_get_writable_path(tcon, from_name, + FIND_WR_WITH_DELETE, &cfile); rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, co, DELETE, SMB2_OP_RENAME, cfile, NULL); } @@ -1149,6 +1151,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, cfile, NULL, NULL, dentry); if (rc == -EINVAL) { cifs_dbg(FYI, "invalid lease key, resending request without lease"); + cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, &in_iov, &(int){SMB2_OP_SET_EOF}, 1, @@ -1195,6 +1198,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, const unsigned int xid, struct cifs_tcon *tcon, const char *full_path, + bool directory, struct kvec *reparse_iov, struct kvec *xattr_iov) { @@ -1202,16 +1206,19 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifsFileInfo *cfile; struct inode *new = NULL; + int out_buftype[4] = {}; + struct kvec out_iov[4] = {}; struct kvec in_iov[2]; int cmds[2]; int rc; + int i; oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_CREATE, - CREATE_NOT_DIR | OPEN_REPARSE_POINT, + (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT, ACL_NO_MODE); if (xattr_iov) oparms.ea_cctx = xattr_iov; @@ -1225,7 +1232,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, cmds[1] = SMB2_OP_POSIX_QUERY_INFO; cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, - in_iov, cmds, 2, cfile, NULL, NULL, NULL); + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); if (!rc) { rc = smb311_posix_get_inode_info(&new, full_path, data, sb, xid); @@ -1234,12 +1241,29 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, cmds[1] = SMB2_OP_QUERY_INFO; cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, - in_iov, cmds, 2, cfile, NULL, NULL, NULL); + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); if (!rc) { rc = cifs_get_inode_info(&new, full_path, data, sb, xid, NULL); } } + + + /* + * If CREATE was successful but SMB2_OP_SET_REPARSE failed then + * remove the intermediate object created by CREATE. Otherwise + * empty object stay on the server when reparse call failed. + */ + if (rc && + out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER && + ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS && + (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER || + ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS)) + smb2_unlink(xid, tcon, full_path, cifs_sb, NULL); + + for (i = 0; i < ARRAY_SIZE(out_buftype); i++) + free_rsp_buf(out_buftype[i], out_iov[i].iov_base); + return rc ? ERR_PTR(rc) : new; } |