smbd/smb2_ioctl: check sparseness for dup extents
authorDavid Disseldorp <ddiss@samba.org>
Fri, 30 Sep 2016 18:53:07 +0000 (20:53 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 10 May 2017 06:22:19 +0000 (08:22 +0200)
FSCTL_DUPLICATE_EXTENTS_TO_FILE should fail if the source is marked
sparse while the target is not:

From: Jeff McCashland
To: David Disseldorp
Subject: RE: FSCTL_DUPLICATE_EXTENTS_TO_FILE questions, 116092214702946
Date: Tue, 27 Dec 2016 18:06:14 +0000

...
We have updated the spec for future release:

Section 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE Reply
Changed description of STATUS_NOT_SUPPORTED error code to:
"--The source and target destination ranges overlap on the same file.
--Source file is sparse, while -target is a non-sparse file.
--The source range is beyond the source file's allocation size."

Signed-off-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Ralph Böhme <slow@samba.org>
source3/smbd/smb2_ioctl_filesys.c

index 54a28e0ef7f663b9e24fcc46c597994772c40259..41c5129f298bbe30accf54952bf4e42141a6b41e 100644 (file)
@@ -78,6 +78,28 @@ static NTSTATUS fsctl_dup_extents_check_overlap(struct files_struct *src_fsp,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS fsctl_dup_extents_check_sparse(struct files_struct *src_fsp,
+                                              struct files_struct *dst_fsp)
+{
+       /*
+        * 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE Reply...
+        * STATUS_NOT_SUPPORTED: Target file is sparse, while source
+        *                       is a non-sparse file.
+        *
+        * WS2016 has the following behaviour (MS are in the process of fixing
+        * the spec):
+        * STATUS_NOT_SUPPORTED is returned if the source is sparse, while the
+        * target is non-sparse. However, if target is sparse while the source
+        * is non-sparse, then FSCTL_DUPLICATE_EXTENTS_TO_FILE completes
+        * successfully.
+        */
+       if ((src_fsp->is_sparse) && (!dst_fsp->is_sparse)) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       return NT_STATUS_OK;
+}
+
 struct fsctl_dup_extents_state {
        struct tevent_context *ev;
        struct connection_struct *conn;
@@ -163,6 +185,12 @@ static struct tevent_req *fsctl_dup_extents_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       status = fsctl_dup_extents_check_sparse(src_fsp, dst_fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
        subreq = SMB_VFS_COPY_CHUNK_SEND(dst_fsp->conn, state, ev,
                                         src_fsp, state->dup_extents.source_off,
                                         dst_fsp, state->dup_extents.target_off,