Commit c9432ad5 authored by Pali Rohár's avatar Pali Rohár Committed by Steve French

cifs: Remove intermediate object of failed create reparse call

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.

This ensures that if the creating of special files is unsupported by the
server then no empty file stay on the server as a result of unsupported
operation.

Fixes: 102466f3 ("smb: client: allow creating special files via reparse points")
Signed-off-by: default avatarPali Rohár <pali@kernel.org>
Acked-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 1eecd880
...@@ -1205,9 +1205,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, ...@@ -1205,9 +1205,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
struct inode *new = NULL; struct inode *new = NULL;
int out_buftype[4] = {};
struct kvec out_iov[4] = {};
struct kvec in_iov[2]; struct kvec in_iov[2];
int cmds[2]; int cmds[2];
int rc; int rc;
int i;
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
SYNCHRONIZE | DELETE | SYNCHRONIZE | DELETE |
...@@ -1228,7 +1231,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, ...@@ -1228,7 +1231,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cmds[1] = SMB2_OP_POSIX_QUERY_INFO; cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, 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) { if (!rc) {
rc = smb311_posix_get_inode_info(&new, full_path, rc = smb311_posix_get_inode_info(&new, full_path,
data, sb, xid); data, sb, xid);
...@@ -1237,12 +1240,29 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, ...@@ -1237,12 +1240,29 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cmds[1] = SMB2_OP_QUERY_INFO; cmds[1] = SMB2_OP_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, 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) { if (!rc) {
rc = cifs_get_inode_info(&new, full_path, rc = cifs_get_inode_info(&new, full_path,
data, sb, xid, NULL); 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; return rc ? ERR_PTR(rc) : new;
} }
......
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