LCOV - code coverage report
Current view: top level - source4/torture/smb2 - ioctl.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 1031 3206 32.2 %
Date: 2024-06-13 04:01:37 Functions: 89 98 90.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for SMB2 ioctl operations
       5             : 
       6             :    Copyright (C) David Disseldorp 2011-2016
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "librpc/gen_ndr/security.h"
      24             : #include "libcli/smb2/smb2.h"
      25             : #include "libcli/smb2/smb2_calls.h"
      26             : #include "torture/torture.h"
      27             : #include "torture/smb2/proto.h"
      28             : #include "../libcli/smb/smbXcli_base.h"
      29             : #include "librpc/gen_ndr/ndr_ioctl.h"
      30             : #include "lib/cmdline/cmdline.h"
      31             : #include "libcli/resolve/resolve.h"
      32             : #include "lib/param/param.h"
      33             : #include "lib/util/tevent_ntstatus.h"
      34             : 
      35             : #define FNAME   "testfsctl.dat"
      36             : #define FNAME2  "testfsctl2.dat"
      37             : #define DNAME   "testfsctl_dir"
      38             : 
      39             : /*
      40             :    basic testing of SMB2 shadow copy calls
      41             : */
      42           1 : static bool test_ioctl_get_shadow_copy(struct torture_context *torture,
      43             :                                        struct smb2_tree *tree)
      44             : {
      45             :         struct smb2_handle h;
      46             :         uint8_t buf[100];
      47             :         NTSTATUS status;
      48             :         union smb_ioctl ioctl;
      49           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
      50             : 
      51           1 :         smb2_util_unlink(tree, FNAME);
      52             : 
      53           1 :         status = torture_smb2_testfile(tree, FNAME, &h);
      54           1 :         torture_assert_ntstatus_ok(torture, status, "create write");
      55             : 
      56           1 :         ZERO_ARRAY(buf);
      57           1 :         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
      58           1 :         torture_assert_ntstatus_ok(torture, status, "write");
      59             : 
      60           1 :         ZERO_STRUCT(ioctl);
      61           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
      62           1 :         ioctl.smb2.in.file.handle = h;
      63           1 :         ioctl.smb2.in.function = FSCTL_SRV_ENUM_SNAPS;
      64           1 :         ioctl.smb2.in.max_output_response = 16;
      65           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
      66             : 
      67           1 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
      68           1 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)
      69           1 :          || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) {
      70           1 :                 torture_skip(torture, "FSCTL_SRV_ENUM_SNAPS not supported\n");
      71             :         }
      72           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_ENUM_SNAPS");
      73             : 
      74           0 :         return true;
      75             : }
      76             : 
      77             : /*
      78             :    basic testing of the SMB2 server side copy ioctls
      79             : */
      80           1 : static bool test_ioctl_req_resume_key(struct torture_context *torture,
      81             :                                       struct smb2_tree *tree)
      82             : {
      83             :         struct smb2_handle h;
      84             :         uint8_t buf[100];
      85             :         NTSTATUS status;
      86             :         union smb_ioctl ioctl;
      87           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
      88             :         struct req_resume_key_rsp res_key;
      89             :         enum ndr_err_code ndr_ret;
      90             : 
      91           1 :         smb2_util_unlink(tree, FNAME);
      92             : 
      93           1 :         status = torture_smb2_testfile(tree, FNAME, &h);
      94           1 :         torture_assert_ntstatus_ok(torture, status, "create write");
      95             : 
      96           1 :         ZERO_ARRAY(buf);
      97           1 :         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
      98           1 :         torture_assert_ntstatus_ok(torture, status, "write");
      99             : 
     100           1 :         ZERO_STRUCT(ioctl);
     101           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     102           1 :         ioctl.smb2.in.file.handle = h;
     103           1 :         ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
     104           1 :         ioctl.smb2.in.max_output_response = 32;
     105           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     106             : 
     107           1 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     108           1 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
     109             : 
     110           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
     111             :                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
     112           0 :         torture_assert_ndr_success(torture, ndr_ret,
     113             :                                    "ndr_pull_req_resume_key_rsp");
     114             : 
     115           0 :         NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
     116             : 
     117           0 :         talloc_free(tmp_ctx);
     118           0 :         return true;
     119             : }
     120             : 
     121             : /*
     122             :    testing fetching a resume key twice for one file handle
     123             : */
     124           1 : static bool test_ioctl_req_two_resume_keys(struct torture_context *torture,
     125             :                                            struct smb2_tree *tree)
     126             : {
     127             :         struct smb2_handle h;
     128             :         uint8_t buf[100];
     129             :         NTSTATUS status;
     130             :         union smb_ioctl ioctl;
     131           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     132             :         struct req_resume_key_rsp res_key;
     133             :         enum ndr_err_code ndr_ret;
     134             : 
     135           1 :         smb2_util_unlink(tree, FNAME);
     136             : 
     137           1 :         status = torture_smb2_testfile(tree, FNAME, &h);
     138           1 :         torture_assert_ntstatus_ok(torture, status, "create write");
     139             : 
     140           1 :         ZERO_ARRAY(buf);
     141           1 :         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
     142           1 :         torture_assert_ntstatus_ok(torture, status, "write");
     143             : 
     144           1 :         ZERO_STRUCT(ioctl);
     145           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     146           1 :         ioctl.smb2.in.file.handle = h;
     147           1 :         ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
     148           1 :         ioctl.smb2.in.max_output_response = 32;
     149           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     150             : 
     151           1 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     152           1 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
     153             : 
     154           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
     155             :                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
     156           0 :         torture_assert_ndr_success(torture, ndr_ret,
     157             :                                    "ndr_pull_req_resume_key_rsp");
     158             : 
     159           0 :         NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
     160             : 
     161           0 :         ZERO_STRUCT(ioctl);
     162           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
     163           0 :         ioctl.smb2.in.file.handle = h;
     164           0 :         ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
     165           0 :         ioctl.smb2.in.max_output_response = 32;
     166           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     167             : 
     168           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     169           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
     170             : 
     171           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
     172             :                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
     173           0 :         torture_assert_ndr_success(torture, ndr_ret,
     174             :                                    "ndr_pull_req_resume_key_rsp");
     175             : 
     176           0 :         NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
     177             : 
     178           0 :         talloc_free(tmp_ctx);
     179           0 :         return true;
     180             : }
     181             : 
     182      882016 : static uint64_t patt_hash(uint64_t off)
     183             : {
     184      882016 :         return off;
     185             : }
     186             : 
     187          43 : static bool write_pattern(struct torture_context *torture,
     188             :                           struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
     189             :                           struct smb2_handle h, uint64_t off, uint64_t len,
     190             :                           uint64_t patt_off)
     191             : {
     192             :         NTSTATUS status;
     193             :         uint64_t i;
     194             :         uint8_t *buf;
     195          43 :         uint64_t io_sz = MIN(1024 * 64, len);
     196             : 
     197          43 :         if (len == 0) {
     198           0 :                 return true;
     199             :         }
     200             : 
     201          43 :         torture_assert(torture, (len % 8) == 0, "invalid write len");
     202             : 
     203          43 :         buf = talloc_zero_size(mem_ctx, io_sz);
     204          43 :         torture_assert(torture, (buf != NULL), "no memory for file data buf");
     205             : 
     206         132 :         while (len > 0) {
     207      110298 :                 for (i = 0; i <= io_sz - 8; i += 8) {
     208      110252 :                         SBVAL(buf, i, patt_hash(patt_off));
     209      110252 :                         patt_off += 8;
     210             :                 }
     211             : 
     212          46 :                 status = smb2_util_write(tree, h,
     213             :                                          buf, off, io_sz);
     214          46 :                 torture_assert_ntstatus_ok(torture, status, "file write");
     215             : 
     216          46 :                 len -= io_sz;
     217          46 :                 off += io_sz;
     218             :         }
     219             : 
     220          43 :         talloc_free(buf);
     221             : 
     222          43 :         return true;
     223             : }
     224             : 
     225           0 : static bool check_pattern(struct torture_context *torture,
     226             :                           struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
     227             :                           struct smb2_handle h, uint64_t off, uint64_t len,
     228             :                           uint64_t patt_off)
     229             : {
     230           0 :         if (len == 0) {
     231           0 :                 return true;
     232             :         }
     233             : 
     234           0 :         torture_assert(torture, (len % 8) == 0, "invalid read len");
     235             : 
     236           0 :         while (len > 0) {
     237             :                 uint64_t i;
     238             :                 struct smb2_read r;
     239             :                 NTSTATUS status;
     240           0 :                 uint64_t io_sz = MIN(1024 * 64, len);
     241             : 
     242           0 :                 ZERO_STRUCT(r);
     243           0 :                 r.in.file.handle = h;
     244           0 :                 r.in.length      = io_sz;
     245           0 :                 r.in.offset      = off;
     246           0 :                 status = smb2_read(tree, mem_ctx, &r);
     247           0 :                 torture_assert_ntstatus_ok(torture, status, "read");
     248             : 
     249           0 :                 torture_assert_u64_equal(torture, r.out.data.length, io_sz,
     250             :                                          "read data len mismatch");
     251             : 
     252           0 :                 for (i = 0; i <= io_sz - 8; i += 8, patt_off += 8) {
     253           0 :                         uint64_t data = BVAL(r.out.data.data, i);
     254           0 :                         torture_assert_u64_equal(torture, data, patt_hash(patt_off),
     255             :                                                  talloc_asprintf(torture, "read data "
     256             :                                                                  "pattern bad at %llu\n",
     257             :                                                                  (unsigned long long)off + i));
     258             :                 }
     259           0 :                 talloc_free(r.out.data.data);
     260           0 :                 len -= io_sz;
     261           0 :                 off += io_sz;
     262             :         }
     263             : 
     264           0 :         return true;
     265             : }
     266             : 
     267           0 : static bool check_zero(struct torture_context *torture,
     268             :                        struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
     269             :                        struct smb2_handle h, uint64_t off, uint64_t len)
     270             : {
     271             :         uint64_t i;
     272             :         struct smb2_read r;
     273             :         NTSTATUS status;
     274             : 
     275           0 :         if (len == 0) {
     276           0 :                 return true;
     277             :         }
     278             : 
     279           0 :         ZERO_STRUCT(r);
     280           0 :         r.in.file.handle = h;
     281           0 :         r.in.length      = len;
     282           0 :         r.in.offset      = off;
     283           0 :         status = smb2_read(tree, mem_ctx, &r);
     284           0 :         torture_assert_ntstatus_ok(torture, status, "read");
     285             : 
     286           0 :         torture_assert_u64_equal(torture, r.out.data.length, len,
     287             :                                  "read data len mismatch");
     288             : 
     289           0 :         for (i = 0; i <= len - 8; i += 8) {
     290           0 :                 uint64_t data = BVAL(r.out.data.data, i);
     291           0 :                 torture_assert_u64_equal(torture, data, 0,
     292             :                                          talloc_asprintf(mem_ctx, "read zero "
     293             :                                                          "bad at %llu\n",
     294             :                                                          (unsigned long long)i));
     295             :         }
     296             : 
     297           0 :         talloc_free(r.out.data.data);
     298           0 :         return true;
     299             : }
     300             : 
     301         103 : static bool test_setup_open(struct torture_context *torture,
     302             :                             struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
     303             :                             const char *fname,
     304             :                             struct smb2_handle *fh,
     305             :                             uint32_t desired_access,
     306             :                             uint32_t file_attributes)
     307             : {
     308             :         struct smb2_create io;
     309             :         NTSTATUS status;
     310             : 
     311         103 :         ZERO_STRUCT(io);
     312         103 :         io.in.desired_access = desired_access;
     313         103 :         io.in.file_attributes = file_attributes;
     314         103 :         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     315         103 :         io.in.share_access =
     316             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     317             :                 NTCREATEX_SHARE_ACCESS_READ|
     318             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     319         103 :         if (file_attributes & FILE_ATTRIBUTE_DIRECTORY) {
     320           3 :                 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     321             :         }
     322         103 :         io.in.fname = fname;
     323             : 
     324         103 :         status = smb2_create(tree, mem_ctx, &io);
     325         103 :         torture_assert_ntstatus_ok(torture, status, "file create");
     326             : 
     327         103 :         *fh = io.out.file.handle;
     328             : 
     329         103 :         return true;
     330             : }
     331             : 
     332         101 : static bool test_setup_create_fill(struct torture_context *torture,
     333             :                                    struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
     334             :                                    const char *fname,
     335             :                                    struct smb2_handle *fh,
     336             :                                    uint64_t size,
     337             :                                    uint32_t desired_access,
     338             :                                    uint32_t file_attributes)
     339             : {
     340             :         bool ok;
     341         101 :         uint32_t initial_access = desired_access;
     342             : 
     343         101 :         if (size > 0) {
     344          43 :                 initial_access |= SEC_FILE_APPEND_DATA;
     345             :         }
     346             : 
     347         101 :         smb2_util_unlink(tree, fname);
     348             : 
     349         101 :         ok = test_setup_open(torture, tree, mem_ctx,
     350             :                              fname,
     351             :                              fh,
     352             :                              initial_access,
     353             :                              file_attributes);
     354         101 :         torture_assert(torture, ok, "file create");
     355             : 
     356         101 :         if (size > 0) {
     357          43 :                 ok = write_pattern(torture, tree, mem_ctx, *fh, 0, size, 0);
     358          43 :                 torture_assert(torture, ok, "write pattern");
     359             :         }
     360             : 
     361         101 :         if (initial_access != desired_access) {
     362           2 :                 smb2_util_close(tree, *fh);
     363           2 :                 ok = test_setup_open(torture, tree, mem_ctx,
     364             :                                      fname,
     365             :                                      fh,
     366             :                                      desired_access,
     367             :                                      file_attributes);
     368           2 :                 torture_assert(torture, ok, "file open");
     369             :         }
     370             : 
     371         101 :         return true;
     372             : }
     373             : 
     374          22 : static bool test_setup_copy_chunk(struct torture_context *torture,
     375             :                                   struct smb2_tree *src_tree,
     376             :                                   struct smb2_tree *dst_tree,
     377             :                                   TALLOC_CTX *mem_ctx,
     378             :                                   uint32_t nchunks,
     379             :                                   const char *src_name,
     380             :                                   struct smb2_handle *src_h,
     381             :                                   uint64_t src_size,
     382             :                                   uint32_t src_desired_access,
     383             :                                   const char *dst_name,
     384             :                                   struct smb2_handle *dest_h,
     385             :                                   uint64_t dest_size,
     386             :                                   uint32_t dest_desired_access,
     387             :                                   struct srv_copychunk_copy *cc_copy,
     388             :                                   union smb_ioctl *ioctl)
     389             : {
     390             :         struct req_resume_key_rsp res_key;
     391             :         bool ok;
     392             :         NTSTATUS status;
     393             :         enum ndr_err_code ndr_ret;
     394             : 
     395          22 :         ok = test_setup_create_fill(torture, src_tree, mem_ctx, src_name,
     396             :                                     src_h, src_size, src_desired_access,
     397             :                                     FILE_ATTRIBUTE_NORMAL);
     398          22 :         torture_assert(torture, ok, "src file create fill");
     399             : 
     400          22 :         ok = test_setup_create_fill(torture, dst_tree, mem_ctx, dst_name,
     401             :                                     dest_h, dest_size, dest_desired_access,
     402             :                                     FILE_ATTRIBUTE_NORMAL);
     403          22 :         torture_assert(torture, ok, "dest file create fill");
     404             : 
     405          22 :         ZERO_STRUCTPN(ioctl);
     406          22 :         ioctl->smb2.level = RAW_IOCTL_SMB2;
     407          22 :         ioctl->smb2.in.file.handle = *src_h;
     408          22 :         ioctl->smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
     409             :         /* Allow for Key + ContextLength + Context */
     410          22 :         ioctl->smb2.in.max_output_response = 32;
     411          22 :         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     412             : 
     413          22 :         status = smb2_ioctl(src_tree, mem_ctx, &ioctl->smb2);
     414          22 :         torture_assert_ntstatus_ok(torture, status,
     415             :                                    "FSCTL_SRV_REQUEST_RESUME_KEY");
     416             : 
     417           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl->smb2.out.out, mem_ctx, &res_key,
     418             :                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
     419             : 
     420           0 :         torture_assert_ndr_success(torture, ndr_ret,
     421             :                                    "ndr_pull_req_resume_key_rsp");
     422             : 
     423           0 :         ZERO_STRUCTPN(ioctl);
     424           0 :         ioctl->smb2.level = RAW_IOCTL_SMB2;
     425           0 :         ioctl->smb2.in.file.handle = *dest_h;
     426           0 :         ioctl->smb2.in.function = FSCTL_SRV_COPYCHUNK;
     427           0 :         ioctl->smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp);
     428           0 :         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
     429             : 
     430           0 :         ZERO_STRUCTPN(cc_copy);
     431           0 :         memcpy(cc_copy->source_key, res_key.resume_key, ARRAY_SIZE(cc_copy->source_key));
     432           0 :         cc_copy->chunk_count = nchunks;
     433           0 :         cc_copy->chunks = talloc_zero_array(mem_ctx, struct srv_copychunk, nchunks);
     434           0 :         torture_assert(torture, (cc_copy->chunks != NULL), "no memory for chunks");
     435             : 
     436           0 :         return true;
     437             : }
     438             : 
     439             : 
     440           0 : static bool check_copy_chunk_rsp(struct torture_context *torture,
     441             :                                  struct srv_copychunk_rsp *cc_rsp,
     442             :                                  uint32_t ex_chunks_written,
     443             :                                  uint32_t ex_chunk_bytes_written,
     444             :                                  uint32_t ex_total_bytes_written)
     445             : {
     446           0 :         torture_assert_int_equal(torture, cc_rsp->chunks_written,
     447             :                                  ex_chunks_written, "num chunks");
     448           0 :         torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written,
     449             :                                  ex_chunk_bytes_written, "chunk bytes written");
     450           0 :         torture_assert_int_equal(torture, cc_rsp->total_bytes_written,
     451             :                                  ex_total_bytes_written, "chunk total bytes");
     452           0 :         return true;
     453             : }
     454             : 
     455           1 : static bool test_ioctl_copy_chunk_simple(struct torture_context *torture,
     456             :                                          struct smb2_tree *tree)
     457             : {
     458             :         struct smb2_handle src_h;
     459             :         struct smb2_handle dest_h;
     460             :         NTSTATUS status;
     461             :         union smb_ioctl ioctl;
     462           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     463             :         struct srv_copychunk_copy cc_copy;
     464             :         struct srv_copychunk_rsp cc_rsp;
     465             :         enum ndr_err_code ndr_ret;
     466             :         bool ok;
     467             : 
     468           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     469             :                                    1, /* 1 chunk */
     470             :                                    FNAME,
     471             :                                    &src_h, 4096, /* fill 4096 byte src file */
     472             :                                    SEC_RIGHTS_FILE_ALL,
     473             :                                    FNAME2,
     474             :                                    &dest_h, 0,      /* 0 byte dest file */
     475             :                                    SEC_RIGHTS_FILE_ALL,
     476             :                                    &cc_copy,
     477             :                                    &ioctl);
     478           1 :         if (!ok) {
     479           1 :                 torture_fail(torture, "setup copy chunk error");
     480             :         }
     481             : 
     482             :         /* copy all src file data (via a single chunk desc) */
     483           0 :         cc_copy.chunks[0].source_off = 0;
     484           0 :         cc_copy.chunks[0].target_off = 0;
     485           0 :         cc_copy.chunks[0].length = 4096;
     486             : 
     487           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     488             :                                        &cc_copy,
     489             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     490           0 :         torture_assert_ndr_success(torture, ndr_ret,
     491             :                                    "ndr_push_srv_copychunk_copy");
     492             : 
     493           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     494           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
     495             : 
     496           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     497             :                                        &cc_rsp,
     498             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     499           0 :         torture_assert_ndr_success(torture, ndr_ret,
     500             :                                    "ndr_pull_srv_copychunk_rsp");
     501             : 
     502           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     503             :                                   1,    /* chunks written */
     504             :                                   0,    /* chunk bytes unsuccessfully written */
     505             :                                   4096); /* total bytes written */
     506           0 :         if (!ok) {
     507           0 :                 torture_fail(torture, "bad copy chunk response data");
     508             :         }
     509             : 
     510           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
     511           0 :         if (!ok) {
     512           0 :                 torture_fail(torture, "inconsistent file data");
     513             :         }
     514             : 
     515           0 :         smb2_util_close(tree, src_h);
     516           0 :         smb2_util_close(tree, dest_h);
     517           0 :         talloc_free(tmp_ctx);
     518           0 :         return true;
     519             : }
     520             : 
     521           1 : static bool test_ioctl_copy_chunk_multi(struct torture_context *torture,
     522             :                                         struct smb2_tree *tree)
     523             : {
     524             :         struct smb2_handle src_h;
     525             :         struct smb2_handle dest_h;
     526             :         NTSTATUS status;
     527             :         union smb_ioctl ioctl;
     528           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     529             :         struct srv_copychunk_copy cc_copy;
     530             :         struct srv_copychunk_rsp cc_rsp;
     531             :         enum ndr_err_code ndr_ret;
     532             :         bool ok;
     533             : 
     534           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     535             :                                    2, /* chunks */
     536             :                                    FNAME,
     537             :                                    &src_h, 8192, /* src file */
     538             :                                    SEC_RIGHTS_FILE_ALL,
     539             :                                    FNAME2,
     540             :                                    &dest_h, 0,      /* dest file */
     541             :                                    SEC_RIGHTS_FILE_ALL,
     542             :                                    &cc_copy,
     543             :                                    &ioctl);
     544           1 :         if (!ok) {
     545           1 :                 torture_fail(torture, "setup copy chunk error");
     546             :         }
     547             : 
     548             :         /* copy all src file data via two chunks */
     549           0 :         cc_copy.chunks[0].source_off = 0;
     550           0 :         cc_copy.chunks[0].target_off = 0;
     551           0 :         cc_copy.chunks[0].length = 4096;
     552             : 
     553           0 :         cc_copy.chunks[1].source_off = 4096;
     554           0 :         cc_copy.chunks[1].target_off = 4096;
     555           0 :         cc_copy.chunks[1].length = 4096;
     556             : 
     557           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     558             :                                        &cc_copy,
     559             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     560           0 :         torture_assert_ndr_success(torture, ndr_ret,
     561             :                                    "ndr_push_srv_copychunk_copy");
     562             : 
     563           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     564           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
     565             : 
     566           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     567             :                                        &cc_rsp,
     568             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     569           0 :         torture_assert_ndr_success(torture, ndr_ret,
     570             :                                    "ndr_pull_srv_copychunk_rsp");
     571             : 
     572           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     573             :                                   2,    /* chunks written */
     574             :                                   0,    /* chunk bytes unsuccessfully written */
     575             :                                   8192);        /* total bytes written */
     576           0 :         if (!ok) {
     577           0 :                 torture_fail(torture, "bad copy chunk response data");
     578             :         }
     579             : 
     580           0 :         smb2_util_close(tree, src_h);
     581           0 :         smb2_util_close(tree, dest_h);
     582           0 :         talloc_free(tmp_ctx);
     583           0 :         return true;
     584             : }
     585             : 
     586           1 : static bool test_ioctl_copy_chunk_tiny(struct torture_context *torture,
     587             :                                        struct smb2_tree *tree)
     588             : {
     589             :         struct smb2_handle src_h;
     590             :         struct smb2_handle dest_h;
     591             :         NTSTATUS status;
     592             :         union smb_ioctl ioctl;
     593           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     594             :         struct srv_copychunk_copy cc_copy;
     595             :         struct srv_copychunk_rsp cc_rsp;
     596             :         enum ndr_err_code ndr_ret;
     597             :         bool ok;
     598             : 
     599           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     600             :                                    2, /* chunks */
     601             :                                    FNAME,
     602             :                                    &src_h, 96, /* src file */
     603             :                                    SEC_RIGHTS_FILE_ALL,
     604             :                                    FNAME2,
     605             :                                    &dest_h, 0,      /* dest file */
     606             :                                    SEC_RIGHTS_FILE_ALL,
     607             :                                    &cc_copy,
     608             :                                    &ioctl);
     609           1 :         if (!ok) {
     610           1 :                 torture_fail(torture, "setup copy chunk error");
     611             :         }
     612             : 
     613             :         /* copy all src file data via two chunks, sub block size chunks */
     614           0 :         cc_copy.chunks[0].source_off = 0;
     615           0 :         cc_copy.chunks[0].target_off = 0;
     616           0 :         cc_copy.chunks[0].length = 48;
     617             : 
     618           0 :         cc_copy.chunks[1].source_off = 48;
     619           0 :         cc_copy.chunks[1].target_off = 48;
     620           0 :         cc_copy.chunks[1].length = 48;
     621             : 
     622           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     623             :                                        &cc_copy,
     624             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     625           0 :         torture_assert_ndr_success(torture, ndr_ret,
     626             :                                    "ndr_push_srv_copychunk_copy");
     627             : 
     628           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     629           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
     630             : 
     631           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     632             :                                        &cc_rsp,
     633             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     634           0 :         torture_assert_ndr_success(torture, ndr_ret,
     635             :                                    "ndr_pull_srv_copychunk_rsp");
     636             : 
     637           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     638             :                                   2,    /* chunks written */
     639             :                                   0,    /* chunk bytes unsuccessfully written */
     640             :                                   96);  /* total bytes written */
     641           0 :         if (!ok) {
     642           0 :                 torture_fail(torture, "bad copy chunk response data");
     643             :         }
     644             : 
     645           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 96, 0);
     646           0 :         if (!ok) {
     647           0 :                 torture_fail(torture, "inconsistent file data");
     648             :         }
     649             : 
     650           0 :         smb2_util_close(tree, src_h);
     651           0 :         smb2_util_close(tree, dest_h);
     652           0 :         talloc_free(tmp_ctx);
     653           0 :         return true;
     654             : }
     655             : 
     656           1 : static bool test_ioctl_copy_chunk_over(struct torture_context *torture,
     657             :                                        struct smb2_tree *tree)
     658             : {
     659             :         struct smb2_handle src_h;
     660             :         struct smb2_handle dest_h;
     661             :         NTSTATUS status;
     662             :         union smb_ioctl ioctl;
     663           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     664             :         struct srv_copychunk_copy cc_copy;
     665             :         struct srv_copychunk_rsp cc_rsp;
     666             :         enum ndr_err_code ndr_ret;
     667             :         bool ok;
     668             : 
     669           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     670             :                                    2, /* chunks */
     671             :                                    FNAME,
     672             :                                    &src_h, 8192, /* src file */
     673             :                                    SEC_RIGHTS_FILE_ALL,
     674             :                                    FNAME2,
     675             :                                    &dest_h, 4096, /* dest file */
     676             :                                    SEC_RIGHTS_FILE_ALL,
     677             :                                    &cc_copy,
     678             :                                    &ioctl);
     679           1 :         if (!ok) {
     680           1 :                 torture_fail(torture, "setup copy chunk error");
     681             :         }
     682             : 
     683             :         /* first chunk overwrites existing dest data */
     684           0 :         cc_copy.chunks[0].source_off = 0;
     685           0 :         cc_copy.chunks[0].target_off = 0;
     686           0 :         cc_copy.chunks[0].length = 4096;
     687             : 
     688             :         /* second chunk overwrites the first */
     689           0 :         cc_copy.chunks[1].source_off = 4096;
     690           0 :         cc_copy.chunks[1].target_off = 0;
     691           0 :         cc_copy.chunks[1].length = 4096;
     692             : 
     693           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     694             :                                        &cc_copy,
     695             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     696           0 :         torture_assert_ndr_success(torture, ndr_ret,
     697             :                                    "ndr_push_srv_copychunk_copy");
     698             : 
     699           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     700           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
     701             : 
     702           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     703             :                                        &cc_rsp,
     704             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     705           0 :         torture_assert_ndr_success(torture, ndr_ret,
     706             :                                    "ndr_pull_srv_copychunk_rsp");
     707             : 
     708           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     709             :                                   2,    /* chunks written */
     710             :                                   0,    /* chunk bytes unsuccessfully written */
     711             :                                   8192); /* total bytes written */
     712           0 :         if (!ok) {
     713           0 :                 torture_fail(torture, "bad copy chunk response data");
     714             :         }
     715             : 
     716           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 4096);
     717           0 :         if (!ok) {
     718           0 :                 torture_fail(torture, "inconsistent file data");
     719             :         }
     720             : 
     721           0 :         smb2_util_close(tree, src_h);
     722           0 :         smb2_util_close(tree, dest_h);
     723           0 :         talloc_free(tmp_ctx);
     724           0 :         return true;
     725             : }
     726             : 
     727           1 : static bool test_ioctl_copy_chunk_append(struct torture_context *torture,
     728             :                                        struct smb2_tree *tree)
     729             : {
     730             :         struct smb2_handle src_h;
     731             :         struct smb2_handle dest_h;
     732             :         NTSTATUS status;
     733             :         union smb_ioctl ioctl;
     734           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     735             :         struct srv_copychunk_copy cc_copy;
     736             :         struct srv_copychunk_rsp cc_rsp;
     737             :         enum ndr_err_code ndr_ret;
     738             :         bool ok;
     739             : 
     740           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     741             :                                    2, /* chunks */
     742             :                                    FNAME,
     743             :                                    &src_h, 4096, /* src file */
     744             :                                    SEC_RIGHTS_FILE_ALL,
     745             :                                    FNAME2,
     746             :                                    &dest_h, 0,      /* dest file */
     747             :                                    SEC_RIGHTS_FILE_ALL,
     748             :                                    &cc_copy,
     749             :                                    &ioctl);
     750           1 :         if (!ok) {
     751           1 :                 torture_fail(torture, "setup copy chunk error");
     752             :         }
     753             : 
     754           0 :         cc_copy.chunks[0].source_off = 0;
     755           0 :         cc_copy.chunks[0].target_off = 0;
     756           0 :         cc_copy.chunks[0].length = 4096;
     757             : 
     758             :         /* second chunk appends the same data to the first */
     759           0 :         cc_copy.chunks[1].source_off = 0;
     760           0 :         cc_copy.chunks[1].target_off = 4096;
     761           0 :         cc_copy.chunks[1].length = 4096;
     762             : 
     763           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     764             :                                        &cc_copy,
     765             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     766           0 :         torture_assert_ndr_success(torture, ndr_ret,
     767             :                                    "ndr_push_srv_copychunk_copy");
     768             : 
     769           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     770           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
     771             : 
     772           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     773             :                                        &cc_rsp,
     774             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     775           0 :         torture_assert_ndr_success(torture, ndr_ret,
     776             :                                    "ndr_pull_srv_copychunk_rsp");
     777             : 
     778           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     779             :                                   2,    /* chunks written */
     780             :                                   0,    /* chunk bytes unsuccessfully written */
     781             :                                   8192); /* total bytes written */
     782           0 :         if (!ok) {
     783           0 :                 torture_fail(torture, "bad copy chunk response data");
     784             :         }
     785             : 
     786           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
     787           0 :         if (!ok) {
     788           0 :                 torture_fail(torture, "inconsistent file data");
     789             :         }
     790             : 
     791           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
     792           0 :         if (!ok) {
     793           0 :                 torture_fail(torture, "inconsistent file data");
     794             :         }
     795             : 
     796           0 :         smb2_util_close(tree, src_h);
     797           0 :         smb2_util_close(tree, dest_h);
     798           0 :         talloc_free(tmp_ctx);
     799           0 :         return true;
     800             : }
     801             : 
     802           1 : static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
     803             :                                          struct smb2_tree *tree)
     804             : {
     805             :         struct smb2_handle src_h;
     806             :         struct smb2_handle dest_h;
     807             :         NTSTATUS status;
     808             :         union smb_ioctl ioctl;
     809           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     810             :         struct srv_copychunk_copy cc_copy;
     811             :         struct srv_copychunk_rsp cc_rsp;
     812             :         enum ndr_err_code ndr_ret;
     813             :         bool ok;
     814             : 
     815           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     816             :                                    1, /* chunks */
     817             :                                    FNAME,
     818             :                                    &src_h, 4096, /* src file */
     819             :                                    SEC_RIGHTS_FILE_ALL,
     820             :                                    FNAME2,
     821             :                                    &dest_h, 0,      /* dest file */
     822             :                                    SEC_RIGHTS_FILE_ALL,
     823             :                                    &cc_copy,
     824             :                                    &ioctl);
     825           1 :         if (!ok) {
     826           1 :                 torture_fail(torture, "setup copy chunk error");
     827             :         }
     828             : 
     829             :         /* send huge chunk length request */
     830           0 :         cc_copy.chunks[0].source_off = 0;
     831           0 :         cc_copy.chunks[0].target_off = 0;
     832           0 :         cc_copy.chunks[0].length = UINT_MAX;
     833             : 
     834           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     835             :                                        &cc_copy,
     836             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     837           0 :         torture_assert_ndr_success(torture, ndr_ret, "marshalling request");
     838             : 
     839           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     840           0 :         torture_assert_ntstatus_equal(torture, status,
     841             :                                       NT_STATUS_INVALID_PARAMETER,
     842             :                                       "bad oversize chunk response");
     843             : 
     844           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     845             :                                        &cc_rsp,
     846             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     847           0 :         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
     848             : 
     849           0 :         torture_comment(torture, "limit max chunks, got %u\n",
     850             :                         cc_rsp.chunks_written);
     851           0 :         torture_comment(torture, "limit max chunk len, got %u\n",
     852             :                         cc_rsp.chunk_bytes_written);
     853           0 :         torture_comment(torture, "limit max total bytes, got %u\n",
     854             :                         cc_rsp.total_bytes_written);
     855             : 
     856           0 :         smb2_util_close(tree, src_h);
     857           0 :         smb2_util_close(tree, dest_h);
     858           0 :         talloc_free(tmp_ctx);
     859           0 :         return true;
     860             : }
     861             : 
     862           1 : static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
     863             :                                           struct smb2_tree *tree)
     864             : {
     865             :         struct smb2_handle src_h;
     866             :         struct smb2_handle src_h2;
     867             :         struct smb2_handle dest_h;
     868             :         NTSTATUS status;
     869             :         union smb_ioctl ioctl;
     870           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
     871             :         struct srv_copychunk_copy cc_copy;
     872             :         struct srv_copychunk_rsp cc_rsp;
     873             :         enum ndr_err_code ndr_ret;
     874             :         bool ok;
     875             :         struct smb2_lock lck;
     876             :         struct smb2_lock_element el[1];
     877             : 
     878           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
     879             :                                    1, /* chunks */
     880             :                                    FNAME,
     881             :                                    &src_h, 4096, /* src file */
     882             :                                    SEC_RIGHTS_FILE_ALL,
     883             :                                    FNAME2,
     884             :                                    &dest_h, 0,      /* dest file */
     885             :                                    SEC_RIGHTS_FILE_ALL,
     886             :                                    &cc_copy,
     887             :                                    &ioctl);
     888           1 :         if (!ok) {
     889           1 :                 torture_fail(torture, "setup copy chunk error");
     890             :         }
     891             : 
     892           0 :         cc_copy.chunks[0].source_off = 0;
     893           0 :         cc_copy.chunks[0].target_off = 0;
     894           0 :         cc_copy.chunks[0].length = 4096;
     895             : 
     896             :         /* open and lock the copychunk src file */
     897           0 :         status = torture_smb2_testfile(tree, FNAME, &src_h2);
     898           0 :         torture_assert_ntstatus_ok(torture, status, "2nd src open");
     899             : 
     900           0 :         lck.in.lock_count       = 0x0001;
     901           0 :         lck.in.lock_sequence    = 0x00000000;
     902           0 :         lck.in.file.handle      = src_h2;
     903           0 :         lck.in.locks            = el;
     904           0 :         el[0].offset            = cc_copy.chunks[0].source_off;
     905           0 :         el[0].length            = cc_copy.chunks[0].length;
     906           0 :         el[0].reserved          = 0;
     907           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
     908             : 
     909           0 :         status = smb2_lock(tree, &lck);
     910           0 :         torture_assert_ntstatus_ok(torture, status, "lock");
     911             : 
     912           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
     913             :                                        &cc_copy,
     914             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
     915           0 :         torture_assert_ndr_success(torture, ndr_ret,
     916             :                                    "ndr_push_srv_copychunk_copy");
     917             : 
     918           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     919             :         /*
     920             :          * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
     921             :          *
     922             :          * Edgar Olougouna @ MS wrote:
     923             :          * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
     924             :          * discrepancy observed between Windows versions, we confirm that the
     925             :          * behavior change is expected.
     926             :          *
     927             :          * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
     928             :          * to move the chunks from the source to the destination.
     929             :          * These ReadFile/WriteFile APIs go through the byte-range lock checks,
     930             :          * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
     931             :          *
     932             :          * Prior to Windows Server 2012, CopyChunk used mapped sections to move
     933             :          * the data. And byte range locks are not enforced on mapped I/O, and
     934             :          * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
     935             :          */
     936           0 :         torture_assert_ntstatus_equal(torture, status,
     937             :                                       NT_STATUS_FILE_LOCK_CONFLICT,
     938             :                                       "FSCTL_SRV_COPYCHUNK locked");
     939             : 
     940             :         /* should get cc response data with the lock conflict status */
     941           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     942             :                                        &cc_rsp,
     943             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     944           0 :         torture_assert_ndr_success(torture, ndr_ret,
     945             :                                    "ndr_pull_srv_copychunk_rsp");
     946           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     947             :                                   0,    /* chunks written */
     948             :                                   0,    /* chunk bytes unsuccessfully written */
     949             :                                   0);   /* total bytes written */
     950             : 
     951           0 :         lck.in.lock_count       = 0x0001;
     952           0 :         lck.in.lock_sequence    = 0x00000001;
     953           0 :         lck.in.file.handle      = src_h2;
     954           0 :         lck.in.locks            = el;
     955           0 :         el[0].offset            = cc_copy.chunks[0].source_off;
     956           0 :         el[0].length            = cc_copy.chunks[0].length;
     957           0 :         el[0].reserved          = 0;
     958           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
     959           0 :         status = smb2_lock(tree, &lck);
     960           0 :         torture_assert_ntstatus_ok(torture, status, "unlock");
     961             : 
     962           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
     963           0 :         torture_assert_ntstatus_ok(torture, status,
     964             :                                    "FSCTL_SRV_COPYCHUNK unlocked");
     965             : 
     966           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
     967             :                                        &cc_rsp,
     968             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
     969           0 :         torture_assert_ndr_success(torture, ndr_ret,
     970             :                                    "ndr_pull_srv_copychunk_rsp");
     971             : 
     972           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
     973             :                                   1,    /* chunks written */
     974             :                                   0,    /* chunk bytes unsuccessfully written */
     975             :                                   4096); /* total bytes written */
     976           0 :         if (!ok) {
     977           0 :                 torture_fail(torture, "bad copy chunk response data");
     978             :         }
     979             : 
     980           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
     981           0 :         if (!ok) {
     982           0 :                 torture_fail(torture, "inconsistent file data");
     983             :         }
     984             : 
     985           0 :         smb2_util_close(tree, src_h2);
     986           0 :         smb2_util_close(tree, src_h);
     987           0 :         smb2_util_close(tree, dest_h);
     988           0 :         talloc_free(tmp_ctx);
     989           0 :         return true;
     990             : }
     991             : 
     992           1 : static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
     993             :                                            struct smb2_tree *tree)
     994             : {
     995             :         struct smb2_handle src_h;
     996             :         struct smb2_handle dest_h;
     997             :         struct smb2_handle dest_h2;
     998             :         NTSTATUS status;
     999             :         union smb_ioctl ioctl;
    1000           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1001             :         struct srv_copychunk_copy cc_copy;
    1002             :         struct srv_copychunk_rsp cc_rsp;
    1003             :         enum ndr_err_code ndr_ret;
    1004             :         bool ok;
    1005             :         struct smb2_lock lck;
    1006             :         struct smb2_lock_element el[1];
    1007             : 
    1008           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1009             :                                    1, /* chunks */
    1010             :                                    FNAME,
    1011             :                                    &src_h, 4096, /* src file */
    1012             :                                    SEC_RIGHTS_FILE_ALL,
    1013             :                                    FNAME2,
    1014             :                                    &dest_h, 4096,   /* dest file */
    1015             :                                    SEC_RIGHTS_FILE_ALL,
    1016             :                                    &cc_copy,
    1017             :                                    &ioctl);
    1018           1 :         if (!ok) {
    1019           1 :                 torture_fail(torture, "setup copy chunk error");
    1020             :         }
    1021             : 
    1022           0 :         cc_copy.chunks[0].source_off = 0;
    1023           0 :         cc_copy.chunks[0].target_off = 0;
    1024           0 :         cc_copy.chunks[0].length = 4096;
    1025             : 
    1026             :         /* open and lock the copychunk dest file */
    1027           0 :         status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
    1028           0 :         torture_assert_ntstatus_ok(torture, status, "2nd src open");
    1029             : 
    1030           0 :         lck.in.lock_count       = 0x0001;
    1031           0 :         lck.in.lock_sequence    = 0x00000000;
    1032           0 :         lck.in.file.handle      = dest_h2;
    1033           0 :         lck.in.locks            = el;
    1034           0 :         el[0].offset            = cc_copy.chunks[0].target_off;
    1035           0 :         el[0].length            = cc_copy.chunks[0].length;
    1036           0 :         el[0].reserved          = 0;
    1037           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    1038             : 
    1039           0 :         status = smb2_lock(tree, &lck);
    1040           0 :         torture_assert_ntstatus_ok(torture, status, "lock");
    1041             : 
    1042           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1043             :                                        &cc_copy,
    1044             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1045           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1046             :                                    "ndr_push_srv_copychunk_copy");
    1047             : 
    1048           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1049           0 :         torture_assert_ntstatus_equal(torture, status,
    1050             :                                       NT_STATUS_FILE_LOCK_CONFLICT,
    1051             :                                       "FSCTL_SRV_COPYCHUNK locked");
    1052             : 
    1053           0 :         lck.in.lock_count       = 0x0001;
    1054           0 :         lck.in.lock_sequence    = 0x00000001;
    1055           0 :         lck.in.file.handle      = dest_h2;
    1056           0 :         lck.in.locks            = el;
    1057           0 :         el[0].offset            = cc_copy.chunks[0].target_off;
    1058           0 :         el[0].length            = cc_copy.chunks[0].length;
    1059           0 :         el[0].reserved          = 0;
    1060           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    1061           0 :         status = smb2_lock(tree, &lck);
    1062           0 :         torture_assert_ntstatus_ok(torture, status, "unlock");
    1063             : 
    1064           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1065           0 :         torture_assert_ntstatus_ok(torture, status,
    1066             :                                    "FSCTL_SRV_COPYCHUNK unlocked");
    1067             : 
    1068           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1069             :                                        &cc_rsp,
    1070             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1071           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1072             :                                    "ndr_pull_srv_copychunk_rsp");
    1073             : 
    1074           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1075             :                                   1,    /* chunks written */
    1076             :                                   0,    /* chunk bytes unsuccessfully written */
    1077             :                                   4096); /* total bytes written */
    1078           0 :         if (!ok) {
    1079           0 :                 torture_fail(torture, "bad copy chunk response data");
    1080             :         }
    1081             : 
    1082           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
    1083           0 :         if (!ok) {
    1084           0 :                 torture_fail(torture, "inconsistent file data");
    1085             :         }
    1086             : 
    1087           0 :         smb2_util_close(tree, dest_h2);
    1088           0 :         smb2_util_close(tree, src_h);
    1089           0 :         smb2_util_close(tree, dest_h);
    1090           0 :         talloc_free(tmp_ctx);
    1091           0 :         return true;
    1092             : }
    1093             : 
    1094           1 : static bool test_ioctl_copy_chunk_bad_key(struct torture_context *torture,
    1095             :                                           struct smb2_tree *tree)
    1096             : {
    1097             :         struct smb2_handle src_h;
    1098             :         struct smb2_handle dest_h;
    1099             :         NTSTATUS status;
    1100             :         union smb_ioctl ioctl;
    1101           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1102             :         struct srv_copychunk_copy cc_copy;
    1103             :         enum ndr_err_code ndr_ret;
    1104             :         bool ok;
    1105             : 
    1106           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1107             :                                    1,
    1108             :                                    FNAME,
    1109             :                                    &src_h, 4096,
    1110             :                                    SEC_RIGHTS_FILE_ALL,
    1111             :                                    FNAME2,
    1112             :                                    &dest_h, 0,
    1113             :                                    SEC_RIGHTS_FILE_ALL,
    1114             :                                    &cc_copy,
    1115             :                                    &ioctl);
    1116           1 :         if (!ok) {
    1117           1 :                 torture_fail(torture, "setup copy chunk error");
    1118             :         }
    1119             : 
    1120             :         /* overwrite the resume key with a bogus value */
    1121           0 :         memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
    1122             : 
    1123           0 :         cc_copy.chunks[0].source_off = 0;
    1124           0 :         cc_copy.chunks[0].target_off = 0;
    1125           0 :         cc_copy.chunks[0].length = 4096;
    1126             : 
    1127           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1128             :                                        &cc_copy,
    1129             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1130           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1131             :                                    "ndr_push_srv_copychunk_copy");
    1132             : 
    1133             :         /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
    1134           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1135           0 :         torture_assert_ntstatus_equal(torture, status,
    1136             :                                       NT_STATUS_OBJECT_NAME_NOT_FOUND,
    1137             :                                       "FSCTL_SRV_COPYCHUNK");
    1138             : 
    1139           0 :         smb2_util_close(tree, src_h);
    1140           0 :         smb2_util_close(tree, dest_h);
    1141           0 :         talloc_free(tmp_ctx);
    1142           0 :         return true;
    1143             : }
    1144             : 
    1145           1 : static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context *torture,
    1146             :                                               struct smb2_tree *tree)
    1147             : {
    1148             :         struct smb2_handle src_h;
    1149             :         struct smb2_handle dest_h;
    1150             :         NTSTATUS status;
    1151             :         union smb_ioctl ioctl;
    1152           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1153             :         struct srv_copychunk_copy cc_copy;
    1154             :         struct srv_copychunk_rsp cc_rsp;
    1155             :         enum ndr_err_code ndr_ret;
    1156             :         bool ok;
    1157             : 
    1158           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1159             :                                    1,
    1160             :                                    FNAME,
    1161             :                                    &src_h, 8192,
    1162             :                                    SEC_RIGHTS_FILE_ALL,
    1163             :                                    FNAME2,
    1164             :                                    &dest_h, 0,
    1165             :                                    SEC_RIGHTS_FILE_ALL,
    1166             :                                    &cc_copy,
    1167             :                                    &ioctl);
    1168           1 :         if (!ok) {
    1169           1 :                 torture_fail(torture, "setup copy chunk error");
    1170             :         }
    1171             : 
    1172             :         /* the source is also the destination */
    1173           0 :         ioctl.smb2.in.file.handle = src_h;
    1174             : 
    1175             :         /* non-overlapping */
    1176           0 :         cc_copy.chunks[0].source_off = 0;
    1177           0 :         cc_copy.chunks[0].target_off = 4096;
    1178           0 :         cc_copy.chunks[0].length = 4096;
    1179             : 
    1180           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1181             :                                        &cc_copy,
    1182             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1183           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1184             :                                    "ndr_push_srv_copychunk_copy");
    1185             : 
    1186           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1187           0 :         torture_assert_ntstatus_ok(torture, status,
    1188             :                                    "FSCTL_SRV_COPYCHUNK");
    1189             : 
    1190           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1191             :                                        &cc_rsp,
    1192             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1193           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1194             :                                    "ndr_pull_srv_copychunk_rsp");
    1195             : 
    1196           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1197             :                                   1,    /* chunks written */
    1198             :                                   0,    /* chunk bytes unsuccessfully written */
    1199             :                                   4096); /* total bytes written */
    1200           0 :         if (!ok) {
    1201           0 :                 torture_fail(torture, "bad copy chunk response data");
    1202             :         }
    1203             : 
    1204           0 :         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 4096, 0);
    1205           0 :         if (!ok) {
    1206           0 :                 torture_fail(torture, "inconsistent file data");
    1207             :         }
    1208           0 :         ok = check_pattern(torture, tree, tmp_ctx, src_h, 4096, 4096, 0);
    1209           0 :         if (!ok) {
    1210           0 :                 torture_fail(torture, "inconsistent file data");
    1211             :         }
    1212             : 
    1213           0 :         smb2_util_close(tree, src_h);
    1214           0 :         smb2_util_close(tree, dest_h);
    1215           0 :         talloc_free(tmp_ctx);
    1216           0 :         return true;
    1217             : }
    1218             : 
    1219             : /*
    1220             :  * Test a single-chunk copychunk request, where the source and target ranges
    1221             :  * overlap, and the SourceKey refers to the same target file. E.g:
    1222             :  *
    1223             :  * Initial State
    1224             :  * -------------
    1225             :  *      File:           src_and_dest
    1226             :  *      Offset:         0123456789
    1227             :  *      Data:           abcdefghij
    1228             :  *
    1229             :  * Request
    1230             :  * -------
    1231             :  *      FSCTL_SRV_COPYCHUNK(src_and_dest)
    1232             :  *      SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
    1233             :  *      ChunkCount = 1
    1234             :  *      Chunks[0].SourceOffset = 0
    1235             :  *      Chunks[0].TargetOffset = 4
    1236             :  *      Chunks[0].Length = 6
    1237             :  *
    1238             :  * Resultant State
    1239             :  * ---------------
    1240             :  *      File:           src_and_dest
    1241             :  *      Offset:         0123456789
    1242             :  *      Data:           abcdabcdef
    1243             :  *
    1244             :  * The resultant contents of src_and_dest is dependent on the server's
    1245             :  * copy algorithm. In the above example, the server uses an IO buffer
    1246             :  * large enough to hold the entire six-byte source data before writing
    1247             :  * to TargetOffset. If the server were to use a four-byte IO buffer and
    1248             :  * started reads/writes from the lowest offset, then the two overlapping
    1249             :  * bytes in the above example would be overwritten before being read. The
    1250             :  * resultant file contents would be abcdabcdab.
    1251             :  *
    1252             :  * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
    1253             :  * after this offset are written before being read. Windows 2012 on the
    1254             :  * other hand appears to use a buffer large enough to hold its maximum
    1255             :  * supported chunk size (1M). Samba currently uses a 64k copy buffer by
    1256             :  * default (vfs_cc_state.buf).
    1257             :  *
    1258             :  * This test uses an 8-byte overlap at 2040-2048, so that it passes against
    1259             :  * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
    1260             :  * to use a different copy algorithm to 2008r2.
    1261             :  */
    1262             : static bool
    1263           1 : test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context *torture,
    1264             :                                           struct smb2_tree *tree)
    1265             : {
    1266             :         struct smb2_handle src_h;
    1267             :         struct smb2_handle dest_h;
    1268             :         NTSTATUS status;
    1269             :         union smb_ioctl ioctl;
    1270           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1271             :         struct srv_copychunk_copy cc_copy;
    1272             :         struct srv_copychunk_rsp cc_rsp;
    1273             :         enum ndr_err_code ndr_ret;
    1274             :         bool ok;
    1275             : 
    1276             :         /* exceed the vfs_default copy buffer */
    1277           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1278             :                                    1,
    1279             :                                    FNAME,
    1280             :                                    &src_h, 2048 * 2,
    1281             :                                    SEC_RIGHTS_FILE_ALL,
    1282             :                                    FNAME2,
    1283             :                                    &dest_h, 0,
    1284             :                                    SEC_RIGHTS_FILE_ALL,
    1285             :                                    &cc_copy,
    1286             :                                    &ioctl);
    1287           1 :         if (!ok) {
    1288           1 :                 torture_fail(torture, "setup copy chunk error");
    1289             :         }
    1290             : 
    1291             :         /* the source is also the destination */
    1292           0 :         ioctl.smb2.in.file.handle = src_h;
    1293             : 
    1294             :         /* 8 bytes overlap between source and target ranges */
    1295           0 :         cc_copy.chunks[0].source_off = 0;
    1296           0 :         cc_copy.chunks[0].target_off = 2048 - 8;
    1297           0 :         cc_copy.chunks[0].length = 2048;
    1298             : 
    1299           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1300             :                                        &cc_copy,
    1301             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1302           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1303             :                                    "ndr_push_srv_copychunk_copy");
    1304             : 
    1305           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1306           0 :         torture_assert_ntstatus_ok(torture, status,
    1307             :                                    "FSCTL_SRV_COPYCHUNK");
    1308             : 
    1309           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1310             :                                        &cc_rsp,
    1311             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1312           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1313             :                                    "ndr_pull_srv_copychunk_rsp");
    1314             : 
    1315           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1316             :                                   1,    /* chunks written */
    1317             :                                   0,    /* chunk bytes unsuccessfully written */
    1318             :                                   2048); /* total bytes written */
    1319           0 :         if (!ok) {
    1320           0 :                 torture_fail(torture, "bad copy chunk response data");
    1321             :         }
    1322             : 
    1323           0 :         ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 2048 - 8, 0);
    1324           0 :         if (!ok) {
    1325           0 :                 torture_fail(torture, "inconsistent file data");
    1326             :         }
    1327           0 :         ok = check_pattern(torture, tree, tmp_ctx, src_h, 2048 - 8, 2048, 0);
    1328           0 :         if (!ok) {
    1329           0 :                 torture_fail(torture, "inconsistent file data");
    1330             :         }
    1331             : 
    1332           0 :         smb2_util_close(tree, src_h);
    1333           0 :         smb2_util_close(tree, dest_h);
    1334           0 :         talloc_free(tmp_ctx);
    1335           0 :         return true;
    1336             : }
    1337             : 
    1338           1 : static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
    1339             :                                              struct smb2_tree *tree)
    1340             : {
    1341             :         struct smb2_handle src_h;
    1342             :         struct smb2_handle dest_h;
    1343             :         NTSTATUS status;
    1344             :         union smb_ioctl ioctl;
    1345           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1346             :         struct srv_copychunk_copy cc_copy;
    1347             :         enum ndr_err_code ndr_ret;
    1348             :         bool ok;
    1349             :         /* read permission on src */
    1350           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
    1351             :                                    FNAME, &src_h, 4096, /* fill 4096 byte src file */
    1352             :                                    SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
    1353             :                                    FNAME2, &dest_h, 0, /* 0 byte dest file */
    1354             :                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
    1355           1 :         if (!ok) {
    1356           1 :                 torture_fail(torture, "setup copy chunk error");
    1357             :         }
    1358             : 
    1359           0 :         cc_copy.chunks[0].source_off = 0;
    1360           0 :         cc_copy.chunks[0].target_off = 0;
    1361           0 :         cc_copy.chunks[0].length = 4096;
    1362             : 
    1363           0 :         ndr_ret = ndr_push_struct_blob(
    1364             :             &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
    1365             :             (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1366           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1367             :                                    "ndr_push_srv_copychunk_copy");
    1368             : 
    1369           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1370           0 :         torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
    1371             :                                       "FSCTL_SRV_COPYCHUNK");
    1372             : 
    1373           0 :         smb2_util_close(tree, src_h);
    1374           0 :         smb2_util_close(tree, dest_h);
    1375             : 
    1376             :         /* execute permission on src */
    1377           0 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
    1378             :                                    FNAME, &src_h, 4096, /* fill 4096 byte src file */
    1379             :                                    SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
    1380             :                                    FNAME2, &dest_h, 0, /* 0 byte dest file */
    1381             :                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
    1382           0 :         if (!ok) {
    1383           0 :                 torture_fail(torture, "setup copy chunk error");
    1384             :         }
    1385             : 
    1386           0 :         cc_copy.chunks[0].source_off = 0;
    1387           0 :         cc_copy.chunks[0].target_off = 0;
    1388           0 :         cc_copy.chunks[0].length = 4096;
    1389             : 
    1390           0 :         ndr_ret = ndr_push_struct_blob(
    1391             :             &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
    1392             :             (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1393           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1394             :                                    "ndr_push_srv_copychunk_copy");
    1395             : 
    1396           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1397           0 :         torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
    1398             :                                       "FSCTL_SRV_COPYCHUNK");
    1399             : 
    1400           0 :         smb2_util_close(tree, src_h);
    1401           0 :         smb2_util_close(tree, dest_h);
    1402             : 
    1403             :         /* neither read nor execute permission on src */
    1404           0 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
    1405             :                                    FNAME, &src_h, 4096, /* fill 4096 byte src file */
    1406             :                                    SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
    1407             :                                    0, /* 0 byte dest file */
    1408             :                                    SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
    1409           0 :         if (!ok) {
    1410           0 :                 torture_fail(torture, "setup copy chunk error");
    1411             :         }
    1412             : 
    1413           0 :         cc_copy.chunks[0].source_off = 0;
    1414           0 :         cc_copy.chunks[0].target_off = 0;
    1415           0 :         cc_copy.chunks[0].length = 4096;
    1416             : 
    1417           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1418             :                                        &cc_copy,
    1419             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1420           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1421             :                                    "ndr_push_srv_copychunk_copy");
    1422             : 
    1423           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1424           0 :         torture_assert_ntstatus_equal(torture, status,
    1425             :                                       NT_STATUS_ACCESS_DENIED,
    1426             :                                       "FSCTL_SRV_COPYCHUNK");
    1427             : 
    1428           0 :         smb2_util_close(tree, src_h);
    1429           0 :         smb2_util_close(tree, dest_h);
    1430             : 
    1431             :         /* no write permission on dest */
    1432           0 :         ok = test_setup_copy_chunk(
    1433             :             torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
    1434             :             FNAME, &src_h, 4096, /* fill 4096 byte src file */
    1435             :             SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
    1436             :             0, /* 0 byte dest file */
    1437             :             (SEC_RIGHTS_FILE_ALL &
    1438             :              ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)),
    1439             :             &cc_copy, &ioctl);
    1440           0 :         if (!ok) {
    1441           0 :                 torture_fail(torture, "setup copy chunk error");
    1442             :         }
    1443             : 
    1444           0 :         cc_copy.chunks[0].source_off = 0;
    1445           0 :         cc_copy.chunks[0].target_off = 0;
    1446           0 :         cc_copy.chunks[0].length = 4096;
    1447             : 
    1448           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1449             :                                        &cc_copy,
    1450             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1451           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1452             :                                    "ndr_push_srv_copychunk_copy");
    1453             : 
    1454           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1455           0 :         torture_assert_ntstatus_equal(torture, status,
    1456             :                                       NT_STATUS_ACCESS_DENIED,
    1457             :                                       "FSCTL_SRV_COPYCHUNK");
    1458             : 
    1459           0 :         smb2_util_close(tree, src_h);
    1460           0 :         smb2_util_close(tree, dest_h);
    1461             : 
    1462             :         /* no read permission on dest */
    1463           0 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
    1464             :                                    FNAME, &src_h, 4096, /* fill 4096 byte src file */
    1465             :                                    SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
    1466             :                                    FNAME2, &dest_h, 0, /* 0 byte dest file */
    1467             :                                    (SEC_RIGHTS_FILE_ALL & ~SEC_FILE_READ_DATA),
    1468             :                                    &cc_copy, &ioctl);
    1469           0 :         if (!ok) {
    1470           0 :                 torture_fail(torture, "setup copy chunk error");
    1471             :         }
    1472             : 
    1473           0 :         cc_copy.chunks[0].source_off = 0;
    1474           0 :         cc_copy.chunks[0].target_off = 0;
    1475           0 :         cc_copy.chunks[0].length = 4096;
    1476             : 
    1477           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1478             :                                        &cc_copy,
    1479             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1480           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1481             :                                    "ndr_push_srv_copychunk_copy");
    1482             : 
    1483             :         /*
    1484             :          * FSCTL_SRV_COPYCHUNK requires read permission on dest,
    1485             :          * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
    1486             :          */
    1487           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1488           0 :         torture_assert_ntstatus_equal(torture, status,
    1489             :                                       NT_STATUS_ACCESS_DENIED,
    1490             :                                       "FSCTL_SRV_COPYCHUNK");
    1491             : 
    1492           0 :         smb2_util_close(tree, src_h);
    1493           0 :         smb2_util_close(tree, dest_h);
    1494           0 :         talloc_free(tmp_ctx);
    1495             : 
    1496           0 :         return true;
    1497             : }
    1498             : 
    1499           1 : static bool test_ioctl_copy_chunk_write_access(struct torture_context *torture,
    1500             :                                                struct smb2_tree *tree)
    1501             : {
    1502             :         struct smb2_handle src_h;
    1503             :         struct smb2_handle dest_h;
    1504             :         NTSTATUS status;
    1505             :         union smb_ioctl ioctl;
    1506           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1507             :         struct srv_copychunk_copy cc_copy;
    1508             :         enum ndr_err_code ndr_ret;
    1509             :         bool ok;
    1510             : 
    1511             :         /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
    1512           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1513             :                                    1, /* 1 chunk */
    1514             :                                    FNAME,
    1515             :                                    &src_h, 4096, /* fill 4096 byte src file */
    1516             :                                    SEC_RIGHTS_FILE_ALL,
    1517             :                                    FNAME2,
    1518             :                                    &dest_h, 0,      /* 0 byte dest file */
    1519             :                                    (SEC_RIGHTS_FILE_WRITE
    1520             :                                     | SEC_RIGHTS_FILE_EXECUTE),
    1521             :                                    &cc_copy,
    1522             :                                    &ioctl);
    1523           1 :         if (!ok) {
    1524           1 :                 torture_fail(torture, "setup copy chunk error");
    1525             :         }
    1526             : 
    1527           0 :         ioctl.smb2.in.function = FSCTL_SRV_COPYCHUNK_WRITE;
    1528           0 :         cc_copy.chunks[0].source_off = 0;
    1529           0 :         cc_copy.chunks[0].target_off = 0;
    1530           0 :         cc_copy.chunks[0].length = 4096;
    1531             : 
    1532           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1533             :                                        &cc_copy,
    1534             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1535           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1536             :                                    "ndr_push_srv_copychunk_copy");
    1537             : 
    1538           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1539           0 :         torture_assert_ntstatus_ok(torture, status,
    1540             :                                    "FSCTL_SRV_COPYCHUNK_WRITE");
    1541             : 
    1542           0 :         smb2_util_close(tree, src_h);
    1543           0 :         smb2_util_close(tree, dest_h);
    1544           0 :         talloc_free(tmp_ctx);
    1545             : 
    1546           0 :         return true;
    1547             : }
    1548             : 
    1549           1 : static bool test_ioctl_copy_chunk_src_exceed(struct torture_context *torture,
    1550             :                                              struct smb2_tree *tree)
    1551             : {
    1552             :         struct smb2_handle src_h;
    1553             :         struct smb2_handle dest_h;
    1554             :         NTSTATUS status;
    1555             :         union smb_ioctl ioctl;
    1556           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1557             :         struct srv_copychunk_copy cc_copy;
    1558             :         struct srv_copychunk_rsp cc_rsp;
    1559             :         enum ndr_err_code ndr_ret;
    1560             :         bool ok;
    1561             : 
    1562           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1563             :                                    1, /* 1 chunk */
    1564             :                                    FNAME,
    1565             :                                    &src_h, 4096, /* fill 4096 byte src file */
    1566             :                                    SEC_RIGHTS_FILE_ALL,
    1567             :                                    FNAME2,
    1568             :                                    &dest_h, 0,      /* 0 byte dest file */
    1569             :                                    SEC_RIGHTS_FILE_ALL,
    1570             :                                    &cc_copy,
    1571             :                                    &ioctl);
    1572           1 :         if (!ok) {
    1573           1 :                 torture_fail(torture, "setup copy chunk error");
    1574             :         }
    1575             : 
    1576             :         /* Request copy where off + length exceeds size of src */
    1577           0 :         cc_copy.chunks[0].source_off = 1024;
    1578           0 :         cc_copy.chunks[0].target_off = 0;
    1579           0 :         cc_copy.chunks[0].length = 4096;
    1580             : 
    1581           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1582             :                                        &cc_copy,
    1583             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1584           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1585             :                                    "ndr_push_srv_copychunk_copy");
    1586             : 
    1587           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1588           0 :         torture_assert_ntstatus_equal(torture, status,
    1589             :                                       NT_STATUS_INVALID_VIEW_SIZE,
    1590             :                                       "FSCTL_SRV_COPYCHUNK oversize");
    1591             : 
    1592             :         /* Request copy where length exceeds size of src */
    1593           0 :         cc_copy.chunks[0].source_off = 1024;
    1594           0 :         cc_copy.chunks[0].target_off = 0;
    1595           0 :         cc_copy.chunks[0].length = 3072;
    1596             : 
    1597           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1598             :                                        &cc_copy,
    1599             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1600           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1601             :                                    "ndr_push_srv_copychunk_copy");
    1602             : 
    1603           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1604           0 :         torture_assert_ntstatus_ok(torture, status,
    1605             :                                    "FSCTL_SRV_COPYCHUNK just right");
    1606             : 
    1607           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1608             :                                        &cc_rsp,
    1609             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1610           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1611             :                                    "ndr_pull_srv_copychunk_rsp");
    1612             : 
    1613           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1614             :                                   1,    /* chunks written */
    1615             :                                   0,    /* chunk bytes unsuccessfully written */
    1616             :                                   3072); /* total bytes written */
    1617           0 :         if (!ok) {
    1618           0 :                 torture_fail(torture, "bad copy chunk response data");
    1619             :         }
    1620             : 
    1621           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 3072, 1024);
    1622           0 :         if (!ok) {
    1623           0 :                 torture_fail(torture, "inconsistent file data");
    1624             :         }
    1625             : 
    1626           0 :         smb2_util_close(tree, src_h);
    1627           0 :         smb2_util_close(tree, dest_h);
    1628           0 :         talloc_free(tmp_ctx);
    1629           0 :         return true;
    1630             : }
    1631             : 
    1632             : static bool
    1633           1 : test_ioctl_copy_chunk_src_exceed_multi(struct torture_context *torture,
    1634             :                                        struct smb2_tree *tree)
    1635             : {
    1636             :         struct smb2_handle src_h;
    1637             :         struct smb2_handle dest_h;
    1638             :         NTSTATUS status;
    1639             :         union smb_ioctl ioctl;
    1640           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1641             :         struct srv_copychunk_copy cc_copy;
    1642             :         struct srv_copychunk_rsp cc_rsp;
    1643             :         enum ndr_err_code ndr_ret;
    1644             :         bool ok;
    1645             : 
    1646           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1647             :                                    2, /* 2 chunks */
    1648             :                                    FNAME,
    1649             :                                    &src_h, 8192, /* fill 8192 byte src file */
    1650             :                                    SEC_RIGHTS_FILE_ALL,
    1651             :                                    FNAME2,
    1652             :                                    &dest_h, 0,      /* 0 byte dest file */
    1653             :                                    SEC_RIGHTS_FILE_ALL,
    1654             :                                    &cc_copy,
    1655             :                                    &ioctl);
    1656           1 :         if (!ok) {
    1657           1 :                 torture_fail(torture, "setup copy chunk error");
    1658             :         }
    1659             : 
    1660             :         /* Request copy where off + length exceeds size of src */
    1661           0 :         cc_copy.chunks[0].source_off = 0;
    1662           0 :         cc_copy.chunks[0].target_off = 0;
    1663           0 :         cc_copy.chunks[0].length = 4096;
    1664             : 
    1665           0 :         cc_copy.chunks[1].source_off = 4096;
    1666           0 :         cc_copy.chunks[1].target_off = 4096;
    1667           0 :         cc_copy.chunks[1].length = 8192;
    1668             : 
    1669           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1670             :                                        &cc_copy,
    1671             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1672           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1673             :                                    "ndr_push_srv_copychunk_copy");
    1674             : 
    1675           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1676           0 :         torture_assert_ntstatus_equal(torture, status,
    1677             :                                       NT_STATUS_INVALID_VIEW_SIZE,
    1678             :                                       "FSCTL_SRV_COPYCHUNK oversize");
    1679           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1680             :                                        &cc_rsp,
    1681             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1682           0 :         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
    1683             : 
    1684             :         /* first chunk should still be written */
    1685           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1686             :                                   1,    /* chunks written */
    1687             :                                   0,    /* chunk bytes unsuccessfully written */
    1688             :                                   4096); /* total bytes written */
    1689           0 :         if (!ok) {
    1690           0 :                 torture_fail(torture, "bad copy chunk response data");
    1691             :         }
    1692           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
    1693           0 :         if (!ok) {
    1694           0 :                 torture_fail(torture, "inconsistent file data");
    1695             :         }
    1696             : 
    1697           0 :         smb2_util_close(tree, src_h);
    1698           0 :         smb2_util_close(tree, dest_h);
    1699           0 :         talloc_free(tmp_ctx);
    1700           0 :         return true;
    1701             : }
    1702             : 
    1703           1 : static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context *torture,
    1704             :                                               struct smb2_tree *tree)
    1705             : {
    1706             :         struct smb2_handle src_h;
    1707             :         struct smb2_handle dest_h;
    1708             :         NTSTATUS status;
    1709             :         union smb_ioctl ioctl;
    1710             :         struct smb2_read r;
    1711           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1712             :         struct srv_copychunk_copy cc_copy;
    1713             :         struct srv_copychunk_rsp cc_rsp;
    1714             :         enum ndr_err_code ndr_ret;
    1715             :         bool ok;
    1716             :         int i;
    1717             : 
    1718           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1719             :                                    1, /* 1 chunk */
    1720             :                                    FNAME,
    1721             :                                    &src_h, 4096, /* fill 4096 byte src file */
    1722             :                                    SEC_RIGHTS_FILE_ALL,
    1723             :                                    FNAME2,
    1724             :                                    &dest_h, 0,      /* 0 byte dest file */
    1725             :                                    SEC_RIGHTS_FILE_ALL,
    1726             :                                    &cc_copy,
    1727             :                                    &ioctl);
    1728           1 :         if (!ok) {
    1729           1 :                 torture_fail(torture, "setup copy chunk error");
    1730             :         }
    1731             : 
    1732             :         /* copy all src file data (via a single chunk desc) */
    1733           0 :         cc_copy.chunks[0].source_off = 0;
    1734           0 :         cc_copy.chunks[0].target_off = 4096;
    1735           0 :         cc_copy.chunks[0].length = 4096;
    1736             : 
    1737           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1738             :                                        &cc_copy,
    1739             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1740           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1741             :                                    "ndr_push_srv_copychunk_copy");
    1742             : 
    1743           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1744           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
    1745             : 
    1746           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1747             :                                        &cc_rsp,
    1748             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1749           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1750             :                                    "ndr_pull_srv_copychunk_rsp");
    1751             : 
    1752           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1753             :                                   1,    /* chunks written */
    1754             :                                   0,    /* chunk bytes unsuccessfully written */
    1755             :                                   4096); /* total bytes written */
    1756           0 :         if (!ok) {
    1757           0 :                 torture_fail(torture, "bad copy chunk response data");
    1758             :         }
    1759             : 
    1760             :         /* check for zeros in first 4k */
    1761           0 :         ZERO_STRUCT(r);
    1762           0 :         r.in.file.handle = dest_h;
    1763           0 :         r.in.length      = 4096;
    1764           0 :         r.in.offset      = 0;
    1765           0 :         status = smb2_read(tree, tmp_ctx, &r);
    1766           0 :         torture_assert_ntstatus_ok(torture, status, "read");
    1767             : 
    1768           0 :         torture_assert_u64_equal(torture, r.out.data.length, 4096,
    1769             :                                  "read data len mismatch");
    1770             : 
    1771           0 :         for (i = 0; i < 4096; i++) {
    1772           0 :                 torture_assert(torture, (r.out.data.data[i] == 0),
    1773             :                                "sparse did not pass class");
    1774             :         }
    1775             : 
    1776           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
    1777           0 :         if (!ok) {
    1778           0 :                 torture_fail(torture, "inconsistent file data");
    1779             :         }
    1780             : 
    1781           0 :         smb2_util_close(tree, src_h);
    1782           0 :         smb2_util_close(tree, dest_h);
    1783           0 :         talloc_free(tmp_ctx);
    1784           0 :         return true;
    1785             : }
    1786             : 
    1787             : /*
    1788             :  * set the ioctl MaxOutputResponse size to less than
    1789             :  * sizeof(struct srv_copychunk_rsp)
    1790             :  */
    1791           1 : static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture,
    1792             :                                                 struct smb2_tree *tree)
    1793             : {
    1794             :         struct smb2_handle src_h;
    1795             :         struct smb2_handle dest_h;
    1796             :         NTSTATUS status;
    1797             :         union smb_ioctl ioctl;
    1798           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1799             :         struct srv_copychunk_copy cc_copy;
    1800             :         enum ndr_err_code ndr_ret;
    1801             :         bool ok;
    1802             : 
    1803           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1804             :                                    1, /* 1 chunk */
    1805             :                                    FNAME,
    1806             :                                    &src_h, 4096, /* fill 4096 byte src file */
    1807             :                                    SEC_RIGHTS_FILE_ALL,
    1808             :                                    FNAME2,
    1809             :                                    &dest_h, 0,      /* 0 byte dest file */
    1810             :                                    SEC_RIGHTS_FILE_ALL,
    1811             :                                    &cc_copy,
    1812             :                                    &ioctl);
    1813           1 :         if (!ok) {
    1814           1 :                 torture_fail(torture, "setup copy chunk error");
    1815             :         }
    1816             : 
    1817           0 :         cc_copy.chunks[0].source_off = 0;
    1818           0 :         cc_copy.chunks[0].target_off = 0;
    1819           0 :         cc_copy.chunks[0].length = 4096;
    1820             :         /* req is valid, but use undersize max_output_response */
    1821           0 :         ioctl.smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp) - 1;
    1822             : 
    1823           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1824             :                                        &cc_copy,
    1825             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1826           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1827             :                                    "ndr_push_srv_copychunk_copy");
    1828             : 
    1829           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1830           0 :         torture_assert_ntstatus_equal(torture, status,
    1831             :                                       NT_STATUS_INVALID_PARAMETER,
    1832             :                                       "FSCTL_SRV_COPYCHUNK");
    1833             : 
    1834           0 :         smb2_util_close(tree, src_h);
    1835           0 :         smb2_util_close(tree, dest_h);
    1836           0 :         talloc_free(tmp_ctx);
    1837           0 :         return true;
    1838             : }
    1839             : 
    1840           1 : static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
    1841             :                                               struct smb2_tree *tree)
    1842             : {
    1843             :         struct smb2_handle src_h;
    1844             :         struct smb2_handle dest_h;
    1845             :         NTSTATUS status;
    1846             :         union smb_ioctl ioctl;
    1847             :         union smb_fileinfo q;
    1848           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    1849             :         struct srv_copychunk_copy cc_copy;
    1850             :         struct srv_copychunk_rsp cc_rsp;
    1851             :         enum ndr_err_code ndr_ret;
    1852             :         bool ok;
    1853             : 
    1854           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1855             :                                    1, /* 1 chunk */
    1856             :                                    FNAME,
    1857             :                                    &src_h, 4096, /* fill 4096 byte src file */
    1858             :                                    SEC_RIGHTS_FILE_ALL,
    1859             :                                    FNAME2,
    1860             :                                    &dest_h, 0,      /* 0 byte dest file */
    1861             :                                    SEC_RIGHTS_FILE_ALL,
    1862             :                                    &cc_copy,
    1863             :                                    &ioctl);
    1864           1 :         if (!ok) {
    1865           1 :                 torture_fail(torture, "setup copy chunk error");
    1866             :         }
    1867             : 
    1868             :         /* zero length server-side copy (via a single chunk desc) */
    1869           0 :         cc_copy.chunks[0].source_off = 0;
    1870           0 :         cc_copy.chunks[0].target_off = 0;
    1871           0 :         cc_copy.chunks[0].length = 0;
    1872             : 
    1873           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    1874             :                                        &cc_copy,
    1875             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1876           0 :         torture_assert_ndr_success(torture, ndr_ret,
    1877             :                                    "ndr_push_srv_copychunk_copy");
    1878             : 
    1879           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    1880           0 :         torture_assert_ntstatus_equal(torture, status,
    1881             :                                       NT_STATUS_INVALID_PARAMETER,
    1882             :                                       "bad zero-length chunk response");
    1883             : 
    1884           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    1885             :                                        &cc_rsp,
    1886             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1887           0 :         torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
    1888             : 
    1889           0 :         ZERO_STRUCT(q);
    1890           0 :         q.all_info2.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    1891           0 :         q.all_info2.in.file.handle = dest_h;
    1892           0 :         status = smb2_getinfo_file(tree, torture, &q);
    1893           0 :         torture_assert_ntstatus_ok(torture, status, "getinfo");
    1894             : 
    1895           0 :         torture_assert_int_equal(torture, q.all_info2.out.size, 0,
    1896             :                                  "size after zero len clone");
    1897             : 
    1898           0 :         smb2_util_close(tree, src_h);
    1899           0 :         smb2_util_close(tree, dest_h);
    1900           0 :         talloc_free(tmp_ctx);
    1901           0 :         return true;
    1902             : }
    1903             : 
    1904           1 : static bool copy_one_stream(struct torture_context *torture,
    1905             :                             struct smb2_tree *tree,
    1906             :                             TALLOC_CTX *tmp_ctx,
    1907             :                             const char *src_sname,
    1908             :                             const char *dst_sname)
    1909             : {
    1910           1 :         struct smb2_handle src_h = {{0}};
    1911           1 :         struct smb2_handle dest_h = {{0}};
    1912             :         NTSTATUS status;
    1913             :         union smb_ioctl io;
    1914             :         struct srv_copychunk_copy cc_copy;
    1915             :         struct srv_copychunk_rsp cc_rsp;
    1916             :         enum ndr_err_code ndr_ret;
    1917           1 :         bool ok = false;
    1918             : 
    1919           1 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    1920             :                                    1, /* 1 chunk */
    1921             :                                    src_sname,
    1922             :                                    &src_h, 256, /* fill 256 byte src file */
    1923             :                                    SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
    1924             :                                    dst_sname,
    1925             :                                    &dest_h, 0,      /* 0 byte dest file */
    1926             :                                    SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
    1927             :                                    &cc_copy,
    1928             :                                    &io);
    1929           1 :         torture_assert_goto(torture, ok == true, ok, done,
    1930             :                             "setup copy chunk error\n");
    1931             : 
    1932             :         /* copy all src file data (via a single chunk desc) */
    1933           0 :         cc_copy.chunks[0].source_off = 0;
    1934           0 :         cc_copy.chunks[0].target_off = 0;
    1935           0 :         cc_copy.chunks[0].length = 256;
    1936             : 
    1937           0 :         ndr_ret = ndr_push_struct_blob(
    1938             :                 &io.smb2.in.out, tmp_ctx, &cc_copy,
    1939             :                 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    1940             : 
    1941           0 :         torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
    1942             :                                    "ndr_push_srv_copychunk_copy\n");
    1943             : 
    1944           0 :         status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
    1945           0 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done,
    1946             :                                         "FSCTL_SRV_COPYCHUNK\n");
    1947             : 
    1948           0 :         ndr_ret = ndr_pull_struct_blob(
    1949             :                 &io.smb2.out.out, tmp_ctx, &cc_rsp,
    1950             :                 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    1951             : 
    1952           0 :         torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
    1953             :                                    "ndr_pull_srv_copychunk_rsp\n");
    1954             : 
    1955           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    1956             :                                   1,    /* chunks written */
    1957             :                                   0,    /* chunk bytes unsuccessfully written */
    1958             :                                   256); /* total bytes written */
    1959           0 :         torture_assert_goto(torture, ok == true, ok, done,
    1960             :                             "bad copy chunk response data\n");
    1961             : 
    1962           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0);
    1963           0 :         if (!ok) {
    1964           0 :                 torture_fail(torture, "inconsistent file data\n");
    1965             :         }
    1966             : 
    1967           0 : done:
    1968           1 :         if (!smb2_util_handle_empty(src_h)) {
    1969           1 :                 smb2_util_close(tree, src_h);
    1970             :         }
    1971           1 :         if (!smb2_util_handle_empty(dest_h)) {
    1972           1 :                 smb2_util_close(tree, dest_h);
    1973             :         }
    1974             : 
    1975           1 :         return ok;
    1976             : }
    1977             : 
    1978             : /**
    1979             :  * Create a file
    1980             :  **/
    1981           2 : static bool torture_setup_file(TALLOC_CTX *mem_ctx,
    1982             :                                struct smb2_tree *tree,
    1983             :                                const char *name)
    1984             : {
    1985             :         struct smb2_create io;
    1986             :         NTSTATUS status;
    1987             : 
    1988           2 :         smb2_util_unlink(tree, name);
    1989           2 :         ZERO_STRUCT(io);
    1990           2 :         io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
    1991           2 :         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
    1992           2 :         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
    1993           2 :         io.in.share_access =
    1994             :                 NTCREATEX_SHARE_ACCESS_DELETE|
    1995             :                 NTCREATEX_SHARE_ACCESS_READ|
    1996             :                 NTCREATEX_SHARE_ACCESS_WRITE;
    1997           2 :         io.in.create_options = 0;
    1998           2 :         io.in.fname = name;
    1999             : 
    2000           2 :         status = smb2_create(tree, mem_ctx, &io);
    2001           2 :         if (!NT_STATUS_IS_OK(status)) {
    2002           0 :                 return false;
    2003             :         }
    2004             : 
    2005           2 :         status = smb2_util_close(tree, io.out.file.handle);
    2006           2 :         if (!NT_STATUS_IS_OK(status)) {
    2007           0 :                 return false;
    2008             :         }
    2009             : 
    2010           2 :         return true;
    2011             : }
    2012             : 
    2013           1 : static bool test_copy_chunk_streams(struct torture_context *torture,
    2014             :                                     struct smb2_tree *tree)
    2015             : {
    2016           1 :         const char *src_name = "src";
    2017           1 :         const char *dst_name = "dst";
    2018             :         struct names {
    2019             :                 const char *src_sname;
    2020             :                 const char *dst_sname;
    2021           1 :         } names[] = {
    2022             :                 { "src:foo", "dst:foo" }
    2023             :         };
    2024             :         int i;
    2025           1 :         TALLOC_CTX *tmp_ctx = NULL;
    2026           1 :         bool ok = false;
    2027             : 
    2028           1 :         tmp_ctx = talloc_new(tree);
    2029           1 :         torture_assert_not_null_goto(torture, tmp_ctx, ok, done,
    2030             :                                      "torture_setup_file\n");
    2031             : 
    2032           1 :         ok = torture_setup_file(torture, tree, src_name);
    2033           1 :         torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
    2034           1 :         ok = torture_setup_file(torture, tree, dst_name);
    2035           1 :         torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
    2036             : 
    2037           1 :         for (i = 0; i < ARRAY_SIZE(names); i++) {
    2038           1 :                 ok = copy_one_stream(torture, tree, tmp_ctx,
    2039             :                                      names[i].src_sname,
    2040             :                                      names[i].dst_sname);
    2041           1 :                 torture_assert_goto(torture, ok == true, ok, done,
    2042             :                                     "copy_one_stream failed\n");
    2043             :         }
    2044             : 
    2045           0 : done:
    2046           1 :         smb2_util_unlink(tree, src_name);
    2047           1 :         smb2_util_unlink(tree, dst_name);
    2048           1 :         talloc_free(tmp_ctx);
    2049           1 :         return ok;
    2050             : }
    2051             : 
    2052           1 : static bool test_copy_chunk_across_shares(struct torture_context *tctx,
    2053             :                                           struct smb2_tree *tree)
    2054             : {
    2055           1 :         TALLOC_CTX *mem_ctx = NULL;
    2056           1 :         struct smb2_tree *tree2 = NULL;
    2057           1 :         struct smb2_handle src_h = {{0}};
    2058           1 :         struct smb2_handle dest_h = {{0}};
    2059             :         union smb_ioctl ioctl;
    2060             :         struct srv_copychunk_copy cc_copy;
    2061             :         struct srv_copychunk_rsp cc_rsp;
    2062             :         enum ndr_err_code ndr_ret;
    2063             :         NTSTATUS status;
    2064           1 :         bool ok = false;
    2065             : 
    2066           1 :         mem_ctx = talloc_new(tctx);
    2067           1 :         torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
    2068             :                                      "talloc_new\n");
    2069             : 
    2070           1 :         ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
    2071           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2072             :                             "torture_smb2_tree_connect failed\n");
    2073             : 
    2074           1 :         ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
    2075             :                                    1, /* 1 chunk */
    2076             :                                    FNAME,
    2077             :                                    &src_h, 4096, /* fill 4096 byte src file */
    2078             :                                    SEC_RIGHTS_FILE_ALL,
    2079             :                                    FNAME2,
    2080             :                                    &dest_h, 0,      /* 0 byte dest file */
    2081             :                                    SEC_RIGHTS_FILE_ALL,
    2082             :                                    &cc_copy,
    2083             :                                    &ioctl);
    2084           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2085             :                             "test_setup_copy_chunk failed\n");
    2086             : 
    2087           0 :         cc_copy.chunks[0].source_off = 0;
    2088           0 :         cc_copy.chunks[0].target_off = 0;
    2089           0 :         cc_copy.chunks[0].length = 4096;
    2090             : 
    2091           0 :         ndr_ret = ndr_push_struct_blob(
    2092             :                 &ioctl.smb2.in.out, mem_ctx, &cc_copy,
    2093             :                 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    2094           0 :         torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
    2095             :                                         "ndr_push_srv_copychunk_copy\n");
    2096             : 
    2097           0 :         status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
    2098           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
    2099             :                                         "FSCTL_SRV_COPYCHUNK\n");
    2100             : 
    2101           0 :         ndr_ret = ndr_pull_struct_blob(
    2102             :                 &ioctl.smb2.out.out, mem_ctx, &cc_rsp,
    2103             :                 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    2104             : 
    2105           0 :         torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
    2106             :                                    "ndr_pull_srv_copychunk_rsp\n");
    2107             : 
    2108           0 :         ok = check_copy_chunk_rsp(tctx, &cc_rsp,
    2109             :                                   1,    /* chunks written */
    2110             :                                   0,    /* chunk bytes unsuccessfully written */
    2111             :                                   4096); /* total bytes written */
    2112           0 :         torture_assert_goto(tctx, ok == true, ok, done,
    2113             :                             "bad copy chunk response data\n");
    2114             : 
    2115           0 :         ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 0, 4096, 0);
    2116           0 :         torture_assert_goto(tctx, ok == true, ok, done,
    2117             :                             "inconsistent file data\n");
    2118             : 
    2119           1 : done:
    2120           1 :         TALLOC_FREE(mem_ctx);
    2121           1 :         if (!smb2_util_handle_empty(src_h)) {
    2122           1 :                 smb2_util_close(tree, src_h);
    2123             :         }
    2124           1 :         if (!smb2_util_handle_empty(dest_h)) {
    2125           1 :                 smb2_util_close(tree2, dest_h);
    2126             :         }
    2127           1 :         smb2_util_unlink(tree, FNAME);
    2128           1 :         smb2_util_unlink(tree2, FNAME2);
    2129           1 :         if (tree2 != NULL) {
    2130           1 :                 smb2_tdis(tree2);
    2131             :         }
    2132           1 :         return ok;
    2133             : }
    2134             : 
    2135             : /* Test closing the src handle */
    2136           1 : static bool test_copy_chunk_across_shares2(struct torture_context *tctx,
    2137             :                                            struct smb2_tree *tree)
    2138             : {
    2139           1 :         TALLOC_CTX *mem_ctx = NULL;
    2140           1 :         struct smb2_tree *tree2 = NULL;
    2141           1 :         struct smb2_handle src_h = {{0}};
    2142           1 :         struct smb2_handle dest_h = {{0}};
    2143             :         union smb_ioctl ioctl;
    2144             :         struct srv_copychunk_copy cc_copy;
    2145             :         enum ndr_err_code ndr_ret;
    2146             :         NTSTATUS status;
    2147           1 :         bool ok = false;
    2148             : 
    2149           1 :         mem_ctx = talloc_new(tctx);
    2150           1 :         torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
    2151             :                                      "talloc_new\n");
    2152             : 
    2153           1 :         ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
    2154           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2155             :                             "torture_smb2_tree_connect failed\n");
    2156             : 
    2157           1 :         ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
    2158             :                                    1, /* 1 chunk */
    2159             :                                    FNAME,
    2160             :                                    &src_h, 4096, /* fill 4096 byte src file */
    2161             :                                    SEC_RIGHTS_FILE_ALL,
    2162             :                                    FNAME2,
    2163             :                                    &dest_h, 0,      /* 0 byte dest file */
    2164             :                                    SEC_RIGHTS_FILE_ALL,
    2165             :                                    &cc_copy,
    2166             :                                    &ioctl);
    2167           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2168             :                             "test_setup_copy_chunk failed\n");
    2169             : 
    2170           0 :         status = smb2_util_close(tree, src_h);
    2171           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
    2172             :                             "smb2_util_close failed\n");
    2173           0 :         ZERO_STRUCT(src_h);
    2174             : 
    2175           0 :         cc_copy.chunks[0].source_off = 0;
    2176           0 :         cc_copy.chunks[0].target_off = 0;
    2177           0 :         cc_copy.chunks[0].length = 4096;
    2178             : 
    2179           0 :         ndr_ret = ndr_push_struct_blob(
    2180             :                 &ioctl.smb2.in.out, mem_ctx, &cc_copy,
    2181             :                 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    2182           0 :         torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
    2183             :                                         "ndr_push_srv_copychunk_copy\n");
    2184             : 
    2185           0 :         status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
    2186           0 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    2187             :                                            ok, done, "smb2_ioctl failed\n");
    2188             : 
    2189           1 : done:
    2190           1 :         TALLOC_FREE(mem_ctx);
    2191           1 :         if (!smb2_util_handle_empty(src_h)) {
    2192           1 :                 smb2_util_close(tree, src_h);
    2193             :         }
    2194           1 :         if (!smb2_util_handle_empty(dest_h)) {
    2195           1 :                 smb2_util_close(tree2, dest_h);
    2196             :         }
    2197           1 :         smb2_util_unlink(tree, FNAME);
    2198           1 :         smb2_util_unlink(tree2, FNAME2);
    2199           1 :         if (tree2 != NULL) {
    2200           1 :                 smb2_tdis(tree2);
    2201             :         }
    2202           1 :         return ok;
    2203             : }
    2204             : 
    2205             : /* Test offset works */
    2206           1 : static bool test_copy_chunk_across_shares3(struct torture_context *tctx,
    2207             :                                            struct smb2_tree *tree)
    2208             : {
    2209           1 :         TALLOC_CTX *mem_ctx = NULL;
    2210           1 :         struct smb2_tree *tree2 = NULL;
    2211           1 :         struct smb2_handle src_h = {{0}};
    2212           1 :         struct smb2_handle dest_h = {{0}};
    2213             :         union smb_ioctl ioctl;
    2214             :         struct srv_copychunk_copy cc_copy;
    2215             :         struct srv_copychunk_rsp cc_rsp;
    2216             :         enum ndr_err_code ndr_ret;
    2217             :         NTSTATUS status;
    2218           1 :         bool ok = false;
    2219             : 
    2220           1 :         mem_ctx = talloc_new(tctx);
    2221           1 :         torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
    2222             :                                      "talloc_new\n");
    2223             : 
    2224           1 :         ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
    2225           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2226             :                             "torture_smb2_tree_connect failed\n");
    2227             : 
    2228           1 :         ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
    2229             :                                    2, /* 2 chunks */
    2230             :                                    FNAME,
    2231             :                                    &src_h, 4096, /* fill 4096 byte src file */
    2232             :                                    SEC_RIGHTS_FILE_ALL,
    2233             :                                    FNAME2,
    2234             :                                    &dest_h, 0,      /* 0 byte dest file */
    2235             :                                    SEC_RIGHTS_FILE_ALL,
    2236             :                                    &cc_copy,
    2237             :                                    &ioctl);
    2238           1 :         torture_assert_goto(tctx, ok == true, ok, done,
    2239             :                             "test_setup_copy_chunk failed\n");
    2240             : 
    2241           0 :         cc_copy.chunks[0].source_off = 0;
    2242           0 :         cc_copy.chunks[0].target_off = 0;
    2243           0 :         cc_copy.chunks[0].length = 4096;
    2244             : 
    2245             :         /* second chunk appends the same data to the first */
    2246           0 :         cc_copy.chunks[1].source_off = 0;
    2247           0 :         cc_copy.chunks[1].target_off = 4096;
    2248           0 :         cc_copy.chunks[1].length = 4096;
    2249             : 
    2250           0 :         ndr_ret = ndr_push_struct_blob(
    2251             :                 &ioctl.smb2.in.out, mem_ctx, &cc_copy,
    2252             :                 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    2253           0 :         torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
    2254             :                                         "ndr_push_srv_copychunk_copy\n");
    2255             : 
    2256           0 :         status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
    2257           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "smb2_ioctl failed\n");
    2258             : 
    2259           0 :         ndr_ret = ndr_pull_struct_blob(
    2260             :                 &ioctl.smb2.out.out, mem_ctx, &cc_rsp,
    2261             :                 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    2262             : 
    2263           0 :         torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
    2264             :                                    "ndr_pull_srv_copychunk_rsp\n");
    2265             : 
    2266           0 :         ok = check_copy_chunk_rsp(tctx, &cc_rsp,
    2267             :                                   2,    /* chunks written */
    2268             :                                   0,    /* chunk bytes unsuccessfully written */
    2269             :                                   8192); /* total bytes written */
    2270           0 :         torture_assert_goto(tctx, ok == true, ok, done,
    2271             :                             "check_copy_chunk_rsp failed\n");
    2272             : 
    2273           0 :         ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 0, 4096, 0);
    2274           0 :         torture_assert_goto(tctx, ok == true, ok, done,
    2275             :                             "check_pattern failed\n");
    2276             : 
    2277           0 :         ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 4096, 4096, 0);
    2278           0 :         torture_assert_goto(tctx, ok == true, ok, done,
    2279             :                             "check_pattern failed\n");
    2280             : 
    2281           1 : done:
    2282           1 :         TALLOC_FREE(mem_ctx);
    2283           1 :         if (!smb2_util_handle_empty(src_h)) {
    2284           1 :                 smb2_util_close(tree, src_h);
    2285             :         }
    2286           1 :         if (!smb2_util_handle_empty(dest_h)) {
    2287           1 :                 smb2_util_close(tree2, dest_h);
    2288             :         }
    2289           1 :         smb2_util_unlink(tree, FNAME);
    2290           1 :         smb2_util_unlink(tree2, FNAME2);
    2291           1 :         if (tree2 != NULL) {
    2292           1 :                 smb2_tdis(tree2);
    2293             :         }
    2294           1 :         return ok;
    2295             : }
    2296             : 
    2297          11 : static NTSTATUS test_ioctl_compress_fs_supported(struct torture_context *torture,
    2298             :                                                  struct smb2_tree *tree,
    2299             :                                                  TALLOC_CTX *mem_ctx,
    2300             :                                                  struct smb2_handle *fh,
    2301             :                                                  bool *compress_support)
    2302             : {
    2303             :         NTSTATUS status;
    2304             :         union smb_fsinfo info;
    2305             : 
    2306          11 :         ZERO_STRUCT(info);
    2307          11 :         info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
    2308          11 :         info.generic.handle = *fh;
    2309          11 :         status = smb2_getinfo_fs(tree, tree, &info);
    2310          11 :         if (!NT_STATUS_IS_OK(status)) {
    2311           0 :                 return status;
    2312             :         }
    2313             : 
    2314          11 :         if (info.attribute_info.out.fs_attr & FILE_FILE_COMPRESSION) {
    2315           0 :                 *compress_support = true;
    2316             :         } else {
    2317          11 :                 *compress_support = false;
    2318             :         }
    2319          11 :         return NT_STATUS_OK;
    2320             : }
    2321             : 
    2322           1 : static NTSTATUS test_ioctl_compress_get(struct torture_context *torture,
    2323             :                                         TALLOC_CTX *mem_ctx,
    2324             :                                         struct smb2_tree *tree,
    2325             :                                         struct smb2_handle fh,
    2326             :                                         uint16_t *_compression_fmt)
    2327             : {
    2328             :         union smb_ioctl ioctl;
    2329             :         struct compression_state cmpr_state;
    2330             :         enum ndr_err_code ndr_ret;
    2331             :         NTSTATUS status;
    2332             : 
    2333           1 :         ZERO_STRUCT(ioctl);
    2334           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    2335           1 :         ioctl.smb2.in.file.handle = fh;
    2336           1 :         ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
    2337           1 :         ioctl.smb2.in.max_output_response = sizeof(struct compression_state);
    2338           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    2339             : 
    2340           1 :         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
    2341           1 :         if (!NT_STATUS_IS_OK(status)) {
    2342           1 :                 return status;
    2343             :         }
    2344             : 
    2345           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, mem_ctx,
    2346             :                                        &cmpr_state,
    2347             :                         (ndr_pull_flags_fn_t)ndr_pull_compression_state);
    2348             : 
    2349           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    2350           0 :                 return NT_STATUS_INTERNAL_ERROR;
    2351             :         }
    2352             : 
    2353           0 :         *_compression_fmt = cmpr_state.format;
    2354           0 :         return NT_STATUS_OK;
    2355             : }
    2356             : 
    2357           1 : static NTSTATUS test_ioctl_compress_set(struct torture_context *torture,
    2358             :                                         TALLOC_CTX *mem_ctx,
    2359             :                                         struct smb2_tree *tree,
    2360             :                                         struct smb2_handle fh,
    2361             :                                         uint16_t compression_fmt)
    2362             : {
    2363             :         union smb_ioctl ioctl;
    2364             :         struct compression_state cmpr_state;
    2365             :         enum ndr_err_code ndr_ret;
    2366             :         NTSTATUS status;
    2367             : 
    2368           1 :         ZERO_STRUCT(ioctl);
    2369           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    2370           1 :         ioctl.smb2.in.file.handle = fh;
    2371           1 :         ioctl.smb2.in.function = FSCTL_SET_COMPRESSION;
    2372           1 :         ioctl.smb2.in.max_output_response = 0;
    2373           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    2374             : 
    2375           1 :         cmpr_state.format = compression_fmt;
    2376           1 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, mem_ctx,
    2377             :                                        &cmpr_state,
    2378             :                         (ndr_push_flags_fn_t)ndr_push_compression_state);
    2379           1 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    2380           0 :                 return NT_STATUS_INTERNAL_ERROR;
    2381             :         }
    2382             : 
    2383           1 :         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
    2384           1 :         return status;
    2385             : }
    2386             : 
    2387           1 : static bool test_ioctl_compress_file_flag(struct torture_context *torture,
    2388             :                                             struct smb2_tree *tree)
    2389             : {
    2390             :         struct smb2_handle fh;
    2391             :         NTSTATUS status;
    2392           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2393             :         bool ok;
    2394             :         uint16_t compression_fmt;
    2395             : 
    2396           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2397             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2398             :                                     FILE_ATTRIBUTE_NORMAL);
    2399           1 :         torture_assert(torture, ok, "setup compression file");
    2400             : 
    2401           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2402             :                                                   &ok);
    2403           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2404           1 :         if (!ok) {
    2405           1 :                 smb2_util_close(tree, fh);
    2406           1 :                 torture_skip(torture, "FS compression not supported\n");
    2407             :         }
    2408             : 
    2409           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2410             :                                          &compression_fmt);
    2411           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2412             : 
    2413           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2414             :                        "initial compression state not NONE");
    2415             : 
    2416           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    2417             :                                          COMPRESSION_FORMAT_DEFAULT);
    2418           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2419             : 
    2420           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2421             :                                          &compression_fmt);
    2422           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2423             : 
    2424           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2425             :                        "invalid compression state after set");
    2426             : 
    2427           0 :         smb2_util_close(tree, fh);
    2428           0 :         talloc_free(tmp_ctx);
    2429           0 :         return true;
    2430             : }
    2431             : 
    2432           1 : static bool test_ioctl_compress_dir_inherit(struct torture_context *torture,
    2433             :                                             struct smb2_tree *tree)
    2434             : {
    2435             :         struct smb2_handle dirh;
    2436             :         struct smb2_handle fh;
    2437             :         NTSTATUS status;
    2438           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2439             :         uint16_t compression_fmt;
    2440             :         bool ok;
    2441             :         char path_buf[PATH_MAX];
    2442             : 
    2443           1 :         smb2_deltree(tree, DNAME);
    2444           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2445             :                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
    2446             :                                     FILE_ATTRIBUTE_DIRECTORY);
    2447           1 :         torture_assert(torture, ok, "setup compression directory");
    2448             : 
    2449           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
    2450             :                                                   &ok);
    2451           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2452           1 :         if (!ok) {
    2453           1 :                 smb2_util_close(tree, dirh);
    2454           1 :                 smb2_deltree(tree, DNAME);
    2455           1 :                 torture_skip(torture, "FS compression not supported\n");
    2456             :         }
    2457             : 
    2458             :         /* set compression on parent dir, then check for inheritance */
    2459           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
    2460             :                                          COMPRESSION_FORMAT_LZNT1);
    2461           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2462             : 
    2463           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
    2464             :                                          &compression_fmt);
    2465           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2466             : 
    2467           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2468             :                        "invalid compression state after set");
    2469             : 
    2470           0 :         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
    2471           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2472             :                                     path_buf, &fh, 4096, SEC_RIGHTS_FILE_ALL,
    2473             :                                     FILE_ATTRIBUTE_NORMAL);
    2474           0 :         torture_assert(torture, ok, "setup compression file");
    2475             : 
    2476           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2477             :                                          &compression_fmt);
    2478           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2479             : 
    2480           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2481             :                        "compression attr not inherited by new file");
    2482             : 
    2483             :         /* check compressed data is consistent */
    2484           0 :         ok = check_pattern(torture, tree, tmp_ctx, fh, 0, 4096, 0);
    2485             : 
    2486             :         /* disable dir compression attr, file should remain compressed */
    2487           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
    2488             :                                          COMPRESSION_FORMAT_NONE);
    2489           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2490             : 
    2491           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2492             :                                          &compression_fmt);
    2493           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2494             : 
    2495           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2496             :                        "file compression attr removed after dir change");
    2497           0 :         smb2_util_close(tree, fh);
    2498             : 
    2499             :         /* new files should no longer inherit compression attr */
    2500           0 :         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
    2501           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2502             :                                     path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2503             :                                     FILE_ATTRIBUTE_NORMAL);
    2504           0 :         torture_assert(torture, ok, "setup file");
    2505             : 
    2506           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2507             :                                          &compression_fmt);
    2508           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2509             : 
    2510           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2511             :                        "compression attr present on new file");
    2512             : 
    2513           0 :         smb2_util_close(tree, fh);
    2514           0 :         smb2_util_close(tree, dirh);
    2515           0 :         smb2_deltree(tree, DNAME);
    2516           0 :         talloc_free(tmp_ctx);
    2517           0 :         return true;
    2518             : }
    2519             : 
    2520           1 : static bool test_ioctl_compress_invalid_format(struct torture_context *torture,
    2521             :                                                struct smb2_tree *tree)
    2522             : {
    2523             :         struct smb2_handle fh;
    2524             :         NTSTATUS status;
    2525           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2526             :         bool ok;
    2527             :         uint16_t compression_fmt;
    2528             : 
    2529           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2530             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2531             :                                     FILE_ATTRIBUTE_NORMAL);
    2532           1 :         torture_assert(torture, ok, "setup compression file");
    2533             : 
    2534           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2535             :                                                   &ok);
    2536           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2537           1 :         if (!ok) {
    2538           1 :                 smb2_util_close(tree, fh);
    2539           1 :                 torture_skip(torture, "FS compression not supported\n");
    2540             :         }
    2541             : 
    2542           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    2543             :                                          0x0042); /* bogus */
    2544           0 :         torture_assert_ntstatus_equal(torture, status,
    2545             :                                       NT_STATUS_INVALID_PARAMETER,
    2546             :                                       "invalid FSCTL_SET_COMPRESSION");
    2547             : 
    2548           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2549             :                                          &compression_fmt);
    2550           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2551             : 
    2552           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2553             :                        "initial compression state not NONE");
    2554             : 
    2555           0 :         smb2_util_close(tree, fh);
    2556           0 :         talloc_free(tmp_ctx);
    2557           0 :         return true;
    2558             : }
    2559             : 
    2560           1 : static bool test_ioctl_compress_invalid_buf(struct torture_context *torture,
    2561             :                                             struct smb2_tree *tree)
    2562             : {
    2563             :         struct smb2_handle fh;
    2564             :         NTSTATUS status;
    2565           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2566             :         bool ok;
    2567             :         union smb_ioctl ioctl;
    2568             : 
    2569           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2570             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2571             :                                     FILE_ATTRIBUTE_NORMAL);
    2572           1 :         torture_assert(torture, ok, "setup compression file");
    2573             : 
    2574           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2575             :                                                   &ok);
    2576           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2577           1 :         if (!ok) {
    2578           1 :                 smb2_util_close(tree, fh);
    2579           1 :                 torture_skip(torture, "FS compression not supported\n");
    2580             :         }
    2581             : 
    2582           0 :         ZERO_STRUCT(ioctl);
    2583           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    2584           0 :         ioctl.smb2.in.file.handle = fh;
    2585           0 :         ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
    2586           0 :         ioctl.smb2.in.max_output_response = 0;  /* no room for rsp data */
    2587           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    2588             : 
    2589           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    2590           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_USER_BUFFER)
    2591           0 :          && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
    2592             :                 /* neither Server 2k12 nor 2k8r2 response status */
    2593             :                 torture_assert(torture, true,
    2594             :                                "invalid FSCTL_SET_COMPRESSION");
    2595             :         }
    2596             : 
    2597           0 :         smb2_util_close(tree, fh);
    2598           0 :         talloc_free(tmp_ctx);
    2599           0 :         return true;
    2600             : }
    2601             : 
    2602           1 : static bool test_ioctl_compress_query_file_attr(struct torture_context *torture,
    2603             :                                                 struct smb2_tree *tree)
    2604             : {
    2605             :         struct smb2_handle fh;
    2606             :         union smb_fileinfo io;
    2607             :         NTSTATUS status;
    2608           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2609             :         bool ok;
    2610             : 
    2611           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2612             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2613             :                                     FILE_ATTRIBUTE_NORMAL);
    2614           1 :         torture_assert(torture, ok, "setup compression file");
    2615             : 
    2616           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2617             :                                                   &ok);
    2618           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2619           1 :         if (!ok) {
    2620           1 :                 smb2_util_close(tree, fh);
    2621           1 :                 torture_skip(torture, "FS compression not supported\n");
    2622             :         }
    2623             : 
    2624           0 :         ZERO_STRUCT(io);
    2625           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    2626           0 :         io.generic.in.file.handle = fh;
    2627           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2628           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2629             : 
    2630           0 :         torture_assert(torture,
    2631             :                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
    2632             :                        "compression attr before set");
    2633             : 
    2634           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    2635             :                                          COMPRESSION_FORMAT_DEFAULT);
    2636           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2637             : 
    2638           0 :         ZERO_STRUCT(io);
    2639           0 :         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
    2640           0 :         io.generic.in.file.handle = fh;
    2641           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2642           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2643             : 
    2644           0 :         torture_assert(torture,
    2645             :                        (io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
    2646             :                        "no compression attr after set");
    2647             : 
    2648           0 :         smb2_util_close(tree, fh);
    2649           0 :         talloc_free(tmp_ctx);
    2650           0 :         return true;
    2651             : }
    2652             : 
    2653             : /*
    2654             :  * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
    2655             :  * attribute.
    2656             :  */
    2657           1 : static bool test_ioctl_compress_create_with_attr(struct torture_context *torture,
    2658             :                                                  struct smb2_tree *tree)
    2659             : {
    2660             :         struct smb2_handle fh2;
    2661             :         union smb_fileinfo io;
    2662             :         NTSTATUS status;
    2663           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2664             :         uint16_t compression_fmt;
    2665             :         bool ok;
    2666             : 
    2667           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2668             :                                     FNAME2, &fh2, 0, SEC_RIGHTS_FILE_ALL,
    2669             :                         (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_COMPRESSED));
    2670           1 :         torture_assert(torture, ok, "setup compression file");
    2671             : 
    2672           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh2,
    2673             :                                                   &ok);
    2674           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2675           1 :         if (!ok) {
    2676           1 :                 smb2_util_close(tree, fh2);
    2677           1 :                 torture_skip(torture, "FS compression not supported\n");
    2678             :         }
    2679             : 
    2680           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh2,
    2681             :                                          &compression_fmt);
    2682           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2683             : 
    2684           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2685             :                        "initial compression state not NONE");
    2686             : 
    2687           0 :         ZERO_STRUCT(io);
    2688           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    2689           0 :         io.generic.in.file.handle = fh2;
    2690           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2691           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2692             : 
    2693           0 :         torture_assert(torture,
    2694             :                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
    2695             :                        "incorrect compression attr");
    2696             : 
    2697           0 :         smb2_util_close(tree, fh2);
    2698           0 :         talloc_free(tmp_ctx);
    2699           0 :         return true;
    2700             : }
    2701             : 
    2702           1 : static bool test_ioctl_compress_inherit_disable(struct torture_context *torture,
    2703             :                                                 struct smb2_tree *tree)
    2704             : {
    2705             :         struct smb2_handle fh;
    2706             :         struct smb2_handle dirh;
    2707             :         char path_buf[PATH_MAX];
    2708             :         NTSTATUS status;
    2709           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2710             :         bool ok;
    2711             :         uint16_t compression_fmt;
    2712             : 
    2713             :         struct smb2_create io;
    2714             : 
    2715           1 :         smb2_deltree(tree, DNAME);
    2716           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2717             :                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
    2718             :                                     FILE_ATTRIBUTE_DIRECTORY);
    2719           1 :         torture_assert(torture, ok, "setup compression directory");
    2720             : 
    2721           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
    2722             :                                                   &ok);
    2723           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2724           1 :         if (!ok) {
    2725           1 :                 smb2_util_close(tree, dirh);
    2726           1 :                 smb2_deltree(tree, DNAME);
    2727           1 :                 torture_skip(torture, "FS compression not supported\n");
    2728             :         }
    2729             : 
    2730             :         /* set compression on parent dir, then check for inheritance */
    2731           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
    2732             :                                          COMPRESSION_FORMAT_LZNT1);
    2733           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2734             : 
    2735           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
    2736             :                                          &compression_fmt);
    2737           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2738             : 
    2739           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2740             :                        "invalid compression state after set");
    2741           0 :         smb2_util_close(tree, dirh);
    2742             : 
    2743           0 :         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
    2744           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2745             :                                     path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2746             :                                     FILE_ATTRIBUTE_NORMAL);
    2747           0 :         torture_assert(torture, ok, "setup compression file");
    2748             : 
    2749           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2750             :                                          &compression_fmt);
    2751           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2752             : 
    2753           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
    2754             :                        "compression attr not inherited by new file");
    2755           0 :         smb2_util_close(tree, fh);
    2756             : 
    2757           0 :         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
    2758             : 
    2759             :         /* NO_COMPRESSION option should block inheritance */
    2760           0 :         ZERO_STRUCT(io);
    2761           0 :         io.in.desired_access = SEC_RIGHTS_FILE_ALL;
    2762           0 :         io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2763           0 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
    2764           0 :         io.in.create_options = NTCREATEX_OPTIONS_NO_COMPRESSION;
    2765           0 :         io.in.share_access =
    2766             :                 NTCREATEX_SHARE_ACCESS_DELETE|
    2767             :                 NTCREATEX_SHARE_ACCESS_READ|
    2768             :                 NTCREATEX_SHARE_ACCESS_WRITE;
    2769           0 :         io.in.fname = path_buf;
    2770             : 
    2771           0 :         status = smb2_create(tree, tmp_ctx, &io);
    2772           0 :         torture_assert_ntstatus_ok(torture, status, "file create");
    2773             : 
    2774           0 :         fh = io.out.file.handle;
    2775             : 
    2776           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2777             :                                          &compression_fmt);
    2778           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2779             : 
    2780           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2781             :                        "compression attr inherited by NO_COMPRESSION file");
    2782           0 :         smb2_util_close(tree, fh);
    2783             : 
    2784             : 
    2785           0 :         snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, DNAME);
    2786           0 :         ZERO_STRUCT(io);
    2787           0 :         io.in.desired_access = SEC_RIGHTS_FILE_ALL;
    2788           0 :         io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
    2789           0 :         io.in.create_disposition = NTCREATEX_DISP_CREATE;
    2790           0 :         io.in.create_options = (NTCREATEX_OPTIONS_NO_COMPRESSION
    2791             :                                 | NTCREATEX_OPTIONS_DIRECTORY);
    2792           0 :         io.in.share_access =
    2793             :                 NTCREATEX_SHARE_ACCESS_DELETE|
    2794             :                 NTCREATEX_SHARE_ACCESS_READ|
    2795             :                 NTCREATEX_SHARE_ACCESS_WRITE;
    2796           0 :         io.in.fname = path_buf;
    2797             : 
    2798           0 :         status = smb2_create(tree, tmp_ctx, &io);
    2799           0 :         torture_assert_ntstatus_ok(torture, status, "dir create");
    2800             : 
    2801           0 :         dirh = io.out.file.handle;
    2802             : 
    2803           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
    2804             :                                          &compression_fmt);
    2805           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2806             : 
    2807           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2808             :                        "compression attr inherited by NO_COMPRESSION dir");
    2809           0 :         smb2_util_close(tree, dirh);
    2810           0 :         smb2_deltree(tree, DNAME);
    2811             : 
    2812           0 :         talloc_free(tmp_ctx);
    2813           0 :         return true;
    2814             : }
    2815             : 
    2816             : /* attempting to set compression via SetInfo should not stick */
    2817           1 : static bool test_ioctl_compress_set_file_attr(struct torture_context *torture,
    2818             :                                               struct smb2_tree *tree)
    2819             : {
    2820             :         struct smb2_handle fh;
    2821             :         struct smb2_handle dirh;
    2822             :         union smb_fileinfo io;
    2823             :         union smb_setfileinfo set_io;
    2824             :         uint16_t compression_fmt;
    2825             :         NTSTATUS status;
    2826           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2827             :         bool ok;
    2828             : 
    2829           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2830             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2831             :                                     FILE_ATTRIBUTE_NORMAL);
    2832           1 :         torture_assert(torture, ok, "setup compression file");
    2833             : 
    2834           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2835             :                                                   &ok);
    2836           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2837           1 :         if (!ok) {
    2838           1 :                 smb2_util_close(tree, fh);
    2839           1 :                 torture_skip(torture, "FS compression not supported\n");
    2840             :         }
    2841             : 
    2842           0 :         ZERO_STRUCT(io);
    2843           0 :         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
    2844           0 :         io.generic.in.file.handle = fh;
    2845           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2846           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2847             : 
    2848           0 :         torture_assert(torture,
    2849             :                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
    2850             :                        "compression attr before set");
    2851             : 
    2852           0 :         ZERO_STRUCT(set_io);
    2853           0 :         set_io.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    2854           0 :         set_io.basic_info.in.file.handle = fh;
    2855           0 :         set_io.basic_info.in.create_time = io.basic_info.out.create_time;
    2856           0 :         set_io.basic_info.in.access_time = io.basic_info.out.access_time;
    2857           0 :         set_io.basic_info.in.write_time = io.basic_info.out.write_time;
    2858           0 :         set_io.basic_info.in.change_time = io.basic_info.out.change_time;
    2859           0 :         set_io.basic_info.in.attrib = (io.basic_info.out.attrib
    2860             :                                                 | FILE_ATTRIBUTE_COMPRESSED);
    2861           0 :         status = smb2_setinfo_file(tree, &set_io);
    2862           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
    2863             : 
    2864           0 :         ZERO_STRUCT(io);
    2865           0 :         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
    2866           0 :         io.generic.in.file.handle = fh;
    2867           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2868           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2869             : 
    2870           0 :         torture_assert(torture,
    2871             :                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
    2872             :                 "compression attr after set");
    2873             : 
    2874           0 :         smb2_util_close(tree, fh);
    2875           0 :         smb2_deltree(tree, DNAME);
    2876           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2877             :                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
    2878             :                                     FILE_ATTRIBUTE_DIRECTORY);
    2879           0 :         torture_assert(torture, ok, "setup compression directory");
    2880             : 
    2881           0 :         ZERO_STRUCT(io);
    2882           0 :         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
    2883           0 :         io.generic.in.file.handle = dirh;
    2884           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2885           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2886             : 
    2887           0 :         torture_assert(torture,
    2888             :                 ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
    2889             :                        "compression attr before set");
    2890             : 
    2891           0 :         ZERO_STRUCT(set_io);
    2892           0 :         set_io.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    2893           0 :         set_io.basic_info.in.file.handle = dirh;
    2894           0 :         set_io.basic_info.in.create_time = io.basic_info.out.create_time;
    2895           0 :         set_io.basic_info.in.access_time = io.basic_info.out.access_time;
    2896           0 :         set_io.basic_info.in.write_time = io.basic_info.out.write_time;
    2897           0 :         set_io.basic_info.in.change_time = io.basic_info.out.change_time;
    2898           0 :         set_io.basic_info.in.attrib = (io.basic_info.out.attrib
    2899             :                                                 | FILE_ATTRIBUTE_COMPRESSED);
    2900           0 :         status = smb2_setinfo_file(tree, &set_io);
    2901           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
    2902             : 
    2903           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
    2904             :                                          &compression_fmt);
    2905           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2906             : 
    2907           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2908             :                        "dir compression set after SetInfo");
    2909             : 
    2910           0 :         smb2_util_close(tree, dirh);
    2911           0 :         talloc_free(tmp_ctx);
    2912           0 :         return true;
    2913             : }
    2914             : 
    2915           1 : static bool test_ioctl_compress_perms(struct torture_context *torture,
    2916             :                                       struct smb2_tree *tree)
    2917             : {
    2918             :         struct smb2_handle fh;
    2919             :         uint16_t compression_fmt;
    2920             :         union smb_fileinfo io;
    2921             :         NTSTATUS status;
    2922           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    2923             :         bool ok;
    2924             : 
    2925           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2926             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    2927             :                                     FILE_ATTRIBUTE_NORMAL);
    2928           1 :         torture_assert(torture, ok, "setup compression file");
    2929             : 
    2930           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    2931             :                                                   &ok);
    2932           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    2933           1 :         smb2_util_close(tree, fh);
    2934           1 :         if (!ok) {
    2935           1 :                 torture_skip(torture, "FS compression not supported\n");
    2936             :         }
    2937             : 
    2938             :         /* attempt get compression without READ_ATTR permission */
    2939           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2940             :                                     FNAME, &fh, 0,
    2941             :                         (SEC_RIGHTS_FILE_READ & ~(SEC_FILE_READ_ATTRIBUTE
    2942             :                                                         | SEC_STD_READ_CONTROL
    2943             :                                                         | SEC_FILE_READ_EA)),
    2944             :                                     FILE_ATTRIBUTE_NORMAL);
    2945           0 :         torture_assert(torture, ok, "setup compression file");
    2946             : 
    2947           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2948             :                                          &compression_fmt);
    2949           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2950           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2951             :                        "compression set after create");
    2952           0 :         smb2_util_close(tree, fh);
    2953             : 
    2954             :         /* set compression without WRITE_ATTR permission should succeed */
    2955           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2956             :                                     FNAME, &fh, 0,
    2957             :                         (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
    2958             :                                                         | SEC_STD_WRITE_DAC
    2959             :                                                         | SEC_FILE_WRITE_EA)),
    2960             :                                     FILE_ATTRIBUTE_NORMAL);
    2961           0 :         torture_assert(torture, ok, "setup compression file");
    2962             : 
    2963           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    2964             :                                          COMPRESSION_FORMAT_DEFAULT);
    2965           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    2966           0 :         smb2_util_close(tree, fh);
    2967             : 
    2968           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    2969             :                                     FNAME, &fh, SEC_RIGHTS_FILE_ALL,
    2970             :                                     FILE_ATTRIBUTE_NORMAL);
    2971           0 :         torture_assert(torture, ok, "setup compression file");
    2972           0 :         ZERO_STRUCT(io);
    2973           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    2974           0 :         io.generic.in.file.handle = fh;
    2975           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    2976           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    2977             : 
    2978           0 :         torture_assert(torture,
    2979             :                        (io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
    2980             :                        "incorrect compression attr");
    2981           0 :         smb2_util_close(tree, fh);
    2982             : 
    2983             :         /* attempt get compression without READ_DATA permission */
    2984           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2985             :                                     FNAME, &fh, 0,
    2986             :                         (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
    2987             :                                     FILE_ATTRIBUTE_NORMAL);
    2988           0 :         torture_assert(torture, ok, "setup compression file");
    2989             : 
    2990           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    2991             :                                          &compression_fmt);
    2992           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    2993           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    2994             :                        "compression enabled after set");
    2995           0 :         smb2_util_close(tree, fh);
    2996             : 
    2997             :         /* attempt get compression with only SYNCHRONIZE permission */
    2998           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    2999             :                                     FNAME, &fh, 0,
    3000             :                                     SEC_STD_SYNCHRONIZE,
    3001             :                                     FILE_ATTRIBUTE_NORMAL);
    3002           0 :         torture_assert(torture, ok, "setup compression file");
    3003             : 
    3004           0 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    3005             :                                          &compression_fmt);
    3006           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    3007           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    3008             :                        "compression not enabled after set");
    3009           0 :         smb2_util_close(tree, fh);
    3010             : 
    3011             :         /* attempt to set compression without WRITE_DATA permission */
    3012           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3013             :                                     FNAME, &fh, 0,
    3014             :                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
    3015             :                                     FILE_ATTRIBUTE_NORMAL);
    3016           0 :         torture_assert(torture, ok, "setup compression file");
    3017             : 
    3018           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    3019             :                                          COMPRESSION_FORMAT_DEFAULT);
    3020           0 :         torture_assert_ntstatus_equal(torture, status,
    3021             :                                       NT_STATUS_ACCESS_DENIED,
    3022             :                                       "FSCTL_SET_COMPRESSION permission");
    3023           0 :         smb2_util_close(tree, fh);
    3024             : 
    3025           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3026             :                                     FNAME, &fh, 0,
    3027             :                         (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
    3028             :                                     FILE_ATTRIBUTE_NORMAL);
    3029           0 :         torture_assert(torture, ok, "setup compression file");
    3030             : 
    3031           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    3032             :                                          COMPRESSION_FORMAT_NONE);
    3033           0 :         torture_assert_ntstatus_equal(torture, status,
    3034             :                                       NT_STATUS_ACCESS_DENIED,
    3035             :                                       "FSCTL_SET_COMPRESSION permission");
    3036           0 :         smb2_util_close(tree, fh);
    3037             : 
    3038           0 :         talloc_free(tmp_ctx);
    3039           0 :         return true;
    3040             : }
    3041             : 
    3042           1 : static bool test_ioctl_compress_notsup_get(struct torture_context *torture,
    3043             :                                            struct smb2_tree *tree)
    3044             : {
    3045             :         struct smb2_handle fh;
    3046             :         NTSTATUS status;
    3047           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3048             :         bool ok;
    3049             :         uint16_t compression_fmt;
    3050             : 
    3051           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3052             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3053             :                                     FILE_ATTRIBUTE_NORMAL);
    3054           1 :         torture_assert(torture, ok, "setup compression file");
    3055             : 
    3056             :         /* skip if the server DOES support compression */
    3057           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    3058             :                                                   &ok);
    3059           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3060           1 :         if (ok) {
    3061           0 :                 smb2_util_close(tree, fh);
    3062           0 :                 torture_skip(torture, "FS compression supported\n");
    3063             :         }
    3064             : 
    3065             :         /*
    3066             :          * Despite not supporting compression, we should get a successful
    3067             :          * response indicating that the file is uncompressed - like WS2016.
    3068             :          */
    3069           1 :         status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
    3070             :                                          &compression_fmt);
    3071           1 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
    3072             : 
    3073           0 :         torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
    3074             :                        "initial compression state not NONE");
    3075             : 
    3076           0 :         smb2_util_close(tree, fh);
    3077           0 :         talloc_free(tmp_ctx);
    3078           0 :         return true;
    3079             : }
    3080             : 
    3081           1 : static bool test_ioctl_compress_notsup_set(struct torture_context *torture,
    3082             :                                            struct smb2_tree *tree)
    3083             : {
    3084             :         struct smb2_handle fh;
    3085             :         NTSTATUS status;
    3086           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3087             :         bool ok;
    3088             : 
    3089           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3090             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3091             :                                     FILE_ATTRIBUTE_NORMAL);
    3092           1 :         torture_assert(torture, ok, "setup compression file");
    3093             : 
    3094             :         /* skip if the server DOES support compression */
    3095           1 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    3096             :                                                   &ok);
    3097           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3098           1 :         if (ok) {
    3099           0 :                 smb2_util_close(tree, fh);
    3100           0 :                 torture_skip(torture, "FS compression supported\n");
    3101             :         }
    3102             : 
    3103           1 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    3104             :                                          COMPRESSION_FORMAT_DEFAULT);
    3105           1 :         torture_assert_ntstatus_equal(torture, status,
    3106             :                                       NT_STATUS_NOT_SUPPORTED,
    3107             :                                       "FSCTL_SET_COMPRESSION default");
    3108             : 
    3109             :         /*
    3110             :          * Despite not supporting compression, we should get a successful
    3111             :          * response for set(COMPRESSION_FORMAT_NONE) - like WS2016 ReFS.
    3112             :          */
    3113           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    3114             :                                          COMPRESSION_FORMAT_NONE);
    3115           0 :         torture_assert_ntstatus_ok(torture, status,
    3116             :                                    "FSCTL_SET_COMPRESSION none");
    3117             : 
    3118           0 :         smb2_util_close(tree, fh);
    3119           0 :         talloc_free(tmp_ctx);
    3120           0 :         return true;
    3121             : }
    3122             : 
    3123             : /*
    3124             :    basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
    3125             : */
    3126           1 : static bool test_ioctl_network_interface_info(struct torture_context *torture,
    3127             :                                       struct smb2_tree *tree)
    3128             : {
    3129             :         union smb_ioctl ioctl;
    3130             :         struct smb2_handle fh;
    3131             :         NTSTATUS status;
    3132           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3133             :         struct fsctl_net_iface_info net_iface;
    3134             :         enum ndr_err_code ndr_ret;
    3135             :         uint32_t caps;
    3136             : 
    3137           1 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    3138           1 :         if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
    3139           1 :                 torture_skip(torture, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
    3140             :         }
    3141             : 
    3142           0 :         ZERO_STRUCT(ioctl);
    3143           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3144           0 :         fh.data[0] = UINT64_MAX;
    3145           0 :         fh.data[1] = UINT64_MAX;
    3146           0 :         ioctl.smb2.in.file.handle = fh;
    3147           0 :         ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
    3148           0 :         ioctl.smb2.in.max_output_response = 0x10000; /* Windows client sets this to 64KiB */
    3149           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3150             : 
    3151           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3152           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    3153             : 
    3154           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &net_iface,
    3155             :                         (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info);
    3156           0 :         torture_assert_ndr_success(torture, ndr_ret,
    3157             :                                    "ndr_pull_fsctl_net_iface_info");
    3158             : 
    3159           0 :         NDR_PRINT_DEBUG(fsctl_net_iface_info, &net_iface);
    3160             : 
    3161           0 :         talloc_free(tmp_ctx);
    3162           0 :         return true;
    3163             : }
    3164             : 
    3165             : /*
    3166             :  * Check whether all @fs_support_flags are set in the server's
    3167             :  * RAW_QFS_ATTRIBUTE_INFORMATION FileSystemAttributes response.
    3168             :  */
    3169          31 : static NTSTATUS test_ioctl_fs_supported(struct torture_context *torture,
    3170             :                                         struct smb2_tree *tree,
    3171             :                                         TALLOC_CTX *mem_ctx,
    3172             :                                         struct smb2_handle *fh,
    3173             :                                         uint64_t fs_support_flags,
    3174             :                                         bool *supported)
    3175             : {
    3176             :         NTSTATUS status;
    3177             :         union smb_fsinfo info;
    3178             : 
    3179          31 :         ZERO_STRUCT(info);
    3180          31 :         info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
    3181          31 :         info.generic.handle = *fh;
    3182          31 :         status = smb2_getinfo_fs(tree, tree, &info);
    3183          31 :         if (!NT_STATUS_IS_OK(status)) {
    3184           0 :                 return status;
    3185             :         }
    3186             : 
    3187          31 :         if ((info.attribute_info.out.fs_attr & fs_support_flags)
    3188             :                                                         == fs_support_flags) {
    3189           0 :                 *supported = true;
    3190             :         } else {
    3191          31 :                 *supported = false;
    3192             :         }
    3193          31 :         return NT_STATUS_OK;
    3194             : }
    3195             : 
    3196           0 : static NTSTATUS test_ioctl_sparse_req(struct torture_context *torture,
    3197             :                                       TALLOC_CTX *mem_ctx,
    3198             :                                       struct smb2_tree *tree,
    3199             :                                       struct smb2_handle fh,
    3200             :                                       bool set)
    3201             : {
    3202             :         union smb_ioctl ioctl;
    3203             :         NTSTATUS status;
    3204             :         uint8_t set_sparse;
    3205             : 
    3206           0 :         ZERO_STRUCT(ioctl);
    3207           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3208           0 :         ioctl.smb2.in.file.handle = fh;
    3209           0 :         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
    3210           0 :         ioctl.smb2.in.max_output_response = 0;
    3211           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3212           0 :         set_sparse = (set ? 0xFF : 0x0);
    3213           0 :         ioctl.smb2.in.out.data = &set_sparse;
    3214           0 :         ioctl.smb2.in.out.length = sizeof(set_sparse);
    3215             : 
    3216           0 :         status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
    3217           0 :         return status;
    3218             : }
    3219             : 
    3220           0 : static NTSTATUS test_sparse_get(struct torture_context *torture,
    3221             :                                 TALLOC_CTX *mem_ctx,
    3222             :                                 struct smb2_tree *tree,
    3223             :                                 struct smb2_handle fh,
    3224             :                                 bool *_is_sparse)
    3225             : {
    3226             :         union smb_fileinfo io;
    3227             :         NTSTATUS status;
    3228             : 
    3229           0 :         ZERO_STRUCT(io);
    3230           0 :         io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
    3231           0 :         io.generic.in.file.handle = fh;
    3232           0 :         status = smb2_getinfo_file(tree, mem_ctx, &io);
    3233           0 :         if (!NT_STATUS_IS_OK(status)) {
    3234           0 :                 return status;
    3235             :         }
    3236           0 :         *_is_sparse = !!(io.basic_info.out.attrib & FILE_ATTRIBUTE_SPARSE);
    3237             : 
    3238           0 :         return status;
    3239             : }
    3240             : 
    3241             : /*
    3242             :  * Manually test setting and clearing sparse flag. Intended for file system
    3243             :  * specifc tests to toggle the flag through SMB and check the status in the
    3244             :  * file system.
    3245             :  */
    3246           0 : bool test_ioctl_set_sparse(struct torture_context *tctx)
    3247             : {
    3248           0 :         bool set, ret = true;
    3249           0 :         const char *filename = NULL;
    3250           0 :         struct smb2_create create = { };
    3251           0 :         struct smb2_tree *tree = NULL;
    3252             :         NTSTATUS status;
    3253             : 
    3254           0 :         set = torture_setting_bool(tctx, "set_sparse", true);
    3255           0 :         filename = torture_setting_string(tctx, "filename", NULL);
    3256             : 
    3257           0 :         if (filename == NULL) {
    3258           0 :                 torture_fail(tctx, "Need to provide filename through "
    3259             :                              "--option=torture:filename=testfile\n");
    3260             :                 return false;
    3261             :         }
    3262             : 
    3263           0 :         if (!torture_smb2_connection(tctx, &tree)) {
    3264           0 :                 torture_comment(tctx, "Initializing smb2 connection failed.\n");
    3265           0 :                 return false;
    3266             :         }
    3267             : 
    3268           0 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    3269           0 :         create.in.create_options = 0;
    3270           0 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    3271           0 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    3272             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    3273             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    3274           0 :         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    3275           0 :         create.in.fname = filename;
    3276             : 
    3277           0 :         status = smb2_create(tree, tctx, &create);
    3278           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3279             :                                         "CREATE failed.\n");
    3280             : 
    3281           0 :         status = test_ioctl_sparse_req(tctx, tctx, tree,
    3282             :                                        create.out.file.handle, set);
    3283           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3284             :                                         "FSCTL_SET_SPARSE failed.\n");
    3285           0 : done:
    3286             : 
    3287           0 :         return ret;
    3288             : }
    3289             : 
    3290           1 : static bool test_ioctl_sparse_file_flag(struct torture_context *torture,
    3291             :                                         struct smb2_tree *tree)
    3292             : {
    3293             :         struct smb2_handle fh;
    3294             :         union smb_fileinfo io;
    3295             :         NTSTATUS status;
    3296           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3297             :         bool ok;
    3298             :         bool is_sparse;
    3299             : 
    3300           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3301             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3302             :                                     FILE_ATTRIBUTE_NORMAL);
    3303           1 :         torture_assert(torture, ok, "setup file");
    3304             : 
    3305           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3306             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3307           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3308           1 :         if (!ok) {
    3309           1 :                 smb2_util_close(tree, fh);
    3310           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3311             :         }
    3312             : 
    3313           0 :         ZERO_STRUCT(io);
    3314           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    3315           0 :         io.generic.in.file.handle = fh;
    3316           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    3317           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
    3318             : 
    3319           0 :         torture_assert(torture,
    3320             :                 ((io.all_info2.out.attrib & FILE_ATTRIBUTE_SPARSE) == 0),
    3321             :                        "sparse attr before set");
    3322             : 
    3323           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    3324           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3325             : 
    3326           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3327           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3328           0 :         torture_assert(torture, is_sparse, "no sparse attr after set");
    3329             : 
    3330           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
    3331           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3332             : 
    3333           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3334           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3335           0 :         torture_assert(torture, !is_sparse, "sparse attr after unset");
    3336             : 
    3337           0 :         smb2_util_close(tree, fh);
    3338           0 :         talloc_free(tmp_ctx);
    3339           0 :         return true;
    3340             : }
    3341             : 
    3342           1 : static bool test_ioctl_sparse_file_attr(struct torture_context *torture,
    3343             :                                         struct smb2_tree *tree)
    3344             : {
    3345             :         struct smb2_handle fh;
    3346             :         NTSTATUS status;
    3347           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3348             :         bool ok;
    3349             :         bool is_sparse;
    3350             : 
    3351           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3352             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3353             :                         (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SPARSE));
    3354           1 :         torture_assert(torture, ok, "setup file");
    3355             : 
    3356           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3357             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3358           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3359           1 :         if (!ok) {
    3360           1 :                 smb2_util_close(tree, fh);
    3361           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3362             :         }
    3363             : 
    3364           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3365           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3366           0 :         torture_assert(torture, !is_sparse, "sparse attr on open");
    3367             : 
    3368           0 :         smb2_util_close(tree, fh);
    3369           0 :         talloc_free(tmp_ctx);
    3370           0 :         return true;
    3371             : }
    3372             : 
    3373           1 : static bool test_ioctl_sparse_dir_flag(struct torture_context *torture,
    3374             :                                         struct smb2_tree *tree)
    3375             : {
    3376             :         struct smb2_handle dirh;
    3377             :         NTSTATUS status;
    3378           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3379             :         bool ok;
    3380             : 
    3381           1 :         smb2_deltree(tree, DNAME);
    3382           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3383             :                                     DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
    3384             :                                     FILE_ATTRIBUTE_DIRECTORY);
    3385           1 :         torture_assert(torture, ok, "setup sparse directory");
    3386             : 
    3387           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &dirh,
    3388             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3389           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3390           1 :         if (!ok) {
    3391           1 :                 smb2_util_close(tree, dirh);
    3392           1 :                 smb2_deltree(tree, DNAME);
    3393           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3394             :         }
    3395             : 
    3396             :         /* set sparse dir should fail, check for 2k12 & 2k8 response */
    3397           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dirh, true);
    3398           0 :         torture_assert_ntstatus_equal(torture, status,
    3399             :                                       NT_STATUS_INVALID_PARAMETER,
    3400             :                                       "dir FSCTL_SET_SPARSE status");
    3401             : 
    3402           0 :         smb2_util_close(tree, dirh);
    3403           0 :         smb2_deltree(tree, DNAME);
    3404           0 :         talloc_free(tmp_ctx);
    3405           0 :         return true;
    3406             : }
    3407             : 
    3408             : /*
    3409             :  * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse
    3410             :  * buffer to indicate whether the flag should be set or cleared. When sent
    3411             :  * without a buffer, it must be handled as if SetSparse=TRUE.
    3412             :  */
    3413           1 : static bool test_ioctl_sparse_set_nobuf(struct torture_context *torture,
    3414             :                                         struct smb2_tree *tree)
    3415             : {
    3416             :         struct smb2_handle fh;
    3417             :         union smb_ioctl ioctl;
    3418             :         NTSTATUS status;
    3419           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3420             :         bool ok;
    3421             :         bool is_sparse;
    3422             : 
    3423           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3424             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3425             :                                     FILE_ATTRIBUTE_NORMAL);
    3426           1 :         torture_assert(torture, ok, "setup file");
    3427             : 
    3428           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3429             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3430           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3431           1 :         if (!ok) {
    3432           1 :                 smb2_util_close(tree, fh);
    3433           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3434             :         }
    3435             : 
    3436           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3437           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3438           0 :         torture_assert(torture, !is_sparse, "sparse attr before set");
    3439             : 
    3440           0 :         ZERO_STRUCT(ioctl);
    3441           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3442           0 :         ioctl.smb2.in.file.handle = fh;
    3443           0 :         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
    3444           0 :         ioctl.smb2.in.max_output_response = 0;
    3445           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3446             :         /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */
    3447             : 
    3448           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3449           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3450             : 
    3451           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3452           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3453           0 :         torture_assert(torture, is_sparse, "no sparse attr after set");
    3454             : 
    3455             :         /* second non-SetSparse request shouldn't toggle sparse */
    3456           0 :         ZERO_STRUCT(ioctl);
    3457           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3458           0 :         ioctl.smb2.in.file.handle = fh;
    3459           0 :         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
    3460           0 :         ioctl.smb2.in.max_output_response = 0;
    3461           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3462             : 
    3463           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3464           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3465             : 
    3466           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3467           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3468           0 :         torture_assert(torture, is_sparse, "no sparse attr after 2nd set");
    3469             : 
    3470           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
    3471           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3472             : 
    3473           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3474           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3475           0 :         torture_assert(torture, !is_sparse, "sparse attr after unset");
    3476             : 
    3477           0 :         smb2_util_close(tree, fh);
    3478           0 :         talloc_free(tmp_ctx);
    3479           0 :         return true;
    3480             : }
    3481             : 
    3482           1 : static bool test_ioctl_sparse_set_oversize(struct torture_context *torture,
    3483             :                                            struct smb2_tree *tree)
    3484             : {
    3485             :         struct smb2_handle fh;
    3486             :         union smb_ioctl ioctl;
    3487             :         NTSTATUS status;
    3488           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3489             :         bool ok;
    3490             :         bool is_sparse;
    3491             :         uint8_t buf[100];
    3492             : 
    3493           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3494             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3495             :                                     FILE_ATTRIBUTE_NORMAL);
    3496           1 :         torture_assert(torture, ok, "setup file");
    3497             : 
    3498           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3499             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3500           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3501           1 :         if (!ok) {
    3502           1 :                 smb2_util_close(tree, fh);
    3503           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3504             :         }
    3505             : 
    3506           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3507           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3508           0 :         torture_assert(torture, !is_sparse, "sparse attr before set");
    3509             : 
    3510           0 :         ZERO_STRUCT(ioctl);
    3511           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3512           0 :         ioctl.smb2.in.file.handle = fh;
    3513           0 :         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
    3514           0 :         ioctl.smb2.in.max_output_response = 0;
    3515           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3516             : 
    3517             :         /*
    3518             :          * Attach a request buffer larger than FILE_SET_SPARSE_BUFFER
    3519             :          * Windows still successfully processes the request.
    3520             :          */
    3521           0 :         ZERO_ARRAY(buf);
    3522           0 :         buf[0] = 0xFF; /* attempt to set sparse */
    3523           0 :         ioctl.smb2.in.out.data = buf;
    3524           0 :         ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
    3525             : 
    3526           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3527           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3528             : 
    3529           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3530           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3531           0 :         torture_assert(torture, is_sparse, "no sparse attr after set");
    3532             : 
    3533           0 :         ZERO_STRUCT(ioctl);
    3534           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3535           0 :         ioctl.smb2.in.file.handle = fh;
    3536           0 :         ioctl.smb2.in.function = FSCTL_SET_SPARSE;
    3537           0 :         ioctl.smb2.in.max_output_response = 0;
    3538           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3539             : 
    3540           0 :         ZERO_ARRAY(buf); /* clear sparse */
    3541           0 :         ioctl.smb2.in.out.data = buf;
    3542           0 :         ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
    3543             : 
    3544           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3545           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3546             : 
    3547           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3548           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3549           0 :         torture_assert(torture, !is_sparse, "sparse attr after clear");
    3550             : 
    3551           0 :         smb2_util_close(tree, fh);
    3552           0 :         talloc_free(tmp_ctx);
    3553           0 :         return true;
    3554             : }
    3555             : 
    3556           0 : static NTSTATUS test_ioctl_qar_req(struct torture_context *torture,
    3557             :                                    TALLOC_CTX *mem_ctx,
    3558             :                                    struct smb2_tree *tree,
    3559             :                                    struct smb2_handle fh,
    3560             :                                    int64_t req_off,
    3561             :                                    int64_t req_len,
    3562             :                                    struct file_alloced_range_buf **_rsp,
    3563             :                                    uint64_t *_rsp_count)
    3564             : {
    3565             :         union smb_ioctl ioctl;
    3566             :         NTSTATUS status;
    3567             :         enum ndr_err_code ndr_ret;
    3568             :         struct file_alloced_range_buf far_buf;
    3569           0 :         struct file_alloced_range_buf *far_rsp = NULL;
    3570           0 :         uint64_t far_count = 0;
    3571             :         int i;
    3572           0 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3573           0 :         if (tmp_ctx == NULL) {
    3574           0 :                 return NT_STATUS_NO_MEMORY;
    3575             :         }
    3576             : 
    3577           0 :         ZERO_STRUCT(ioctl);
    3578           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3579           0 :         ioctl.smb2.in.file.handle = fh;
    3580           0 :         ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
    3581           0 :         ioctl.smb2.in.max_output_response = 1024;
    3582           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3583             : 
    3584           0 :         far_buf.file_off = req_off;
    3585           0 :         far_buf.len = req_len;
    3586             : 
    3587           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    3588             :                                        &far_buf,
    3589             :                         (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
    3590           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    3591           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    3592           0 :                 goto err_out;
    3593             :         }
    3594             : 
    3595           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3596           0 :         if (!NT_STATUS_IS_OK(status)) {
    3597           0 :                 goto err_out;
    3598             :         }
    3599             : 
    3600           0 :         if (ioctl.smb2.out.out.length == 0) {
    3601           0 :                 goto done;
    3602             :         }
    3603             : 
    3604           0 :         if ((ioctl.smb2.out.out.length % sizeof(far_buf)) != 0) {
    3605           0 :                 torture_comment(torture, "invalid qry_alloced rsp len: %zd:",
    3606             :                                 ioctl.smb2.out.out.length);
    3607           0 :                 status = NT_STATUS_INVALID_VIEW_SIZE;
    3608           0 :                 goto err_out;
    3609             :         }
    3610             : 
    3611           0 :         far_count = (ioctl.smb2.out.out.length / sizeof(far_buf));
    3612           0 :         far_rsp = talloc_array(mem_ctx, struct file_alloced_range_buf,
    3613             :                                far_count);
    3614           0 :         if (far_rsp == NULL) {
    3615           0 :                 status = NT_STATUS_NO_MEMORY;
    3616           0 :                 goto err_out;
    3617             :         }
    3618             : 
    3619           0 :         for (i = 0; i < far_count; i++) {
    3620           0 :                 ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    3621           0 :                                                &far_rsp[i],
    3622             :                         (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
    3623           0 :                 if (ndr_ret != NDR_ERR_SUCCESS) {
    3624           0 :                         status = NT_STATUS_UNSUCCESSFUL;
    3625           0 :                         goto err_out;
    3626             :                 }
    3627             :                 /* move to next buffer */
    3628           0 :                 ioctl.smb2.out.out.data += sizeof(far_buf);
    3629           0 :                 ioctl.smb2.out.out.length -= sizeof(far_buf);
    3630             :         }
    3631             : 
    3632           0 : done:
    3633           0 :         *_rsp = far_rsp;
    3634           0 :         *_rsp_count = far_count;
    3635           0 :         status = NT_STATUS_OK;
    3636           0 : err_out:
    3637           0 :         talloc_free(tmp_ctx);
    3638           0 :         return status;
    3639             : }
    3640             : 
    3641           1 : static bool test_ioctl_sparse_qar(struct torture_context *torture,
    3642             :                                   struct smb2_tree *tree)
    3643             : {
    3644             :         struct smb2_handle fh;
    3645             :         NTSTATUS status;
    3646           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3647             :         bool ok;
    3648             :         bool is_sparse;
    3649           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    3650           1 :         uint64_t far_count = 0;
    3651             : 
    3652             :         /* zero length file, shouldn't have any ranges */
    3653           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3654             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3655             :                                     FILE_ATTRIBUTE_NORMAL);
    3656           1 :         torture_assert(torture, ok, "setup file");
    3657             : 
    3658           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3659             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3660           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3661           1 :         if (!ok) {
    3662           1 :                 smb2_util_close(tree, fh);
    3663           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3664             :         }
    3665             : 
    3666           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3667           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3668           0 :         torture_assert(torture, !is_sparse, "sparse attr before set");
    3669             : 
    3670           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    3671             :                                     0,  /* off */
    3672             :                                     0,  /* len */
    3673             :                                     &far_rsp,
    3674             :                                     &far_count);
    3675           0 :         torture_assert_ntstatus_ok(torture, status,
    3676             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    3677           0 :         torture_assert_u64_equal(torture, far_count, 0,
    3678             :                                  "unexpected response len");
    3679             : 
    3680           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    3681             :                                     0,  /* off */
    3682             :                                     1024,       /* len */
    3683             :                                     &far_rsp,
    3684             :                                     &far_count);
    3685           0 :         torture_assert_ntstatus_ok(torture, status,
    3686             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    3687           0 :         torture_assert_u64_equal(torture, far_count, 0,
    3688             :                                  "unexpected response len");
    3689             : 
    3690           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    3691           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    3692             : 
    3693           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    3694           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    3695           0 :         torture_assert(torture, is_sparse, "no sparse attr after set");
    3696             : 
    3697           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    3698             :                                     0,  /* off */
    3699             :                                     1024,       /* len */
    3700             :                                     &far_rsp,
    3701             :                                     &far_count);
    3702           0 :         torture_assert_ntstatus_ok(torture, status,
    3703             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    3704           0 :         torture_assert_u64_equal(torture, far_count, 0,
    3705             :                                  "unexpected response len");
    3706             : 
    3707             :         /* write into the (now) sparse file at 4k offset */
    3708           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    3709             :                            4096,        /* off */
    3710             :                            1024,        /* len */
    3711             :                            4096);       /* pattern offset */
    3712           0 :         torture_assert(torture, ok, "write pattern");
    3713             : 
    3714             :         /*
    3715             :          * Query range before write off. Whether it's allocated or not is FS
    3716             :          * dependent. NTFS deallocates chunks in 64K increments, but others
    3717             :          * (e.g. XFS, Btrfs, etc.) may deallocate 4K chunks.
    3718             :          */
    3719           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    3720             :                                     0,  /* off */
    3721             :                                     4096,       /* len */
    3722             :                                     &far_rsp,
    3723             :                                     &far_count);
    3724           0 :         torture_assert_ntstatus_ok(torture, status,
    3725             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    3726           0 :         if (far_count == 0) {
    3727           0 :                 torture_comment(torture, "FS deallocated 4K chunk\n");
    3728             :         } else {
    3729             :                 /* expect fully allocated */
    3730           0 :                 torture_assert_u64_equal(torture, far_count, 1,
    3731             :                                          "unexpected response len");
    3732           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
    3733           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 4096, "far len");
    3734             :         }
    3735             : 
    3736             :         /*
    3737             :          * Query range before and past write, it should be allocated up to the
    3738             :          * end of the write.
    3739             :          */
    3740           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    3741             :                                     0,  /* off */
    3742             :                                     8192,       /* len */
    3743             :                                     &far_rsp,
    3744             :                                     &far_count);
    3745           0 :         torture_assert_ntstatus_ok(torture, status,
    3746             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    3747           0 :         torture_assert_u64_equal(torture, far_count, 1,
    3748             :                                  "unexpected response len");
    3749             :         /* FS dependent */
    3750           0 :         if (far_rsp[0].file_off == 4096) {
    3751             :                 /* 4K chunk unallocated */
    3752           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 4096, "far offset");
    3753           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 1024, "far len");
    3754             :         } else {
    3755             :                 /* expect fully allocated */
    3756           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
    3757           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 5120, "far len");
    3758             :         }
    3759             : 
    3760           0 :         smb2_util_close(tree, fh);
    3761           0 :         talloc_free(tmp_ctx);
    3762           0 :         return true;
    3763             : }
    3764             : 
    3765           1 : static bool test_ioctl_sparse_qar_malformed(struct torture_context *torture,
    3766             :                                             struct smb2_tree *tree)
    3767             : {
    3768             :         struct smb2_handle fh;
    3769             :         union smb_ioctl ioctl;
    3770             :         struct file_alloced_range_buf far_buf;
    3771             :         NTSTATUS status;
    3772             :         enum ndr_err_code ndr_ret;
    3773           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    3774             :         bool ok;
    3775             :         size_t old_len;
    3776             : 
    3777             :         /* zero length file, shouldn't have any ranges */
    3778           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    3779             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    3780             :                                     FILE_ATTRIBUTE_NORMAL);
    3781           1 :         torture_assert(torture, ok, "setup file");
    3782             : 
    3783           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    3784             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    3785           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    3786           1 :         if (!ok) {
    3787           1 :                 smb2_util_close(tree, fh);
    3788           1 :                 torture_skip(torture, "Sparse files not supported\n");
    3789             :         }
    3790             : 
    3791             :         /* no allocated ranges, no space for range response, should pass */
    3792           0 :         ZERO_STRUCT(ioctl);
    3793           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3794           0 :         ioctl.smb2.in.file.handle = fh;
    3795           0 :         ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
    3796           0 :         ioctl.smb2.in.max_output_response = 0;
    3797           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3798             : 
    3799           0 :         far_buf.file_off = 0;
    3800           0 :         far_buf.len = 1024;
    3801           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    3802             :                                        &far_buf,
    3803             :                         (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
    3804           0 :         torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
    3805             : 
    3806           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3807           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_ALLOCATED_RANGES");
    3808             : 
    3809             :         /* write into the file at 4k offset */
    3810           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    3811             :                            0,           /* off */
    3812             :                            1024,        /* len */
    3813             :                            0);          /* pattern offset */
    3814           0 :         torture_assert(torture, ok, "write pattern");
    3815             : 
    3816             :         /* allocated range, no space for range response, should fail */
    3817           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3818           0 :         torture_assert_ntstatus_equal(torture, status,
    3819             :                                       NT_STATUS_BUFFER_TOO_SMALL, "qar no space");
    3820             : 
    3821             :         /* oversize (2x) file_alloced_range_buf in request, should pass */
    3822           0 :         ioctl.smb2.in.max_output_response = 1024;
    3823           0 :         old_len = ioctl.smb2.in.out.length;
    3824           0 :         ok = data_blob_realloc(tmp_ctx, &ioctl.smb2.in.out,
    3825           0 :                                (ioctl.smb2.in.out.length * 2));
    3826           0 :         torture_assert(torture, ok, "2x data buffer");
    3827           0 :         memcpy(ioctl.smb2.in.out.data + old_len, ioctl.smb2.in.out.data,
    3828             :                old_len);
    3829           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3830           0 :         torture_assert_ntstatus_ok(torture, status, "qar too big");
    3831             : 
    3832             :         /* no file_alloced_range_buf in request, should fail */
    3833           0 :         data_blob_free(&ioctl.smb2.in.out);
    3834           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3835           0 :         torture_assert_ntstatus_equal(torture, status,
    3836             :                                       NT_STATUS_INVALID_PARAMETER, "qar empty");
    3837             : 
    3838           0 :         return true;
    3839             : }
    3840             : 
    3841           1 : bool test_ioctl_alternate_data_stream(struct torture_context *tctx)
    3842             : {
    3843           1 :         bool ret = false;
    3844           1 :         const char *fname = DNAME "\\test_stream_ioctl_dir";
    3845           1 :         const char *sname = DNAME "\\test_stream_ioctl_dir:stream";
    3846             :         NTSTATUS status;
    3847           1 :         struct smb2_create create = {};
    3848           1 :         struct smb2_tree *tree = NULL;
    3849           1 :         struct smb2_handle h1 = {{0}};
    3850             :         union smb_ioctl ioctl;
    3851             : 
    3852           1 :         if (!torture_smb2_connection(tctx, &tree)) {
    3853           0 :                 torture_comment(tctx, "Initializing smb2 connection failed.\n");
    3854           0 :                 return false;
    3855             :         }
    3856             : 
    3857           1 :         smb2_deltree(tree, DNAME);
    3858             : 
    3859           1 :         status = torture_smb2_testdir(tree, DNAME, &h1);
    3860           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3861             :                                         "torture_smb2_testdir failed\n");
    3862             : 
    3863           1 :         status = smb2_util_close(tree, h1);
    3864           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3865             :                                         "smb2_util_close failed\n");
    3866           1 :         create = (struct smb2_create) {
    3867             :                 .in.desired_access = SEC_FILE_ALL,
    3868             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
    3869             :                 .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
    3870             :                 .in.create_disposition = NTCREATEX_DISP_CREATE,
    3871             :                 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
    3872             :                 .in.fname = fname,
    3873             :         };
    3874             : 
    3875           1 :         status = smb2_create(tree, tctx, &create);
    3876           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3877             :                                         "smb2_create failed\n");
    3878             : 
    3879           1 :         h1 = create.out.file.handle;
    3880           1 :         status = smb2_util_close(tree, h1);
    3881           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3882             :                                         "smb2_util_close failed\n");
    3883             : 
    3884           1 :         create = (struct smb2_create) {
    3885             :                 .in.desired_access = SEC_FILE_ALL,
    3886             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
    3887             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
    3888             :                 .in.create_disposition = NTCREATEX_DISP_CREATE,
    3889             :                 .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
    3890             :                 .in.fname = sname,
    3891             :         };
    3892           1 :         status = smb2_create(tree, tctx, &create);
    3893           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3894             :                                         "smb2_create failed\n");
    3895           1 :         h1 = create.out.file.handle;
    3896             : 
    3897           1 :         ZERO_STRUCT(ioctl);
    3898           1 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3899           1 :         ioctl.smb2.in.file.handle = h1;
    3900           1 :         ioctl.smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
    3901           1 :         ioctl.smb2.in.max_output_response = 64;
    3902           1 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3903           1 :         status = smb2_ioctl(tree, tctx, &ioctl.smb2);
    3904           1 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    3905             :                                         "smb2_ioctl failed\n");
    3906           0 :         ret = true;
    3907             : 
    3908           1 : done:
    3909             : 
    3910           1 :         smb2_util_close(tree, h1);
    3911           1 :         smb2_deltree(tree, DNAME);
    3912           1 :         return ret;
    3913             : }
    3914             : 
    3915             : /*
    3916             :  * 2.3.57 FSCTL_SET_ZERO_DATA Request
    3917             :  *
    3918             :  * How an implementation zeros data within a file is implementation-dependent.
    3919             :  * A file system MAY choose to deallocate regions of disk space that have been
    3920             :  * zeroed.<50>
    3921             :  * <50>
    3922             :  * ... NTFS might deallocate disk space in the file if the file is stored on an
    3923             :  * NTFS volume, and the file is sparse or compressed. It will free any allocated
    3924             :  * space in chunks of 64 kilobytes that begin at an offset that is a multiple of
    3925             :  * 64 kilobytes. Other bytes in the file (prior to the first freed 64-kilobyte
    3926             :  * chunk and after the last freed 64-kilobyte chunk) will be zeroed but not
    3927             :  * deallocated.
    3928             :  */
    3929           0 : static NTSTATUS test_ioctl_zdata_req(struct torture_context *torture,
    3930             :                                      TALLOC_CTX *mem_ctx,
    3931             :                                      struct smb2_tree *tree,
    3932             :                                      struct smb2_handle fh,
    3933             :                                      int64_t off,
    3934             :                                      int64_t beyond_final_zero)
    3935             : {
    3936             :         union smb_ioctl ioctl;
    3937             :         NTSTATUS status;
    3938             :         enum ndr_err_code ndr_ret;
    3939             :         struct file_zero_data_info zdata_info;
    3940           0 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3941           0 :         if (tmp_ctx == NULL) {
    3942           0 :                 return NT_STATUS_NO_MEMORY;
    3943             :         }
    3944             : 
    3945           0 :         ZERO_STRUCT(ioctl);
    3946           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    3947           0 :         ioctl.smb2.in.file.handle = fh;
    3948           0 :         ioctl.smb2.in.function = FSCTL_SET_ZERO_DATA;
    3949           0 :         ioctl.smb2.in.max_output_response = 0;
    3950           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    3951             : 
    3952           0 :         zdata_info.file_off = off;
    3953           0 :         zdata_info.beyond_final_zero = beyond_final_zero;
    3954             : 
    3955           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    3956             :                                        &zdata_info,
    3957             :                         (ndr_push_flags_fn_t)ndr_push_file_zero_data_info);
    3958           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    3959           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    3960           0 :                 goto err_out;
    3961             :         }
    3962             : 
    3963           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    3964           0 :         if (!NT_STATUS_IS_OK(status)) {
    3965           0 :                 goto err_out;
    3966             :         }
    3967             : 
    3968           0 :         status = NT_STATUS_OK;
    3969           0 : err_out:
    3970           0 :         talloc_free(tmp_ctx);
    3971           0 :         return status;
    3972             : }
    3973             : 
    3974           0 : bool test_ioctl_zero_data(struct torture_context *tctx)
    3975             : {
    3976           0 :         bool ret = true;
    3977             :         int offset, beyond_final_zero;
    3978             :         const char *filename;
    3979             :         NTSTATUS status;
    3980           0 :         struct smb2_create create = { };
    3981           0 :         struct smb2_tree *tree = NULL;
    3982             : 
    3983           0 :         offset = torture_setting_int(tctx, "offset", -1);
    3984             : 
    3985           0 :         if (offset < 0) {
    3986           0 :                 torture_fail(tctx, "Need to provide non-negative offset "
    3987             :                              "through --option=torture:offset=NNN\n");
    3988             :                 return false;
    3989             :         }
    3990             : 
    3991           0 :         beyond_final_zero = torture_setting_int(tctx, "beyond_final_zero",
    3992             :                                                 -1);
    3993           0 :         if (beyond_final_zero < 0) {
    3994           0 :                 torture_fail(tctx, "Need to provide non-negative "
    3995             :                              "'beyond final zero' through "
    3996             :                              "--option=torture:beyond_final_zero=NNN\n");
    3997             :                 return false;
    3998             :         }
    3999           0 :         filename = torture_setting_string(tctx, "filename", NULL);
    4000           0 :         if (filename == NULL) {
    4001           0 :                 torture_fail(tctx, "Need to provide filename through "
    4002             :                              "--option=torture:filename=testfile\n");
    4003             :                 return false;
    4004             :         }
    4005             : 
    4006           0 :         if (!torture_smb2_connection(tctx, &tree)) {
    4007           0 :                 torture_comment(tctx, "Initializing smb2 connection failed.\n");
    4008           0 :                 return false;
    4009             :         }
    4010             : 
    4011           0 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    4012           0 :         create.in.create_options = 0;
    4013           0 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    4014           0 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    4015             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    4016             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    4017           0 :         create.in.create_disposition = NTCREATEX_DISP_OPEN;
    4018           0 :         create.in.fname = filename;
    4019             : 
    4020           0 :         status = smb2_create(tree, tctx, &create);
    4021           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    4022             :                                         "CREATE failed.\n");
    4023             : 
    4024           0 :         status = test_ioctl_zdata_req(tctx, tctx, tree,
    4025             :                                       create.out.file.handle,
    4026             :                                       offset,
    4027             :                                       beyond_final_zero);
    4028           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    4029             :                                         "FSCTL_ZERO_DATA failed.\n");
    4030             : 
    4031           0 : done:
    4032           0 :         return ret;
    4033             : }
    4034             : 
    4035           1 : static bool test_ioctl_sparse_punch(struct torture_context *torture,
    4036             :                                     struct smb2_tree *tree)
    4037             : {
    4038             :         struct smb2_handle fh;
    4039             :         NTSTATUS status;
    4040           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4041             :         bool ok;
    4042             :         bool is_sparse;
    4043           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    4044           1 :         uint64_t far_count = 0;
    4045             : 
    4046           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4047             :                                     FNAME, &fh, 4096, SEC_RIGHTS_FILE_ALL,
    4048             :                                     FILE_ATTRIBUTE_NORMAL);
    4049           1 :         torture_assert(torture, ok, "setup file");
    4050             : 
    4051           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    4052             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4053           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4054           1 :         if (!ok) {
    4055           1 :                 smb2_util_close(tree, fh);
    4056           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4057             :         }
    4058             : 
    4059           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4060           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4061           0 :         torture_assert(torture, !is_sparse, "sparse attr before set");
    4062             : 
    4063             :         /* zero (hole-punch) the data, without sparse flag */
    4064           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4065             :                                       0,        /* off */
    4066             :                                       4096);    /* beyond_final_zero */
    4067           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4068             : 
    4069           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4070             :                                     0,          /* off */
    4071             :                                     4096,       /* len */
    4072             :                                     &far_rsp,
    4073             :                                     &far_count);
    4074           0 :         torture_assert_ntstatus_ok(torture, status,
    4075             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4076           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4077             :                                  "unexpected response len");
    4078             : 
    4079             :         /* expect fully allocated */
    4080           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4081             :                                  "unexpected far off");
    4082           0 :         torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
    4083             :                                  "unexpected far len");
    4084             :         /* check that the data is now zeroed */
    4085           0 :         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
    4086           0 :         torture_assert(torture, ok, "non-sparse zeroed range");
    4087             : 
    4088             :         /* set sparse */
    4089           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4090           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4091             : 
    4092             :         /* still fully allocated on NTFS, see note below for Samba */
    4093           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4094             :                                     0,          /* off */
    4095             :                                     4096,       /* len */
    4096             :                                     &far_rsp,
    4097             :                                     &far_count);
    4098           0 :         torture_assert_ntstatus_ok(torture, status,
    4099             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4100             :         /*
    4101             :          * FS specific: Samba uses PUNCH_HOLE to zero the range, and
    4102             :          * subsequently uses fallocate() to allocate the punched range if the
    4103             :          * file is marked non-sparse and "strict allocate" is enabled. In both
    4104             :          * cases, the zeroed range will not be detected by SEEK_DATA, so the
    4105             :          * range won't be present in QAR responses until the file is marked
    4106             :          * non-sparse again.
    4107             :          */
    4108           0 :         if (far_count == 0) {
    4109           0 :                 torture_comment(torture, "non-sparse zeroed range disappeared "
    4110             :                                 "after marking sparse\n");
    4111             :         } else {
    4112             :                 /* NTFS: range remains fully allocated */
    4113           0 :                 torture_assert_u64_equal(torture, far_count, 1,
    4114             :                                          "unexpected response len");
    4115           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4116             :                                          "unexpected far off");
    4117           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
    4118             :                                          "unexpected far len");
    4119             :         }
    4120             : 
    4121             :         /* zero (hole-punch) the data, _with_ sparse flag */
    4122           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4123             :                                       0,        /* off */
    4124             :                                       4096);    /* beyond_final_zero */
    4125           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4126             : 
    4127             :         /* the range should no longer be alloced */
    4128           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4129             :                                     0,          /* off */
    4130             :                                     4096,       /* len */
    4131             :                                     &far_rsp,
    4132             :                                     &far_count);
    4133           0 :         torture_assert_ntstatus_ok(torture, status,
    4134             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4135           0 :         torture_assert_u64_equal(torture, far_count, 0,
    4136             :                                  "unexpected response len");
    4137             : 
    4138           0 :         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
    4139           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4140             : 
    4141             :         /* remove sparse flag, this should "unsparse" the zeroed range */
    4142           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
    4143           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4144             : 
    4145           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4146             :                                     0,          /* off */
    4147             :                                     4096,       /* len */
    4148             :                                     &far_rsp,
    4149             :                                     &far_count);
    4150           0 :         torture_assert_ntstatus_ok(torture, status,
    4151             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4152           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4153             :                                  "unexpected response len");
    4154             :         /* expect fully allocated */
    4155           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4156             :                                  "unexpected far off");
    4157           0 :         torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
    4158             :                                  "unexpected far len");
    4159             : 
    4160           0 :         ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
    4161           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4162             : 
    4163           0 :         smb2_util_close(tree, fh);
    4164           0 :         talloc_free(tmp_ctx);
    4165           0 :         return true;
    4166             : }
    4167             : 
    4168             : /*
    4169             :  * Find the point at which a zeroed range in a sparse file is deallocated by the
    4170             :  * underlying filesystem. NTFS on Windows Server 2012 deallocates chunks in 64k
    4171             :  * increments. Also check whether zeroed neighbours are merged for deallocation.
    4172             :  */
    4173           1 : static bool test_ioctl_sparse_hole_dealloc(struct torture_context *torture,
    4174             :                                            struct smb2_tree *tree)
    4175             : {
    4176             :         struct smb2_handle fh;
    4177             :         NTSTATUS status;
    4178           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4179             :         bool ok;
    4180             :         uint64_t file_size;
    4181             :         uint64_t hlen;
    4182           1 :         uint64_t dealloc_chunk_len = 0;
    4183           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    4184           1 :         uint64_t far_count = 0;
    4185             : 
    4186           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4187             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    4188             :                                     FILE_ATTRIBUTE_NORMAL);
    4189           1 :         torture_assert(torture, ok, "setup file 1");
    4190             : 
    4191             :         /* check for FS sparse file */
    4192           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    4193             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4194           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4195           1 :         if (!ok) {
    4196           1 :                 smb2_util_close(tree, fh);
    4197           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4198             :         }
    4199             : 
    4200             :         /* set sparse */
    4201           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4202           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4203             : 
    4204           0 :         file_size = 1024 * 1024;
    4205             : 
    4206           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    4207             :                            0,           /* off */
    4208             :                            file_size,   /* len */
    4209             :                            0);  /* pattern offset */
    4210           0 :         torture_assert(torture, ok, "write pattern");
    4211             : 
    4212             :          /* check allocated ranges, should be fully allocated */
    4213           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4214             :                                     0,                  /* off */
    4215             :                                     file_size,          /* len */
    4216             :                                     &far_rsp,
    4217             :                                     &far_count);
    4218           0 :         torture_assert_ntstatus_ok(torture, status,
    4219             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4220           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4221             :                                  "unexpected response len");
    4222           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4223             :                                  "unexpected far off");
    4224           0 :         torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
    4225             :                                  "unexpected far len");
    4226             : 
    4227             :         /* punch holes in sizes of 1k increments */
    4228           0 :         for (hlen = 0; hlen <= file_size; hlen += 4096) {
    4229             : 
    4230             :                 /* punch a hole from zero to the current increment */
    4231           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4232             :                                               0,        /* off */
    4233             :                                               hlen);    /* beyond_final_zero */
    4234           0 :                 torture_assert_ntstatus_ok(torture, status, "zero_data");
    4235             : 
    4236             :                 /* ensure hole is zeroed, and pattern is consistent */
    4237           0 :                 ok = check_zero(torture, tree, tmp_ctx, fh, 0, hlen);
    4238           0 :                 torture_assert(torture, ok, "sparse zeroed range");
    4239             : 
    4240           0 :                 ok = check_pattern(torture, tree, tmp_ctx, fh, hlen,
    4241             :                                    file_size - hlen, hlen);
    4242           0 :                 torture_assert(torture, ok, "allocated pattern range");
    4243             : 
    4244             :                  /* Check allocated ranges, hole might have been deallocated */
    4245           0 :                 status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4246             :                                             0,          /* off */
    4247             :                                             file_size,  /* len */
    4248             :                                             &far_rsp,
    4249             :                                             &far_count);
    4250           0 :                 torture_assert_ntstatus_ok(torture, status,
    4251             :                                            "FSCTL_QUERY_ALLOCATED_RANGES");
    4252           0 :                 if ((hlen == file_size) && (far_count == 0)) {
    4253             :                         /* hole covered entire file, deallocation occurred */
    4254           0 :                         dealloc_chunk_len = file_size;
    4255           0 :                         break;
    4256             :                 }
    4257             : 
    4258           0 :                 torture_assert_u64_equal(torture, far_count, 1,
    4259             :                                          "unexpected response len");
    4260           0 :                 if (far_rsp[0].file_off != 0) {
    4261             :                         /*
    4262             :                          * We now know the hole punch length needed to trigger a
    4263             :                          * deallocation on this FS...
    4264             :                          */
    4265           0 :                         dealloc_chunk_len = hlen;
    4266           0 :                         torture_comment(torture, "hole punch %ju@0 resulted in "
    4267             :                                         "deallocation of %ju@0\n",
    4268             :                                         (uintmax_t)hlen,
    4269           0 :                                         (uintmax_t)far_rsp[0].file_off);
    4270           0 :                         torture_assert_u64_equal(torture,
    4271             :                                                  file_size - far_rsp[0].len,
    4272             :                                                  far_rsp[0].file_off,
    4273             :                                                  "invalid alloced range");
    4274           0 :                         break;
    4275             :                 }
    4276             :         }
    4277             : 
    4278           0 :         if (dealloc_chunk_len == 0) {
    4279           0 :                 torture_comment(torture, "strange, this FS never deallocates"
    4280             :                                 "zeroed ranges in sparse files\n");
    4281           0 :                 return true;    /* FS specific, not a failure */
    4282             :         }
    4283             : 
    4284             :         /*
    4285             :          * Check whether deallocation occurs when the (now known)
    4286             :          * deallocation chunk size is punched via two ZERO_DATA requests.
    4287             :          * I.e. Does the FS merge the two ranges and deallocate the chunk?
    4288             :          * NTFS on Windows Server 2012 does not.
    4289             :          */
    4290           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    4291             :                            0,           /* off */
    4292             :                            file_size,   /* len */
    4293             :                            0);  /* pattern offset */
    4294           0 :         torture_assert(torture, ok, "write pattern");
    4295             : 
    4296             :         /* divide dealloc chunk size by two, to use as punch length */
    4297           0 :         hlen = dealloc_chunk_len >> 1;
    4298             : 
    4299             :         /*
    4300             :          *                     /half of dealloc chunk size           1M\
    4301             :          *                     |                                       |
    4302             :          * /offset 0           |                   /dealloc chunk size |
    4303             :          * |------------------ |-------------------|-------------------|
    4304             :          * | zeroed, 1st punch | zeroed, 2nd punch | existing pattern  |
    4305             :          */
    4306           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4307             :                                       0,        /* off */
    4308             :                                       hlen);    /* beyond final zero */
    4309           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4310             : 
    4311           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4312             :                                       hlen,     /* off */
    4313             :                                       dealloc_chunk_len); /* beyond final */
    4314           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4315             : 
    4316             :         /* ensure holes are zeroed, and pattern is consistent */
    4317           0 :         ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
    4318           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4319             : 
    4320           0 :         ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
    4321             :                            file_size - dealloc_chunk_len, dealloc_chunk_len);
    4322           0 :         torture_assert(torture, ok, "allocated pattern range");
    4323             : 
    4324           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4325             :                                     0,                  /* off */
    4326             :                                     file_size,          /* len */
    4327             :                                     &far_rsp,
    4328             :                                     &far_count);
    4329           0 :         torture_assert_ntstatus_ok(torture, status,
    4330             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4331             : 
    4332           0 :         if ((far_count == 0) && (dealloc_chunk_len == file_size)) {
    4333           0 :                 torture_comment(torture, "holes merged for deallocation of "
    4334             :                                 "full file\n");
    4335           0 :                 return true;
    4336             :         }
    4337           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4338             :                                  "unexpected response len");
    4339           0 :         if (far_rsp[0].file_off == dealloc_chunk_len) {
    4340           0 :                 torture_comment(torture, "holes merged for deallocation of "
    4341             :                                 "%ju chunk\n", (uintmax_t)dealloc_chunk_len);
    4342           0 :                 torture_assert_u64_equal(torture,
    4343             :                                          file_size - far_rsp[0].len,
    4344             :                                          far_rsp[0].file_off,
    4345             :                                          "invalid alloced range");
    4346             :         } else {
    4347           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4348             :                                          "unexpected deallocation");
    4349           0 :                 torture_comment(torture, "holes not merged for deallocation\n");
    4350             :         }
    4351             : 
    4352           0 :         smb2_util_close(tree, fh);
    4353             : 
    4354             :         /*
    4355             :          * Check whether an unwritten range is allocated when a sparse file is
    4356             :          * written to at an offset past the dealloc chunk size:
    4357             :          *
    4358             :          *                     /dealloc chunk size
    4359             :          * /offset 0           |
    4360             :          * |------------------ |-------------------|
    4361             :          * |     unwritten     |      pattern      |
    4362             :          */
    4363           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4364             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    4365             :                                     FILE_ATTRIBUTE_NORMAL);
    4366           0 :         torture_assert(torture, ok, "setup file 1");
    4367             : 
    4368             :         /* set sparse */
    4369           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4370           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4371             : 
    4372           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    4373             :                            dealloc_chunk_len,   /* off */
    4374             :                            1024,                /* len */
    4375             :                            dealloc_chunk_len);  /* pattern offset */
    4376           0 :         torture_assert(torture, ok, "write pattern");
    4377             : 
    4378           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4379             :                                     0,                          /* off */
    4380           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4381             :                                     &far_rsp,
    4382             :                                     &far_count);
    4383           0 :         torture_assert_ntstatus_ok(torture, status,
    4384             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4385           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4386             :                                  "unexpected response len");
    4387           0 :         if (far_rsp[0].file_off == 0) {
    4388           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len,
    4389             :                                          dealloc_chunk_len + 1024,
    4390             :                                          "unexpected far len");
    4391           0 :                 torture_comment(torture, "unwritten range fully allocated\n");
    4392             :         } else {
    4393           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
    4394             :                                          "unexpected deallocation");
    4395           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
    4396             :                                          "unexpected far len");
    4397           0 :                 torture_comment(torture, "unwritten range not allocated\n");
    4398             :         }
    4399             : 
    4400           0 :         ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
    4401           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4402             : 
    4403           0 :         ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
    4404             :                            1024, dealloc_chunk_len);
    4405           0 :         torture_assert(torture, ok, "allocated pattern range");
    4406             : 
    4407             :         /* unsparse, should now be fully allocated */
    4408           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
    4409           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4410             : 
    4411           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4412             :                                     0,                          /* off */
    4413           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4414             :                                     &far_rsp,
    4415             :                                     &far_count);
    4416           0 :         torture_assert_ntstatus_ok(torture, status,
    4417             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4418           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4419             :                                  "unexpected response len");
    4420           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4421             :                                  "unexpected deallocation");
    4422           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    4423             :                                  dealloc_chunk_len + 1024,
    4424             :                                  "unexpected far len");
    4425             : 
    4426           0 :         smb2_util_close(tree, fh);
    4427           0 :         talloc_free(tmp_ctx);
    4428           0 :         return true;
    4429             : }
    4430             : 
    4431             : /* check whether a file with compression and sparse attrs can be deallocated */
    4432           1 : static bool test_ioctl_sparse_compressed(struct torture_context *torture,
    4433             :                                          struct smb2_tree *tree)
    4434             : {
    4435             :         struct smb2_handle fh;
    4436             :         NTSTATUS status;
    4437           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4438             :         bool ok;
    4439           1 :         uint64_t file_size = 1024 * 1024;
    4440           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    4441           1 :         uint64_t far_count = 0;
    4442             : 
    4443           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4444             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    4445             :                                     FILE_ATTRIBUTE_NORMAL);
    4446           1 :         torture_assert(torture, ok, "setup file 1");
    4447             : 
    4448             :         /* check for FS sparse file and compression support */
    4449           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    4450             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4451           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4452           1 :         if (!ok) {
    4453           1 :                 smb2_util_close(tree, fh);
    4454           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4455             :         }
    4456             : 
    4457           0 :         status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
    4458             :                                                   &ok);
    4459           0 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4460           0 :         if (!ok) {
    4461           0 :                 smb2_util_close(tree, fh);
    4462           0 :                 torture_skip(torture, "FS compression not supported\n");
    4463             :         }
    4464             : 
    4465             :         /* set compression and write some data */
    4466           0 :         status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
    4467             :                                          COMPRESSION_FORMAT_DEFAULT);
    4468           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
    4469             : 
    4470           0 :         ok = write_pattern(torture, tree, tmp_ctx, fh,
    4471             :                            0,           /* off */
    4472             :                            file_size,   /* len */
    4473             :                            0);          /* pattern offset */
    4474           0 :         torture_assert(torture, ok, "write pattern");
    4475             : 
    4476             :         /* set sparse - now sparse and compressed */
    4477           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4478           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4479             : 
    4480             :          /* check allocated ranges, should be fully alloced */
    4481           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4482             :                                     0,          /* off */
    4483             :                                     file_size,  /* len */
    4484             :                                     &far_rsp,
    4485             :                                     &far_count);
    4486           0 :         torture_assert_ntstatus_ok(torture, status,
    4487             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4488           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4489             :                                  "unexpected response len");
    4490           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4491             :                                  "unexpected far off");
    4492           0 :         torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
    4493             :                                  "unexpected far len");
    4494             : 
    4495             :         /* zero (hole-punch) all data, with sparse and compressed attrs */
    4496           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4497             :                                       0,                /* off */
    4498             :                                       file_size);       /* beyond_final_zero */
    4499           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4500             : 
    4501             :          /*
    4502             :           * Windows Server 2012 still deallocates a zeroed range when a sparse
    4503             :           * file carries the compression attribute.
    4504             :           */
    4505           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4506             :                                     0,          /* off */
    4507             :                                     file_size,  /* len */
    4508             :                                     &far_rsp,
    4509             :                                     &far_count);
    4510           0 :         torture_assert_ntstatus_ok(torture, status,
    4511             :                                    "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4512           0 :         if (far_count == 0) {
    4513           0 :                 torture_comment(torture, "sparse & compressed file "
    4514             :                                 "deallocated after hole-punch\n");
    4515             :         } else {
    4516           0 :                 torture_assert_u64_equal(torture, far_count, 1,
    4517             :                                          "unexpected response len");
    4518           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4519             :                                          "unexpected far off");
    4520           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
    4521             :                                          "unexpected far len");
    4522           0 :                 torture_comment(torture, "sparse & compressed file fully "
    4523             :                                 "allocated after hole-punch\n");
    4524             :         }
    4525             : 
    4526           0 :         smb2_util_close(tree, fh);
    4527           0 :         talloc_free(tmp_ctx);
    4528           0 :         return true;
    4529             : }
    4530             : 
    4531             : /*
    4532             :  * Create a sparse file, then attempt to copy unallocated and allocated ranges
    4533             :  * into a target file using FSCTL_SRV_COPYCHUNK.
    4534             :  */
    4535           1 : static bool test_ioctl_sparse_copy_chunk(struct torture_context *torture,
    4536             :                                          struct smb2_tree *tree)
    4537             : {
    4538             :         struct smb2_handle src_h;
    4539             :         struct smb2_handle dest_h;
    4540             :         NTSTATUS status;
    4541           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4542             :         bool ok;
    4543           1 :         uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
    4544           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    4545           1 :         uint64_t far_count = 0;
    4546             :         union smb_ioctl ioctl;
    4547             :         struct srv_copychunk_copy cc_copy;
    4548             :         struct srv_copychunk_rsp cc_rsp;
    4549             :         enum ndr_err_code ndr_ret;
    4550             : 
    4551           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4552             :                                     FNAME, &src_h, 0, SEC_RIGHTS_FILE_ALL,
    4553             :                                     FILE_ATTRIBUTE_NORMAL);
    4554           1 :         torture_assert(torture, ok, "setup file");
    4555             : 
    4556             :         /* check for FS sparse file support */
    4557           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &src_h,
    4558             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4559           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4560           1 :         smb2_util_close(tree, src_h);
    4561           1 :         if (!ok) {
    4562           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4563             :         }
    4564             : 
    4565           0 :         ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
    4566             :                                    1, /* chunks */
    4567             :                                    FNAME,
    4568             :                                    &src_h, 0, /* src file */
    4569             :                                    SEC_RIGHTS_FILE_ALL,
    4570             :                                    FNAME2,
    4571             :                                    &dest_h, 0,      /* dest file */
    4572             :                                    SEC_RIGHTS_FILE_ALL,
    4573             :                                    &cc_copy,
    4574             :                                    &ioctl);
    4575           0 :         torture_assert(torture, ok, "setup copy chunk error");
    4576             : 
    4577             :         /* set sparse */
    4578           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, src_h, true);
    4579           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4580             : 
    4581             :         /* start after dealloc_chunk_len, to create an unwritten sparse range */
    4582           0 :         ok = write_pattern(torture, tree, tmp_ctx, src_h,
    4583             :                            dealloc_chunk_len,   /* off */
    4584             :                            1024,        /* len */
    4585             :                            dealloc_chunk_len);  /* pattern offset */
    4586           0 :         torture_assert(torture, ok, "write pattern");
    4587             : 
    4588             :          /* Skip test if 64k chunk is allocated - FS specific */
    4589           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, src_h,
    4590             :                                     0,                          /* off */
    4591           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4592             :                                     &far_rsp,
    4593             :                                     &far_count);
    4594           0 :         torture_assert_ntstatus_ok(torture, status,
    4595             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4596           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4597             :                                  "unexpected response len");
    4598           0 :         if (far_rsp[0].file_off == 0) {
    4599           0 :                 torture_skip(torture, "unwritten range fully allocated\n");
    4600             :         }
    4601             : 
    4602           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
    4603             :                                  "unexpected allocation");
    4604           0 :         torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
    4605             :                                  "unexpected far len");
    4606             : 
    4607             :         /* copy-chunk unallocated + written ranges into non-sparse dest */
    4608             : 
    4609           0 :         cc_copy.chunks[0].source_off = 0;
    4610           0 :         cc_copy.chunks[0].target_off = 0;
    4611           0 :         cc_copy.chunks[0].length = dealloc_chunk_len + 1024;
    4612             : 
    4613           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    4614             :                                        &cc_copy,
    4615             :                         (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    4616           0 :         torture_assert_ndr_success(torture, ndr_ret,
    4617             :                                    "ndr_push_srv_copychunk_copy");
    4618             : 
    4619           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    4620           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
    4621             : 
    4622           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    4623             :                                        &cc_rsp,
    4624             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    4625           0 :         torture_assert_ndr_success(torture, ndr_ret,
    4626             :                                    "ndr_pull_srv_copychunk_rsp");
    4627             : 
    4628           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    4629             :                                   1,    /* chunks written */
    4630             :                                   0,    /* chunk bytes unsuccessfully written */
    4631             :                                   dealloc_chunk_len + 1024); /* bytes written */
    4632           0 :         torture_assert(torture, ok, "bad copy chunk response data");
    4633             : 
    4634           0 :         ok = check_zero(torture, tree, tmp_ctx, dest_h, 0, dealloc_chunk_len);
    4635           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4636             : 
    4637           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, dealloc_chunk_len,
    4638             :                            1024, dealloc_chunk_len);
    4639           0 :         torture_assert(torture, ok, "copychunked range");
    4640             : 
    4641             :         /* copied range should be allocated in non-sparse dest */
    4642           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
    4643             :                                     0,                          /* off */
    4644           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4645             :                                     &far_rsp,
    4646             :                                     &far_count);
    4647           0 :         torture_assert_ntstatus_ok(torture, status,
    4648             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4649           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4650             :                                  "unexpected response len");
    4651           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4652             :                                  "unexpected allocation");
    4653           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    4654             :                                  dealloc_chunk_len + 1024,
    4655             :                                  "unexpected far len");
    4656             : 
    4657             :         /* set dest as sparse */
    4658           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dest_h, true);
    4659           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4660             : 
    4661             :         /* zero (hole-punch) all data */
    4662           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, dest_h,
    4663             :                                       0,                /* off */
    4664           0 :                                       dealloc_chunk_len + 1024);
    4665           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    4666             : 
    4667             :         /* zeroed range might be deallocated */
    4668           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
    4669             :                                     0,                          /* off */
    4670           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4671             :                                     &far_rsp,
    4672             :                                     &far_count);
    4673           0 :         torture_assert_ntstatus_ok(torture, status,
    4674             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4675           0 :         if (far_count == 0) {
    4676             :                 /* FS specific (e.g. NTFS) */
    4677           0 :                 torture_comment(torture, "FS deallocates file on full-range "
    4678             :                                 "punch\n");
    4679             :         } else {
    4680             :                 /* FS specific (e.g. EXT4) */
    4681           0 :                 torture_comment(torture, "FS doesn't deallocate file on "
    4682             :                                 "full-range punch\n");
    4683             :         }
    4684           0 :         ok = check_zero(torture, tree, tmp_ctx, dest_h, 0,
    4685             :                         dealloc_chunk_len + 1024);
    4686           0 :         torture_assert(torture, ok, "punched zeroed range");
    4687             : 
    4688             :         /* copy-chunk again, this time with sparse dest */
    4689           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    4690           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
    4691             : 
    4692           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    4693             :                                        &cc_rsp,
    4694             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    4695           0 :         torture_assert_ndr_success(torture, ndr_ret,
    4696             :                                    "ndr_pull_srv_copychunk_rsp");
    4697             : 
    4698           0 :         ok = check_copy_chunk_rsp(torture, &cc_rsp,
    4699             :                                   1,    /* chunks written */
    4700             :                                   0,    /* chunk bytes unsuccessfully written */
    4701             :                                   dealloc_chunk_len + 1024); /* bytes written */
    4702           0 :         torture_assert(torture, ok, "bad copy chunk response data");
    4703             : 
    4704           0 :         ok = check_zero(torture, tree, tmp_ctx, dest_h, 0, dealloc_chunk_len);
    4705           0 :         torture_assert(torture, ok, "sparse zeroed range");
    4706             : 
    4707           0 :         ok = check_pattern(torture, tree, tmp_ctx, dest_h, dealloc_chunk_len,
    4708             :                            1024, dealloc_chunk_len);
    4709           0 :         torture_assert(torture, ok, "copychunked range");
    4710             : 
    4711             :         /* copied range may be allocated in sparse dest */
    4712           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
    4713             :                                     0,                          /* off */
    4714           0 :                                     dealloc_chunk_len + 1024,   /* len */
    4715             :                                     &far_rsp,
    4716             :                                     &far_count);
    4717           0 :         torture_assert_ntstatus_ok(torture, status,
    4718             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4719           0 :         torture_assert_u64_equal(torture, far_count, 1,
    4720             :                                  "unexpected response len");
    4721             :         /*
    4722             :          * FS specific: sparse region may be unallocated in dest if copy-chunk
    4723             :          *              is handled in a sparse preserving way - E.g. vfs_btrfs
    4724             :          *              with BTRFS_IOC_CLONE_RANGE.
    4725             :          */
    4726           0 :         if (far_rsp[0].file_off == dealloc_chunk_len) {
    4727           0 :                 torture_comment(torture, "copy-chunk sparse range preserved\n");
    4728           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
    4729             :                                          "unexpected far len");
    4730             :         } else {
    4731           0 :                 torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    4732             :                                          "unexpected allocation");
    4733           0 :                 torture_assert_u64_equal(torture, far_rsp[0].len,
    4734             :                                          dealloc_chunk_len + 1024,
    4735             :                                          "unexpected far len");
    4736             :         }
    4737             : 
    4738           0 :         smb2_util_close(tree, src_h);
    4739           0 :         smb2_util_close(tree, dest_h);
    4740           0 :         talloc_free(tmp_ctx);
    4741           0 :         return true;
    4742             : }
    4743             : 
    4744           1 : static bool test_ioctl_sparse_punch_invalid(struct torture_context *torture,
    4745             :                                             struct smb2_tree *tree)
    4746             : {
    4747             :         struct smb2_handle fh;
    4748             :         NTSTATUS status;
    4749           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4750             :         bool ok;
    4751             :         bool is_sparse;
    4752             :         int i;
    4753             : 
    4754           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4755             :                                     FNAME, &fh, 4096, SEC_RIGHTS_FILE_ALL,
    4756             :                                     FILE_ATTRIBUTE_NORMAL);
    4757           1 :         torture_assert(torture, ok, "setup file");
    4758             : 
    4759           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    4760             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4761           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4762           1 :         if (!ok) {
    4763           1 :                 smb2_util_close(tree, fh);
    4764           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4765             :         }
    4766             : 
    4767           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4768           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4769           0 :         torture_assert(torture, !is_sparse, "sparse attr before set");
    4770             : 
    4771             :         /* loop twice, without and with sparse attrib */
    4772           0 :         for (i = 0; i <= 1;  i++) {
    4773             :                 union smb_fileinfo io;
    4774           0 :                 struct file_alloced_range_buf *far_rsp = NULL;
    4775           0 :                 uint64_t far_count = 0;
    4776             : 
    4777             :                 /* get size before & after. zero data should never change it */
    4778           0 :                 ZERO_STRUCT(io);
    4779           0 :                 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    4780           0 :                 io.generic.in.file.handle = fh;
    4781           0 :                 status = smb2_getinfo_file(tree, tmp_ctx, &io);
    4782           0 :                 torture_assert_ntstatus_ok(torture, status, "getinfo");
    4783           0 :                 torture_assert_int_equal(torture, (int)io.all_info2.out.size,
    4784             :                                          4096, "size after IO");
    4785             : 
    4786             :                 /* valid 8 byte zero data, but after EOF */
    4787           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4788             :                                               4096,     /* off */
    4789             :                                               4104);    /* beyond_final_zero */
    4790           0 :                 torture_assert_ntstatus_ok(torture, status, "zero_data");
    4791             : 
    4792             :                 /* valid 8 byte zero data, but after EOF */
    4793           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4794             :                                               8192,     /* off */
    4795             :                                               8200);    /* beyond_final_zero */
    4796           0 :                 torture_assert_ntstatus_ok(torture, status, "zero_data");
    4797             : 
    4798           0 :                 ZERO_STRUCT(io);
    4799           0 :                 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    4800           0 :                 io.generic.in.file.handle = fh;
    4801           0 :                 status = smb2_getinfo_file(tree, tmp_ctx, &io);
    4802           0 :                 torture_assert_ntstatus_ok(torture, status, "getinfo");
    4803           0 :                 torture_assert_int_equal(torture, (int)io.all_info2.out.size,
    4804             :                                          4096, "size after IO");
    4805             : 
    4806             :                 /* valid 0 byte zero data, without sparse flag */
    4807           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4808             :                                               4095,     /* off */
    4809             :                                               4095);    /* beyond_final_zero */
    4810           0 :                 torture_assert_ntstatus_ok(torture, status, "zero_data");
    4811             : 
    4812             :                 /* INVALID off is past beyond_final_zero */
    4813           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    4814             :                                               4096,     /* off */
    4815             :                                               4095);    /* beyond_final_zero */
    4816           0 :                 torture_assert_ntstatus_equal(torture, status,
    4817             :                                               NT_STATUS_INVALID_PARAMETER,
    4818             :                                               "invalid zero_data");
    4819             : 
    4820             :                 /* zero length QAR - valid */
    4821           0 :                 status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4822             :                                             0,                  /* off */
    4823             :                                             0,                  /* len */
    4824             :                                             &far_rsp, &far_count);
    4825           0 :                 torture_assert_ntstatus_ok(torture, status,
    4826             :                                 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4827           0 :                 torture_assert_u64_equal(torture, far_count, 0,
    4828             :                                          "unexpected response len");
    4829             : 
    4830             :                 /* QAR after EOF - valid */
    4831           0 :                 status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4832             :                                             4096,               /* off */
    4833             :                                             1024,               /* len */
    4834             :                                             &far_rsp, &far_count);
    4835           0 :                 torture_assert_ntstatus_ok(torture, status,
    4836             :                                 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    4837           0 :                 torture_assert_u64_equal(torture, far_count, 0,
    4838             :                                          "unexpected response len");
    4839             : 
    4840             :                 /* set sparse */
    4841           0 :                 status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh,
    4842             :                                                true);
    4843           0 :                 torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4844             :         }
    4845             : 
    4846           0 :         smb2_util_close(tree, fh);
    4847           0 :         talloc_free(tmp_ctx);
    4848           0 :         return true;
    4849             : }
    4850             : 
    4851           1 : static bool test_ioctl_sparse_perms(struct torture_context *torture,
    4852             :                                     struct smb2_tree *tree)
    4853             : {
    4854             :         struct smb2_handle fh;
    4855             :         NTSTATUS status;
    4856           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    4857             :         bool ok;
    4858             :         bool is_sparse;
    4859           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    4860           1 :         uint64_t far_count = 0;
    4861             : 
    4862           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4863             :                                     FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
    4864             :                                     FILE_ATTRIBUTE_NORMAL);
    4865           1 :         torture_assert(torture, ok, "setup file");
    4866             : 
    4867           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    4868             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    4869           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    4870           1 :         smb2_util_close(tree, fh);
    4871           1 :         if (!ok) {
    4872           1 :                 torture_skip(torture, "Sparse files not supported\n");
    4873             :         }
    4874             : 
    4875             :         /* set sparse without WRITE_ATTR permission should succeed */
    4876           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4877             :                                     FNAME, &fh, 0,
    4878             :                         (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
    4879             :                                                         | SEC_STD_WRITE_DAC
    4880             :                                                         | SEC_FILE_WRITE_EA)),
    4881             :                                     FILE_ATTRIBUTE_NORMAL);
    4882           0 :         torture_assert(torture, ok, "setup file");
    4883             : 
    4884           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4885           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4886           0 :         smb2_util_close(tree, fh);
    4887             : 
    4888           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4889             :                              FNAME, &fh, SEC_RIGHTS_FILE_ALL,
    4890             :                              FILE_ATTRIBUTE_NORMAL);
    4891           0 :         torture_assert(torture, ok, "setup file");
    4892           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4893           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4894           0 :         torture_assert(torture, is_sparse, "sparse after set");
    4895           0 :         smb2_util_close(tree, fh);
    4896             : 
    4897             :         /* attempt get sparse without READ_DATA permission */
    4898           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4899             :                                     FNAME, &fh, 0,
    4900             :                         (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
    4901             :                                     FILE_ATTRIBUTE_NORMAL);
    4902           0 :         torture_assert(torture, ok, "setup file");
    4903             : 
    4904           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4905           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4906           0 :         torture_assert(torture, !is_sparse, "sparse set");
    4907           0 :         smb2_util_close(tree, fh);
    4908             : 
    4909             :         /* attempt to set sparse with only WRITE_ATTR permission */
    4910           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4911             :                                     FNAME, &fh, 0,
    4912             :                                     SEC_FILE_WRITE_ATTRIBUTE,
    4913             :                                     FILE_ATTRIBUTE_NORMAL);
    4914           0 :         torture_assert(torture, ok, "setup file");
    4915             : 
    4916           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4917           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4918           0 :         smb2_util_close(tree, fh);
    4919             : 
    4920             :         /* attempt to set sparse with only WRITE_DATA permission */
    4921           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4922             :                                     FNAME, &fh, 0,
    4923             :                                     SEC_FILE_WRITE_DATA,
    4924             :                                     FILE_ATTRIBUTE_NORMAL);
    4925           0 :         torture_assert(torture, ok, "setup file");
    4926             : 
    4927           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4928           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4929           0 :         smb2_util_close(tree, fh);
    4930             : 
    4931           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4932             :                              FNAME, &fh, SEC_RIGHTS_FILE_ALL,
    4933             :                              FILE_ATTRIBUTE_NORMAL);
    4934           0 :         torture_assert(torture, ok, "setup file");
    4935           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4936           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4937           0 :         torture_assert(torture, is_sparse, "sparse after set");
    4938           0 :         smb2_util_close(tree, fh);
    4939             : 
    4940             :         /* attempt to set sparse with only APPEND_DATA permission */
    4941           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4942             :                                     FNAME, &fh, 0,
    4943             :                                     SEC_FILE_APPEND_DATA,
    4944             :                                     FILE_ATTRIBUTE_NORMAL);
    4945           0 :         torture_assert(torture, ok, "setup file");
    4946             : 
    4947           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4948           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    4949           0 :         smb2_util_close(tree, fh);
    4950             : 
    4951           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4952             :                              FNAME, &fh, SEC_RIGHTS_FILE_ALL,
    4953             :                              FILE_ATTRIBUTE_NORMAL);
    4954           0 :         torture_assert(torture, ok, "setup file");
    4955           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4956           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4957           0 :         torture_assert(torture, is_sparse, "sparse after set");
    4958           0 :         smb2_util_close(tree, fh);
    4959             : 
    4960             :         /* attempt to set sparse with only WRITE_EA permission - should fail */
    4961           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    4962             :                                     FNAME, &fh, 0,
    4963             :                                     SEC_FILE_WRITE_EA,
    4964             :                                     FILE_ATTRIBUTE_NORMAL);
    4965           0 :         torture_assert(torture, ok, "setup file");
    4966             : 
    4967           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    4968           0 :         torture_assert_ntstatus_equal(torture, status,
    4969             :                                       NT_STATUS_ACCESS_DENIED,
    4970             :                                       "FSCTL_SET_SPARSE permission");
    4971           0 :         smb2_util_close(tree, fh);
    4972             : 
    4973           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4974             :                              FNAME, &fh, SEC_RIGHTS_FILE_ALL,
    4975             :                              FILE_ATTRIBUTE_NORMAL);
    4976           0 :         torture_assert(torture, ok, "setup file");
    4977           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    4978           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    4979           0 :         torture_assert(torture, !is_sparse, "sparse after set");
    4980           0 :         smb2_util_close(tree, fh);
    4981             : 
    4982             :         /* attempt QAR with only READ_ATTR permission - should fail */
    4983           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4984             :                              FNAME, &fh, SEC_FILE_READ_ATTRIBUTE,
    4985             :                              FILE_ATTRIBUTE_NORMAL);
    4986           0 :         torture_assert(torture, ok, "setup file");
    4987           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    4988             :                                     4096,               /* off */
    4989             :                                     1024,               /* len */
    4990             :                                     &far_rsp, &far_count);
    4991           0 :         torture_assert_ntstatus_equal(torture, status,
    4992             :                                       NT_STATUS_ACCESS_DENIED,
    4993             :                         "FSCTL_QUERY_ALLOCATED_RANGES req passed");
    4994           0 :         smb2_util_close(tree, fh);
    4995             : 
    4996             :         /* attempt QAR with only READ_DATA permission */
    4997           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    4998             :                              FNAME, &fh, SEC_FILE_READ_DATA,
    4999             :                              FILE_ATTRIBUTE_NORMAL);
    5000           0 :         torture_assert(torture, ok, "setup file");
    5001           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5002             :                                     0,          /* off */
    5003             :                                     1024,               /* len */
    5004             :                                     &far_rsp, &far_count);
    5005           0 :         torture_assert_ntstatus_ok(torture, status,
    5006             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5007           0 :         torture_assert_u64_equal(torture, far_count, 0,
    5008             :                                  "unexpected response len");
    5009           0 :         smb2_util_close(tree, fh);
    5010             : 
    5011             :         /* attempt QAR with only READ_EA permission - should fail */
    5012           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    5013             :                              FNAME, &fh, SEC_FILE_READ_EA,
    5014             :                              FILE_ATTRIBUTE_NORMAL);
    5015           0 :         torture_assert(torture, ok, "setup file");
    5016           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5017             :                                     4096,               /* off */
    5018             :                                     1024,               /* len */
    5019             :                                     &far_rsp, &far_count);
    5020           0 :         torture_assert_ntstatus_equal(torture, status,
    5021             :                                       NT_STATUS_ACCESS_DENIED,
    5022             :                         "FSCTL_QUERY_ALLOCATED_RANGES req passed");
    5023           0 :         smb2_util_close(tree, fh);
    5024             : 
    5025             :         /* setup file for ZERO_DATA permissions tests */
    5026           0 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    5027             :                                     FNAME, &fh, 8192,
    5028             :                                     SEC_RIGHTS_FILE_ALL,
    5029             :                                     FILE_ATTRIBUTE_NORMAL);
    5030           0 :         torture_assert(torture, ok, "setup file");
    5031             : 
    5032           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    5033           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    5034           0 :         smb2_util_close(tree, fh);
    5035             : 
    5036             :         /* attempt ZERO_DATA with only WRITE_ATTR permission - should fail */
    5037           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    5038             :                              FNAME, &fh, SEC_FILE_WRITE_ATTRIBUTE,
    5039             :                              FILE_ATTRIBUTE_NORMAL);
    5040           0 :         torture_assert(torture, ok, "setup file");
    5041           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5042             :                                       0,        /* off */
    5043             :                                       4096);    /* beyond_final_zero */
    5044           0 :         torture_assert_ntstatus_equal(torture, status,
    5045             :                                       NT_STATUS_ACCESS_DENIED,
    5046             :                                       "zero_data permission");
    5047           0 :         smb2_util_close(tree, fh);
    5048             : 
    5049             :         /* attempt ZERO_DATA with only WRITE_DATA permission */
    5050           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    5051             :                              FNAME, &fh, SEC_FILE_WRITE_DATA,
    5052             :                              FILE_ATTRIBUTE_NORMAL);
    5053           0 :         torture_assert(torture, ok, "setup file");
    5054           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5055             :                                       0,        /* off */
    5056             :                                       4096);    /* beyond_final_zero */
    5057           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    5058           0 :         smb2_util_close(tree, fh);
    5059             : 
    5060             :         /* attempt ZERO_DATA with only APPEND_DATA permission - should fail */
    5061           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    5062             :                              FNAME, &fh, SEC_FILE_APPEND_DATA,
    5063             :                              FILE_ATTRIBUTE_NORMAL);
    5064           0 :         torture_assert(torture, ok, "setup file");
    5065           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5066             :                                       0,        /* off */
    5067             :                                       4096);    /* beyond_final_zero */
    5068           0 :         torture_assert_ntstatus_equal(torture, status,
    5069             :                                       NT_STATUS_ACCESS_DENIED,
    5070             :                                       "zero_data permission");
    5071           0 :         smb2_util_close(tree, fh);
    5072             : 
    5073             :         /* attempt ZERO_DATA with only WRITE_EA permission - should fail */
    5074           0 :         ok = test_setup_open(torture, tree, tmp_ctx,
    5075             :                              FNAME, &fh, SEC_FILE_WRITE_EA,
    5076             :                              FILE_ATTRIBUTE_NORMAL);
    5077           0 :         torture_assert(torture, ok, "setup file");
    5078           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5079             :                                       0,        /* off */
    5080             :                                       4096);    /* beyond_final_zero */
    5081           0 :         torture_assert_ntstatus_equal(torture, status,
    5082             :                                       NT_STATUS_ACCESS_DENIED,
    5083             :                                       "zero_data permission");
    5084           0 :         smb2_util_close(tree, fh);
    5085             : 
    5086           0 :         talloc_free(tmp_ctx);
    5087           0 :         return true;
    5088             : }
    5089             : 
    5090           1 : static bool test_ioctl_sparse_lck(struct torture_context *torture,
    5091             :                                   struct smb2_tree *tree)
    5092             : {
    5093             :         struct smb2_handle fh;
    5094             :         struct smb2_handle fh2;
    5095             :         NTSTATUS status;
    5096           1 :         uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
    5097           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5098             :         bool ok;
    5099             :         bool is_sparse;
    5100             :         struct smb2_lock lck;
    5101             :         struct smb2_lock_element el[1];
    5102           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    5103           1 :         uint64_t far_count = 0;
    5104             : 
    5105           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx, FNAME, &fh,
    5106             :                                     dealloc_chunk_len, SEC_RIGHTS_FILE_ALL,
    5107             :                                     FILE_ATTRIBUTE_NORMAL);
    5108           1 :         torture_assert(torture, ok, "setup file");
    5109             : 
    5110           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    5111             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    5112           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    5113           1 :         if (!ok) {
    5114           1 :                 torture_skip(torture, "Sparse files not supported\n");
    5115             :                 smb2_util_close(tree, fh);
    5116             :         }
    5117             : 
    5118             :         /* open and lock via separate fh2 */
    5119           0 :         status = torture_smb2_testfile(tree, FNAME, &fh2);
    5120           0 :         torture_assert_ntstatus_ok(torture, status, "2nd src open");
    5121             : 
    5122           0 :         lck.in.lock_count       = 0x0001;
    5123           0 :         lck.in.lock_sequence    = 0x00000000;
    5124           0 :         lck.in.file.handle      = fh2;
    5125           0 :         lck.in.locks            = el;
    5126           0 :         el[0].offset            = 0;
    5127           0 :         el[0].length            = dealloc_chunk_len;
    5128           0 :         el[0].reserved          = 0;
    5129           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    5130             : 
    5131           0 :         status = smb2_lock(tree, &lck);
    5132           0 :         torture_assert_ntstatus_ok(torture, status, "lock");
    5133             : 
    5134             :         /* set sparse while locked */
    5135           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    5136           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    5137             : 
    5138           0 :         status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
    5139           0 :         torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
    5140           0 :         torture_assert(torture, is_sparse, "sparse attr after set");
    5141             : 
    5142             :         /* zero data over locked range should fail */
    5143           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5144             :                                       0,        /* off */
    5145             :                                       4096);    /* beyond_final_zero */
    5146           0 :         torture_assert_ntstatus_equal(torture, status,
    5147             :                                       NT_STATUS_FILE_LOCK_CONFLICT,
    5148             :                                       "zero_data locked");
    5149             : 
    5150             :         /* QAR over locked range should pass */
    5151           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5152             :                                     0,          /* off */
    5153             :                                     4096,       /* len */
    5154             :                                     &far_rsp, &far_count);
    5155           0 :         torture_assert_ntstatus_ok(torture, status,
    5156             :                         "FSCTL_QUERY_ALLOCATED_RANGES locked");
    5157           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5158             :                                  "unexpected response len");
    5159           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    5160             :                                  "unexpected allocation");
    5161           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5162             :                                  4096,
    5163             :                                  "unexpected far len");
    5164             : 
    5165             :         /* zero data over range past EOF should pass */
    5166           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5167             :                                       dealloc_chunk_len,        /* off */
    5168           0 :                                       dealloc_chunk_len + 4096);
    5169           0 :         torture_assert_ntstatus_ok(torture, status,
    5170             :                                    "zero_data past EOF locked");
    5171             : 
    5172             :         /* QAR over range past EOF should pass */
    5173           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5174             :                                     dealloc_chunk_len,          /* off */
    5175             :                                     4096,                       /* len */
    5176             :                                     &far_rsp, &far_count);
    5177           0 :         torture_assert_ntstatus_ok(torture, status,
    5178             :                         "FSCTL_QUERY_ALLOCATED_RANGES past EOF locked");
    5179           0 :         torture_assert_u64_equal(torture, far_count, 0,
    5180             :                                  "unexpected response len");
    5181             : 
    5182           0 :         lck.in.lock_count       = 0x0001;
    5183           0 :         lck.in.lock_sequence    = 0x00000001;
    5184           0 :         lck.in.file.handle      = fh2;
    5185           0 :         lck.in.locks            = el;
    5186           0 :         el[0].offset            = 0;
    5187           0 :         el[0].length            = dealloc_chunk_len;
    5188           0 :         el[0].reserved          = 0;
    5189           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    5190           0 :         status = smb2_lock(tree, &lck);
    5191           0 :         torture_assert_ntstatus_ok(torture, status, "unlock");
    5192             : 
    5193           0 :         smb2_util_close(tree, fh2);
    5194           0 :         smb2_util_close(tree, fh);
    5195           0 :         talloc_free(tmp_ctx);
    5196           0 :         return true;
    5197             : }
    5198             : 
    5199             : /* alleviate QAR off-by-one bug paranoia - help me ob1 */
    5200           1 : static bool test_ioctl_sparse_qar_ob1(struct torture_context *torture,
    5201             :                                       struct smb2_tree *tree)
    5202             : {
    5203             :         struct smb2_handle fh;
    5204             :         NTSTATUS status;
    5205           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5206             :         bool ok;
    5207           1 :         uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
    5208           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    5209           1 :         uint64_t far_count = 0;
    5210             : 
    5211           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    5212             :                                     FNAME, &fh, dealloc_chunk_len * 2,
    5213             :                                     SEC_RIGHTS_FILE_ALL,
    5214             :                                     FILE_ATTRIBUTE_NORMAL);
    5215           1 :         torture_assert(torture, ok, "setup file");
    5216             : 
    5217           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    5218             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    5219           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    5220           1 :         if (!ok) {
    5221           1 :                 torture_skip(torture, "Sparse files not supported\n");
    5222             :                 smb2_util_close(tree, fh);
    5223             :         }
    5224             : 
    5225             :         /* non-sparse QAR with range one before EOF */
    5226           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5227             :                                     0,                          /* off */
    5228           0 :                                     dealloc_chunk_len * 2 - 1,  /* len */
    5229             :                                     &far_rsp, &far_count);
    5230           0 :         torture_assert_ntstatus_ok(torture, status,
    5231             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5232           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5233             :                                  "unexpected response len");
    5234           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    5235             :                                  "unexpected allocation");
    5236           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5237             :                                  dealloc_chunk_len * 2 - 1,
    5238             :                                  "unexpected far len");
    5239             : 
    5240             :         /* non-sparse QAR with range one after EOF */
    5241           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5242             :                                     0,                          /* off */
    5243           0 :                                     dealloc_chunk_len * 2 + 1,  /* len */
    5244             :                                     &far_rsp, &far_count);
    5245           0 :         torture_assert_ntstatus_ok(torture, status,
    5246             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5247           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5248             :                                  "unexpected response len");
    5249           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    5250             :                                  "unexpected allocation");
    5251           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5252             :                                  dealloc_chunk_len * 2,
    5253             :                                  "unexpected far len");
    5254             : 
    5255             :         /* non-sparse QAR with range one after EOF from off=1 */
    5256           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5257             :                                     1,                          /* off */
    5258           0 :                                     dealloc_chunk_len * 2,      /* len */
    5259             :                                     &far_rsp, &far_count);
    5260           0 :         torture_assert_ntstatus_ok(torture, status,
    5261             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5262           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5263             :                                  "unexpected response len");
    5264           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 1,
    5265             :                                  "unexpected allocation");
    5266           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5267             :                                  dealloc_chunk_len * 2 - 1,
    5268             :                                  "unexpected far len");
    5269             : 
    5270           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    5271           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    5272             : 
    5273             :         /* punch out second chunk */
    5274           0 :         status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5275             :                                       dealloc_chunk_len,        /* off */
    5276           0 :                                       dealloc_chunk_len * 2);
    5277           0 :         torture_assert_ntstatus_ok(torture, status, "zero_data");
    5278             : 
    5279             :         /* sparse QAR with range one before hole */
    5280           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5281             :                                     0,                          /* off */
    5282           0 :                                     dealloc_chunk_len - 1,      /* len */
    5283             :                                     &far_rsp, &far_count);
    5284           0 :         torture_assert_ntstatus_ok(torture, status,
    5285             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5286           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5287             :                                  "unexpected response len");
    5288           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    5289             :                                  "unexpected allocation");
    5290           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5291             :                                  dealloc_chunk_len - 1,
    5292             :                                  "unexpected far len");
    5293             : 
    5294             :         /* sparse QAR with range one after hole */
    5295           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5296             :                                     0,                          /* off */
    5297           0 :                                     dealloc_chunk_len + 1,      /* len */
    5298             :                                     &far_rsp, &far_count);
    5299           0 :         torture_assert_ntstatus_ok(torture, status,
    5300             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5301           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5302             :                                  "unexpected response len");
    5303           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
    5304             :                                  "unexpected allocation");
    5305           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5306             :                                  dealloc_chunk_len,
    5307             :                                  "unexpected far len");
    5308             : 
    5309             :         /* sparse QAR with range one after hole from off=1 */
    5310           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5311             :                                     1,                          /* off */
    5312             :                                     dealloc_chunk_len,          /* len */
    5313             :                                     &far_rsp, &far_count);
    5314           0 :         torture_assert_ntstatus_ok(torture, status,
    5315             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5316           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5317             :                                  "unexpected response len");
    5318           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off, 1,
    5319             :                                  "unexpected allocation");
    5320           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5321             :                                  dealloc_chunk_len - 1,
    5322             :                                  "unexpected far len");
    5323             : 
    5324             :         /* sparse QAR with range one before EOF from off=chunk_len-1 */
    5325           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5326           0 :                                     dealloc_chunk_len - 1,      /* off */
    5327             :                                     dealloc_chunk_len,          /* len */
    5328             :                                     &far_rsp, &far_count);
    5329           0 :         torture_assert_ntstatus_ok(torture, status,
    5330             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5331           0 :         torture_assert_u64_equal(torture, far_count, 1,
    5332             :                                  "unexpected response len");
    5333           0 :         torture_assert_u64_equal(torture, far_rsp[0].file_off,
    5334             :                                  dealloc_chunk_len - 1,
    5335             :                                  "unexpected allocation");
    5336           0 :         torture_assert_u64_equal(torture, far_rsp[0].len,
    5337             :                                  1, "unexpected far len");
    5338             : 
    5339             :         /* sparse QAR with range one after EOF from off=chunk_len+1 */
    5340           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5341           0 :                                     dealloc_chunk_len + 1,      /* off */
    5342             :                                     dealloc_chunk_len,          /* len */
    5343             :                                     &far_rsp, &far_count);
    5344           0 :         torture_assert_ntstatus_ok(torture, status,
    5345             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5346           0 :         torture_assert_u64_equal(torture, far_count, 0,
    5347             :                                  "unexpected response len");
    5348           0 :         smb2_util_close(tree, fh);
    5349           0 :         talloc_free(tmp_ctx);
    5350           0 :         return true;
    5351             : }
    5352             : 
    5353             : /* test QAR with multi-range responses */
    5354           1 : static bool test_ioctl_sparse_qar_multi(struct torture_context *torture,
    5355             :                                         struct smb2_tree *tree)
    5356             : {
    5357             :         struct smb2_handle fh;
    5358             :         NTSTATUS status;
    5359           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5360             :         bool ok;
    5361           1 :         uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
    5362             :         uint64_t this_off;
    5363             :         int i;
    5364           1 :         struct file_alloced_range_buf *far_rsp = NULL;
    5365           1 :         uint64_t far_count = 0;
    5366             : 
    5367           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    5368             :                                     FNAME, &fh, dealloc_chunk_len * 2,
    5369             :                                     SEC_RIGHTS_FILE_ALL,
    5370             :                                     FILE_ATTRIBUTE_NORMAL);
    5371           1 :         torture_assert(torture, ok, "setup file");
    5372             : 
    5373           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    5374             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    5375           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    5376           1 :         if (!ok) {
    5377           1 :                 torture_skip(torture, "Sparse files not supported\n");
    5378             :                 smb2_util_close(tree, fh);
    5379             :         }
    5380             : 
    5381           0 :         status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
    5382           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
    5383             : 
    5384             :         /* each loop, write out two chunks and punch the first out */
    5385           0 :         for (i = 0; i < 10; i++) {
    5386           0 :                 this_off = i * dealloc_chunk_len * 2;
    5387             : 
    5388           0 :                 ok = write_pattern(torture, tree, tmp_ctx, fh,
    5389             :                                    this_off,                    /* off */
    5390             :                                    dealloc_chunk_len * 2,       /* len */
    5391             :                                    this_off);           /* pattern offset */
    5392           0 :                 torture_assert(torture, ok, "write pattern");
    5393             : 
    5394           0 :                 status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
    5395             :                                               this_off, /* off */
    5396           0 :                                               this_off + dealloc_chunk_len);
    5397           0 :                 torture_assert_ntstatus_ok(torture, status, "zero_data");
    5398             :         }
    5399             : 
    5400             :         /* should now have one separate region for each iteration */
    5401           0 :         status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
    5402             :                                     0,
    5403           0 :                                     10 * dealloc_chunk_len * 2,
    5404             :                                     &far_rsp, &far_count);
    5405           0 :         torture_assert_ntstatus_ok(torture, status,
    5406             :                         "FSCTL_QUERY_ALLOCATED_RANGES req failed");
    5407           0 :         if (far_count == 1) {
    5408           0 :                 torture_comment(torture, "this FS doesn't deallocate 64K"
    5409             :                                 "zeroed ranges in sparse files\n");
    5410           0 :                 return true;    /* FS specific, not a failure */
    5411             :         }
    5412           0 :         torture_assert_u64_equal(torture, far_count, 10,
    5413             :                                  "unexpected response len");
    5414           0 :         for (i = 0; i < 10; i++) {
    5415           0 :                 this_off = i * dealloc_chunk_len * 2;
    5416             : 
    5417           0 :                 torture_assert_u64_equal(torture, far_rsp[i].file_off,
    5418             :                                          this_off + dealloc_chunk_len,
    5419             :                                          "unexpected allocation");
    5420           0 :                 torture_assert_u64_equal(torture, far_rsp[i].len,
    5421             :                                          dealloc_chunk_len,
    5422             :                                          "unexpected far len");
    5423             :         }
    5424             : 
    5425           0 :         smb2_util_close(tree, fh);
    5426           0 :         talloc_free(tmp_ctx);
    5427           0 :         return true;
    5428             : }
    5429             : 
    5430           1 : static bool test_ioctl_sparse_qar_overflow(struct torture_context *torture,
    5431             :                                            struct smb2_tree *tree)
    5432             : {
    5433             :         struct smb2_handle fh;
    5434             :         union smb_ioctl ioctl;
    5435             :         struct file_alloced_range_buf far_buf;
    5436             :         NTSTATUS status;
    5437             :         enum ndr_err_code ndr_ret;
    5438           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5439             :         bool ok;
    5440             : 
    5441           1 :         ok = test_setup_create_fill(torture, tree, tmp_ctx,
    5442             :                                     FNAME, &fh, 1024, SEC_RIGHTS_FILE_ALL,
    5443             :                                     FILE_ATTRIBUTE_NORMAL);
    5444           1 :         torture_assert(torture, ok, "setup file");
    5445             : 
    5446           1 :         status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
    5447             :                                          FILE_SUPPORTS_SPARSE_FILES, &ok);
    5448           1 :         torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
    5449           1 :         if (!ok) {
    5450           1 :                 smb2_util_close(tree, fh);
    5451           1 :                 torture_skip(torture, "Sparse files not supported\n");
    5452             :         }
    5453             : 
    5454             :         /* no allocated ranges, no space for range response, should pass */
    5455           0 :         ZERO_STRUCT(ioctl);
    5456           0 :         ioctl.smb2.level = RAW_IOCTL_SMB2;
    5457           0 :         ioctl.smb2.in.file.handle = fh;
    5458           0 :         ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
    5459           0 :         ioctl.smb2.in.max_output_response = 1024;
    5460           0 :         ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    5461             : 
    5462             :         /* off + length wraps around to 511 */
    5463           0 :         far_buf.file_off = 512;
    5464           0 :         far_buf.len = 0xffffffffffffffffLL;
    5465           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    5466             :                                        &far_buf,
    5467             :                         (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
    5468           0 :         torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
    5469             : 
    5470           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5471           0 :         torture_assert_ntstatus_equal(torture, status,
    5472             :                                       NT_STATUS_INVALID_PARAMETER,
    5473             :                                       "FSCTL_QUERY_ALLOCATED_RANGES overflow");
    5474             : 
    5475           0 :         return true;
    5476             : }
    5477             : 
    5478           1 : static NTSTATUS test_ioctl_trim_supported(struct torture_context *torture,
    5479             :                                           struct smb2_tree *tree,
    5480             :                                           TALLOC_CTX *mem_ctx,
    5481             :                                           struct smb2_handle *fh,
    5482             :                                           bool *trim_support)
    5483             : {
    5484             :         NTSTATUS status;
    5485             :         union smb_fsinfo info;
    5486             : 
    5487           1 :         ZERO_STRUCT(info);
    5488           1 :         info.generic.level = RAW_QFS_SECTOR_SIZE_INFORMATION;
    5489           1 :         info.generic.handle = *fh;
    5490           1 :         status = smb2_getinfo_fs(tree, tree, &info);
    5491           1 :         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
    5492             :                 /*
    5493             :                  * Windows < Server 2012, 8 etc. don't support this info level
    5494             :                  * or the trim ioctl. Ignore the error and let the caller skip.
    5495             :                  */
    5496           0 :                 *trim_support = false;
    5497           0 :                 return NT_STATUS_OK;
    5498           1 :         } else if (!NT_STATUS_IS_OK(status)) {
    5499           0 :                 return status;
    5500             :         }
    5501             : 
    5502           1 :         torture_comment(torture, "sector size info: lb/s=%u, pb/sA=%u, "
    5503             :                         "pb/sP=%u, fse/sA=%u, flags=0x%x, bosa=%u, bopa=%u\n",
    5504           1 :             (unsigned)info.sector_size_info.out.logical_bytes_per_sector,
    5505           1 :             (unsigned)info.sector_size_info.out.phys_bytes_per_sector_atomic,
    5506           1 :             (unsigned)info.sector_size_info.out.phys_bytes_per_sector_perf,
    5507           1 :   (unsigned)info.sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic,
    5508           1 :             (unsigned)info.sector_size_info.out.flags,
    5509           1 :             (unsigned)info.sector_size_info.out.byte_off_sector_align,
    5510           1 :             (unsigned)info.sector_size_info.out.byte_off_partition_align);
    5511             : 
    5512           1 :         if (info.sector_size_info.out.flags & QFS_SSINFO_FLAGS_TRIM_ENABLED) {
    5513           0 :                 *trim_support = true;
    5514             :         } else {
    5515           1 :                 *trim_support = false;
    5516             :         }
    5517           1 :         return NT_STATUS_OK;
    5518             : }
    5519             : 
    5520           1 : static bool test_setup_trim(struct torture_context *torture,
    5521             :                             struct smb2_tree *tree,
    5522             :                             TALLOC_CTX *mem_ctx,
    5523             :                             uint32_t num_ranges,
    5524             :                             struct smb2_handle *fh,
    5525             :                             uint64_t file_size,
    5526             :                             uint32_t desired_access,
    5527             :                             struct fsctl_file_level_trim_req *trim_req,
    5528             :                             union smb_ioctl *ioctl)
    5529             : {
    5530             :         bool ok;
    5531             : 
    5532           1 :         ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME,
    5533             :                                     fh, file_size, desired_access,
    5534             :                                     FILE_ATTRIBUTE_NORMAL);
    5535           1 :         torture_assert(torture, ok, "src file create fill");
    5536             : 
    5537           1 :         ZERO_STRUCTPN(ioctl);
    5538           1 :         ioctl->smb2.level = RAW_IOCTL_SMB2;
    5539           1 :         ioctl->smb2.in.file.handle = *fh;
    5540           1 :         ioctl->smb2.in.function = FSCTL_FILE_LEVEL_TRIM;
    5541             :         ioctl->smb2.in.max_output_response
    5542           1 :                                 = sizeof(struct fsctl_file_level_trim_rsp);
    5543           1 :         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    5544             : 
    5545           1 :         ZERO_STRUCTPN(trim_req);
    5546             :         /* leave key as zero for now. TODO test locking with differing keys */
    5547           1 :         trim_req->num_ranges = num_ranges;
    5548           1 :         trim_req->ranges = talloc_zero_array(mem_ctx,
    5549             :                                              struct file_level_trim_range,
    5550             :                                              num_ranges);
    5551           1 :         torture_assert(torture, (trim_req->ranges != NULL), "no memory for ranges");
    5552             : 
    5553           1 :         return true;
    5554             : }
    5555             : 
    5556           1 : static bool test_ioctl_trim_simple(struct torture_context *torture,
    5557             :                                    struct smb2_tree *tree)
    5558             : {
    5559             :         struct smb2_handle fh;
    5560             :         NTSTATUS status;
    5561             :         union smb_ioctl ioctl;
    5562             :         bool trim_supported;
    5563           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5564             :         struct fsctl_file_level_trim_req trim_req;
    5565             :         struct fsctl_file_level_trim_rsp trim_rsp;
    5566           1 :         uint64_t trim_chunk_len = 64 * 1024;    /* trim 64K chunks */
    5567             :         enum ndr_err_code ndr_ret;
    5568             :         bool ok;
    5569             : 
    5570           1 :         ok = test_setup_trim(torture, tree, tmp_ctx,
    5571             :                              1, /* 1 range */
    5572             :                              &fh, 2 * trim_chunk_len, /* fill 128K file */
    5573             :                              SEC_RIGHTS_FILE_ALL,
    5574             :                              &trim_req,
    5575             :                              &ioctl);
    5576           1 :         if (!ok) {
    5577           0 :                 torture_fail(torture, "setup trim error");
    5578             :         }
    5579             : 
    5580           1 :         status = test_ioctl_trim_supported(torture, tree, tmp_ctx, &fh,
    5581             :                                            &trim_supported);
    5582           1 :         torture_assert_ntstatus_ok(torture, status, "fsinfo");
    5583           1 :         if (!trim_supported) {
    5584           1 :                 smb2_util_close(tree, fh);
    5585           1 :                 talloc_free(tmp_ctx);
    5586           1 :                 torture_skip(torture, "trim not supported\n");
    5587             :         }
    5588             : 
    5589             :         /* trim first chunk, leave second */
    5590           0 :         trim_req.ranges[0].off = 0;
    5591           0 :         trim_req.ranges[0].len = trim_chunk_len;
    5592             : 
    5593           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx, &trim_req,
    5594             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_file_level_trim_req);
    5595           0 :         torture_assert_ndr_success(torture, ndr_ret,
    5596             :                                    "ndr_push_fsctl_file_level_trim_req");
    5597             : 
    5598           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5599           0 :         torture_assert_ntstatus_ok(torture, status, "FILE_LEVEL_TRIM_RANGE");
    5600             : 
    5601           0 :         ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
    5602             :                                        &trim_rsp,
    5603             :                        (ndr_pull_flags_fn_t)ndr_pull_fsctl_file_level_trim_rsp);
    5604           0 :         torture_assert_ndr_success(torture, ndr_ret,
    5605             :                                    "ndr_pull_fsctl_file_level_trim_rsp");
    5606             : 
    5607           0 :         torture_assert_int_equal(torture, trim_rsp.num_ranges_processed, 1, "");
    5608             : 
    5609             :         /* second half of the file should remain consitent */
    5610           0 :         ok = check_pattern(torture, tree, tmp_ctx, fh, trim_chunk_len,
    5611             :                            trim_chunk_len, trim_chunk_len);
    5612           0 :         torture_assert(torture, ok, "non-trimmed range inconsistent");
    5613             : 
    5614           0 :         return true;
    5615             : }
    5616             : 
    5617          14 : static bool test_setup_dup_extents(struct torture_context *tctx,
    5618             :                                    struct smb2_tree *tree,
    5619             :                                    TALLOC_CTX *mem_ctx,
    5620             :                                    struct smb2_handle *src_h,
    5621             :                                    uint64_t src_size,
    5622             :                                    uint32_t src_desired_access,
    5623             :                                    struct smb2_handle *dest_h,
    5624             :                                    uint64_t dest_size,
    5625             :                                    uint32_t dest_desired_access,
    5626             :                                    struct fsctl_dup_extents_to_file *dup_ext_buf,
    5627             :                                    union smb_ioctl *ioctl)
    5628             : {
    5629             :         bool ok;
    5630             : 
    5631          14 :         ok = test_setup_create_fill(tctx, tree, mem_ctx, FNAME,
    5632             :                                     src_h, src_size, src_desired_access,
    5633             :                                     FILE_ATTRIBUTE_NORMAL);
    5634          14 :         torture_assert(tctx, ok, "src file create fill");
    5635             : 
    5636          14 :         ok = test_setup_create_fill(tctx, tree, mem_ctx, FNAME2,
    5637             :                                     dest_h, dest_size, dest_desired_access,
    5638             :                                     FILE_ATTRIBUTE_NORMAL);
    5639          14 :         torture_assert(tctx, ok, "dest file create fill");
    5640             : 
    5641          14 :         ZERO_STRUCTPN(ioctl);
    5642          14 :         ioctl->smb2.level = RAW_IOCTL_SMB2;
    5643          14 :         ioctl->smb2.in.file.handle = *dest_h;
    5644          14 :         ioctl->smb2.in.function = FSCTL_DUP_EXTENTS_TO_FILE;
    5645          14 :         ioctl->smb2.in.max_output_response = 0;
    5646          14 :         ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    5647             : 
    5648          14 :         ZERO_STRUCTPN(dup_ext_buf);
    5649          14 :         smb2_push_handle(dup_ext_buf->source_fid, src_h);
    5650             : 
    5651          14 :         return true;
    5652             : }
    5653             : 
    5654           1 : static bool test_ioctl_dup_extents_simple(struct torture_context *tctx,
    5655             :                                           struct smb2_tree *tree)
    5656             : {
    5657             :         struct smb2_handle src_h;
    5658             :         struct smb2_handle dest_h;
    5659             :         NTSTATUS status;
    5660             :         union smb_ioctl ioctl;
    5661           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5662             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    5663             :         enum ndr_err_code ndr_ret;
    5664             :         union smb_fileinfo io;
    5665             :         union smb_setfileinfo sinfo;
    5666             :         bool ok;
    5667             : 
    5668           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    5669             :                                     &src_h, 4096, /* fill 4096 byte src file */
    5670             :                                     SEC_RIGHTS_FILE_ALL,
    5671             :                                     &dest_h, 0,     /* 0 byte dest file */
    5672             :                                     SEC_RIGHTS_FILE_ALL,
    5673             :                                     &dup_ext_buf,
    5674             :                                     &ioctl);
    5675           1 :         if (!ok) {
    5676           0 :                 torture_fail(tctx, "setup dup extents error");
    5677             :         }
    5678             : 
    5679           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    5680             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    5681           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    5682           1 :         if (!ok) {
    5683           1 :                 smb2_util_close(tree, src_h);
    5684           1 :                 smb2_util_close(tree, dest_h);
    5685           1 :                 talloc_free(tmp_ctx);
    5686           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    5687             :         }
    5688             : 
    5689             :         /* extend dest to match src len */
    5690           0 :         ZERO_STRUCT(sinfo);
    5691           0 :         sinfo.end_of_file_info.level =
    5692             :                 RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    5693           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    5694           0 :         sinfo.end_of_file_info.in.size = 4096;
    5695           0 :         status = smb2_setinfo_file(tree, &sinfo);
    5696           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    5697             : 
    5698             :         /* copy all src file data */
    5699           0 :         dup_ext_buf.source_off = 0;
    5700           0 :         dup_ext_buf.target_off = 0;
    5701           0 :         dup_ext_buf.byte_count = 4096;
    5702             : 
    5703           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    5704             :                                        &dup_ext_buf,
    5705             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    5706           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    5707             :                                    "ndr_push_fsctl_dup_extents_to_file");
    5708             : 
    5709           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5710           0 :         torture_assert_ntstatus_ok(tctx, status,
    5711             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    5712             : 
    5713             :         /* the file size shouldn't have been changed by this operation! */
    5714           0 :         ZERO_STRUCT(io);
    5715           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5716           0 :         io.generic.in.file.handle = dest_h;
    5717           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5718           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5719           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5720             :                                  4096, "size after IO");
    5721             : 
    5722           0 :         smb2_util_close(tree, src_h);
    5723           0 :         smb2_util_close(tree, dest_h);
    5724             : 
    5725             :         /* reopen for pattern check */
    5726           0 :         ok = test_setup_open(tctx, tree, tmp_ctx, FNAME, &src_h,
    5727             :                              SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
    5728           0 :         torture_assert_ntstatus_ok(tctx, status, "src open after dup");
    5729           0 :         ok = test_setup_open(tctx, tree, tmp_ctx, FNAME2, &dest_h,
    5730             :                              SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
    5731           0 :         torture_assert_ntstatus_ok(tctx, status, "dest open after dup");
    5732             : 
    5733           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
    5734           0 :         if (!ok) {
    5735           0 :                 torture_fail(tctx, "inconsistent src file data");
    5736             :         }
    5737             : 
    5738           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
    5739           0 :         if (!ok) {
    5740           0 :                 torture_fail(tctx, "inconsistent dest file data");
    5741             :         }
    5742             : 
    5743           0 :         smb2_util_close(tree, src_h);
    5744           0 :         smb2_util_close(tree, dest_h);
    5745           0 :         talloc_free(tmp_ctx);
    5746           0 :         return true;
    5747             : }
    5748             : 
    5749           1 : static bool test_ioctl_dup_extents_len_beyond_dest(struct torture_context *tctx,
    5750             :                                                    struct smb2_tree *tree)
    5751             : {
    5752             :         struct smb2_handle src_h;
    5753             :         struct smb2_handle dest_h;
    5754             :         NTSTATUS status;
    5755             :         union smb_ioctl ioctl;
    5756           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5757             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    5758             :         enum ndr_err_code ndr_ret;
    5759             :         union smb_fileinfo io;
    5760             :         union smb_setfileinfo sinfo;
    5761             :         bool ok;
    5762             : 
    5763           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    5764             :                                     &src_h, 32768, /* fill 32768 byte src file */
    5765             :                                     SEC_RIGHTS_FILE_ALL,
    5766             :                                     &dest_h, 0,     /* 0 byte dest file */
    5767             :                                     SEC_RIGHTS_FILE_ALL,
    5768             :                                     &dup_ext_buf,
    5769             :                                     &ioctl);
    5770           1 :         if (!ok) {
    5771           0 :                 torture_fail(tctx, "setup dup extents error");
    5772             :         }
    5773             : 
    5774           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    5775             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    5776           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    5777           1 :         if (!ok) {
    5778           1 :                 smb2_util_close(tree, src_h);
    5779           1 :                 smb2_util_close(tree, dest_h);
    5780           1 :                 talloc_free(tmp_ctx);
    5781           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    5782             :         }
    5783             : 
    5784           0 :         ZERO_STRUCT(io);
    5785           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5786           0 :         io.generic.in.file.handle = dest_h;
    5787           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5788           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5789           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5790             :                                  0, "size after IO");
    5791             : 
    5792             :         /* copy all src file data */
    5793           0 :         dup_ext_buf.source_off = 0;
    5794           0 :         dup_ext_buf.target_off = 0;
    5795           0 :         dup_ext_buf.byte_count = 32768;
    5796             : 
    5797           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    5798             :                                        &dup_ext_buf,
    5799             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    5800           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    5801             :                                    "ndr_push_fsctl_dup_extents_to_file");
    5802             : 
    5803           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5804             : #if 0
    5805             :         /*
    5806             :          * 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE Reply - this should fail, but
    5807             :          * passes against WS2016 RTM!
    5808             :          */
    5809             :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
    5810             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    5811             : #endif
    5812             : 
    5813             :         /* the file sizes shouldn't have been changed */
    5814           0 :         ZERO_STRUCT(io);
    5815           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5816           0 :         io.generic.in.file.handle = src_h;
    5817           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5818           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5819           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5820             :                                  32768, "size after IO");
    5821             : 
    5822           0 :         ZERO_STRUCT(io);
    5823           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5824           0 :         io.generic.in.file.handle = dest_h;
    5825           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5826           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5827           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5828             :                                  0, "size after IO");
    5829             : 
    5830             :         /* extend dest */
    5831           0 :         ZERO_STRUCT(sinfo);
    5832           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    5833           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    5834           0 :         sinfo.end_of_file_info.in.size = 32768;
    5835           0 :         status = smb2_setinfo_file(tree, &sinfo);
    5836           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    5837             : 
    5838           0 :         ok = check_zero(tctx, tree, tmp_ctx, dest_h, 0, 32768);
    5839           0 :         if (!ok) {
    5840           0 :                 torture_fail(tctx, "inconsistent file data");
    5841             :         }
    5842             : 
    5843             :         /* reissue ioctl, now with enough space */
    5844           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5845           0 :         torture_assert_ntstatus_ok(tctx, status,
    5846             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    5847             : 
    5848           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    5849           0 :         if (!ok) {
    5850           0 :                 torture_fail(tctx, "inconsistent file data");
    5851             :         }
    5852             : 
    5853           0 :         smb2_util_close(tree, src_h);
    5854           0 :         smb2_util_close(tree, dest_h);
    5855           0 :         talloc_free(tmp_ctx);
    5856           0 :         return true;
    5857             : }
    5858             : 
    5859           1 : static bool test_ioctl_dup_extents_len_beyond_src(struct torture_context *tctx,
    5860             :                                                   struct smb2_tree *tree)
    5861             : {
    5862             :         struct smb2_handle src_h;
    5863             :         struct smb2_handle dest_h;
    5864             :         NTSTATUS status;
    5865             :         union smb_ioctl ioctl;
    5866           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5867             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    5868             :         enum ndr_err_code ndr_ret;
    5869             :         union smb_fileinfo io;
    5870             :         bool ok;
    5871             : 
    5872           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    5873             :                                     &src_h, 32768, /* fill 32768 byte src file */
    5874             :                                     SEC_RIGHTS_FILE_ALL,
    5875             :                                     &dest_h, 0,     /* 0 byte dest file */
    5876             :                                     SEC_RIGHTS_FILE_ALL,
    5877             :                                     &dup_ext_buf,
    5878             :                                     &ioctl);
    5879           1 :         if (!ok) {
    5880           0 :                 torture_fail(tctx, "setup dup extents error");
    5881             :         }
    5882             : 
    5883           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    5884             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    5885           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    5886           1 :         if (!ok) {
    5887           1 :                 smb2_util_close(tree, src_h);
    5888           1 :                 smb2_util_close(tree, dest_h);
    5889           1 :                 talloc_free(tmp_ctx);
    5890           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    5891             :         }
    5892             : 
    5893           0 :         ZERO_STRUCT(io);
    5894           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5895           0 :         io.generic.in.file.handle = dest_h;
    5896           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5897           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5898           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5899             :                                  0, "size after IO");
    5900             : 
    5901             :         /* exceed src file len */
    5902           0 :         dup_ext_buf.source_off = 0;
    5903           0 :         dup_ext_buf.target_off = 0;
    5904           0 :         dup_ext_buf.byte_count = 32768 * 2;
    5905             : 
    5906           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    5907             :                                        &dup_ext_buf,
    5908             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    5909           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    5910             :                                    "ndr_push_fsctl_dup_extents_to_file");
    5911             : 
    5912           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5913           0 :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
    5914             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    5915             : 
    5916             :         /* the file sizes shouldn't have been changed */
    5917           0 :         ZERO_STRUCT(io);
    5918           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5919           0 :         io.generic.in.file.handle = src_h;
    5920           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5921           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5922           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5923             :                                  32768, "size after IO");
    5924             : 
    5925           0 :         ZERO_STRUCT(io);
    5926           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5927           0 :         io.generic.in.file.handle = dest_h;
    5928           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5929           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5930           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5931             :                                  0, "size after IO");
    5932             : 
    5933           0 :         smb2_util_close(tree, src_h);
    5934           0 :         smb2_util_close(tree, dest_h);
    5935           0 :         talloc_free(tmp_ctx);
    5936           0 :         return true;
    5937             : }
    5938             : 
    5939           1 : static bool test_ioctl_dup_extents_len_zero(struct torture_context *tctx,
    5940             :                                             struct smb2_tree *tree)
    5941             : {
    5942             :         struct smb2_handle src_h;
    5943             :         struct smb2_handle dest_h;
    5944             :         NTSTATUS status;
    5945             :         union smb_ioctl ioctl;
    5946           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    5947             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    5948             :         enum ndr_err_code ndr_ret;
    5949             :         union smb_fileinfo io;
    5950             :         bool ok;
    5951             : 
    5952           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    5953             :                                     &src_h, 32768, /* fill 32768 byte src file */
    5954             :                                     SEC_RIGHTS_FILE_ALL,
    5955             :                                     &dest_h, 0,     /* 0 byte dest file */
    5956             :                                     SEC_RIGHTS_FILE_ALL,
    5957             :                                     &dup_ext_buf,
    5958             :                                     &ioctl);
    5959           1 :         if (!ok) {
    5960           0 :                 torture_fail(tctx, "setup dup extents error");
    5961             :         }
    5962             : 
    5963           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    5964             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    5965           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    5966           1 :         if (!ok) {
    5967           1 :                 smb2_util_close(tree, src_h);
    5968           1 :                 smb2_util_close(tree, dest_h);
    5969           1 :                 talloc_free(tmp_ctx);
    5970           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    5971             :         }
    5972             : 
    5973           0 :         ZERO_STRUCT(io);
    5974           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5975           0 :         io.generic.in.file.handle = dest_h;
    5976           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5977           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    5978           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    5979             :                                  0, "size after IO");
    5980             : 
    5981           0 :         dup_ext_buf.source_off = 0;
    5982           0 :         dup_ext_buf.target_off = 0;
    5983           0 :         dup_ext_buf.byte_count = 0;
    5984             : 
    5985           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    5986             :                                        &dup_ext_buf,
    5987             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    5988           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    5989             :                                    "ndr_push_fsctl_dup_extents_to_file");
    5990             : 
    5991           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    5992           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    5993             : 
    5994             :         /* the file sizes shouldn't have been changed */
    5995           0 :         ZERO_STRUCT(io);
    5996           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    5997           0 :         io.generic.in.file.handle = src_h;
    5998           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    5999           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    6000           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    6001             :                                  32768, "size after IO");
    6002             : 
    6003           0 :         ZERO_STRUCT(io);
    6004           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    6005           0 :         io.generic.in.file.handle = dest_h;
    6006           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    6007           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    6008           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    6009             :                                  0, "size after IO");
    6010             : 
    6011           0 :         smb2_util_close(tree, src_h);
    6012           0 :         smb2_util_close(tree, dest_h);
    6013           0 :         talloc_free(tmp_ctx);
    6014           0 :         return true;
    6015             : }
    6016             : 
    6017           1 : static bool test_ioctl_dup_extents_sparse_src(struct torture_context *tctx,
    6018             :                                               struct smb2_tree *tree)
    6019             : {
    6020             :         struct smb2_handle src_h;
    6021             :         struct smb2_handle dest_h;
    6022             :         NTSTATUS status;
    6023             :         union smb_ioctl ioctl;
    6024           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6025             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6026             :         enum ndr_err_code ndr_ret;
    6027             :         union smb_setfileinfo sinfo;
    6028             :         bool ok;
    6029             : 
    6030           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6031             :                                     &src_h, 0, /* filled after sparse flag */
    6032             :                                     SEC_RIGHTS_FILE_ALL,
    6033             :                                     &dest_h, 0,     /* 0 byte dest file */
    6034             :                                     SEC_RIGHTS_FILE_ALL,
    6035             :                                     &dup_ext_buf,
    6036             :                                     &ioctl);
    6037           1 :         if (!ok) {
    6038           0 :                 torture_fail(tctx, "setup dup extents error");
    6039             :         }
    6040             : 
    6041           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6042             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING
    6043             :                                          | FILE_SUPPORTS_SPARSE_FILES, &ok);
    6044           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6045           1 :         if (!ok) {
    6046           1 :                 smb2_util_close(tree, src_h);
    6047           1 :                 smb2_util_close(tree, dest_h);
    6048           1 :                 talloc_free(tmp_ctx);
    6049           1 :                 torture_skip(tctx,
    6050             :                         "block refcounting and sparse files not supported\n");
    6051             :         }
    6052             : 
    6053             :         /* set sparse flag on src */
    6054           0 :         status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, src_h, true);
    6055           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
    6056             : 
    6057           0 :         ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
    6058           0 :         torture_assert(tctx, ok, "write pattern");
    6059             : 
    6060             :         /* extend dest */
    6061           0 :         ZERO_STRUCT(sinfo);
    6062           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    6063           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    6064           0 :         sinfo.end_of_file_info.in.size = 4096;
    6065           0 :         status = smb2_setinfo_file(tree, &sinfo);
    6066           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    6067             : 
    6068             :         /* copy all src file data */
    6069           0 :         dup_ext_buf.source_off = 0;
    6070           0 :         dup_ext_buf.target_off = 0;
    6071           0 :         dup_ext_buf.byte_count = 4096;
    6072             : 
    6073           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6074             :                                        &dup_ext_buf,
    6075             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6076           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6077             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6078             : 
    6079             :         /*
    6080             :          * src is sparse, but spec says: 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE
    6081             :          * Reply...  STATUS_NOT_SUPPORTED: Target file is sparse, while source
    6082             :          *                                 is a non-sparse file.
    6083             :          */
    6084           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6085           0 :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
    6086             :                                       "FSCTL_DUP_EXTENTS_TO_FILE");
    6087             : 
    6088           0 :         smb2_util_close(tree, src_h);
    6089           0 :         smb2_util_close(tree, dest_h);
    6090           0 :         talloc_free(tmp_ctx);
    6091           0 :         return true;
    6092             : }
    6093             : 
    6094           1 : static bool test_ioctl_dup_extents_sparse_dest(struct torture_context *tctx,
    6095             :                                                struct smb2_tree *tree)
    6096             : {
    6097             :         struct smb2_handle src_h;
    6098             :         struct smb2_handle dest_h;
    6099             :         NTSTATUS status;
    6100             :         union smb_ioctl ioctl;
    6101           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6102             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6103             :         enum ndr_err_code ndr_ret;
    6104             :         union smb_setfileinfo sinfo;
    6105             :         bool ok;
    6106             : 
    6107           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6108             :                                     &src_h, 4096, /* fill 4096 byte src file */
    6109             :                                     SEC_RIGHTS_FILE_ALL,
    6110             :                                     &dest_h, 0,     /* 0 byte dest file */
    6111             :                                     SEC_RIGHTS_FILE_ALL,
    6112             :                                     &dup_ext_buf,
    6113             :                                     &ioctl);
    6114           1 :         if (!ok) {
    6115           0 :                 torture_fail(tctx, "setup dup extents error");
    6116             :         }
    6117             : 
    6118           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6119             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING
    6120             :                                          | FILE_SUPPORTS_SPARSE_FILES, &ok);
    6121           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6122           1 :         if (!ok) {
    6123           1 :                 smb2_util_close(tree, src_h);
    6124           1 :                 smb2_util_close(tree, dest_h);
    6125           1 :                 talloc_free(tmp_ctx);
    6126           1 :                 torture_skip(tctx,
    6127             :                         "block refcounting and sparse files not supported\n");
    6128             :         }
    6129             : 
    6130             :         /* set sparse flag on dest */
    6131           0 :         status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, dest_h, true);
    6132           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
    6133             : 
    6134             :         /* extend dest */
    6135           0 :         ZERO_STRUCT(sinfo);
    6136           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    6137           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    6138           0 :         sinfo.end_of_file_info.in.size = dup_ext_buf.byte_count;
    6139           0 :         status = smb2_setinfo_file(tree, &sinfo);
    6140           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    6141             : 
    6142             :         /* copy all src file data */
    6143           0 :         dup_ext_buf.source_off = 0;
    6144           0 :         dup_ext_buf.target_off = 0;
    6145           0 :         dup_ext_buf.byte_count = 4096;
    6146             : 
    6147           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6148             :                                        &dup_ext_buf,
    6149             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6150           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6151             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6152             : 
    6153             :         /*
    6154             :          * dest is sparse, but spec says: 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE
    6155             :          * Reply...  STATUS_NOT_SUPPORTED: Target file is sparse, while source
    6156             :          *                                 is a non-sparse file.
    6157             :          */
    6158           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6159           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    6160             : 
    6161           0 :         smb2_util_close(tree, src_h);
    6162           0 :         smb2_util_close(tree, dest_h);
    6163           0 :         talloc_free(tmp_ctx);
    6164           0 :         return true;
    6165             : }
    6166             : 
    6167           1 : static bool test_ioctl_dup_extents_sparse_both(struct torture_context *tctx,
    6168             :                                                struct smb2_tree *tree)
    6169             : {
    6170             :         struct smb2_handle src_h;
    6171             :         struct smb2_handle dest_h;
    6172             :         NTSTATUS status;
    6173             :         union smb_ioctl ioctl;
    6174           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6175             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6176             :         enum ndr_err_code ndr_ret;
    6177             :         union smb_setfileinfo sinfo;
    6178             :         bool ok;
    6179             : 
    6180           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6181             :                                     &src_h, 0, /* fill 4096 byte src file */
    6182             :                                     SEC_RIGHTS_FILE_ALL,
    6183             :                                     &dest_h, 0,     /* 0 byte dest file */
    6184             :                                     SEC_RIGHTS_FILE_ALL,
    6185             :                                     &dup_ext_buf,
    6186             :                                     &ioctl);
    6187           1 :         if (!ok) {
    6188           0 :                 torture_fail(tctx, "setup dup extents error");
    6189             :         }
    6190             : 
    6191           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6192             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING
    6193             :                                          | FILE_SUPPORTS_SPARSE_FILES, &ok);
    6194           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6195           1 :         if (!ok) {
    6196           1 :                 smb2_util_close(tree, src_h);
    6197           1 :                 smb2_util_close(tree, dest_h);
    6198           1 :                 talloc_free(tmp_ctx);
    6199           1 :                 torture_skip(tctx,
    6200             :                         "block refcounting and sparse files not supported\n");
    6201             :         }
    6202             : 
    6203             :         /* set sparse flag on src and dest */
    6204           0 :         status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, src_h, true);
    6205           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
    6206           0 :         status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, dest_h, true);
    6207           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
    6208             : 
    6209           0 :         ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
    6210           0 :         torture_assert(tctx, ok, "write pattern");
    6211             : 
    6212             :         /* extend dest */
    6213           0 :         ZERO_STRUCT(sinfo);
    6214           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    6215           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    6216           0 :         sinfo.end_of_file_info.in.size = 4096;
    6217           0 :         status = smb2_setinfo_file(tree, &sinfo);
    6218           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    6219             : 
    6220             :         /* copy all src file data */
    6221           0 :         dup_ext_buf.source_off = 0;
    6222           0 :         dup_ext_buf.target_off = 0;
    6223           0 :         dup_ext_buf.byte_count = 4096;
    6224             : 
    6225           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6226             :                                        &dup_ext_buf,
    6227             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6228           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6229             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6230             : 
    6231           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6232           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    6233             : 
    6234           0 :         smb2_util_close(tree, src_h);
    6235           0 :         smb2_util_close(tree, dest_h);
    6236             : 
    6237             :         /* reopen for pattern check */
    6238           0 :         ok = test_setup_open(tctx, tree, tmp_ctx, FNAME2, &dest_h,
    6239             :                              SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
    6240           0 :         torture_assert_ntstatus_ok(tctx, status, "dest open ater dup");
    6241             : 
    6242           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
    6243           0 :         if (!ok) {
    6244           0 :                 torture_fail(tctx, "inconsistent file data");
    6245             :         }
    6246             : 
    6247           0 :         smb2_util_close(tree, dest_h);
    6248           0 :         talloc_free(tmp_ctx);
    6249           0 :         return true;
    6250             : }
    6251             : 
    6252           1 : static bool test_ioctl_dup_extents_src_is_dest(struct torture_context *tctx,
    6253             :                                            struct smb2_tree *tree)
    6254             : {
    6255             :         struct smb2_handle src_h;
    6256             :         struct smb2_handle dest_h;
    6257             :         NTSTATUS status;
    6258             :         union smb_ioctl ioctl;
    6259           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6260             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6261             :         enum ndr_err_code ndr_ret;
    6262             :         union smb_fileinfo io;
    6263             :         bool ok;
    6264             : 
    6265           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6266             :                                     &src_h, 32768, /* fill 32768 byte src file */
    6267             :                                     SEC_RIGHTS_FILE_ALL,
    6268             :                                     &dest_h, 0,
    6269             :                                     SEC_RIGHTS_FILE_ALL,
    6270             :                                     &dup_ext_buf,
    6271             :                                     &ioctl);
    6272           1 :         if (!ok) {
    6273           0 :                 torture_fail(tctx, "setup dup extents error");
    6274             :         }
    6275             :         /* dest_h not needed for this test */
    6276           1 :         smb2_util_close(tree, dest_h);
    6277             : 
    6278           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6279             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    6280           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6281           1 :         if (!ok) {
    6282           1 :                 smb2_util_close(tree, src_h);
    6283           1 :                 talloc_free(tmp_ctx);
    6284           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    6285             :         }
    6286             : 
    6287             :         /* src and dest are the same file handle */
    6288           0 :         ioctl.smb2.in.file.handle = src_h;
    6289             : 
    6290             :         /* no overlap between src and tgt */
    6291           0 :         dup_ext_buf.source_off = 0;
    6292           0 :         dup_ext_buf.target_off = 16384;
    6293           0 :         dup_ext_buf.byte_count = 16384;
    6294             : 
    6295           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6296             :                                        &dup_ext_buf,
    6297             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6298           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6299             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6300             : 
    6301           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6302           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    6303             : 
    6304             :         /* the file size shouldn't have been changed */
    6305           0 :         ZERO_STRUCT(io);
    6306           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    6307           0 :         io.generic.in.file.handle = src_h;
    6308           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    6309           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    6310           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    6311             :                                  32768, "size after IO");
    6312             : 
    6313           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 16384, 0);
    6314           0 :         if (!ok) {
    6315           0 :                 torture_fail(tctx, "inconsistent file data");
    6316             :         }
    6317           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 16384, 16384, 0);
    6318           0 :         if (!ok) {
    6319           0 :                 torture_fail(tctx, "inconsistent file data");
    6320             :         }
    6321             : 
    6322           0 :         smb2_util_close(tree, src_h);
    6323           0 :         talloc_free(tmp_ctx);
    6324           0 :         return true;
    6325             : }
    6326             : 
    6327             : /*
    6328             :  * unlike copy-chunk, dup extents doesn't support overlapping ranges between
    6329             :  * source and target. This makes it a *lot* cleaner to implement on the server.
    6330             :  */
    6331             : static bool
    6332           1 : test_ioctl_dup_extents_src_is_dest_overlap(struct torture_context *tctx,
    6333             :                                            struct smb2_tree *tree)
    6334             : {
    6335             :         struct smb2_handle src_h;
    6336             :         struct smb2_handle dest_h;
    6337             :         NTSTATUS status;
    6338             :         union smb_ioctl ioctl;
    6339           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6340             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6341             :         enum ndr_err_code ndr_ret;
    6342             :         union smb_fileinfo io;
    6343             :         bool ok;
    6344             : 
    6345           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6346             :                                     &src_h, 32768, /* fill 32768 byte src file */
    6347             :                                     SEC_RIGHTS_FILE_ALL,
    6348             :                                     &dest_h, 0,
    6349             :                                     SEC_RIGHTS_FILE_ALL,
    6350             :                                     &dup_ext_buf,
    6351             :                                     &ioctl);
    6352           1 :         if (!ok) {
    6353           0 :                 torture_fail(tctx, "setup dup extents error");
    6354             :         }
    6355             :         /* dest_h not needed for this test */
    6356           1 :         smb2_util_close(tree, dest_h);
    6357             : 
    6358           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6359             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    6360           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6361           1 :         if (!ok) {
    6362           1 :                 smb2_util_close(tree, src_h);
    6363           1 :                 talloc_free(tmp_ctx);
    6364           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    6365             :         }
    6366             : 
    6367             :         /* src and dest are the same file handle */
    6368           0 :         ioctl.smb2.in.file.handle = src_h;
    6369             : 
    6370             :         /* 8K overlap between src and tgt */
    6371           0 :         dup_ext_buf.source_off = 0;
    6372           0 :         dup_ext_buf.target_off = 8192;
    6373           0 :         dup_ext_buf.byte_count = 16384;
    6374             : 
    6375           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6376             :                                        &dup_ext_buf,
    6377             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6378           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6379             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6380             : 
    6381           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6382           0 :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
    6383             :                                       "FSCTL_DUP_EXTENTS_TO_FILE");
    6384             : 
    6385             :         /* the file size and data should match beforehand */
    6386           0 :         ZERO_STRUCT(io);
    6387           0 :         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
    6388           0 :         io.generic.in.file.handle = src_h;
    6389           0 :         status = smb2_getinfo_file(tree, tmp_ctx, &io);
    6390           0 :         torture_assert_ntstatus_ok(tctx, status, "getinfo");
    6391           0 :         torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
    6392             :                                  32768, "size after IO");
    6393             : 
    6394           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
    6395           0 :         if (!ok) {
    6396           0 :                 torture_fail(tctx, "inconsistent file data");
    6397             :         }
    6398             : 
    6399           0 :         smb2_util_close(tree, src_h);
    6400           0 :         talloc_free(tmp_ctx);
    6401           0 :         return true;
    6402             : }
    6403             : 
    6404             : /*
    6405             :  * The compression tests won't run against Windows servers yet - ReFS doesn't
    6406             :  * (yet) offer support for compression.
    6407             :  */
    6408           1 : static bool test_ioctl_dup_extents_compressed_src(struct torture_context *tctx,
    6409             :                                                   struct smb2_tree *tree)
    6410             : {
    6411             :         struct smb2_handle src_h;
    6412             :         struct smb2_handle dest_h;
    6413             :         NTSTATUS status;
    6414             :         union smb_ioctl ioctl;
    6415           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6416             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6417             :         enum ndr_err_code ndr_ret;
    6418             :         union smb_setfileinfo sinfo;
    6419             :         bool ok;
    6420             : 
    6421           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6422             :                                     &src_h, 0, /* filled after compressed flag */
    6423             :                                     SEC_RIGHTS_FILE_ALL,
    6424             :                                     &dest_h, 0,
    6425             :                                     SEC_RIGHTS_FILE_ALL,
    6426             :                                     &dup_ext_buf,
    6427             :                                     &ioctl);
    6428           1 :         if (!ok) {
    6429           0 :                 torture_fail(tctx, "setup dup extents error");
    6430             :         }
    6431             : 
    6432           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6433             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING
    6434             :                                          | FILE_FILE_COMPRESSION, &ok);
    6435           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6436           1 :         if (!ok) {
    6437           1 :                 smb2_util_close(tree, src_h);
    6438           1 :                 smb2_util_close(tree, dest_h);
    6439           1 :                 talloc_free(tmp_ctx);
    6440           1 :                 torture_skip(tctx,
    6441             :                         "block refcounting and compressed files not supported\n");
    6442             :         }
    6443             : 
    6444             :         /* set compressed flag on src */
    6445           0 :         status = test_ioctl_compress_set(tctx, tmp_ctx, tree, src_h,
    6446             :                                          COMPRESSION_FORMAT_DEFAULT);
    6447           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_COMPRESSION");
    6448             : 
    6449           0 :         ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
    6450           0 :         torture_assert(tctx, ok, "write pattern");
    6451             : 
    6452             :         /* extend dest */
    6453           0 :         ZERO_STRUCT(sinfo);
    6454           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    6455           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    6456           0 :         sinfo.end_of_file_info.in.size = 4096;
    6457           0 :         status = smb2_setinfo_file(tree, &sinfo);
    6458           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    6459             : 
    6460             :         /* copy all src file data */
    6461           0 :         dup_ext_buf.source_off = 0;
    6462           0 :         dup_ext_buf.target_off = 0;
    6463           0 :         dup_ext_buf.byte_count = 4096;
    6464             : 
    6465           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6466             :                                        &dup_ext_buf,
    6467             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6468           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6469             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6470             : 
    6471           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6472           0 :         torture_assert_ntstatus_ok(tctx, status,
    6473             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    6474             : 
    6475           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
    6476           0 :         if (!ok) {
    6477           0 :                 torture_fail(tctx, "inconsistent file data");
    6478             :         }
    6479             : 
    6480           0 :         smb2_util_close(tree, src_h);
    6481           0 :         smb2_util_close(tree, dest_h);
    6482           0 :         talloc_free(tmp_ctx);
    6483           0 :         return true;
    6484             : }
    6485             : 
    6486           1 : static bool test_ioctl_dup_extents_compressed_dest(struct torture_context *tctx,
    6487             :                                                    struct smb2_tree *tree)
    6488             : {
    6489             :         struct smb2_handle src_h;
    6490             :         struct smb2_handle dest_h;
    6491             :         NTSTATUS status;
    6492             :         union smb_ioctl ioctl;
    6493           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6494             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6495             :         enum ndr_err_code ndr_ret;
    6496             :         union smb_setfileinfo sinfo;
    6497             :         bool ok;
    6498             : 
    6499           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6500             :                                     &src_h, 4096,
    6501             :                                     SEC_RIGHTS_FILE_ALL,
    6502             :                                     &dest_h, 0,
    6503             :                                     SEC_RIGHTS_FILE_ALL,
    6504             :                                     &dup_ext_buf,
    6505             :                                     &ioctl);
    6506           1 :         if (!ok) {
    6507           0 :                 torture_fail(tctx, "setup dup extents error");
    6508             :         }
    6509             : 
    6510           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6511             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING
    6512             :                                          | FILE_FILE_COMPRESSION, &ok);
    6513           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6514           1 :         if (!ok) {
    6515           1 :                 smb2_util_close(tree, src_h);
    6516           1 :                 smb2_util_close(tree, dest_h);
    6517           1 :                 talloc_free(tmp_ctx);
    6518           1 :                 torture_skip(tctx,
    6519             :                         "block refcounting and compressed files not supported\n");
    6520             :         }
    6521             : 
    6522             :         /* set compressed flag on dest */
    6523           0 :         status = test_ioctl_compress_set(tctx, tmp_ctx, tree, dest_h,
    6524             :                                          COMPRESSION_FORMAT_DEFAULT);
    6525           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_COMPRESSION");
    6526             : 
    6527             :         /* extend dest */
    6528           0 :         ZERO_STRUCT(sinfo);
    6529           0 :         sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    6530           0 :         sinfo.end_of_file_info.in.file.handle = dest_h;
    6531           0 :         sinfo.end_of_file_info.in.size = 4096;
    6532           0 :         status = smb2_setinfo_file(tree, &sinfo);
    6533           0 :         torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
    6534             : 
    6535             :         /* copy all src file data */
    6536           0 :         dup_ext_buf.source_off = 0;
    6537           0 :         dup_ext_buf.target_off = 0;
    6538           0 :         dup_ext_buf.byte_count = 4096;
    6539             : 
    6540           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6541             :                                        &dup_ext_buf,
    6542             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6543           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6544             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6545             : 
    6546           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6547           0 :         torture_assert_ntstatus_ok(tctx, status,
    6548             :                                    "FSCTL_DUP_EXTENTS_TO_FILE");
    6549             : 
    6550           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
    6551           0 :         if (!ok) {
    6552           0 :                 torture_fail(tctx, "inconsistent file data");
    6553             :         }
    6554             : 
    6555           0 :         smb2_util_close(tree, src_h);
    6556           0 :         smb2_util_close(tree, dest_h);
    6557           0 :         talloc_free(tmp_ctx);
    6558           0 :         return true;
    6559             : }
    6560             : 
    6561           1 : static bool test_ioctl_dup_extents_bad_handle(struct torture_context *tctx,
    6562             :                                               struct smb2_tree *tree)
    6563             : {
    6564             :         struct smb2_handle src_h;
    6565             :         struct smb2_handle dest_h;
    6566             :         struct smb2_handle bogus_h;
    6567             :         NTSTATUS status;
    6568             :         union smb_ioctl ioctl;
    6569           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6570             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6571             :         enum ndr_err_code ndr_ret;
    6572             :         bool ok;
    6573             : 
    6574           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6575             :                                     &src_h, 32768, /* fill 32768 byte src file */
    6576             :                                     SEC_RIGHTS_FILE_ALL,
    6577             :                                     &dest_h, 32768,
    6578             :                                     SEC_RIGHTS_FILE_ALL,
    6579             :                                     &dup_ext_buf,
    6580             :                                     &ioctl);
    6581           1 :         if (!ok) {
    6582           0 :                 torture_fail(tctx, "setup dup extents error");
    6583             :         }
    6584             : 
    6585           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6586             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    6587           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6588           1 :         if (!ok) {
    6589           1 :                 smb2_util_close(tree, src_h);
    6590           1 :                 smb2_util_close(tree, dest_h);
    6591           1 :                 talloc_free(tmp_ctx);
    6592           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    6593             :         }
    6594             : 
    6595             :         /* open and close a file, keeping the handle as now a "bogus" handle */
    6596           0 :         ok = test_setup_create_fill(tctx, tree, tmp_ctx, "bogus_file",
    6597             :                                     &bogus_h, 0, SEC_RIGHTS_FILE_ALL,
    6598             :                                     FILE_ATTRIBUTE_NORMAL);
    6599           0 :         torture_assert(tctx, ok, "bogus file create fill");
    6600           0 :         smb2_util_close(tree, bogus_h);
    6601             : 
    6602             :         /* bogus dest file handle */
    6603           0 :         ioctl.smb2.in.file.handle = bogus_h;
    6604             : 
    6605           0 :         dup_ext_buf.source_off = 0;
    6606           0 :         dup_ext_buf.target_off = 0;
    6607           0 :         dup_ext_buf.byte_count = 32768;
    6608             : 
    6609           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6610             :                                        &dup_ext_buf,
    6611             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6612           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6613             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6614             : 
    6615           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6616           0 :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_CLOSED,
    6617             :                                       "FSCTL_DUP_EXTENTS_TO_FILE");
    6618             : 
    6619           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
    6620           0 :         if (!ok) {
    6621           0 :                 torture_fail(tctx, "inconsistent file data");
    6622             :         }
    6623           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    6624           0 :         if (!ok) {
    6625           0 :                 torture_fail(tctx, "inconsistent file data");
    6626             :         }
    6627             : 
    6628             :         /* reinstate dest, add bogus src file handle */
    6629           0 :         ioctl.smb2.in.file.handle = dest_h;
    6630           0 :         smb2_push_handle(dup_ext_buf.source_fid, &bogus_h);
    6631             : 
    6632           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6633             :                                        &dup_ext_buf,
    6634             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6635           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6636             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6637             : 
    6638           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6639           0 :         torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_HANDLE,
    6640             :                                       "FSCTL_DUP_EXTENTS_TO_FILE");
    6641             : 
    6642           0 :         ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
    6643           0 :         if (!ok) {
    6644           0 :                 torture_fail(tctx, "inconsistent file data");
    6645             :         }
    6646           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    6647           0 :         if (!ok) {
    6648           0 :                 torture_fail(tctx, "inconsistent file data");
    6649             :         }
    6650             : 
    6651           0 :         smb2_util_close(tree, src_h);
    6652           0 :         smb2_util_close(tree, dest_h);
    6653           0 :         talloc_free(tmp_ctx);
    6654           0 :         return true;
    6655             : }
    6656             : 
    6657           1 : static bool test_ioctl_dup_extents_src_lck(struct torture_context *tctx,
    6658             :                                            struct smb2_tree *tree)
    6659             : {
    6660             :         struct smb2_handle src_h;
    6661             :         struct smb2_handle src_h2;
    6662             :         struct smb2_handle dest_h;
    6663             :         NTSTATUS status;
    6664             :         union smb_ioctl ioctl;
    6665           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6666             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6667             :         enum ndr_err_code ndr_ret;
    6668             :         bool ok;
    6669             :         struct smb2_lock lck;
    6670             :         struct smb2_lock_element el[1];
    6671             : 
    6672           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6673             :                                     &src_h, 32768, /* fill 32768 byte src file */
    6674             :                                     SEC_RIGHTS_FILE_ALL,
    6675             :                                     &dest_h, 0,
    6676             :                                     SEC_RIGHTS_FILE_ALL,
    6677             :                                     &dup_ext_buf,
    6678             :                                     &ioctl);
    6679           1 :         if (!ok) {
    6680           0 :                 torture_fail(tctx, "setup dup extents error");
    6681             :         }
    6682             : 
    6683           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6684             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    6685           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6686           1 :         if (!ok) {
    6687           1 :                 smb2_util_close(tree, src_h);
    6688           1 :                 smb2_util_close(tree, dest_h);
    6689           1 :                 talloc_free(tmp_ctx);
    6690           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    6691             :         }
    6692             : 
    6693             :         /* dest pattern is different to src */
    6694           0 :         ok = write_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 32768);
    6695           0 :         torture_assert(tctx, ok, "write pattern");
    6696             : 
    6697             :         /* setup dup ext req, values used for locking */
    6698           0 :         dup_ext_buf.source_off = 0;
    6699           0 :         dup_ext_buf.target_off = 0;
    6700           0 :         dup_ext_buf.byte_count = 32768;
    6701             : 
    6702             :         /* open and lock the dup extents src file */
    6703           0 :         status = torture_smb2_testfile(tree, FNAME, &src_h2);
    6704           0 :         torture_assert_ntstatus_ok(tctx, status, "2nd src open");
    6705             : 
    6706           0 :         lck.in.lock_count       = 0x0001;
    6707           0 :         lck.in.lock_sequence    = 0x00000000;
    6708           0 :         lck.in.file.handle      = src_h2;
    6709           0 :         lck.in.locks            = el;
    6710           0 :         el[0].offset            = dup_ext_buf.source_off;
    6711           0 :         el[0].length            = dup_ext_buf.byte_count;
    6712           0 :         el[0].reserved          = 0;
    6713           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    6714             : 
    6715           0 :         status = smb2_lock(tree, &lck);
    6716           0 :         torture_assert_ntstatus_ok(tctx, status, "lock");
    6717             : 
    6718           0 :         status = smb2_util_write(tree, src_h,
    6719             :                                  "conflicted", 0, sizeof("conflicted"));
    6720           0 :         torture_assert_ntstatus_equal(tctx, status,
    6721             :                                 NT_STATUS_FILE_LOCK_CONFLICT, "file write");
    6722             : 
    6723           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6724             :                                        &dup_ext_buf,
    6725             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6726           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6727             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6728             : 
    6729             :         /*
    6730             :          * In contrast to copy-chunk, dup extents doesn't cause a lock conflict
    6731             :          * here.
    6732             :          */
    6733           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6734           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    6735             : 
    6736           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    6737           0 :         if (!ok) {
    6738           0 :                 torture_fail(tctx, "inconsistent file data");
    6739             :         }
    6740             : 
    6741           0 :         lck.in.lock_count       = 0x0001;
    6742           0 :         lck.in.lock_sequence    = 0x00000001;
    6743           0 :         lck.in.file.handle      = src_h2;
    6744           0 :         lck.in.locks            = el;
    6745           0 :         el[0].offset            = dup_ext_buf.source_off;
    6746           0 :         el[0].length            = dup_ext_buf.byte_count;
    6747           0 :         el[0].reserved          = 0;
    6748           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    6749           0 :         status = smb2_lock(tree, &lck);
    6750           0 :         torture_assert_ntstatus_ok(tctx, status, "unlock");
    6751             : 
    6752           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6753           0 :         torture_assert_ntstatus_ok(tctx, status,
    6754             :                                    "FSCTL_DUP_EXTENTS_TO_FILE unlocked");
    6755             : 
    6756           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    6757           0 :         if (!ok) {
    6758           0 :                 torture_fail(tctx, "inconsistent file data");
    6759             :         }
    6760             : 
    6761           0 :         smb2_util_close(tree, src_h2);
    6762           0 :         smb2_util_close(tree, src_h);
    6763           0 :         smb2_util_close(tree, dest_h);
    6764           0 :         talloc_free(tmp_ctx);
    6765           0 :         return true;
    6766             : }
    6767             : 
    6768           1 : static bool test_ioctl_dup_extents_dest_lck(struct torture_context *tctx,
    6769             :                                             struct smb2_tree *tree)
    6770             : {
    6771             :         struct smb2_handle src_h;
    6772             :         struct smb2_handle dest_h;
    6773             :         struct smb2_handle dest_h2;
    6774             :         NTSTATUS status;
    6775             :         union smb_ioctl ioctl;
    6776           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6777             :         struct fsctl_dup_extents_to_file dup_ext_buf;
    6778             :         enum ndr_err_code ndr_ret;
    6779             :         bool ok;
    6780             :         struct smb2_lock lck;
    6781             :         struct smb2_lock_element el[1];
    6782             : 
    6783           1 :         ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
    6784             :                                     &src_h, 32768, /* fill 32768 byte src file */
    6785             :                                     SEC_RIGHTS_FILE_ALL,
    6786             :                                     &dest_h, 0,
    6787             :                                     SEC_RIGHTS_FILE_ALL,
    6788             :                                     &dup_ext_buf,
    6789             :                                     &ioctl);
    6790           1 :         if (!ok) {
    6791           0 :                 torture_fail(tctx, "setup dup extents error");
    6792             :         }
    6793             : 
    6794           1 :         status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
    6795             :                                          FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
    6796           1 :         torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
    6797           1 :         if (!ok) {
    6798           1 :                 smb2_util_close(tree, src_h);
    6799           1 :                 smb2_util_close(tree, dest_h);
    6800           1 :                 talloc_free(tmp_ctx);
    6801           1 :                 torture_skip(tctx, "block refcounting not supported\n");
    6802             :         }
    6803             : 
    6804             :         /* dest pattern is different to src */
    6805           0 :         ok = write_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 32768);
    6806           0 :         torture_assert(tctx, ok, "write pattern");
    6807             : 
    6808             :         /* setup dup ext req, values used for locking */
    6809           0 :         dup_ext_buf.source_off = 0;
    6810           0 :         dup_ext_buf.target_off = 0;
    6811           0 :         dup_ext_buf.byte_count = 32768;
    6812             : 
    6813             :         /* open and lock the dup extents dest file */
    6814           0 :         status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
    6815           0 :         torture_assert_ntstatus_ok(tctx, status, "2nd src open");
    6816             : 
    6817           0 :         lck.in.lock_count       = 0x0001;
    6818           0 :         lck.in.lock_sequence    = 0x00000000;
    6819           0 :         lck.in.file.handle      = dest_h2;
    6820           0 :         lck.in.locks            = el;
    6821           0 :         el[0].offset            = dup_ext_buf.source_off;
    6822           0 :         el[0].length            = dup_ext_buf.byte_count;
    6823           0 :         el[0].reserved          = 0;
    6824           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    6825             : 
    6826           0 :         status = smb2_lock(tree, &lck);
    6827           0 :         torture_assert_ntstatus_ok(tctx, status, "lock");
    6828             : 
    6829           0 :         status = smb2_util_write(tree, dest_h,
    6830             :                                  "conflicted", 0, sizeof("conflicted"));
    6831           0 :         torture_assert_ntstatus_equal(tctx, status,
    6832             :                                 NT_STATUS_FILE_LOCK_CONFLICT, "file write");
    6833             : 
    6834           0 :         ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
    6835             :                                        &dup_ext_buf,
    6836             :                        (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
    6837           0 :         torture_assert_ndr_success(tctx, ndr_ret,
    6838             :                                    "ndr_push_fsctl_dup_extents_to_file");
    6839             : 
    6840             :         /*
    6841             :          * In contrast to copy-chunk, dup extents doesn't cause a lock conflict
    6842             :          * here.
    6843             :          */
    6844           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6845           0 :         torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
    6846             : 
    6847           0 :         lck.in.lock_count       = 0x0001;
    6848           0 :         lck.in.lock_sequence    = 0x00000001;
    6849           0 :         lck.in.file.handle      = dest_h2;
    6850           0 :         lck.in.locks            = el;
    6851           0 :         el[0].offset            = dup_ext_buf.source_off;
    6852           0 :         el[0].length            = dup_ext_buf.byte_count;
    6853           0 :         el[0].reserved          = 0;
    6854           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    6855           0 :         status = smb2_lock(tree, &lck);
    6856           0 :         torture_assert_ntstatus_ok(tctx, status, "unlock");
    6857             : 
    6858           0 :         status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
    6859           0 :         torture_assert_ntstatus_ok(tctx, status,
    6860             :                                    "FSCTL_DUP_EXTENTS_TO_FILE unlocked");
    6861             : 
    6862           0 :         ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
    6863           0 :         if (!ok) {
    6864           0 :                 torture_fail(tctx, "inconsistent file data");
    6865             :         }
    6866             : 
    6867           0 :         smb2_util_close(tree, src_h);
    6868           0 :         smb2_util_close(tree, dest_h);
    6869           0 :         smb2_util_close(tree, dest_h2);
    6870           0 :         talloc_free(tmp_ctx);
    6871           0 :         return true;
    6872             : }
    6873             : 
    6874             : /*
    6875             :    basic regression test for BUG 14607
    6876             :    https://bugzilla.samba.org/show_bug.cgi?id=14607
    6877             : */
    6878           1 : static bool test_ioctl_bug14607(struct torture_context *torture,
    6879             :                                 struct smb2_tree *tree)
    6880             : {
    6881           1 :         TALLOC_CTX *tmp_ctx = talloc_new(tree);
    6882             :         uint32_t timeout_msec;
    6883             :         NTSTATUS status;
    6884           1 :         DATA_BLOB out_input_buffer = data_blob_null;
    6885           1 :         DATA_BLOB out_output_buffer = data_blob_null;
    6886             : 
    6887           1 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
    6888             : 
    6889           2 :         status = smb2cli_ioctl(tree->session->transport->conn,
    6890             :                                timeout_msec,
    6891           1 :                                tree->session->smbXcli,
    6892             :                                tree->smbXcli,
    6893             :                                UINT64_MAX, /* in_fid_persistent */
    6894             :                                UINT64_MAX, /* in_fid_volatile */
    6895             :                                FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8,
    6896             :                                0, /* in_max_input_length */
    6897             :                                NULL, /* in_input_buffer */
    6898             :                                1, /* in_max_output_length */
    6899             :                                NULL, /* in_output_buffer */
    6900             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    6901             :                                tmp_ctx,
    6902             :                                &out_input_buffer,
    6903             :                                &out_output_buffer);
    6904           2 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
    6905           2 :             NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
    6906           2 :             NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) ||
    6907           1 :             NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST))
    6908             :         {
    6909           1 :                 torture_comment(torture,
    6910             :                                 "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8: %s\n",
    6911             :                                 nt_errstr(status));
    6912           1 :                 torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8\n");
    6913             :         }
    6914           0 :         torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8");
    6915             : 
    6916           0 :         torture_assert_int_equal(torture, out_output_buffer.length, 1,
    6917             :                                  "output length");
    6918           0 :         torture_assert_int_equal(torture, out_output_buffer.data[0], 8,
    6919             :                                  "output buffer byte should be 8");
    6920             : 
    6921           0 :         talloc_free(tmp_ctx);
    6922           0 :         return true;
    6923             : }
    6924             : 
    6925             : /*
    6926             :    basic regression test for BUG 14769
    6927             :    https://bugzilla.samba.org/show_bug.cgi?id=14769
    6928             : */
    6929           1 : static bool test_ioctl_bug14769(struct torture_context *torture,
    6930             :                                 struct smb2_tree *tree)
    6931             : {
    6932             :         NTSTATUS status;
    6933           1 :         const char *fname = "bug14769";
    6934           1 :         bool ret = false;
    6935             :         struct smb2_handle h;
    6936             :         struct smb2_ioctl ioctl;
    6937             :         struct smb2_close cl;
    6938           1 :         struct smb2_request *smb2arr[2] = { 0 };
    6939           1 :         uint8_t tosend_msec = 200;
    6940           1 :         DATA_BLOB send_buf = { &tosend_msec, 1 };
    6941             : 
    6942             :         /* Create a test file. */
    6943           1 :         smb2_util_unlink(tree, fname);
    6944           1 :         status = torture_smb2_testfile(tree, fname, &h);
    6945           1 :         torture_assert_ntstatus_ok(torture, status, "create bug14769");
    6946             : 
    6947             :         /*
    6948             :          * Send (not receive) the FSCTL.
    6949             :          * This should go async with a wait time of 200 msec.
    6950             :          */
    6951           1 :         ZERO_STRUCT(ioctl);
    6952           1 :         ioctl.in.file.handle = h;
    6953           1 :         ioctl.in.function = FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP;
    6954           1 :         ioctl.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
    6955           1 :         ioctl.in.out = send_buf;
    6956             : 
    6957           1 :         smb2arr[0] = smb2_ioctl_send(tree, &ioctl);
    6958           1 :         torture_assert_goto(torture,
    6959             :                             smb2arr[0] != NULL,
    6960             :                             ret,
    6961             :                             done,
    6962             :                             "smb2_ioctl_send failed\n");
    6963             :         /* Immediately send the close. */
    6964           1 :         ZERO_STRUCT(cl);
    6965           1 :         cl.in.file.handle = h;
    6966           1 :         cl.in.flags = 0;
    6967           1 :         smb2arr[1] = smb2_close_send(tree, &cl);
    6968           1 :         torture_assert_goto(torture,
    6969             :                             smb2arr[1] != NULL,
    6970             :                             ret,
    6971             :                             done,
    6972             :                             "smb2_close_send failed\n");
    6973             : 
    6974             :         /* Now get the FSCTL reply. */
    6975             :         /*
    6976             :          * If we suffer from bug #14769 this will fail as
    6977             :          * the ioctl will return with NT_STATUS_FILE_CLOSED,
    6978             :          * as the close will have closed the handle without
    6979             :          * waiting for the ioctl to complete. The server shouldn't
    6980             :          * complete the close until the ioctl finishes.
    6981             :          */
    6982           1 :         status = smb2_ioctl_recv(smb2arr[0], tree, &ioctl);
    6983           1 :         torture_assert_ntstatus_ok_goto(torture,
    6984             :                                         status,
    6985             :                                         ret,
    6986             :                                         done,
    6987             :                                         "smb2_ioctl_recv failed\n");
    6988             : 
    6989             :         /* Followed by the close reply. */
    6990           0 :         status = smb2_close_recv(smb2arr[1], &cl);
    6991           0 :         torture_assert_ntstatus_ok_goto(torture,
    6992             :                                         status,
    6993             :                                         ret,
    6994             :                                         done,
    6995             :                                         "smb2_ioctl_close failed\n");
    6996           0 :         ret = true;
    6997             : 
    6998           1 :   done:
    6999           1 :         smb2_util_unlink(tree, fname);
    7000           1 :         return ret;
    7001             : }
    7002             : 
    7003             : /*
    7004             :    basic regression test for BUG 14788,
    7005             :    with FSCTL_VALIDATE_NEGOTIATE_INFO
    7006             :    https://bugzilla.samba.org/show_bug.cgi?id=14788
    7007             : */
    7008           1 : static bool test_ioctl_bug14788_VALIDATE_NEGOTIATE(struct torture_context *torture,
    7009             :                                 struct smb2_tree *tree0)
    7010             : {
    7011           1 :         const char *host = torture_setting_string(torture, "host", NULL);
    7012           1 :         const char *share = torture_setting_string(torture, "share", NULL);
    7013           1 :         const char *noperm_share = torture_setting_string(torture, "noperm_share", "noperm");
    7014           1 :         struct smb2_transport *transport0 = tree0->session->transport;
    7015             :         struct smbcli_options options;
    7016           1 :         struct smb2_transport *transport = NULL;
    7017           1 :         struct smb2_tree *tree = NULL;
    7018           1 :         struct smb2_session *session = NULL;
    7019           1 :         uint16_t noperm_flags = 0;
    7020           1 :         const char *noperm_unc = NULL;
    7021           1 :         struct smb2_tree *noperm_tree = NULL;
    7022             :         uint32_t timeout_msec;
    7023           1 :         struct tevent_req *subreq = NULL;
    7024           1 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    7025             :         NTSTATUS status;
    7026             : 
    7027           1 :         if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
    7028           1 :                 torture_skip(torture, "Can't test without SMB 3 support");
    7029             :         }
    7030             : 
    7031           0 :         options = transport0->options;
    7032           0 :         options.client_guid = GUID_random();
    7033           0 :         options.min_protocol = PROTOCOL_SMB3_00;
    7034           0 :         options.max_protocol = PROTOCOL_SMB3_02;
    7035             : 
    7036           0 :         status = smb2_connect(torture,
    7037             :                               host,
    7038             :                               lpcfg_smb_ports(torture->lp_ctx),
    7039             :                               share,
    7040             :                               lpcfg_resolve_context(torture->lp_ctx),
    7041             :                               credentials,
    7042             :                               &tree,
    7043             :                               torture->ev,
    7044             :                               &options,
    7045             :                               lpcfg_socket_options(torture->lp_ctx),
    7046             :                               lpcfg_gensec_settings(torture, torture->lp_ctx)
    7047             :                               );
    7048           0 :         torture_assert_ntstatus_ok(torture, status, "smb2_connect options failed");
    7049           0 :         session = tree->session;
    7050           0 :         transport = session->transport;
    7051             : 
    7052           0 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
    7053             : 
    7054           0 :         subreq = smb2cli_validate_negotiate_info_send(torture,
    7055             :                                                       torture->ev,
    7056             :                                                       transport->conn,
    7057             :                                                       timeout_msec,
    7058             :                                                       session->smbXcli,
    7059           0 :                                                       tree->smbXcli);
    7060           0 :         torture_assert(torture,
    7061             :                        tevent_req_poll_ntstatus(subreq, torture->ev, &status),
    7062             :                        "tevent_req_poll_ntstatus");
    7063           0 :         status = smb2cli_validate_negotiate_info_recv(subreq);
    7064           0 :         torture_assert_ntstatus_ok(torture, status, "smb2cli_validate_negotiate_info");
    7065             : 
    7066           0 :         noperm_unc = talloc_asprintf(torture, "\\\\%s\\%s", host, noperm_share);
    7067           0 :         torture_assert(torture, noperm_unc != NULL, "talloc_asprintf");
    7068             : 
    7069           0 :         noperm_tree = smb2_tree_init(session, torture, false);
    7070           0 :         torture_assert(torture, noperm_tree != NULL, "smb2_tree_init");
    7071             : 
    7072           0 :         status = smb2cli_raw_tcon(transport->conn,
    7073             :                                   SMB2_HDR_FLAG_SIGNED,
    7074             :                                   0, /* clear_flags */
    7075             :                                   timeout_msec,
    7076             :                                   session->smbXcli,
    7077             :                                   noperm_tree->smbXcli,
    7078             :                                   noperm_flags,
    7079             :                                   noperm_unc);
    7080           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_BAD_NETWORK_NAME)) {
    7081           0 :                 torture_skip(torture, talloc_asprintf(torture,
    7082             :                              "noperm_unc[%s] %s",
    7083             :                              noperm_unc, nt_errstr(status)));
    7084             :         }
    7085           0 :         torture_assert_ntstatus_ok(torture, status,
    7086             :                                    talloc_asprintf(torture,
    7087             :                                    "smb2cli_tcon(%s)",
    7088             :                                    noperm_unc));
    7089             : 
    7090           0 :         subreq = smb2cli_validate_negotiate_info_send(torture,
    7091             :                                                       torture->ev,
    7092             :                                                       transport->conn,
    7093             :                                                       timeout_msec,
    7094             :                                                       session->smbXcli,
    7095             :                                                       noperm_tree->smbXcli);
    7096           0 :         torture_assert(torture,
    7097             :                        tevent_req_poll_ntstatus(subreq, torture->ev, &status),
    7098             :                        "tevent_req_poll_ntstatus");
    7099           0 :         status = smb2cli_validate_negotiate_info_recv(subreq);
    7100           0 :         torture_assert_ntstatus_ok(torture, status, "smb2cli_validate_negotiate_info noperm");
    7101             : 
    7102           0 :         return true;
    7103             : }
    7104             : 
    7105             : /*
    7106             :    basic regression test for BUG 14788,
    7107             :    with FSCTL_QUERY_NETWORK_INTERFACE_INFO
    7108             :    https://bugzilla.samba.org/show_bug.cgi?id=14788
    7109             : */
    7110           1 : static bool test_ioctl_bug14788_NETWORK_INTERFACE(struct torture_context *torture,
    7111             :                                 struct smb2_tree *tree0)
    7112             : {
    7113           1 :         const char *host = torture_setting_string(torture, "host", NULL);
    7114           1 :         const char *share = torture_setting_string(torture, "share", NULL);
    7115           1 :         const char *noperm_share = torture_setting_string(torture, "noperm_share", "noperm");
    7116           1 :         struct smb2_transport *transport0 = tree0->session->transport;
    7117             :         struct smbcli_options options;
    7118           1 :         struct smb2_transport *transport = NULL;
    7119           1 :         struct smb2_tree *tree = NULL;
    7120           1 :         struct smb2_session *session = NULL;
    7121           1 :         uint16_t noperm_flags = 0;
    7122           1 :         const char *noperm_unc = NULL;
    7123           1 :         struct smb2_tree *noperm_tree = NULL;
    7124             :         uint32_t timeout_msec;
    7125           1 :         DATA_BLOB out_input_buffer = data_blob_null;
    7126           1 :         DATA_BLOB out_output_buffer = data_blob_null;
    7127           1 :         struct cli_credentials *credentials = samba_cmdline_get_creds();
    7128             :         NTSTATUS status;
    7129             : 
    7130           1 :         if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
    7131           1 :                 torture_skip(torture, "Can't test without SMB 3 support");
    7132             :         }
    7133             : 
    7134           0 :         options = transport0->options;
    7135           0 :         options.client_guid = GUID_random();
    7136           0 :         options.min_protocol = PROTOCOL_SMB3_00;
    7137           0 :         options.max_protocol = PROTOCOL_SMB3_02;
    7138             : 
    7139           0 :         status = smb2_connect(torture,
    7140             :                               host,
    7141             :                               lpcfg_smb_ports(torture->lp_ctx),
    7142             :                               share,
    7143             :                               lpcfg_resolve_context(torture->lp_ctx),
    7144             :                               credentials,
    7145             :                               &tree,
    7146             :                               torture->ev,
    7147             :                               &options,
    7148             :                               lpcfg_socket_options(torture->lp_ctx),
    7149             :                               lpcfg_gensec_settings(torture, torture->lp_ctx)
    7150             :                               );
    7151           0 :         torture_assert_ntstatus_ok(torture, status, "smb2_connect options failed");
    7152           0 :         session = tree->session;
    7153           0 :         transport = session->transport;
    7154             : 
    7155           0 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
    7156             : 
    7157             :         /*
    7158             :          * A valid FSCTL_QUERY_NETWORK_INTERFACE_INFO
    7159             :          */
    7160           0 :         status = smb2cli_ioctl(transport->conn,
    7161             :                                timeout_msec,
    7162             :                                session->smbXcli,
    7163           0 :                                tree->smbXcli,
    7164             :                                UINT64_MAX, /* in_fid_persistent */
    7165             :                                UINT64_MAX, /* in_fid_volatile */
    7166             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7167             :                                0, /* in_max_input_length */
    7168             :                                NULL, /* in_input_buffer */
    7169             :                                UINT16_MAX, /* in_max_output_length */
    7170             :                                NULL, /* in_output_buffer */
    7171             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7172             :                                torture,
    7173             :                                &out_input_buffer,
    7174             :                                &out_output_buffer);
    7175           0 :         torture_assert_ntstatus_ok(torture, status,
    7176             :                                    "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7177             : 
    7178             :         /*
    7179             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7180             :          * with file_id_* is being UINT64_MAX and
    7181             :          * in_max_output_length = 1.
    7182             :          *
    7183             :          * This demonstrates NT_STATUS_BUFFER_TOO_SMALL
    7184             :          * if the server is not able to return the
    7185             :          * whole response buffer to the client.
    7186             :          */
    7187           0 :         status = smb2cli_ioctl(transport->conn,
    7188             :                                timeout_msec,
    7189             :                                session->smbXcli,
    7190           0 :                                tree->smbXcli,
    7191             :                                UINT64_MAX, /* in_fid_persistent */
    7192             :                                UINT64_MAX, /* in_fid_volatile */
    7193             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7194             :                                0, /* in_max_input_length */
    7195             :                                NULL, /* in_input_buffer */
    7196             :                                1, /* in_max_output_length */
    7197             :                                NULL, /* in_output_buffer */
    7198             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7199             :                                torture,
    7200             :                                &out_input_buffer,
    7201             :                                &out_output_buffer);
    7202           0 :         torture_assert_ntstatus_equal(torture, status,
    7203             :                                       NT_STATUS_BUFFER_TOO_SMALL,
    7204             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7205             : 
    7206             :         /*
    7207             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7208             :          * with file_id_* not being UINT64_MAX.
    7209             :          *
    7210             :          * This gives INVALID_PARAMETER instead
    7211             :          * of FILE_CLOSED.
    7212             :          */
    7213           0 :         status = smb2cli_ioctl(transport->conn,
    7214             :                                timeout_msec,
    7215             :                                session->smbXcli,
    7216           0 :                                tree->smbXcli,
    7217             :                                INT64_MAX, /* in_fid_persistent */
    7218             :                                INT64_MAX, /* in_fid_volatile */
    7219             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7220             :                                0, /* in_max_input_length */
    7221             :                                NULL, /* in_input_buffer */
    7222             :                                UINT16_MAX, /* in_max_output_length */
    7223             :                                NULL, /* in_output_buffer */
    7224             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7225             :                                torture,
    7226             :                                &out_input_buffer,
    7227             :                                &out_output_buffer);
    7228           0 :         torture_assert_ntstatus_equal(torture, status,
    7229             :                                       NT_STATUS_INVALID_PARAMETER,
    7230             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7231             : 
    7232             :         /*
    7233             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7234             :          * with file_id_* not being UINT64_MAX and
    7235             :          * in_max_output_length = 1.
    7236             :          *
    7237             :          * This proves INVALID_PARAMETER instead
    7238             :          * of BUFFER_TOO_SMALL.
    7239             :          */
    7240           0 :         status = smb2cli_ioctl(transport->conn,
    7241             :                                timeout_msec,
    7242             :                                session->smbXcli,
    7243           0 :                                tree->smbXcli,
    7244             :                                INT64_MAX, /* in_fid_persistent */
    7245             :                                INT64_MAX, /* in_fid_volatile */
    7246             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7247             :                                0, /* in_max_input_length */
    7248             :                                NULL, /* in_input_buffer */
    7249             :                                1, /* in_max_output_length */
    7250             :                                NULL, /* in_output_buffer */
    7251             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7252             :                                torture,
    7253             :                                &out_input_buffer,
    7254             :                                &out_output_buffer);
    7255           0 :         torture_assert_ntstatus_equal(torture, status,
    7256             :                                       NT_STATUS_INVALID_PARAMETER,
    7257             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7258             : 
    7259           0 :         noperm_unc = talloc_asprintf(torture, "\\\\%s\\%s", host, noperm_share);
    7260           0 :         torture_assert(torture, noperm_unc != NULL, "talloc_asprintf");
    7261             : 
    7262           0 :         noperm_tree = smb2_tree_init(session, torture, false);
    7263           0 :         torture_assert(torture, noperm_tree != NULL, "smb2_tree_init");
    7264             : 
    7265           0 :         status = smb2cli_raw_tcon(transport->conn,
    7266             :                                   SMB2_HDR_FLAG_SIGNED,
    7267             :                                   0, /* clear_flags */
    7268             :                                   timeout_msec,
    7269             :                                   session->smbXcli,
    7270             :                                   noperm_tree->smbXcli,
    7271             :                                   noperm_flags,
    7272             :                                   noperm_unc);
    7273           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_BAD_NETWORK_NAME)) {
    7274           0 :                 torture_skip(torture, talloc_asprintf(torture,
    7275             :                              "noperm_unc[%s] %s",
    7276             :                              noperm_unc, nt_errstr(status)));
    7277             :         }
    7278           0 :         torture_assert_ntstatus_ok(torture, status,
    7279             :                                    talloc_asprintf(torture,
    7280             :                                    "smb2cli_tcon(%s)",
    7281             :                                    noperm_unc));
    7282             : 
    7283             :         /*
    7284             :          * A valid FSCTL_QUERY_NETWORK_INTERFACE_INFO
    7285             :          */
    7286           0 :         status = smb2cli_ioctl(transport->conn,
    7287             :                                timeout_msec,
    7288             :                                session->smbXcli,
    7289             :                                noperm_tree->smbXcli,
    7290             :                                UINT64_MAX, /* in_fid_persistent */
    7291             :                                UINT64_MAX, /* in_fid_volatile */
    7292             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7293             :                                0, /* in_max_input_length */
    7294             :                                NULL, /* in_input_buffer */
    7295             :                                UINT16_MAX, /* in_max_output_length */
    7296             :                                NULL, /* in_output_buffer */
    7297             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7298             :                                torture,
    7299             :                                &out_input_buffer,
    7300             :                                &out_output_buffer);
    7301           0 :         torture_assert_ntstatus_ok(torture, status,
    7302             :                                    "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7303             : 
    7304             :         /*
    7305             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7306             :          * with file_id_* is being UINT64_MAX and
    7307             :          * in_max_output_length = 1.
    7308             :          *
    7309             :          * This demonstrates NT_STATUS_BUFFER_TOO_SMALL
    7310             :          * if the server is not able to return the
    7311             :          * whole response buffer to the client.
    7312             :          */
    7313           0 :         status = smb2cli_ioctl(transport->conn,
    7314             :                                timeout_msec,
    7315             :                                session->smbXcli,
    7316             :                                noperm_tree->smbXcli,
    7317             :                                UINT64_MAX, /* in_fid_persistent */
    7318             :                                UINT64_MAX, /* in_fid_volatile */
    7319             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7320             :                                0, /* in_max_input_length */
    7321             :                                NULL, /* in_input_buffer */
    7322             :                                1, /* in_max_output_length */
    7323             :                                NULL, /* in_output_buffer */
    7324             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7325             :                                torture,
    7326             :                                &out_input_buffer,
    7327             :                                &out_output_buffer);
    7328           0 :         torture_assert_ntstatus_equal(torture, status,
    7329             :                                       NT_STATUS_BUFFER_TOO_SMALL,
    7330             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7331             : 
    7332             :         /*
    7333             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7334             :          * with file_id_* not being UINT64_MAX.
    7335             :          *
    7336             :          * This gives INVALID_PARAMETER instead
    7337             :          * of FILE_CLOSED.
    7338             :          */
    7339           0 :         status = smb2cli_ioctl(transport->conn,
    7340             :                                timeout_msec,
    7341             :                                session->smbXcli,
    7342             :                                noperm_tree->smbXcli,
    7343             :                                INT64_MAX, /* in_fid_persistent */
    7344             :                                INT64_MAX, /* in_fid_volatile */
    7345             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7346             :                                0, /* in_max_input_length */
    7347             :                                NULL, /* in_input_buffer */
    7348             :                                UINT16_MAX, /* in_max_output_length */
    7349             :                                NULL, /* in_output_buffer */
    7350             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7351             :                                torture,
    7352             :                                &out_input_buffer,
    7353             :                                &out_output_buffer);
    7354           0 :         torture_assert_ntstatus_equal(torture, status,
    7355             :                                       NT_STATUS_INVALID_PARAMETER,
    7356             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7357             : 
    7358             :         /*
    7359             :          * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7360             :          * with file_id_* not being UINT64_MAX and
    7361             :          * in_max_output_length = 1.
    7362             :          *
    7363             :          * This proves INVALID_PARAMETER instead
    7364             :          * of BUFFER_TOO_SMALL.
    7365             :          */
    7366           0 :         status = smb2cli_ioctl(transport->conn,
    7367             :                                timeout_msec,
    7368             :                                session->smbXcli,
    7369             :                                noperm_tree->smbXcli,
    7370             :                                INT64_MAX, /* in_fid_persistent */
    7371             :                                INT64_MAX, /* in_fid_volatile */
    7372             :                                FSCTL_QUERY_NETWORK_INTERFACE_INFO,
    7373             :                                0, /* in_max_input_length */
    7374             :                                NULL, /* in_input_buffer */
    7375             :                                1, /* in_max_output_length */
    7376             :                                NULL, /* in_output_buffer */
    7377             :                                SMB2_IOCTL_FLAG_IS_FSCTL,
    7378             :                                torture,
    7379             :                                &out_input_buffer,
    7380             :                                &out_output_buffer);
    7381           0 :         torture_assert_ntstatus_equal(torture, status,
    7382             :                                       NT_STATUS_INVALID_PARAMETER,
    7383             :                                       "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
    7384             : 
    7385           0 :         return true;
    7386             : }
    7387             : 
    7388             : /*
    7389             :  * testing of SMB2 ioctls
    7390             :  */
    7391         964 : struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
    7392             : {
    7393         964 :         struct torture_suite *suite = torture_suite_create(ctx, "ioctl");
    7394         964 :         struct torture_suite *bug14788 = torture_suite_create(ctx, "bug14788");
    7395             : 
    7396         964 :         torture_suite_add_1smb2_test(suite, "shadow_copy",
    7397             :                                      test_ioctl_get_shadow_copy);
    7398         964 :         torture_suite_add_1smb2_test(suite, "req_resume_key",
    7399             :                                      test_ioctl_req_resume_key);
    7400         964 :         torture_suite_add_1smb2_test(suite, "req_two_resume_keys",
    7401             :                                      test_ioctl_req_two_resume_keys);
    7402         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_simple",
    7403             :                                      test_ioctl_copy_chunk_simple);
    7404         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_multi",
    7405             :                                      test_ioctl_copy_chunk_multi);
    7406         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_tiny",
    7407             :                                      test_ioctl_copy_chunk_tiny);
    7408         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_overwrite",
    7409             :                                      test_ioctl_copy_chunk_over);
    7410         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_append",
    7411             :                                      test_ioctl_copy_chunk_append);
    7412         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_limits",
    7413             :                                      test_ioctl_copy_chunk_limits);
    7414         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_src_lock",
    7415             :                                      test_ioctl_copy_chunk_src_lck);
    7416         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_dest_lock",
    7417             :                                      test_ioctl_copy_chunk_dest_lck);
    7418         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_bad_key",
    7419             :                                      test_ioctl_copy_chunk_bad_key);
    7420         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest",
    7421             :                                      test_ioctl_copy_chunk_src_is_dest);
    7422         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest_overlap",
    7423             :                                      test_ioctl_copy_chunk_src_is_dest_overlap);
    7424         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_bad_access",
    7425             :                                      test_ioctl_copy_chunk_bad_access);
    7426         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_write_access",
    7427             :                                      test_ioctl_copy_chunk_write_access);
    7428         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_src_exceed",
    7429             :                                      test_ioctl_copy_chunk_src_exceed);
    7430         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_src_exceed_multi",
    7431             :                                      test_ioctl_copy_chunk_src_exceed_multi);
    7432         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_sparse_dest",
    7433             :                                      test_ioctl_copy_chunk_sparse_dest);
    7434         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_max_output_sz",
    7435             :                                      test_ioctl_copy_chunk_max_output_sz);
    7436         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_zero_length",
    7437             :                                      test_ioctl_copy_chunk_zero_length);
    7438         964 :         torture_suite_add_1smb2_test(suite, "copy-chunk streams",
    7439             :                                      test_copy_chunk_streams);
    7440         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares",
    7441             :                                      test_copy_chunk_across_shares);
    7442         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares2",
    7443             :                                      test_copy_chunk_across_shares2);
    7444         964 :         torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares3",
    7445             :                                      test_copy_chunk_across_shares3);
    7446         964 :         torture_suite_add_1smb2_test(suite, "compress_file_flag",
    7447             :                                      test_ioctl_compress_file_flag);
    7448         964 :         torture_suite_add_1smb2_test(suite, "compress_dir_inherit",
    7449             :                                      test_ioctl_compress_dir_inherit);
    7450         964 :         torture_suite_add_1smb2_test(suite, "compress_invalid_format",
    7451             :                                      test_ioctl_compress_invalid_format);
    7452         964 :         torture_suite_add_1smb2_test(suite, "compress_invalid_buf",
    7453             :                                      test_ioctl_compress_invalid_buf);
    7454         964 :         torture_suite_add_1smb2_test(suite, "compress_query_file_attr",
    7455             :                                      test_ioctl_compress_query_file_attr);
    7456         964 :         torture_suite_add_1smb2_test(suite, "compress_create_with_attr",
    7457             :                                      test_ioctl_compress_create_with_attr);
    7458         964 :         torture_suite_add_1smb2_test(suite, "compress_inherit_disable",
    7459             :                                      test_ioctl_compress_inherit_disable);
    7460         964 :         torture_suite_add_1smb2_test(suite, "compress_set_file_attr",
    7461             :                                      test_ioctl_compress_set_file_attr);
    7462         964 :         torture_suite_add_1smb2_test(suite, "compress_perms",
    7463             :                                      test_ioctl_compress_perms);
    7464         964 :         torture_suite_add_1smb2_test(suite, "compress_notsup_get",
    7465             :                                      test_ioctl_compress_notsup_get);
    7466         964 :         torture_suite_add_1smb2_test(suite, "compress_notsup_set",
    7467             :                                      test_ioctl_compress_notsup_set);
    7468         964 :         torture_suite_add_1smb2_test(suite, "network_interface_info",
    7469             :                                      test_ioctl_network_interface_info);
    7470         964 :         torture_suite_add_1smb2_test(suite, "sparse_file_flag",
    7471             :                                      test_ioctl_sparse_file_flag);
    7472         964 :         torture_suite_add_1smb2_test(suite, "sparse_file_attr",
    7473             :                                      test_ioctl_sparse_file_attr);
    7474         964 :         torture_suite_add_1smb2_test(suite, "sparse_dir_flag",
    7475             :                                      test_ioctl_sparse_dir_flag);
    7476         964 :         torture_suite_add_1smb2_test(suite, "sparse_set_nobuf",
    7477             :                                      test_ioctl_sparse_set_nobuf);
    7478         964 :         torture_suite_add_1smb2_test(suite, "sparse_set_oversize",
    7479             :                                      test_ioctl_sparse_set_oversize);
    7480         964 :         torture_suite_add_1smb2_test(suite, "sparse_qar",
    7481             :                                      test_ioctl_sparse_qar);
    7482         964 :         torture_suite_add_1smb2_test(suite, "sparse_qar_malformed",
    7483             :                                      test_ioctl_sparse_qar_malformed);
    7484         964 :         torture_suite_add_1smb2_test(suite, "sparse_punch",
    7485             :                                      test_ioctl_sparse_punch);
    7486         964 :         torture_suite_add_1smb2_test(suite, "sparse_hole_dealloc",
    7487             :                                      test_ioctl_sparse_hole_dealloc);
    7488         964 :         torture_suite_add_1smb2_test(suite, "sparse_compressed",
    7489             :                                      test_ioctl_sparse_compressed);
    7490         964 :         torture_suite_add_1smb2_test(suite, "sparse_copy_chunk",
    7491             :                                      test_ioctl_sparse_copy_chunk);
    7492         964 :         torture_suite_add_1smb2_test(suite, "sparse_punch_invalid",
    7493             :                                      test_ioctl_sparse_punch_invalid);
    7494         964 :         torture_suite_add_1smb2_test(suite, "sparse_perms",
    7495             :                                      test_ioctl_sparse_perms);
    7496         964 :         torture_suite_add_1smb2_test(suite, "sparse_lock",
    7497             :                                      test_ioctl_sparse_lck);
    7498         964 :         torture_suite_add_1smb2_test(suite, "sparse_qar_ob1",
    7499             :                                      test_ioctl_sparse_qar_ob1);
    7500         964 :         torture_suite_add_1smb2_test(suite, "sparse_qar_multi",
    7501             :                                      test_ioctl_sparse_qar_multi);
    7502         964 :         torture_suite_add_1smb2_test(suite, "sparse_qar_overflow",
    7503             :                                      test_ioctl_sparse_qar_overflow);
    7504         964 :         torture_suite_add_1smb2_test(suite, "trim_simple",
    7505             :                                      test_ioctl_trim_simple);
    7506         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_simple",
    7507             :                                      test_ioctl_dup_extents_simple);
    7508         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_len_beyond_dest",
    7509             :                                      test_ioctl_dup_extents_len_beyond_dest);
    7510         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_len_beyond_src",
    7511             :                                      test_ioctl_dup_extents_len_beyond_src);
    7512         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_len_zero",
    7513             :                                      test_ioctl_dup_extents_len_zero);
    7514         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_sparse_src",
    7515             :                                      test_ioctl_dup_extents_sparse_src);
    7516         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_sparse_dest",
    7517             :                                      test_ioctl_dup_extents_sparse_dest);
    7518         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_sparse_both",
    7519             :                                      test_ioctl_dup_extents_sparse_both);
    7520         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_src_is_dest",
    7521             :                                      test_ioctl_dup_extents_src_is_dest);
    7522         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_src_is_dest_overlap",
    7523             :                                      test_ioctl_dup_extents_src_is_dest_overlap);
    7524         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_compressed_src",
    7525             :                                      test_ioctl_dup_extents_compressed_src);
    7526         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_compressed_dest",
    7527             :                                      test_ioctl_dup_extents_compressed_dest);
    7528         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_bad_handle",
    7529             :                                      test_ioctl_dup_extents_bad_handle);
    7530         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_src_lock",
    7531             :                                      test_ioctl_dup_extents_src_lck);
    7532         964 :         torture_suite_add_1smb2_test(suite, "dup_extents_dest_lock",
    7533             :                                      test_ioctl_dup_extents_dest_lck);
    7534         964 :         torture_suite_add_1smb2_test(suite, "bug14607",
    7535             :                                      test_ioctl_bug14607);
    7536         964 :         torture_suite_add_1smb2_test(suite, "bug14769",
    7537             :                                      test_ioctl_bug14769);
    7538             : 
    7539         964 :         torture_suite_add_1smb2_test(bug14788, "VALIDATE_NEGOTIATE",
    7540             :                                      test_ioctl_bug14788_VALIDATE_NEGOTIATE);
    7541         964 :         torture_suite_add_1smb2_test(bug14788, "NETWORK_INTERFACE",
    7542             :                                      test_ioctl_bug14788_NETWORK_INTERFACE);
    7543         964 :         torture_suite_add_suite(suite, bug14788);
    7544             : 
    7545         964 :         suite->description = talloc_strdup(suite, "SMB2-IOCTL tests");
    7546             : 
    7547         964 :         return suite;
    7548             : }
    7549             : 

Generated by: LCOV version 1.13