]> Git Repo - linux.git/commitdiff
cifs: Remove intermediate object of failed create reparse call
authorPali Rohár <[email protected]>
Mon, 30 Sep 2024 20:25:10 +0000 (22:25 +0200)
committerSteve French <[email protected]>
Tue, 1 Oct 2024 03:14:05 +0000 (22:14 -0500)
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: 102466f303ff ("smb: client: allow creating special files via reparse points")
Signed-off-by: Pali Rohár <[email protected]>
Acked-by: Paulo Alcantara (Red Hat) <[email protected]>
Signed-off-by: Steve French <[email protected]>
fs/smb/client/smb2inode.c

index b992117377e9207215f16bc1560ad466447c143a..4e9e225520a67b4058cd3e9989ec582c0b96f032 100644 (file)
@@ -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 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 |
@@ -1228,7 +1231,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);
@@ -1237,12 +1240,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;
 }
 
This page took 0.058349 seconds and 4 git commands to generate.