2 Unix SMB/CIFS implementation.
4 test suite for SMB2 ioctl operations
6 Copyright (C) David Disseldorp 2011-2015
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.
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.
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/>.
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"
31 #define FNAME "testfsctl.dat"
32 #define FNAME2 "testfsctl2.dat"
33 #define DNAME "testfsctl_dir"
36 basic testing of SMB2 shadow copy calls
38 static bool test_ioctl_get_shadow_copy(struct torture_context
*torture
,
39 struct smb2_tree
*tree
)
44 union smb_ioctl ioctl
;
45 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
47 smb2_util_unlink(tree
, FNAME
);
49 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
50 torture_assert_ntstatus_ok(torture
, status
, "create write");
53 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
54 torture_assert_ntstatus_ok(torture
, status
, "write");
57 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
58 ioctl
.smb2
.in
.file
.handle
= h
;
59 ioctl
.smb2
.in
.function
= FSCTL_SRV_ENUM_SNAPS
;
60 ioctl
.smb2
.in
.max_response_size
= 16;
61 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
63 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
64 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)
65 || NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_DEVICE_REQUEST
)) {
66 torture_skip(torture
, "FSCTL_SRV_ENUM_SNAPS not supported\n");
68 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_ENUM_SNAPS");
74 basic testing of the SMB2 server side copy ioctls
76 static bool test_ioctl_req_resume_key(struct torture_context
*torture
,
77 struct smb2_tree
*tree
)
82 union smb_ioctl ioctl
;
83 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
84 struct req_resume_key_rsp res_key
;
85 enum ndr_err_code ndr_ret
;
87 smb2_util_unlink(tree
, FNAME
);
89 status
= torture_smb2_testfile(tree
, FNAME
, &h
);
90 torture_assert_ntstatus_ok(torture
, status
, "create write");
93 status
= smb2_util_write(tree
, h
, buf
, 0, ARRAY_SIZE(buf
));
94 torture_assert_ntstatus_ok(torture
, status
, "write");
97 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
98 ioctl
.smb2
.in
.file
.handle
= h
;
99 ioctl
.smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
100 ioctl
.smb2
.in
.max_response_size
= 32;
101 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
103 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
104 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_REQUEST_RESUME_KEY");
106 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &res_key
,
107 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
108 torture_assert_ndr_success(torture
, ndr_ret
,
109 "ndr_pull_req_resume_key_rsp");
111 ndr_print_debug((ndr_print_fn_t
)ndr_print_req_resume_key_rsp
, "yo", &res_key
);
113 talloc_free(tmp_ctx
);
117 static uint64_t patt_hash(uint64_t off
)
122 static bool write_pattern(struct torture_context
*torture
,
123 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
124 struct smb2_handle h
, uint64_t off
, uint64_t len
,
130 uint64_t io_sz
= MIN(1024 * 64, len
);
136 torture_assert(torture
, (len
% 8) == 0, "invalid write len");
138 buf
= talloc_zero_size(mem_ctx
, io_sz
);
139 torture_assert(torture
, (buf
!= NULL
), "no memory for file data buf");
142 for (i
= 0; i
<= io_sz
- 8; i
+= 8) {
143 SBVAL(buf
, i
, patt_hash(patt_off
));
147 status
= smb2_util_write(tree
, h
,
149 torture_assert_ntstatus_ok(torture
, status
, "file write");
160 static bool check_pattern(struct torture_context
*torture
,
161 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
162 struct smb2_handle h
, uint64_t off
, uint64_t len
,
169 torture_assert(torture
, (len
% 8) == 0, "invalid read len");
175 uint64_t io_sz
= MIN(1024 * 64, len
);
178 r
.in
.file
.handle
= h
;
181 status
= smb2_read(tree
, mem_ctx
, &r
);
182 torture_assert_ntstatus_ok(torture
, status
, "read");
184 torture_assert_u64_equal(torture
, r
.out
.data
.length
, io_sz
,
185 "read data len mismatch");
187 for (i
= 0; i
<= io_sz
- 8; i
+= 8, patt_off
+= 8) {
188 uint64_t data
= BVAL(r
.out
.data
.data
, i
);
189 torture_assert_u64_equal(torture
, data
, patt_hash(patt_off
),
190 talloc_asprintf(torture
, "read data "
191 "pattern bad at %llu\n",
192 (unsigned long long)off
+ i
));
194 talloc_free(r
.out
.data
.data
);
202 static bool check_zero(struct torture_context
*torture
,
203 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
204 struct smb2_handle h
, uint64_t off
, uint64_t len
)
215 r
.in
.file
.handle
= h
;
218 status
= smb2_read(tree
, mem_ctx
, &r
);
219 torture_assert_ntstatus_ok(torture
, status
, "read");
221 torture_assert_u64_equal(torture
, r
.out
.data
.length
, len
,
222 "read data len mismatch");
224 for (i
= 0; i
<= len
- 8; i
+= 8) {
225 uint64_t data
= BVAL(r
.out
.data
.data
, i
);
226 torture_assert_u64_equal(torture
, data
, 0,
227 talloc_asprintf(mem_ctx
, "read zero "
229 (unsigned long long)i
));
232 talloc_free(r
.out
.data
.data
);
236 static bool test_setup_open(struct torture_context
*torture
,
237 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
239 struct smb2_handle
*fh
,
240 uint32_t desired_access
,
241 uint32_t file_attributes
)
243 struct smb2_create io
;
247 io
.in
.desired_access
= desired_access
;
248 io
.in
.file_attributes
= file_attributes
;
249 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
251 NTCREATEX_SHARE_ACCESS_DELETE
|
252 NTCREATEX_SHARE_ACCESS_READ
|
253 NTCREATEX_SHARE_ACCESS_WRITE
;
254 if (file_attributes
& FILE_ATTRIBUTE_DIRECTORY
) {
255 io
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
259 status
= smb2_create(tree
, mem_ctx
, &io
);
260 torture_assert_ntstatus_ok(torture
, status
, "file create");
262 *fh
= io
.out
.file
.handle
;
267 static bool test_setup_create_fill(struct torture_context
*torture
,
268 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
270 struct smb2_handle
*fh
,
272 uint32_t desired_access
,
273 uint32_t file_attributes
)
277 smb2_util_unlink(tree
, fname
);
279 ok
= test_setup_open(torture
, tree
, mem_ctx
,
284 torture_assert(torture
, ok
, "file open");
287 ok
= write_pattern(torture
, tree
, mem_ctx
, *fh
, 0, size
, 0);
288 torture_assert(torture
, ok
, "write pattern");
293 static bool test_setup_copy_chunk(struct torture_context
*torture
,
294 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
296 struct smb2_handle
*src_h
,
298 uint32_t src_desired_access
,
299 struct smb2_handle
*dest_h
,
301 uint32_t dest_desired_access
,
302 struct srv_copychunk_copy
*cc_copy
,
303 union smb_ioctl
*ioctl
)
305 struct req_resume_key_rsp res_key
;
308 enum ndr_err_code ndr_ret
;
310 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME
,
311 src_h
, src_size
, src_desired_access
,
312 FILE_ATTRIBUTE_NORMAL
);
313 torture_assert(torture
, ok
, "src file create fill");
315 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME2
,
316 dest_h
, dest_size
, dest_desired_access
,
317 FILE_ATTRIBUTE_NORMAL
);
318 torture_assert(torture
, ok
, "dest file create fill");
320 ZERO_STRUCTPN(ioctl
);
321 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
322 ioctl
->smb2
.in
.file
.handle
= *src_h
;
323 ioctl
->smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
324 /* Allow for Key + ContextLength + Context */
325 ioctl
->smb2
.in
.max_response_size
= 32;
326 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
328 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
->smb2
);
329 torture_assert_ntstatus_ok(torture
, status
,
330 "FSCTL_SRV_REQUEST_RESUME_KEY");
332 ndr_ret
= ndr_pull_struct_blob(&ioctl
->smb2
.out
.out
, mem_ctx
, &res_key
,
333 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
335 torture_assert_ndr_success(torture
, ndr_ret
,
336 "ndr_pull_req_resume_key_rsp");
338 ZERO_STRUCTPN(ioctl
);
339 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
340 ioctl
->smb2
.in
.file
.handle
= *dest_h
;
341 ioctl
->smb2
.in
.function
= FSCTL_SRV_COPYCHUNK
;
342 ioctl
->smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
);
343 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
345 ZERO_STRUCTPN(cc_copy
);
346 memcpy(cc_copy
->source_key
, res_key
.resume_key
, ARRAY_SIZE(cc_copy
->source_key
));
347 cc_copy
->chunk_count
= nchunks
;
348 cc_copy
->chunks
= talloc_zero_array(mem_ctx
, struct srv_copychunk
, nchunks
);
349 torture_assert(torture
, (cc_copy
->chunks
!= NULL
), "no memory for chunks");
355 static bool check_copy_chunk_rsp(struct torture_context
*torture
,
356 struct srv_copychunk_rsp
*cc_rsp
,
357 uint32_t ex_chunks_written
,
358 uint32_t ex_chunk_bytes_written
,
359 uint32_t ex_total_bytes_written
)
361 torture_assert_int_equal(torture
, cc_rsp
->chunks_written
,
362 ex_chunks_written
, "num chunks");
363 torture_assert_int_equal(torture
, cc_rsp
->chunk_bytes_written
,
364 ex_chunk_bytes_written
, "chunk bytes written");
365 torture_assert_int_equal(torture
, cc_rsp
->total_bytes_written
,
366 ex_total_bytes_written
, "chunk total bytes");
370 static bool test_ioctl_copy_chunk_simple(struct torture_context
*torture
,
371 struct smb2_tree
*tree
)
373 struct smb2_handle src_h
;
374 struct smb2_handle dest_h
;
376 union smb_ioctl ioctl
;
377 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
378 struct srv_copychunk_copy cc_copy
;
379 struct srv_copychunk_rsp cc_rsp
;
380 enum ndr_err_code ndr_ret
;
383 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
385 &src_h
, 4096, /* fill 4096 byte src file */
387 &dest_h
, 0, /* 0 byte dest file */
392 torture_fail(torture
, "setup copy chunk error");
395 /* copy all src file data (via a single chunk desc) */
396 cc_copy
.chunks
[0].source_off
= 0;
397 cc_copy
.chunks
[0].target_off
= 0;
398 cc_copy
.chunks
[0].length
= 4096;
400 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
402 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
403 torture_assert_ndr_success(torture
, ndr_ret
,
404 "ndr_push_srv_copychunk_copy");
406 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
407 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
409 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
411 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
412 torture_assert_ndr_success(torture
, ndr_ret
,
413 "ndr_pull_srv_copychunk_rsp");
415 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
416 1, /* chunks written */
417 0, /* chunk bytes unsuccessfully written */
418 4096); /* total bytes written */
420 torture_fail(torture
, "bad copy chunk response data");
423 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
425 torture_fail(torture
, "inconsistent file data");
428 smb2_util_close(tree
, src_h
);
429 smb2_util_close(tree
, dest_h
);
430 talloc_free(tmp_ctx
);
434 static bool test_ioctl_copy_chunk_multi(struct torture_context
*torture
,
435 struct smb2_tree
*tree
)
437 struct smb2_handle src_h
;
438 struct smb2_handle dest_h
;
440 union smb_ioctl ioctl
;
441 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
442 struct srv_copychunk_copy cc_copy
;
443 struct srv_copychunk_rsp cc_rsp
;
444 enum ndr_err_code ndr_ret
;
447 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
449 &src_h
, 8192, /* src file */
451 &dest_h
, 0, /* dest file */
456 torture_fail(torture
, "setup copy chunk error");
459 /* copy all src file data via two chunks */
460 cc_copy
.chunks
[0].source_off
= 0;
461 cc_copy
.chunks
[0].target_off
= 0;
462 cc_copy
.chunks
[0].length
= 4096;
464 cc_copy
.chunks
[1].source_off
= 4096;
465 cc_copy
.chunks
[1].target_off
= 4096;
466 cc_copy
.chunks
[1].length
= 4096;
468 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
470 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
471 torture_assert_ndr_success(torture
, ndr_ret
,
472 "ndr_push_srv_copychunk_copy");
474 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
475 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
477 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
479 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
480 torture_assert_ndr_success(torture
, ndr_ret
,
481 "ndr_pull_srv_copychunk_rsp");
483 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
484 2, /* chunks written */
485 0, /* chunk bytes unsuccessfully written */
486 8192); /* total bytes written */
488 torture_fail(torture
, "bad copy chunk response data");
491 smb2_util_close(tree
, src_h
);
492 smb2_util_close(tree
, dest_h
);
493 talloc_free(tmp_ctx
);
497 static bool test_ioctl_copy_chunk_tiny(struct torture_context
*torture
,
498 struct smb2_tree
*tree
)
500 struct smb2_handle src_h
;
501 struct smb2_handle dest_h
;
503 union smb_ioctl ioctl
;
504 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
505 struct srv_copychunk_copy cc_copy
;
506 struct srv_copychunk_rsp cc_rsp
;
507 enum ndr_err_code ndr_ret
;
510 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
512 &src_h
, 96, /* src file */
514 &dest_h
, 0, /* dest file */
519 torture_fail(torture
, "setup copy chunk error");
522 /* copy all src file data via two chunks, sub block size chunks */
523 cc_copy
.chunks
[0].source_off
= 0;
524 cc_copy
.chunks
[0].target_off
= 0;
525 cc_copy
.chunks
[0].length
= 48;
527 cc_copy
.chunks
[1].source_off
= 48;
528 cc_copy
.chunks
[1].target_off
= 48;
529 cc_copy
.chunks
[1].length
= 48;
531 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
533 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
534 torture_assert_ndr_success(torture
, ndr_ret
,
535 "ndr_push_srv_copychunk_copy");
537 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
538 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
540 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
542 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
543 torture_assert_ndr_success(torture
, ndr_ret
,
544 "ndr_pull_srv_copychunk_rsp");
546 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
547 2, /* chunks written */
548 0, /* chunk bytes unsuccessfully written */
549 96); /* total bytes written */
551 torture_fail(torture
, "bad copy chunk response data");
554 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 96, 0);
556 torture_fail(torture
, "inconsistent file data");
559 smb2_util_close(tree
, src_h
);
560 smb2_util_close(tree
, dest_h
);
561 talloc_free(tmp_ctx
);
565 static bool test_ioctl_copy_chunk_over(struct torture_context
*torture
,
566 struct smb2_tree
*tree
)
568 struct smb2_handle src_h
;
569 struct smb2_handle dest_h
;
571 union smb_ioctl ioctl
;
572 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
573 struct srv_copychunk_copy cc_copy
;
574 struct srv_copychunk_rsp cc_rsp
;
575 enum ndr_err_code ndr_ret
;
578 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
580 &src_h
, 8192, /* src file */
582 &dest_h
, 4096, /* dest file */
587 torture_fail(torture
, "setup copy chunk error");
590 /* first chunk overwrites existing dest data */
591 cc_copy
.chunks
[0].source_off
= 0;
592 cc_copy
.chunks
[0].target_off
= 0;
593 cc_copy
.chunks
[0].length
= 4096;
595 /* second chunk overwrites the first */
596 cc_copy
.chunks
[1].source_off
= 4096;
597 cc_copy
.chunks
[1].target_off
= 0;
598 cc_copy
.chunks
[1].length
= 4096;
600 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
602 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
603 torture_assert_ndr_success(torture
, ndr_ret
,
604 "ndr_push_srv_copychunk_copy");
606 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
607 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
609 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
611 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
612 torture_assert_ndr_success(torture
, ndr_ret
,
613 "ndr_pull_srv_copychunk_rsp");
615 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
616 2, /* chunks written */
617 0, /* chunk bytes unsuccessfully written */
618 8192); /* total bytes written */
620 torture_fail(torture
, "bad copy chunk response data");
623 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 4096);
625 torture_fail(torture
, "inconsistent file data");
628 smb2_util_close(tree
, src_h
);
629 smb2_util_close(tree
, dest_h
);
630 talloc_free(tmp_ctx
);
634 static bool test_ioctl_copy_chunk_append(struct torture_context
*torture
,
635 struct smb2_tree
*tree
)
637 struct smb2_handle src_h
;
638 struct smb2_handle dest_h
;
640 union smb_ioctl ioctl
;
641 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
642 struct srv_copychunk_copy cc_copy
;
643 struct srv_copychunk_rsp cc_rsp
;
644 enum ndr_err_code ndr_ret
;
647 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
649 &src_h
, 4096, /* src file */
651 &dest_h
, 0, /* dest file */
656 torture_fail(torture
, "setup copy chunk error");
659 cc_copy
.chunks
[0].source_off
= 0;
660 cc_copy
.chunks
[0].target_off
= 0;
661 cc_copy
.chunks
[0].length
= 4096;
663 /* second chunk appends the same data to the first */
664 cc_copy
.chunks
[1].source_off
= 0;
665 cc_copy
.chunks
[1].target_off
= 4096;
666 cc_copy
.chunks
[1].length
= 4096;
668 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
670 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
671 torture_assert_ndr_success(torture
, ndr_ret
,
672 "ndr_push_srv_copychunk_copy");
674 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
675 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
677 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
679 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
680 torture_assert_ndr_success(torture
, ndr_ret
,
681 "ndr_pull_srv_copychunk_rsp");
683 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
684 2, /* chunks written */
685 0, /* chunk bytes unsuccessfully written */
686 8192); /* total bytes written */
688 torture_fail(torture
, "bad copy chunk response data");
691 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
693 torture_fail(torture
, "inconsistent file data");
696 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
698 torture_fail(torture
, "inconsistent file data");
701 smb2_util_close(tree
, src_h
);
702 smb2_util_close(tree
, dest_h
);
703 talloc_free(tmp_ctx
);
707 static bool test_ioctl_copy_chunk_limits(struct torture_context
*torture
,
708 struct smb2_tree
*tree
)
710 struct smb2_handle src_h
;
711 struct smb2_handle dest_h
;
713 union smb_ioctl ioctl
;
714 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
715 struct srv_copychunk_copy cc_copy
;
716 struct srv_copychunk_rsp cc_rsp
;
717 enum ndr_err_code ndr_ret
;
720 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
722 &src_h
, 4096, /* src file */
724 &dest_h
, 0, /* dest file */
729 torture_fail(torture
, "setup copy chunk error");
732 /* send huge chunk length request */
733 cc_copy
.chunks
[0].source_off
= 0;
734 cc_copy
.chunks
[0].target_off
= 0;
735 cc_copy
.chunks
[0].length
= UINT_MAX
;
737 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
739 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
740 torture_assert_ndr_success(torture
, ndr_ret
, "marshalling request");
742 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
743 torture_assert_ntstatus_equal(torture
, status
,
744 NT_STATUS_INVALID_PARAMETER
,
745 "bad oversize chunk response");
747 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
749 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
750 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
752 torture_comment(torture
, "limit max chunks, got %u\n",
753 cc_rsp
.chunks_written
);
754 torture_comment(torture
, "limit max chunk len, got %u\n",
755 cc_rsp
.chunk_bytes_written
);
756 torture_comment(torture
, "limit max total bytes, got %u\n",
757 cc_rsp
.total_bytes_written
);
759 smb2_util_close(tree
, src_h
);
760 smb2_util_close(tree
, dest_h
);
761 talloc_free(tmp_ctx
);
765 static bool test_ioctl_copy_chunk_src_lck(struct torture_context
*torture
,
766 struct smb2_tree
*tree
)
768 struct smb2_handle src_h
;
769 struct smb2_handle src_h2
;
770 struct smb2_handle dest_h
;
772 union smb_ioctl ioctl
;
773 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
774 struct srv_copychunk_copy cc_copy
;
775 struct srv_copychunk_rsp cc_rsp
;
776 enum ndr_err_code ndr_ret
;
778 struct smb2_lock lck
;
779 struct smb2_lock_element el
[1];
781 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
783 &src_h
, 4096, /* src file */
785 &dest_h
, 0, /* dest file */
790 torture_fail(torture
, "setup copy chunk error");
793 cc_copy
.chunks
[0].source_off
= 0;
794 cc_copy
.chunks
[0].target_off
= 0;
795 cc_copy
.chunks
[0].length
= 4096;
797 /* open and lock the copychunk src file */
798 status
= torture_smb2_testfile(tree
, FNAME
, &src_h2
);
799 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
801 lck
.in
.lock_count
= 0x0001;
802 lck
.in
.lock_sequence
= 0x00000000;
803 lck
.in
.file
.handle
= src_h2
;
805 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
806 el
[0].length
= cc_copy
.chunks
[0].length
;
808 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
810 status
= smb2_lock(tree
, &lck
);
811 torture_assert_ntstatus_ok(torture
, status
, "lock");
813 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
815 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
816 torture_assert_ndr_success(torture
, ndr_ret
,
817 "ndr_push_srv_copychunk_copy");
819 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
821 * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
823 * Edgar Olougouna @ MS wrote:
824 * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
825 * discrepancy observed between Windows versions, we confirm that the
826 * behavior change is expected.
828 * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
829 * to move the chunks from the source to the destination.
830 * These ReadFile/WriteFile APIs go through the byte-range lock checks,
831 * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
833 * Prior to Windows Server 2012, CopyChunk used mapped sections to move
834 * the data. And byte range locks are not enforced on mapped I/O, and
835 * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
837 torture_assert_ntstatus_equal(torture
, status
,
838 NT_STATUS_FILE_LOCK_CONFLICT
,
839 "FSCTL_SRV_COPYCHUNK locked");
841 /* should get cc response data with the lock conflict status */
842 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
844 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
845 torture_assert_ndr_success(torture
, ndr_ret
,
846 "ndr_pull_srv_copychunk_rsp");
847 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
848 0, /* chunks written */
849 0, /* chunk bytes unsuccessfully written */
850 0); /* total bytes written */
852 lck
.in
.lock_count
= 0x0001;
853 lck
.in
.lock_sequence
= 0x00000001;
854 lck
.in
.file
.handle
= src_h2
;
856 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
857 el
[0].length
= cc_copy
.chunks
[0].length
;
859 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
860 status
= smb2_lock(tree
, &lck
);
861 torture_assert_ntstatus_ok(torture
, status
, "unlock");
863 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
864 torture_assert_ntstatus_ok(torture
, status
,
865 "FSCTL_SRV_COPYCHUNK unlocked");
867 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
869 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
870 torture_assert_ndr_success(torture
, ndr_ret
,
871 "ndr_pull_srv_copychunk_rsp");
873 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
874 1, /* chunks written */
875 0, /* chunk bytes unsuccessfully written */
876 4096); /* total bytes written */
878 torture_fail(torture
, "bad copy chunk response data");
881 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
883 torture_fail(torture
, "inconsistent file data");
886 smb2_util_close(tree
, src_h2
);
887 smb2_util_close(tree
, src_h
);
888 smb2_util_close(tree
, dest_h
);
889 talloc_free(tmp_ctx
);
893 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context
*torture
,
894 struct smb2_tree
*tree
)
896 struct smb2_handle src_h
;
897 struct smb2_handle dest_h
;
898 struct smb2_handle dest_h2
;
900 union smb_ioctl ioctl
;
901 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
902 struct srv_copychunk_copy cc_copy
;
903 struct srv_copychunk_rsp cc_rsp
;
904 enum ndr_err_code ndr_ret
;
906 struct smb2_lock lck
;
907 struct smb2_lock_element el
[1];
909 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
911 &src_h
, 4096, /* src file */
913 &dest_h
, 4096, /* dest file */
918 torture_fail(torture
, "setup copy chunk error");
921 cc_copy
.chunks
[0].source_off
= 0;
922 cc_copy
.chunks
[0].target_off
= 0;
923 cc_copy
.chunks
[0].length
= 4096;
925 /* open and lock the copychunk dest file */
926 status
= torture_smb2_testfile(tree
, FNAME2
, &dest_h2
);
927 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
929 lck
.in
.lock_count
= 0x0001;
930 lck
.in
.lock_sequence
= 0x00000000;
931 lck
.in
.file
.handle
= dest_h2
;
933 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
934 el
[0].length
= cc_copy
.chunks
[0].length
;
936 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
938 status
= smb2_lock(tree
, &lck
);
939 torture_assert_ntstatus_ok(torture
, status
, "lock");
941 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
943 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
944 torture_assert_ndr_success(torture
, ndr_ret
,
945 "ndr_push_srv_copychunk_copy");
947 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
948 torture_assert_ntstatus_equal(torture
, status
,
949 NT_STATUS_FILE_LOCK_CONFLICT
,
950 "FSCTL_SRV_COPYCHUNK locked");
952 lck
.in
.lock_count
= 0x0001;
953 lck
.in
.lock_sequence
= 0x00000001;
954 lck
.in
.file
.handle
= dest_h2
;
956 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
957 el
[0].length
= cc_copy
.chunks
[0].length
;
959 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
960 status
= smb2_lock(tree
, &lck
);
961 torture_assert_ntstatus_ok(torture
, status
, "unlock");
963 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
964 torture_assert_ntstatus_ok(torture
, status
,
965 "FSCTL_SRV_COPYCHUNK unlocked");
967 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
969 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
970 torture_assert_ndr_success(torture
, ndr_ret
,
971 "ndr_pull_srv_copychunk_rsp");
973 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
974 1, /* chunks written */
975 0, /* chunk bytes unsuccessfully written */
976 4096); /* total bytes written */
978 torture_fail(torture
, "bad copy chunk response data");
981 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
983 torture_fail(torture
, "inconsistent file data");
986 smb2_util_close(tree
, dest_h2
);
987 smb2_util_close(tree
, src_h
);
988 smb2_util_close(tree
, dest_h
);
989 talloc_free(tmp_ctx
);
993 static bool test_ioctl_copy_chunk_bad_key(struct torture_context
*torture
,
994 struct smb2_tree
*tree
)
996 struct smb2_handle src_h
;
997 struct smb2_handle dest_h
;
999 union smb_ioctl ioctl
;
1000 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1001 struct srv_copychunk_copy cc_copy
;
1002 enum ndr_err_code ndr_ret
;
1005 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1008 SEC_RIGHTS_FILE_ALL
,
1010 SEC_RIGHTS_FILE_ALL
,
1014 torture_fail(torture
, "setup copy chunk error");
1017 /* overwrite the resume key with a bogus value */
1018 memcpy(cc_copy
.source_key
, "deadbeefdeadbeefdeadbeef", 24);
1020 cc_copy
.chunks
[0].source_off
= 0;
1021 cc_copy
.chunks
[0].target_off
= 0;
1022 cc_copy
.chunks
[0].length
= 4096;
1024 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1026 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1027 torture_assert_ndr_success(torture
, ndr_ret
,
1028 "ndr_push_srv_copychunk_copy");
1030 /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
1031 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1032 torture_assert_ntstatus_equal(torture
, status
,
1033 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
1034 "FSCTL_SRV_COPYCHUNK");
1036 smb2_util_close(tree
, src_h
);
1037 smb2_util_close(tree
, dest_h
);
1038 talloc_free(tmp_ctx
);
1042 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context
*torture
,
1043 struct smb2_tree
*tree
)
1045 struct smb2_handle src_h
;
1046 struct smb2_handle dest_h
;
1048 union smb_ioctl ioctl
;
1049 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1050 struct srv_copychunk_copy cc_copy
;
1051 struct srv_copychunk_rsp cc_rsp
;
1052 enum ndr_err_code ndr_ret
;
1055 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1058 SEC_RIGHTS_FILE_ALL
,
1060 SEC_RIGHTS_FILE_ALL
,
1064 torture_fail(torture
, "setup copy chunk error");
1067 /* the source is also the destination */
1068 ioctl
.smb2
.in
.file
.handle
= src_h
;
1070 /* non-overlapping */
1071 cc_copy
.chunks
[0].source_off
= 0;
1072 cc_copy
.chunks
[0].target_off
= 4096;
1073 cc_copy
.chunks
[0].length
= 4096;
1075 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1077 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1078 torture_assert_ndr_success(torture
, ndr_ret
,
1079 "ndr_push_srv_copychunk_copy");
1081 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1082 torture_assert_ntstatus_ok(torture
, status
,
1083 "FSCTL_SRV_COPYCHUNK");
1085 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1087 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1088 torture_assert_ndr_success(torture
, ndr_ret
,
1089 "ndr_pull_srv_copychunk_rsp");
1091 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1092 1, /* chunks written */
1093 0, /* chunk bytes unsuccessfully written */
1094 4096); /* total bytes written */
1096 torture_fail(torture
, "bad copy chunk response data");
1099 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 4096, 0);
1101 torture_fail(torture
, "inconsistent file data");
1103 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 4096, 4096, 0);
1105 torture_fail(torture
, "inconsistent file data");
1108 smb2_util_close(tree
, src_h
);
1109 smb2_util_close(tree
, dest_h
);
1110 talloc_free(tmp_ctx
);
1115 * Test a single-chunk copychunk request, where the source and target ranges
1116 * overlap, and the SourceKey refers to the same target file. E.g:
1120 * File: src_and_dest
1121 * Offset: 0123456789
1126 * FSCTL_SRV_COPYCHUNK(src_and_dest)
1127 * SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1129 * Chunks[0].SourceOffset = 0
1130 * Chunks[0].TargetOffset = 4
1131 * Chunks[0].Length = 6
1135 * File: src_and_dest
1136 * Offset: 0123456789
1139 * The resultant contents of src_and_dest is dependent on the server's
1140 * copy algorithm. In the above example, the server uses an IO buffer
1141 * large enough to hold the entire six-byte source data before writing
1142 * to TargetOffset. If the server were to use a four-byte IO buffer and
1143 * started reads/writes from the lowest offset, then the two overlapping
1144 * bytes in the above example would be overwritten before being read. The
1145 * resultant file contents would be abcdabcdab.
1147 * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
1148 * after this offset are written before being read. Windows 2012 on the
1149 * other hand appears to use a buffer large enough to hold its maximum
1150 * supported chunk size (1M). Samba currently uses a 64k copy buffer by
1151 * default (vfs_cc_state.buf).
1153 * This test uses an 8-byte overlap at 2040-2048, so that it passes against
1154 * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
1155 * to use a different copy algorithm to 2008r2.
1158 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context
*torture
,
1159 struct smb2_tree
*tree
)
1161 struct smb2_handle src_h
;
1162 struct smb2_handle dest_h
;
1164 union smb_ioctl ioctl
;
1165 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1166 struct srv_copychunk_copy cc_copy
;
1167 struct srv_copychunk_rsp cc_rsp
;
1168 enum ndr_err_code ndr_ret
;
1171 /* exceed the vfs_default copy buffer */
1172 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1175 SEC_RIGHTS_FILE_ALL
,
1177 SEC_RIGHTS_FILE_ALL
,
1181 torture_fail(torture
, "setup copy chunk error");
1184 /* the source is also the destination */
1185 ioctl
.smb2
.in
.file
.handle
= src_h
;
1187 /* 8 bytes overlap between source and target ranges */
1188 cc_copy
.chunks
[0].source_off
= 0;
1189 cc_copy
.chunks
[0].target_off
= 2048 - 8;
1190 cc_copy
.chunks
[0].length
= 2048;
1192 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1194 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1195 torture_assert_ndr_success(torture
, ndr_ret
,
1196 "ndr_push_srv_copychunk_copy");
1198 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1199 torture_assert_ntstatus_ok(torture
, status
,
1200 "FSCTL_SRV_COPYCHUNK");
1202 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1204 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1205 torture_assert_ndr_success(torture
, ndr_ret
,
1206 "ndr_pull_srv_copychunk_rsp");
1208 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1209 1, /* chunks written */
1210 0, /* chunk bytes unsuccessfully written */
1211 2048); /* total bytes written */
1213 torture_fail(torture
, "bad copy chunk response data");
1216 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 2048 - 8, 0);
1218 torture_fail(torture
, "inconsistent file data");
1220 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 2048 - 8, 2048, 0);
1222 torture_fail(torture
, "inconsistent file data");
1225 smb2_util_close(tree
, src_h
);
1226 smb2_util_close(tree
, dest_h
);
1227 talloc_free(tmp_ctx
);
1231 static bool test_ioctl_copy_chunk_bad_access(struct torture_context
*torture
,
1232 struct smb2_tree
*tree
)
1234 struct smb2_handle src_h
;
1235 struct smb2_handle dest_h
;
1237 union smb_ioctl ioctl
;
1238 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1239 struct srv_copychunk_copy cc_copy
;
1240 enum ndr_err_code ndr_ret
;
1243 /* no read permission on src */
1244 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1246 &src_h
, 4096, /* fill 4096 byte src file */
1247 SEC_RIGHTS_FILE_WRITE
,
1248 &dest_h
, 0, /* 0 byte dest file */
1249 SEC_RIGHTS_FILE_ALL
,
1253 torture_fail(torture
, "setup copy chunk error");
1256 cc_copy
.chunks
[0].source_off
= 0;
1257 cc_copy
.chunks
[0].target_off
= 0;
1258 cc_copy
.chunks
[0].length
= 4096;
1260 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1262 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1263 torture_assert_ndr_success(torture
, ndr_ret
,
1264 "ndr_push_srv_copychunk_copy");
1266 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1267 torture_assert_ntstatus_equal(torture
, status
,
1268 NT_STATUS_ACCESS_DENIED
,
1269 "FSCTL_SRV_COPYCHUNK");
1271 smb2_util_close(tree
, src_h
);
1272 smb2_util_close(tree
, dest_h
);
1274 /* no write permission on dest */
1275 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1277 &src_h
, 4096, /* fill 4096 byte src file */
1278 SEC_RIGHTS_FILE_ALL
,
1279 &dest_h
, 0, /* 0 byte dest file */
1280 (SEC_RIGHTS_FILE_READ
1281 | SEC_RIGHTS_FILE_EXECUTE
),
1285 torture_fail(torture
, "setup copy chunk error");
1288 cc_copy
.chunks
[0].source_off
= 0;
1289 cc_copy
.chunks
[0].target_off
= 0;
1290 cc_copy
.chunks
[0].length
= 4096;
1292 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1294 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1295 torture_assert_ndr_success(torture
, ndr_ret
,
1296 "ndr_push_srv_copychunk_copy");
1298 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1299 torture_assert_ntstatus_equal(torture
, status
,
1300 NT_STATUS_ACCESS_DENIED
,
1301 "FSCTL_SRV_COPYCHUNK");
1303 smb2_util_close(tree
, src_h
);
1304 smb2_util_close(tree
, dest_h
);
1306 /* no read permission on dest */
1307 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1309 &src_h
, 4096, /* fill 4096 byte src file */
1310 SEC_RIGHTS_FILE_ALL
,
1311 &dest_h
, 0, /* 0 byte dest file */
1312 (SEC_RIGHTS_FILE_WRITE
1313 | SEC_RIGHTS_FILE_EXECUTE
),
1317 torture_fail(torture
, "setup copy chunk error");
1320 cc_copy
.chunks
[0].source_off
= 0;
1321 cc_copy
.chunks
[0].target_off
= 0;
1322 cc_copy
.chunks
[0].length
= 4096;
1324 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1326 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1327 torture_assert_ndr_success(torture
, ndr_ret
,
1328 "ndr_push_srv_copychunk_copy");
1331 * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1332 * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1334 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1335 torture_assert_ntstatus_equal(torture
, status
,
1336 NT_STATUS_ACCESS_DENIED
,
1337 "FSCTL_SRV_COPYCHUNK");
1339 smb2_util_close(tree
, src_h
);
1340 smb2_util_close(tree
, dest_h
);
1341 talloc_free(tmp_ctx
);
1346 static bool test_ioctl_copy_chunk_write_access(struct torture_context
*torture
,
1347 struct smb2_tree
*tree
)
1349 struct smb2_handle src_h
;
1350 struct smb2_handle dest_h
;
1352 union smb_ioctl ioctl
;
1353 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1354 struct srv_copychunk_copy cc_copy
;
1355 enum ndr_err_code ndr_ret
;
1358 /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1359 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1361 &src_h
, 4096, /* fill 4096 byte src file */
1362 SEC_RIGHTS_FILE_ALL
,
1363 &dest_h
, 0, /* 0 byte dest file */
1364 (SEC_RIGHTS_FILE_WRITE
1365 | SEC_RIGHTS_FILE_EXECUTE
),
1369 torture_fail(torture
, "setup copy chunk error");
1372 ioctl
.smb2
.in
.function
= FSCTL_SRV_COPYCHUNK_WRITE
;
1373 cc_copy
.chunks
[0].source_off
= 0;
1374 cc_copy
.chunks
[0].target_off
= 0;
1375 cc_copy
.chunks
[0].length
= 4096;
1377 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1379 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1380 torture_assert_ndr_success(torture
, ndr_ret
,
1381 "ndr_push_srv_copychunk_copy");
1383 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1384 torture_assert_ntstatus_ok(torture
, status
,
1385 "FSCTL_SRV_COPYCHUNK_WRITE");
1387 smb2_util_close(tree
, src_h
);
1388 smb2_util_close(tree
, dest_h
);
1389 talloc_free(tmp_ctx
);
1394 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context
*torture
,
1395 struct smb2_tree
*tree
)
1397 struct smb2_handle src_h
;
1398 struct smb2_handle dest_h
;
1400 union smb_ioctl ioctl
;
1401 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1402 struct srv_copychunk_copy cc_copy
;
1403 struct srv_copychunk_rsp cc_rsp
;
1404 enum ndr_err_code ndr_ret
;
1407 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1409 &src_h
, 4096, /* fill 4096 byte src file */
1410 SEC_RIGHTS_FILE_ALL
,
1411 &dest_h
, 0, /* 0 byte dest file */
1412 SEC_RIGHTS_FILE_ALL
,
1416 torture_fail(torture
, "setup copy chunk error");
1419 /* Request copy where off + length exceeds size of src */
1420 cc_copy
.chunks
[0].source_off
= 1024;
1421 cc_copy
.chunks
[0].target_off
= 0;
1422 cc_copy
.chunks
[0].length
= 4096;
1424 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1426 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1427 torture_assert_ndr_success(torture
, ndr_ret
,
1428 "ndr_push_srv_copychunk_copy");
1430 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1431 torture_assert_ntstatus_equal(torture
, status
,
1432 NT_STATUS_INVALID_VIEW_SIZE
,
1433 "FSCTL_SRV_COPYCHUNK oversize");
1435 /* Request copy where length exceeds size of src */
1436 cc_copy
.chunks
[0].source_off
= 1024;
1437 cc_copy
.chunks
[0].target_off
= 0;
1438 cc_copy
.chunks
[0].length
= 3072;
1440 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1442 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1443 torture_assert_ndr_success(torture
, ndr_ret
,
1444 "ndr_push_srv_copychunk_copy");
1446 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1447 torture_assert_ntstatus_ok(torture
, status
,
1448 "FSCTL_SRV_COPYCHUNK just right");
1450 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1452 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1453 torture_assert_ndr_success(torture
, ndr_ret
,
1454 "ndr_pull_srv_copychunk_rsp");
1456 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1457 1, /* chunks written */
1458 0, /* chunk bytes unsuccessfully written */
1459 3072); /* total bytes written */
1461 torture_fail(torture
, "bad copy chunk response data");
1464 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 3072, 1024);
1466 torture_fail(torture
, "inconsistent file data");
1469 smb2_util_close(tree
, src_h
);
1470 smb2_util_close(tree
, dest_h
);
1471 talloc_free(tmp_ctx
);
1476 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context
*torture
,
1477 struct smb2_tree
*tree
)
1479 struct smb2_handle src_h
;
1480 struct smb2_handle dest_h
;
1482 union smb_ioctl ioctl
;
1483 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1484 struct srv_copychunk_copy cc_copy
;
1485 struct srv_copychunk_rsp cc_rsp
;
1486 enum ndr_err_code ndr_ret
;
1489 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1491 &src_h
, 8192, /* fill 8192 byte src file */
1492 SEC_RIGHTS_FILE_ALL
,
1493 &dest_h
, 0, /* 0 byte dest file */
1494 SEC_RIGHTS_FILE_ALL
,
1498 torture_fail(torture
, "setup copy chunk error");
1501 /* Request copy where off + length exceeds size of src */
1502 cc_copy
.chunks
[0].source_off
= 0;
1503 cc_copy
.chunks
[0].target_off
= 0;
1504 cc_copy
.chunks
[0].length
= 4096;
1506 cc_copy
.chunks
[1].source_off
= 4096;
1507 cc_copy
.chunks
[1].target_off
= 4096;
1508 cc_copy
.chunks
[1].length
= 8192;
1510 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1512 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1513 torture_assert_ndr_success(torture
, ndr_ret
,
1514 "ndr_push_srv_copychunk_copy");
1516 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1517 torture_assert_ntstatus_equal(torture
, status
,
1518 NT_STATUS_INVALID_VIEW_SIZE
,
1519 "FSCTL_SRV_COPYCHUNK oversize");
1520 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1522 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1523 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1525 /* first chunk should still be written */
1526 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1527 1, /* chunks written */
1528 0, /* chunk bytes unsuccessfully written */
1529 4096); /* total bytes written */
1531 torture_fail(torture
, "bad copy chunk response data");
1533 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
1535 torture_fail(torture
, "inconsistent file data");
1538 smb2_util_close(tree
, src_h
);
1539 smb2_util_close(tree
, dest_h
);
1540 talloc_free(tmp_ctx
);
1544 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context
*torture
,
1545 struct smb2_tree
*tree
)
1547 struct smb2_handle src_h
;
1548 struct smb2_handle dest_h
;
1550 union smb_ioctl ioctl
;
1552 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1553 struct srv_copychunk_copy cc_copy
;
1554 struct srv_copychunk_rsp cc_rsp
;
1555 enum ndr_err_code ndr_ret
;
1559 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1561 &src_h
, 4096, /* fill 4096 byte src file */
1562 SEC_RIGHTS_FILE_ALL
,
1563 &dest_h
, 0, /* 0 byte dest file */
1564 SEC_RIGHTS_FILE_ALL
,
1568 torture_fail(torture
, "setup copy chunk error");
1571 /* copy all src file data (via a single chunk desc) */
1572 cc_copy
.chunks
[0].source_off
= 0;
1573 cc_copy
.chunks
[0].target_off
= 4096;
1574 cc_copy
.chunks
[0].length
= 4096;
1576 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1578 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1579 torture_assert_ndr_success(torture
, ndr_ret
,
1580 "ndr_push_srv_copychunk_copy");
1582 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1583 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
1585 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1587 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1588 torture_assert_ndr_success(torture
, ndr_ret
,
1589 "ndr_pull_srv_copychunk_rsp");
1591 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1592 1, /* chunks written */
1593 0, /* chunk bytes unsuccessfully written */
1594 4096); /* total bytes written */
1596 torture_fail(torture
, "bad copy chunk response data");
1599 /* check for zeros in first 4k */
1601 r
.in
.file
.handle
= dest_h
;
1604 status
= smb2_read(tree
, tmp_ctx
, &r
);
1605 torture_assert_ntstatus_ok(torture
, status
, "read");
1607 torture_assert_u64_equal(torture
, r
.out
.data
.length
, 4096,
1608 "read data len mismatch");
1610 for (i
= 0; i
< 4096; i
++) {
1611 torture_assert(torture
, (r
.out
.data
.data
[i
] == 0),
1612 "sparse did not pass class");
1615 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
1617 torture_fail(torture
, "inconsistent file data");
1620 smb2_util_close(tree
, src_h
);
1621 smb2_util_close(tree
, dest_h
);
1622 talloc_free(tmp_ctx
);
1627 * set the ioctl MaxOutputResponse size to less than
1628 * sizeof(struct srv_copychunk_rsp)
1630 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context
*torture
,
1631 struct smb2_tree
*tree
)
1633 struct smb2_handle src_h
;
1634 struct smb2_handle dest_h
;
1636 union smb_ioctl ioctl
;
1637 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1638 struct srv_copychunk_copy cc_copy
;
1639 enum ndr_err_code ndr_ret
;
1642 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1644 &src_h
, 4096, /* fill 4096 byte src file */
1645 SEC_RIGHTS_FILE_ALL
,
1646 &dest_h
, 0, /* 0 byte dest file */
1647 SEC_RIGHTS_FILE_ALL
,
1651 torture_fail(torture
, "setup copy chunk error");
1654 cc_copy
.chunks
[0].source_off
= 0;
1655 cc_copy
.chunks
[0].target_off
= 0;
1656 cc_copy
.chunks
[0].length
= 4096;
1657 /* req is valid, but use undersize max_response_size */
1658 ioctl
.smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
) - 1;
1660 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1662 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1663 torture_assert_ndr_success(torture
, ndr_ret
,
1664 "ndr_push_srv_copychunk_copy");
1666 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1667 torture_assert_ntstatus_equal(torture
, status
,
1668 NT_STATUS_INVALID_PARAMETER
,
1669 "FSCTL_SRV_COPYCHUNK");
1671 smb2_util_close(tree
, src_h
);
1672 smb2_util_close(tree
, dest_h
);
1673 talloc_free(tmp_ctx
);
1677 static bool test_ioctl_copy_chunk_zero_length(struct torture_context
*torture
,
1678 struct smb2_tree
*tree
)
1680 struct smb2_handle src_h
;
1681 struct smb2_handle dest_h
;
1683 union smb_ioctl ioctl
;
1684 union smb_fileinfo q
;
1685 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1686 struct srv_copychunk_copy cc_copy
;
1687 struct srv_copychunk_rsp cc_rsp
;
1688 enum ndr_err_code ndr_ret
;
1691 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1693 &src_h
, 4096, /* fill 4096 byte src file */
1694 SEC_RIGHTS_FILE_ALL
,
1695 &dest_h
, 0, /* 0 byte dest file */
1696 SEC_RIGHTS_FILE_ALL
,
1700 torture_fail(torture
, "setup copy chunk error");
1703 /* zero length server-side copy (via a single chunk desc) */
1704 cc_copy
.chunks
[0].source_off
= 0;
1705 cc_copy
.chunks
[0].target_off
= 0;
1706 cc_copy
.chunks
[0].length
= 0;
1708 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1710 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1711 torture_assert_ndr_success(torture
, ndr_ret
,
1712 "ndr_push_srv_copychunk_copy");
1714 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1715 torture_assert_ntstatus_equal(torture
, status
,
1716 NT_STATUS_INVALID_PARAMETER
,
1717 "bad zero-length chunk response");
1719 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1721 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1722 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1725 q
.all_info2
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1726 q
.all_info2
.in
.file
.handle
= dest_h
;
1727 status
= smb2_getinfo_file(tree
, torture
, &q
);
1728 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
1730 torture_assert_int_equal(torture
, q
.all_info2
.out
.size
, 0,
1731 "size after zero len clone");
1733 smb2_util_close(tree
, src_h
);
1734 smb2_util_close(tree
, dest_h
);
1735 talloc_free(tmp_ctx
);
1739 static NTSTATUS
test_ioctl_compress_fs_supported(struct torture_context
*torture
,
1740 struct smb2_tree
*tree
,
1741 TALLOC_CTX
*mem_ctx
,
1742 struct smb2_handle
*fh
,
1743 bool *compress_support
)
1746 union smb_fsinfo info
;
1749 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
1750 info
.generic
.handle
= *fh
;
1751 status
= smb2_getinfo_fs(tree
, tree
, &info
);
1752 if (!NT_STATUS_IS_OK(status
)) {
1756 if (info
.attribute_info
.out
.fs_attr
& FILE_FILE_COMPRESSION
) {
1757 *compress_support
= true;
1759 *compress_support
= false;
1761 return NT_STATUS_OK
;
1764 static NTSTATUS
test_ioctl_compress_get(struct torture_context
*torture
,
1765 TALLOC_CTX
*mem_ctx
,
1766 struct smb2_tree
*tree
,
1767 struct smb2_handle fh
,
1768 uint16_t *_compression_fmt
)
1770 union smb_ioctl ioctl
;
1771 struct compression_state cmpr_state
;
1772 enum ndr_err_code ndr_ret
;
1776 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1777 ioctl
.smb2
.in
.file
.handle
= fh
;
1778 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1779 ioctl
.smb2
.in
.max_response_size
= sizeof(struct compression_state
);
1780 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1782 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1783 if (!NT_STATUS_IS_OK(status
)) {
1787 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, mem_ctx
,
1789 (ndr_pull_flags_fn_t
)ndr_pull_compression_state
);
1791 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1792 return NT_STATUS_INTERNAL_ERROR
;
1795 *_compression_fmt
= cmpr_state
.format
;
1796 return NT_STATUS_OK
;
1799 static NTSTATUS
test_ioctl_compress_set(struct torture_context
*torture
,
1800 TALLOC_CTX
*mem_ctx
,
1801 struct smb2_tree
*tree
,
1802 struct smb2_handle fh
,
1803 uint16_t compression_fmt
)
1805 union smb_ioctl ioctl
;
1806 struct compression_state cmpr_state
;
1807 enum ndr_err_code ndr_ret
;
1811 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1812 ioctl
.smb2
.in
.file
.handle
= fh
;
1813 ioctl
.smb2
.in
.function
= FSCTL_SET_COMPRESSION
;
1814 ioctl
.smb2
.in
.max_response_size
= 0;
1815 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1817 cmpr_state
.format
= compression_fmt
;
1818 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, mem_ctx
,
1820 (ndr_push_flags_fn_t
)ndr_push_compression_state
);
1821 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1822 return NT_STATUS_INTERNAL_ERROR
;
1825 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1829 static bool test_ioctl_compress_file_flag(struct torture_context
*torture
,
1830 struct smb2_tree
*tree
)
1832 struct smb2_handle fh
;
1834 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1836 uint16_t compression_fmt
;
1838 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1839 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1840 FILE_ATTRIBUTE_NORMAL
);
1841 torture_assert(torture
, ok
, "setup compression file");
1843 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1845 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1847 smb2_util_close(tree
, fh
);
1848 torture_skip(torture
, "FS compression not supported\n");
1851 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1853 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1855 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1856 "initial compression state not NONE");
1858 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1859 COMPRESSION_FORMAT_DEFAULT
);
1860 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1862 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1864 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1866 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1867 "invalid compression state after set");
1869 smb2_util_close(tree
, fh
);
1870 talloc_free(tmp_ctx
);
1874 static bool test_ioctl_compress_dir_inherit(struct torture_context
*torture
,
1875 struct smb2_tree
*tree
)
1877 struct smb2_handle dirh
;
1878 struct smb2_handle fh
;
1880 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1881 uint16_t compression_fmt
;
1883 char path_buf
[PATH_MAX
];
1885 smb2_deltree(tree
, DNAME
);
1886 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1887 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
1888 FILE_ATTRIBUTE_DIRECTORY
);
1889 torture_assert(torture
, ok
, "setup compression directory");
1891 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
1893 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1895 smb2_util_close(tree
, dirh
);
1896 smb2_deltree(tree
, DNAME
);
1897 torture_skip(torture
, "FS compression not supported\n");
1900 /* set compression on parent dir, then check for inheritance */
1901 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1902 COMPRESSION_FORMAT_LZNT1
);
1903 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1905 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
1907 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1909 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1910 "invalid compression state after set");
1912 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
1913 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1914 path_buf
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
1915 FILE_ATTRIBUTE_NORMAL
);
1916 torture_assert(torture
, ok
, "setup compression file");
1918 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1920 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1922 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1923 "compression attr not inherited by new file");
1925 /* check compressed data is consistent */
1926 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, 0, 4096, 0);
1928 /* disable dir compression attr, file should remain compressed */
1929 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1930 COMPRESSION_FORMAT_NONE
);
1931 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1933 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1935 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1937 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1938 "file compression attr removed after dir change");
1939 smb2_util_close(tree
, fh
);
1941 /* new files should no longer inherit compression attr */
1942 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
1943 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1944 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1945 FILE_ATTRIBUTE_NORMAL
);
1946 torture_assert(torture
, ok
, "setup file");
1948 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1950 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1952 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1953 "compression attr present on new file");
1955 smb2_util_close(tree
, fh
);
1956 smb2_util_close(tree
, dirh
);
1957 smb2_deltree(tree
, DNAME
);
1958 talloc_free(tmp_ctx
);
1962 static bool test_ioctl_compress_invalid_format(struct torture_context
*torture
,
1963 struct smb2_tree
*tree
)
1965 struct smb2_handle fh
;
1967 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1969 uint16_t compression_fmt
;
1971 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1972 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1973 FILE_ATTRIBUTE_NORMAL
);
1974 torture_assert(torture
, ok
, "setup compression file");
1976 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1978 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1980 smb2_util_close(tree
, fh
);
1981 torture_skip(torture
, "FS compression not supported\n");
1984 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1985 0x0042); /* bogus */
1986 torture_assert_ntstatus_equal(torture
, status
,
1987 NT_STATUS_INVALID_PARAMETER
,
1988 "invalid FSCTL_SET_COMPRESSION");
1990 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1992 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1994 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1995 "initial compression state not NONE");
1997 smb2_util_close(tree
, fh
);
1998 talloc_free(tmp_ctx
);
2002 static bool test_ioctl_compress_invalid_buf(struct torture_context
*torture
,
2003 struct smb2_tree
*tree
)
2005 struct smb2_handle fh
;
2007 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2009 union smb_ioctl ioctl
;
2011 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2012 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2013 FILE_ATTRIBUTE_NORMAL
);
2014 torture_assert(torture
, ok
, "setup compression file");
2016 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2018 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2020 smb2_util_close(tree
, fh
);
2021 torture_skip(torture
, "FS compression not supported\n");
2025 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2026 ioctl
.smb2
.in
.file
.handle
= fh
;
2027 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
2028 ioctl
.smb2
.in
.max_response_size
= 0; /* no room for rsp data */
2029 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2031 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2032 if (!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_USER_BUFFER
)
2033 && !NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
2034 /* neither Server 2k12 nor 2k8r2 response status */
2035 torture_assert(torture
, true,
2036 "invalid FSCTL_SET_COMPRESSION");
2039 smb2_util_close(tree
, fh
);
2040 talloc_free(tmp_ctx
);
2044 static bool test_ioctl_compress_query_file_attr(struct torture_context
*torture
,
2045 struct smb2_tree
*tree
)
2047 struct smb2_handle fh
;
2048 union smb_fileinfo io
;
2050 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2053 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2054 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2055 FILE_ATTRIBUTE_NORMAL
);
2056 torture_assert(torture
, ok
, "setup compression file");
2058 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2060 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2062 smb2_util_close(tree
, fh
);
2063 torture_skip(torture
, "FS compression not supported\n");
2067 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2068 io
.generic
.in
.file
.handle
= fh
;
2069 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2070 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2072 torture_assert(torture
,
2073 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2074 "compression attr before set");
2076 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2077 COMPRESSION_FORMAT_DEFAULT
);
2078 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2081 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2082 io
.generic
.in
.file
.handle
= fh
;
2083 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2084 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2086 torture_assert(torture
,
2087 (io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2088 "no compression attr after set");
2090 smb2_util_close(tree
, fh
);
2091 talloc_free(tmp_ctx
);
2096 * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2099 static bool test_ioctl_compress_create_with_attr(struct torture_context
*torture
,
2100 struct smb2_tree
*tree
)
2102 struct smb2_handle fh2
;
2103 union smb_fileinfo io
;
2105 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2106 uint16_t compression_fmt
;
2109 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2110 FNAME2
, &fh2
, 0, SEC_RIGHTS_FILE_ALL
,
2111 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_COMPRESSED
));
2112 torture_assert(torture
, ok
, "setup compression file");
2114 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh2
,
2116 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2118 smb2_util_close(tree
, fh2
);
2119 torture_skip(torture
, "FS compression not supported\n");
2122 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh2
,
2124 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2126 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2127 "initial compression state not NONE");
2130 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2131 io
.generic
.in
.file
.handle
= fh2
;
2132 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2133 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2135 torture_assert(torture
,
2136 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2137 "incorrect compression attr");
2139 smb2_util_close(tree
, fh2
);
2140 talloc_free(tmp_ctx
);
2144 static bool test_ioctl_compress_inherit_disable(struct torture_context
*torture
,
2145 struct smb2_tree
*tree
)
2147 struct smb2_handle fh
;
2148 struct smb2_handle dirh
;
2149 char path_buf
[PATH_MAX
];
2151 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2153 uint16_t compression_fmt
;
2155 struct smb2_create io
;
2157 smb2_deltree(tree
, DNAME
);
2158 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2159 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2160 FILE_ATTRIBUTE_DIRECTORY
);
2161 torture_assert(torture
, ok
, "setup compression directory");
2163 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2165 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2167 smb2_util_close(tree
, dirh
);
2168 smb2_deltree(tree
, DNAME
);
2169 torture_skip(torture
, "FS compression not supported\n");
2172 /* set compression on parent dir, then check for inheritance */
2173 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
2174 COMPRESSION_FORMAT_LZNT1
);
2175 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2177 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2179 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2181 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2182 "invalid compression state after set");
2183 smb2_util_close(tree
, dirh
);
2185 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
2186 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2187 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2188 FILE_ATTRIBUTE_NORMAL
);
2189 torture_assert(torture
, ok
, "setup compression file");
2191 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2193 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2195 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2196 "compression attr not inherited by new file");
2197 smb2_util_close(tree
, fh
);
2199 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
2201 /* NO_COMPRESSION option should block inheritance */
2203 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2204 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2205 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2206 io
.in
.create_options
= NTCREATEX_OPTIONS_NO_COMPRESSION
;
2207 io
.in
.share_access
=
2208 NTCREATEX_SHARE_ACCESS_DELETE
|
2209 NTCREATEX_SHARE_ACCESS_READ
|
2210 NTCREATEX_SHARE_ACCESS_WRITE
;
2211 io
.in
.fname
= path_buf
;
2213 status
= smb2_create(tree
, tmp_ctx
, &io
);
2214 torture_assert_ntstatus_ok(torture
, status
, "file create");
2216 fh
= io
.out
.file
.handle
;
2218 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2220 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2222 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2223 "compression attr inherited by NO_COMPRESSION file");
2224 smb2_util_close(tree
, fh
);
2227 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, DNAME
);
2229 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2230 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2231 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2232 io
.in
.create_options
= (NTCREATEX_OPTIONS_NO_COMPRESSION
2233 | NTCREATEX_OPTIONS_DIRECTORY
);
2234 io
.in
.share_access
=
2235 NTCREATEX_SHARE_ACCESS_DELETE
|
2236 NTCREATEX_SHARE_ACCESS_READ
|
2237 NTCREATEX_SHARE_ACCESS_WRITE
;
2238 io
.in
.fname
= path_buf
;
2240 status
= smb2_create(tree
, tmp_ctx
, &io
);
2241 torture_assert_ntstatus_ok(torture
, status
, "dir create");
2243 dirh
= io
.out
.file
.handle
;
2245 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2247 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2249 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2250 "compression attr inherited by NO_COMPRESSION dir");
2251 smb2_util_close(tree
, dirh
);
2252 smb2_deltree(tree
, DNAME
);
2254 talloc_free(tmp_ctx
);
2258 /* attempting to set compression via SetInfo should not stick */
2259 static bool test_ioctl_compress_set_file_attr(struct torture_context
*torture
,
2260 struct smb2_tree
*tree
)
2262 struct smb2_handle fh
;
2263 struct smb2_handle dirh
;
2264 union smb_fileinfo io
;
2265 union smb_setfileinfo set_io
;
2266 uint16_t compression_fmt
;
2268 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2271 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2272 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2273 FILE_ATTRIBUTE_NORMAL
);
2274 torture_assert(torture
, ok
, "setup compression file");
2276 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2278 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2280 smb2_util_close(tree
, fh
);
2281 torture_skip(torture
, "FS compression not supported\n");
2285 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2286 io
.generic
.in
.file
.handle
= fh
;
2287 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2288 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2290 torture_assert(torture
,
2291 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2292 "compression attr before set");
2294 ZERO_STRUCT(set_io
);
2295 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2296 set_io
.basic_info
.in
.file
.handle
= fh
;
2297 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2298 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2299 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2300 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2301 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2302 | FILE_ATTRIBUTE_COMPRESSED
);
2303 status
= smb2_setinfo_file(tree
, &set_io
);
2304 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2307 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2308 io
.generic
.in
.file
.handle
= fh
;
2309 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2310 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2312 torture_assert(torture
,
2313 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2314 "compression attr after set");
2316 smb2_util_close(tree
, fh
);
2317 smb2_deltree(tree
, DNAME
);
2318 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2319 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2320 FILE_ATTRIBUTE_DIRECTORY
);
2321 torture_assert(torture
, ok
, "setup compression directory");
2324 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2325 io
.generic
.in
.file
.handle
= dirh
;
2326 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2327 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2329 torture_assert(torture
,
2330 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2331 "compression attr before set");
2333 ZERO_STRUCT(set_io
);
2334 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2335 set_io
.basic_info
.in
.file
.handle
= dirh
;
2336 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2337 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2338 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2339 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2340 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2341 | FILE_ATTRIBUTE_COMPRESSED
);
2342 status
= smb2_setinfo_file(tree
, &set_io
);
2343 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2345 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2347 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2349 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2350 "dir compression set after SetInfo");
2352 smb2_util_close(tree
, dirh
);
2353 talloc_free(tmp_ctx
);
2357 static bool test_ioctl_compress_perms(struct torture_context
*torture
,
2358 struct smb2_tree
*tree
)
2360 struct smb2_handle fh
;
2361 uint16_t compression_fmt
;
2362 union smb_fileinfo io
;
2364 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2367 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2368 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2369 FILE_ATTRIBUTE_NORMAL
);
2370 torture_assert(torture
, ok
, "setup compression file");
2372 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2374 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2375 smb2_util_close(tree
, fh
);
2377 torture_skip(torture
, "FS compression not supported\n");
2380 /* attempt get compression without READ_ATTR permission */
2381 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2383 (SEC_RIGHTS_FILE_READ
& ~(SEC_FILE_READ_ATTRIBUTE
2384 | SEC_STD_READ_CONTROL
2385 | SEC_FILE_READ_EA
)),
2386 FILE_ATTRIBUTE_NORMAL
);
2387 torture_assert(torture
, ok
, "setup compression file");
2389 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2391 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2392 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2393 "compression set after create");
2394 smb2_util_close(tree
, fh
);
2396 /* set compression without WRITE_ATTR permission should succeed */
2397 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2399 (SEC_RIGHTS_FILE_WRITE
& ~(SEC_FILE_WRITE_ATTRIBUTE
2401 | SEC_FILE_WRITE_EA
)),
2402 FILE_ATTRIBUTE_NORMAL
);
2403 torture_assert(torture
, ok
, "setup compression file");
2405 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2406 COMPRESSION_FORMAT_DEFAULT
);
2407 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2408 smb2_util_close(tree
, fh
);
2410 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
2411 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
2412 FILE_ATTRIBUTE_NORMAL
);
2413 torture_assert(torture
, ok
, "setup compression file");
2415 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2416 io
.generic
.in
.file
.handle
= fh
;
2417 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2418 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2420 torture_assert(torture
,
2421 (io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2422 "incorrect compression attr");
2423 smb2_util_close(tree
, fh
);
2425 /* attempt get compression without READ_DATA permission */
2426 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2428 (SEC_RIGHTS_FILE_READ
& ~SEC_FILE_READ_DATA
),
2429 FILE_ATTRIBUTE_NORMAL
);
2430 torture_assert(torture
, ok
, "setup compression file");
2432 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2434 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2435 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2436 "compression enabled after set");
2437 smb2_util_close(tree
, fh
);
2439 /* attempt get compression with only SYNCHRONIZE permission */
2440 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2442 SEC_STD_SYNCHRONIZE
,
2443 FILE_ATTRIBUTE_NORMAL
);
2444 torture_assert(torture
, ok
, "setup compression file");
2446 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2448 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2449 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2450 "compression not enabled after set");
2451 smb2_util_close(tree
, fh
);
2453 /* attempt to set compression without WRITE_DATA permission */
2454 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2456 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2457 FILE_ATTRIBUTE_NORMAL
);
2458 torture_assert(torture
, ok
, "setup compression file");
2460 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2461 COMPRESSION_FORMAT_DEFAULT
);
2462 torture_assert_ntstatus_equal(torture
, status
,
2463 NT_STATUS_ACCESS_DENIED
,
2464 "FSCTL_SET_COMPRESSION permission");
2465 smb2_util_close(tree
, fh
);
2467 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2469 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2470 FILE_ATTRIBUTE_NORMAL
);
2471 torture_assert(torture
, ok
, "setup compression file");
2473 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2474 COMPRESSION_FORMAT_NONE
);
2475 torture_assert_ntstatus_equal(torture
, status
,
2476 NT_STATUS_ACCESS_DENIED
,
2477 "FSCTL_SET_COMPRESSION permission");
2478 smb2_util_close(tree
, fh
);
2480 talloc_free(tmp_ctx
);
2485 basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
2487 static bool test_ioctl_network_interface_info(struct torture_context
*torture
,
2488 struct smb2_tree
*tree
)
2490 union smb_ioctl ioctl
;
2491 struct smb2_handle fh
;
2493 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2494 struct fsctl_net_iface_info net_iface
;
2495 enum ndr_err_code ndr_ret
;
2498 caps
= smb2cli_conn_server_capabilities(tree
->session
->transport
->conn
);
2499 if (!(caps
& SMB2_CAP_MULTI_CHANNEL
)) {
2500 torture_skip(torture
, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
2504 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2505 fh
.data
[0] = UINT64_MAX
;
2506 fh
.data
[1] = UINT64_MAX
;
2507 ioctl
.smb2
.in
.file
.handle
= fh
;
2508 ioctl
.smb2
.in
.function
= FSCTL_QUERY_NETWORK_INTERFACE_INFO
;
2509 ioctl
.smb2
.in
.max_response_size
= 0x10000; /* Windows client sets this to 64KiB */
2510 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2512 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2513 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
2515 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &net_iface
,
2516 (ndr_pull_flags_fn_t
)ndr_pull_fsctl_net_iface_info
);
2517 torture_assert_ndr_success(torture
, ndr_ret
,
2518 "ndr_pull_fsctl_net_iface_info");
2520 ndr_print_debug((ndr_print_fn_t
)ndr_print_fsctl_net_iface_info
,
2521 "Network Interface Info", &net_iface
);
2523 talloc_free(tmp_ctx
);
2527 static NTSTATUS
test_ioctl_sparse_fs_supported(struct torture_context
*torture
,
2528 struct smb2_tree
*tree
,
2529 TALLOC_CTX
*mem_ctx
,
2530 struct smb2_handle
*fh
,
2531 bool *sparse_support
)
2534 union smb_fsinfo info
;
2537 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
2538 info
.generic
.handle
= *fh
;
2539 status
= smb2_getinfo_fs(tree
, tree
, &info
);
2540 if (!NT_STATUS_IS_OK(status
)) {
2544 if (info
.attribute_info
.out
.fs_attr
& FILE_SUPPORTS_SPARSE_FILES
) {
2545 *sparse_support
= true;
2547 *sparse_support
= false;
2549 return NT_STATUS_OK
;
2552 static NTSTATUS
test_ioctl_sparse_req(struct torture_context
*torture
,
2553 TALLOC_CTX
*mem_ctx
,
2554 struct smb2_tree
*tree
,
2555 struct smb2_handle fh
,
2558 union smb_ioctl ioctl
;
2563 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2564 ioctl
.smb2
.in
.file
.handle
= fh
;
2565 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2566 ioctl
.smb2
.in
.max_response_size
= 0;
2567 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2568 set_sparse
= (set
? 0xFF : 0x0);
2569 ioctl
.smb2
.in
.out
.data
= &set_sparse
;
2570 ioctl
.smb2
.in
.out
.length
= sizeof(set_sparse
);
2572 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
2576 static NTSTATUS
test_sparse_get(struct torture_context
*torture
,
2577 TALLOC_CTX
*mem_ctx
,
2578 struct smb2_tree
*tree
,
2579 struct smb2_handle fh
,
2582 union smb_fileinfo io
;
2586 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2587 io
.generic
.in
.file
.handle
= fh
;
2588 status
= smb2_getinfo_file(tree
, mem_ctx
, &io
);
2589 if (!NT_STATUS_IS_OK(status
)) {
2592 *_is_sparse
= !!(io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
);
2597 static bool test_ioctl_sparse_file_flag(struct torture_context
*torture
,
2598 struct smb2_tree
*tree
)
2600 struct smb2_handle fh
;
2601 union smb_fileinfo io
;
2603 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2607 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2608 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2609 FILE_ATTRIBUTE_NORMAL
);
2610 torture_assert(torture
, ok
, "setup file");
2612 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2614 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2616 smb2_util_close(tree
, fh
);
2617 torture_skip(torture
, "Sparse files not supported\n");
2621 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2622 io
.generic
.in
.file
.handle
= fh
;
2623 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2624 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2626 torture_assert(torture
,
2627 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
) == 0),
2628 "sparse attr before set");
2630 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
2631 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2633 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2634 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2635 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2637 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
2638 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2640 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2641 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2642 torture_assert(torture
, !is_sparse
, "sparse attr after unset");
2644 smb2_util_close(tree
, fh
);
2645 talloc_free(tmp_ctx
);
2649 static bool test_ioctl_sparse_file_attr(struct torture_context
*torture
,
2650 struct smb2_tree
*tree
)
2652 struct smb2_handle fh
;
2654 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2658 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2659 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2660 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_SPARSE
));
2661 torture_assert(torture
, ok
, "setup file");
2663 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2665 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2667 smb2_util_close(tree
, fh
);
2668 torture_skip(torture
, "Sparse files not supported\n");
2671 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2672 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2673 torture_assert(torture
, !is_sparse
, "sparse attr on open");
2675 smb2_util_close(tree
, fh
);
2676 talloc_free(tmp_ctx
);
2680 static bool test_ioctl_sparse_dir_flag(struct torture_context
*torture
,
2681 struct smb2_tree
*tree
)
2683 struct smb2_handle dirh
;
2685 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2688 smb2_deltree(tree
, DNAME
);
2689 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2690 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2691 FILE_ATTRIBUTE_DIRECTORY
);
2692 torture_assert(torture
, ok
, "setup sparse directory");
2694 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2696 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2698 smb2_util_close(tree
, dirh
);
2699 smb2_deltree(tree
, DNAME
);
2700 torture_skip(torture
, "Sparse files not supported\n");
2703 /* set sparse dir should fail, check for 2k12 & 2k8 response */
2704 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, dirh
, true);
2705 torture_assert_ntstatus_equal(torture
, status
,
2706 NT_STATUS_INVALID_PARAMETER
,
2707 "dir FSCTL_SET_SPARSE status");
2709 smb2_util_close(tree
, dirh
);
2710 smb2_deltree(tree
, DNAME
);
2711 talloc_free(tmp_ctx
);
2716 * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse
2717 * buffer to indicate whether the flag should be set or cleared. When sent
2718 * without a buffer, it must be handled as if SetSparse=TRUE.
2720 static bool test_ioctl_sparse_set_nobuf(struct torture_context
*torture
,
2721 struct smb2_tree
*tree
)
2723 struct smb2_handle fh
;
2724 union smb_ioctl ioctl
;
2726 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2730 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2731 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2732 FILE_ATTRIBUTE_NORMAL
);
2733 torture_assert(torture
, ok
, "setup file");
2735 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2737 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2739 smb2_util_close(tree
, fh
);
2740 torture_skip(torture
, "Sparse files not supported\n");
2743 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2744 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2745 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2748 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2749 ioctl
.smb2
.in
.file
.handle
= fh
;
2750 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2751 ioctl
.smb2
.in
.max_response_size
= 0;
2752 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2753 /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */
2755 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2756 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2758 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2759 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2760 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2762 /* second non-SetSparse request shouldn't toggle sparse */
2764 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2765 ioctl
.smb2
.in
.file
.handle
= fh
;
2766 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2767 ioctl
.smb2
.in
.max_response_size
= 0;
2768 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2770 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2771 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2773 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2774 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2775 torture_assert(torture
, is_sparse
, "no sparse attr after 2nd set");
2777 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
2778 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2780 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2781 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2782 torture_assert(torture
, !is_sparse
, "sparse attr after unset");
2784 smb2_util_close(tree
, fh
);
2785 talloc_free(tmp_ctx
);
2789 static bool test_ioctl_sparse_set_oversize(struct torture_context
*torture
,
2790 struct smb2_tree
*tree
)
2792 struct smb2_handle fh
;
2793 union smb_ioctl ioctl
;
2795 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2800 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2801 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2802 FILE_ATTRIBUTE_NORMAL
);
2803 torture_assert(torture
, ok
, "setup file");
2805 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2807 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2809 smb2_util_close(tree
, fh
);
2810 torture_skip(torture
, "Sparse files not supported\n");
2813 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2814 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2815 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2818 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2819 ioctl
.smb2
.in
.file
.handle
= fh
;
2820 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2821 ioctl
.smb2
.in
.max_response_size
= 0;
2822 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2825 * Attach a request buffer larger than FILE_SET_SPARSE_BUFFER
2826 * Windows still successfully processes the request.
2829 buf
[0] = 0xFF; /* attempt to set sparse */
2830 ioctl
.smb2
.in
.out
.data
= buf
;
2831 ioctl
.smb2
.in
.out
.length
= ARRAY_SIZE(buf
);
2833 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2834 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2836 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2837 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2838 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2841 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2842 ioctl
.smb2
.in
.file
.handle
= fh
;
2843 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2844 ioctl
.smb2
.in
.max_response_size
= 0;
2845 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2847 ZERO_ARRAY(buf
); /* clear sparse */
2848 ioctl
.smb2
.in
.out
.data
= buf
;
2849 ioctl
.smb2
.in
.out
.length
= ARRAY_SIZE(buf
);
2851 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2852 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2854 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2855 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2856 torture_assert(torture
, !is_sparse
, "sparse attr after clear");
2858 smb2_util_close(tree
, fh
);
2859 talloc_free(tmp_ctx
);
2863 static NTSTATUS
test_ioctl_qar_req(struct torture_context
*torture
,
2864 TALLOC_CTX
*mem_ctx
,
2865 struct smb2_tree
*tree
,
2866 struct smb2_handle fh
,
2869 struct file_alloced_range_buf
**_rsp
,
2870 uint64_t *_rsp_count
)
2872 union smb_ioctl ioctl
;
2874 enum ndr_err_code ndr_ret
;
2875 struct file_alloced_range_buf far_buf
;
2876 struct file_alloced_range_buf
*far_rsp
= NULL
;
2877 uint64_t far_count
= 0;
2879 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
2880 if (tmp_ctx
== NULL
) {
2881 return NT_STATUS_NO_MEMORY
;
2885 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2886 ioctl
.smb2
.in
.file
.handle
= fh
;
2887 ioctl
.smb2
.in
.function
= FSCTL_QUERY_ALLOCATED_RANGES
;
2888 ioctl
.smb2
.in
.max_response_size
= 1024;
2889 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2891 far_buf
.file_off
= req_off
;
2892 far_buf
.len
= req_len
;
2894 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
2896 (ndr_push_flags_fn_t
)ndr_push_file_alloced_range_buf
);
2897 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2898 status
= NT_STATUS_UNSUCCESSFUL
;
2902 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2903 if (!NT_STATUS_IS_OK(status
)) {
2907 if (ioctl
.smb2
.out
.out
.length
== 0) {
2911 if ((ioctl
.smb2
.out
.out
.length
% sizeof(far_buf
)) != 0) {
2912 torture_comment(torture
, "invalid qry_alloced rsp len: %zd:",
2913 ioctl
.smb2
.out
.out
.length
);
2914 status
= NT_STATUS_INVALID_VIEW_SIZE
;
2918 far_count
= (ioctl
.smb2
.out
.out
.length
/ sizeof(far_buf
));
2919 far_rsp
= talloc_array(mem_ctx
, struct file_alloced_range_buf
,
2921 if (far_rsp
== NULL
) {
2922 status
= NT_STATUS_NO_MEMORY
;
2926 for (i
= 0; i
< far_count
; i
++) {
2927 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
2929 (ndr_pull_flags_fn_t
)ndr_pull_file_alloced_range_buf
);
2930 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2931 status
= NT_STATUS_UNSUCCESSFUL
;
2934 /* move to next buffer */
2935 ioctl
.smb2
.out
.out
.data
+= sizeof(far_buf
);
2936 ioctl
.smb2
.out
.out
.length
-= sizeof(far_buf
);
2941 *_rsp_count
= far_count
;
2942 status
= NT_STATUS_OK
;
2944 talloc_free(tmp_ctx
);
2948 static bool test_ioctl_sparse_qar(struct torture_context
*torture
,
2949 struct smb2_tree
*tree
)
2951 struct smb2_handle fh
;
2953 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2956 struct file_alloced_range_buf
*far_rsp
= NULL
;
2957 uint64_t far_count
= 0;
2959 /* zero length file, shouldn't have any ranges */
2960 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2961 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2962 FILE_ATTRIBUTE_NORMAL
);
2963 torture_assert(torture
, ok
, "setup file");
2965 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2967 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2969 smb2_util_close(tree
, fh
);
2970 torture_skip(torture
, "Sparse files not supported\n");
2973 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2974 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2975 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2977 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2982 torture_assert_ntstatus_ok(torture
, status
,
2983 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2984 torture_assert_u64_equal(torture
, far_count
, 0,
2985 "unexpected response len");
2987 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2992 torture_assert_ntstatus_ok(torture
, status
,
2993 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2994 torture_assert_u64_equal(torture
, far_count
, 0,
2995 "unexpected response len");
2997 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
2998 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3000 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
3001 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
3002 torture_assert(torture
, is_sparse
, "no sparse attr after set");
3004 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3009 torture_assert_ntstatus_ok(torture
, status
,
3010 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3011 torture_assert_u64_equal(torture
, far_count
, 0,
3012 "unexpected response len");
3014 /* write into the (now) sparse file at 4k offset */
3015 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3018 4096); /* pattern offset */
3019 torture_assert(torture
, ok
, "write pattern");
3022 * Query range before write off. Whether it's allocated or not is FS
3023 * dependent. NTFS deallocates chunks in 64K increments, but others
3024 * (e.g. XFS, Btrfs, etc.) may deallocate 4K chunks.
3026 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3031 torture_assert_ntstatus_ok(torture
, status
,
3032 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3033 if (far_count
== 0) {
3034 torture_comment(torture
, "FS deallocated 4K chunk\n");
3036 /* expect fully allocated */
3037 torture_assert_u64_equal(torture
, far_count
, 1,
3038 "unexpected response len");
3039 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0, "far offset");
3040 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 4096, "far len");
3044 * Query range before and past write, it should be allocated up to the
3047 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3052 torture_assert_ntstatus_ok(torture
, status
,
3053 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3054 torture_assert_u64_equal(torture
, far_count
, 1,
3055 "unexpected response len");
3057 if (far_rsp
[0].file_off
== 4096) {
3058 /* 4K chunk unallocated */
3059 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 4096, "far offset");
3060 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 1024, "far len");
3062 /* expect fully allocated */
3063 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0, "far offset");
3064 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 5120, "far len");
3067 smb2_util_close(tree
, fh
);
3068 talloc_free(tmp_ctx
);
3072 static bool test_ioctl_sparse_qar_malformed(struct torture_context
*torture
,
3073 struct smb2_tree
*tree
)
3075 struct smb2_handle fh
;
3076 union smb_ioctl ioctl
;
3077 struct file_alloced_range_buf far_buf
;
3079 enum ndr_err_code ndr_ret
;
3080 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3084 /* zero length file, shouldn't have any ranges */
3085 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3086 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
3087 FILE_ATTRIBUTE_NORMAL
);
3088 torture_assert(torture
, ok
, "setup file");
3090 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3092 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3094 smb2_util_close(tree
, fh
);
3095 torture_skip(torture
, "Sparse files not supported\n");
3098 /* no allocated ranges, no space for range response, should pass */
3100 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
3101 ioctl
.smb2
.in
.file
.handle
= fh
;
3102 ioctl
.smb2
.in
.function
= FSCTL_QUERY_ALLOCATED_RANGES
;
3103 ioctl
.smb2
.in
.max_response_size
= 0;
3104 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
3106 far_buf
.file_off
= 0;
3108 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
3110 (ndr_push_flags_fn_t
)ndr_push_file_alloced_range_buf
);
3111 torture_assert_ndr_success(torture
, ndr_ret
, "push far ndr buf");
3113 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3114 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_QUERY_ALLOCATED_RANGES");
3116 /* write into the file at 4k offset */
3117 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3120 0); /* pattern offset */
3121 torture_assert(torture
, ok
, "write pattern");
3123 /* allocated range, no space for range response, should fail */
3124 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3125 torture_assert_ntstatus_equal(torture
, status
,
3126 NT_STATUS_BUFFER_TOO_SMALL
, "qar no space");
3128 /* oversize (2x) file_alloced_range_buf in request, should pass */
3129 ioctl
.smb2
.in
.max_response_size
= 1024;
3130 old_len
= ioctl
.smb2
.in
.out
.length
;
3131 ok
= data_blob_realloc(tmp_ctx
, &ioctl
.smb2
.in
.out
,
3132 (ioctl
.smb2
.in
.out
.length
* 2));
3133 torture_assert(torture
, ok
, "2x data buffer");
3134 memcpy(ioctl
.smb2
.in
.out
.data
+ old_len
, ioctl
.smb2
.in
.out
.data
,
3136 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3137 torture_assert_ntstatus_ok(torture
, status
, "qar too big");
3139 /* no file_alloced_range_buf in request, should fail */
3140 data_blob_free(&ioctl
.smb2
.in
.out
);
3141 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3142 torture_assert_ntstatus_equal(torture
, status
,
3143 NT_STATUS_INVALID_PARAMETER
, "qar empty");
3149 * 2.3.57 FSCTL_SET_ZERO_DATA Request
3151 * How an implementation zeros data within a file is implementation-dependent.
3152 * A file system MAY choose to deallocate regions of disk space that have been
3155 * ... NTFS might deallocate disk space in the file if the file is stored on an
3156 * NTFS volume, and the file is sparse or compressed. It will free any allocated
3157 * space in chunks of 64 kilobytes that begin at an offset that is a multiple of
3158 * 64 kilobytes. Other bytes in the file (prior to the first freed 64-kilobyte
3159 * chunk and after the last freed 64-kilobyte chunk) will be zeroed but not
3162 static NTSTATUS
test_ioctl_zdata_req(struct torture_context
*torture
,
3163 TALLOC_CTX
*mem_ctx
,
3164 struct smb2_tree
*tree
,
3165 struct smb2_handle fh
,
3167 int64_t beyond_final_zero
)
3169 union smb_ioctl ioctl
;
3171 enum ndr_err_code ndr_ret
;
3172 struct file_zero_data_info zdata_info
;
3173 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
3174 if (tmp_ctx
== NULL
) {
3175 return NT_STATUS_NO_MEMORY
;
3179 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
3180 ioctl
.smb2
.in
.file
.handle
= fh
;
3181 ioctl
.smb2
.in
.function
= FSCTL_SET_ZERO_DATA
;
3182 ioctl
.smb2
.in
.max_response_size
= 0;
3183 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
3185 zdata_info
.file_off
= off
;
3186 zdata_info
.beyond_final_zero
= beyond_final_zero
;
3188 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
3190 (ndr_push_flags_fn_t
)ndr_push_file_zero_data_info
);
3191 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3192 status
= NT_STATUS_UNSUCCESSFUL
;
3196 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3197 if (!NT_STATUS_IS_OK(status
)) {
3201 status
= NT_STATUS_OK
;
3203 talloc_free(tmp_ctx
);
3207 static bool test_ioctl_sparse_punch(struct torture_context
*torture
,
3208 struct smb2_tree
*tree
)
3210 struct smb2_handle fh
;
3212 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3215 struct file_alloced_range_buf
*far_rsp
= NULL
;
3216 uint64_t far_count
= 0;
3218 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3219 FNAME
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
3220 FILE_ATTRIBUTE_NORMAL
);
3221 torture_assert(torture
, ok
, "setup file");
3223 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3225 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3227 smb2_util_close(tree
, fh
);
3228 torture_skip(torture
, "Sparse files not supported\n");
3231 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
3232 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
3233 torture_assert(torture
, !is_sparse
, "sparse attr before set");
3235 /* zero (hole-punch) the data, without sparse flag */
3236 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3238 4096); /* beyond_final_zero */
3239 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3241 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3246 torture_assert_ntstatus_ok(torture
, status
,
3247 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3248 torture_assert_u64_equal(torture
, far_count
, 1,
3249 "unexpected response len");
3251 /* expect fully allocated */
3252 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3253 "unexpected far off");
3254 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 4096,
3255 "unexpected far len");
3256 /* check that the data is now zeroed */
3257 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, 4096);
3258 torture_assert(torture
, ok
, "non-sparse zeroed range");
3261 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
3262 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3264 /* still fully allocated on NTFS, see note below for Samba */
3265 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3270 torture_assert_ntstatus_ok(torture
, status
,
3271 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3273 * FS specific: Samba uses PUNCH_HOLE to zero the range, and
3274 * subsequently uses fallocate() to allocate the punched range if the
3275 * file is marked non-sparse and "strict allocate" is enabled. In both
3276 * cases, the zeroed range will not be detected by SEEK_DATA, so the
3277 * range won't be present in QAR responses until the file is marked
3280 if (far_count
== 0) {
3281 torture_comment(torture
, "non-sparse zeroed range disappeared "
3282 "after marking sparse\n");
3284 /* NTFS: range remains fully allocated */
3285 torture_assert_u64_equal(torture
, far_count
, 1,
3286 "unexpected response len");
3287 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3288 "unexpected far off");
3289 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 4096,
3290 "unexpected far len");
3293 /* zero (hole-punch) the data, _with_ sparse flag */
3294 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3296 4096); /* beyond_final_zero */
3297 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3299 /* the range should no longer be alloced */
3300 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3305 torture_assert_ntstatus_ok(torture
, status
,
3306 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3307 torture_assert_u64_equal(torture
, far_count
, 0,
3308 "unexpected response len");
3310 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, 4096);
3311 torture_assert(torture
, ok
, "sparse zeroed range");
3313 /* remove sparse flag, this should "unsparse" the zeroed range */
3314 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
3315 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3317 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3322 torture_assert_ntstatus_ok(torture
, status
,
3323 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3324 torture_assert_u64_equal(torture
, far_count
, 1,
3325 "unexpected response len");
3326 /* expect fully allocated */
3327 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3328 "unexpected far off");
3329 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 4096,
3330 "unexpected far len");
3332 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, 4096);
3333 torture_assert(torture
, ok
, "sparse zeroed range");
3335 smb2_util_close(tree
, fh
);
3336 talloc_free(tmp_ctx
);
3341 * Find the point at which a zeroed range in a sparse file is deallocated by the
3342 * underlying filesystem. NTFS on Windows Server 2012 deallocates chunks in 64k
3343 * increments. Also check whether zeroed neighbours are merged for deallocation.
3345 static bool test_ioctl_sparse_hole_dealloc(struct torture_context
*torture
,
3346 struct smb2_tree
*tree
)
3348 struct smb2_handle fh
;
3350 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3354 uint64_t dealloc_chunk_len
= 0;
3355 struct file_alloced_range_buf
*far_rsp
= NULL
;
3356 uint64_t far_count
= 0;
3358 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3359 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
3360 FILE_ATTRIBUTE_NORMAL
);
3361 torture_assert(torture
, ok
, "setup file 1");
3363 /* check for FS sparse file */
3364 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3366 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3368 smb2_util_close(tree
, fh
);
3369 torture_skip(torture
, "Sparse files not supported\n");
3373 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
3374 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3376 file_size
= 1024 * 1024;
3378 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3380 file_size
, /* len */
3381 0); /* pattern offset */
3382 torture_assert(torture
, ok
, "write pattern");
3384 /* check allocated ranges, should be fully allocated */
3385 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3387 file_size
, /* len */
3390 torture_assert_ntstatus_ok(torture
, status
,
3391 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3392 torture_assert_u64_equal(torture
, far_count
, 1,
3393 "unexpected response len");
3394 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3395 "unexpected far off");
3396 torture_assert_u64_equal(torture
, far_rsp
[0].len
, file_size
,
3397 "unexpected far len");
3399 /* punch holes in sizes of 1k increments */
3400 for (hlen
= 0; hlen
<= file_size
; hlen
+= 4096) {
3402 /* punch a hole from zero to the current increment */
3403 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3405 hlen
); /* beyond_final_zero */
3406 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3408 /* ensure hole is zeroed, and pattern is consistent */
3409 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, hlen
);
3410 torture_assert(torture
, ok
, "sparse zeroed range");
3412 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, hlen
,
3413 file_size
- hlen
, hlen
);
3414 torture_assert(torture
, ok
, "allocated pattern range");
3416 /* Check allocated ranges, hole might have been deallocated */
3417 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3419 file_size
, /* len */
3422 torture_assert_ntstatus_ok(torture
, status
,
3423 "FSCTL_QUERY_ALLOCATED_RANGES");
3424 if ((hlen
== file_size
) && (far_count
== 0)) {
3425 /* hole covered entire file, deallocation occurred */
3426 dealloc_chunk_len
= file_size
;
3430 torture_assert_u64_equal(torture
, far_count
, 1,
3431 "unexpected response len");
3432 if (far_rsp
[0].file_off
!= 0) {
3434 * We now know the hole punch length needed to trigger a
3435 * deallocation on this FS...
3437 dealloc_chunk_len
= hlen
;
3438 torture_comment(torture
, "hole punch %lu@0 resulted in "
3439 "deallocation of %lu@0\n", hlen
,
3440 far_rsp
[0].file_off
);
3441 torture_assert_u64_equal(torture
,
3442 file_size
- far_rsp
[0].len
,
3443 far_rsp
[0].file_off
,
3444 "invalid alloced range");
3449 if (dealloc_chunk_len
== 0) {
3450 torture_comment(torture
, "strange, this FS never deallocates"
3451 "zeroed ranges in sparse files\n");
3452 return true; /* FS specific, not a failure */
3456 * Check whether deallocation occurs when the (now known)
3457 * deallocation chunk size is punched via two ZERO_DATA requests.
3458 * I.e. Does the FS merge the two ranges and deallocate the chunk?
3459 * NTFS on Windows Server 2012 does not.
3461 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3463 file_size
, /* len */
3464 0); /* pattern offset */
3465 torture_assert(torture
, ok
, "write pattern");
3467 /* divide dealloc chunk size by two, to use as punch length */
3468 hlen
= dealloc_chunk_len
>> 1;
3471 * /half of dealloc chunk size 1M\
3473 * /offset 0 | /dealloc chunk size |
3474 * |------------------ |-------------------|-------------------|
3475 * | zeroed, 1st punch | zeroed, 2nd punch | existing pattern |
3477 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3479 hlen
); /* beyond final zero */
3480 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3482 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3484 dealloc_chunk_len
); /* beyond final */
3485 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3487 /* ensure holes are zeroed, and pattern is consistent */
3488 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, dealloc_chunk_len
);
3489 torture_assert(torture
, ok
, "sparse zeroed range");
3491 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, dealloc_chunk_len
,
3492 file_size
- dealloc_chunk_len
, dealloc_chunk_len
);
3493 torture_assert(torture
, ok
, "allocated pattern range");
3495 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3497 file_size
, /* len */
3500 torture_assert_ntstatus_ok(torture
, status
,
3501 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3503 if ((far_count
== 0) && (dealloc_chunk_len
== file_size
)) {
3504 torture_comment(torture
, "holes merged for deallocation of "
3508 torture_assert_u64_equal(torture
, far_count
, 1,
3509 "unexpected response len");
3510 if (far_rsp
[0].file_off
== dealloc_chunk_len
) {
3511 torture_comment(torture
, "holes merged for deallocation of "
3512 "%lu chunk\n", dealloc_chunk_len
);
3513 torture_assert_u64_equal(torture
,
3514 file_size
- far_rsp
[0].len
,
3515 far_rsp
[0].file_off
,
3516 "invalid alloced range");
3518 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3519 "unexpected deallocation");
3520 torture_comment(torture
, "holes not merged for deallocation\n");
3523 smb2_util_close(tree
, fh
);
3526 * Check whether an unwritten range is allocated when a sparse file is
3527 * written to at an offset past the dealloc chunk size:
3529 * /dealloc chunk size
3531 * |------------------ |-------------------|
3532 * | unwritten | pattern |
3534 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3535 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
3536 FILE_ATTRIBUTE_NORMAL
);
3537 torture_assert(torture
, ok
, "setup file 1");
3540 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
3541 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3543 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3544 dealloc_chunk_len
, /* off */
3546 dealloc_chunk_len
); /* pattern offset */
3547 torture_assert(torture
, ok
, "write pattern");
3549 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3551 dealloc_chunk_len
+ 1024, /* len */
3554 torture_assert_ntstatus_ok(torture
, status
,
3555 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3556 torture_assert_u64_equal(torture
, far_count
, 1,
3557 "unexpected response len");
3558 if (far_rsp
[0].file_off
== 0) {
3559 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
3560 dealloc_chunk_len
+ 1024,
3561 "unexpected far len");
3562 torture_comment(torture
, "unwritten range fully allocated\n");
3564 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, dealloc_chunk_len
,
3565 "unexpected deallocation");
3566 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 1024,
3567 "unexpected far len");
3568 torture_comment(torture
, "unwritten range not allocated\n");
3571 ok
= check_zero(torture
, tree
, tmp_ctx
, fh
, 0, dealloc_chunk_len
);
3572 torture_assert(torture
, ok
, "sparse zeroed range");
3574 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, dealloc_chunk_len
,
3575 1024, dealloc_chunk_len
);
3576 torture_assert(torture
, ok
, "allocated pattern range");
3578 /* unsparse, should now be fully allocated */
3579 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
3580 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3582 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3584 dealloc_chunk_len
+ 1024, /* len */
3587 torture_assert_ntstatus_ok(torture
, status
,
3588 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3589 torture_assert_u64_equal(torture
, far_count
, 1,
3590 "unexpected response len");
3591 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3592 "unexpected deallocation");
3593 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
3594 dealloc_chunk_len
+ 1024,
3595 "unexpected far len");
3597 smb2_util_close(tree
, fh
);
3598 talloc_free(tmp_ctx
);
3602 /* check whether a file with compression and sparse attrs can be deallocated */
3603 static bool test_ioctl_sparse_compressed(struct torture_context
*torture
,
3604 struct smb2_tree
*tree
)
3606 struct smb2_handle fh
;
3608 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3610 uint64_t file_size
= 1024 * 1024;
3611 struct file_alloced_range_buf
*far_rsp
= NULL
;
3612 uint64_t far_count
= 0;
3614 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3615 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
3616 FILE_ATTRIBUTE_NORMAL
);
3617 torture_assert(torture
, ok
, "setup file 1");
3619 /* check for FS sparse file and compression support */
3620 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3622 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3624 smb2_util_close(tree
, fh
);
3625 torture_skip(torture
, "Sparse files not supported\n");
3628 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3630 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3632 smb2_util_close(tree
, fh
);
3633 torture_skip(torture
, "FS compression not supported\n");
3636 /* set compression and write some data */
3637 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
3638 COMPRESSION_FORMAT_DEFAULT
);
3639 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
3641 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
3643 file_size
, /* len */
3644 0); /* pattern offset */
3645 torture_assert(torture
, ok
, "write pattern");
3647 /* set sparse - now sparse and compressed */
3648 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
3649 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3651 /* check allocated ranges, should be fully alloced */
3652 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3654 file_size
, /* len */
3657 torture_assert_ntstatus_ok(torture
, status
,
3658 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3659 torture_assert_u64_equal(torture
, far_count
, 1,
3660 "unexpected response len");
3661 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3662 "unexpected far off");
3663 torture_assert_u64_equal(torture
, far_rsp
[0].len
, file_size
,
3664 "unexpected far len");
3666 /* zero (hole-punch) all data, with sparse and compressed attrs */
3667 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3669 file_size
); /* beyond_final_zero */
3670 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3673 * Windows Server 2012 still deallocates a zeroed range when a sparse
3674 * file carries the compression attribute.
3676 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3678 file_size
, /* len */
3681 torture_assert_ntstatus_ok(torture
, status
,
3682 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3683 if (far_count
== 0) {
3684 torture_comment(torture
, "sparse & compressed file "
3685 "deallocated after hole-punch\n");
3687 torture_assert_u64_equal(torture
, far_count
, 1,
3688 "unexpected response len");
3689 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3690 "unexpected far off");
3691 torture_assert_u64_equal(torture
, far_rsp
[0].len
, file_size
,
3692 "unexpected far len");
3693 torture_comment(torture
, "sparse & compressed file fully "
3694 "allocated after hole-punch\n");
3697 smb2_util_close(tree
, fh
);
3698 talloc_free(tmp_ctx
);
3703 * Create a sparse file, then attempt to copy unallocated and allocated ranges
3704 * into a target file using FSCTL_SRV_COPYCHUNK.
3706 static bool test_ioctl_sparse_copy_chunk(struct torture_context
*torture
,
3707 struct smb2_tree
*tree
)
3709 struct smb2_handle src_h
;
3710 struct smb2_handle dest_h
;
3712 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3714 uint64_t dealloc_chunk_len
= 64 * 1024; /* Windows 2012 */
3715 struct file_alloced_range_buf
*far_rsp
= NULL
;
3716 uint64_t far_count
= 0;
3717 union smb_ioctl ioctl
;
3718 struct srv_copychunk_copy cc_copy
;
3719 struct srv_copychunk_rsp cc_rsp
;
3720 enum ndr_err_code ndr_ret
;
3722 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3723 FNAME
, &src_h
, 0, SEC_RIGHTS_FILE_ALL
,
3724 FILE_ATTRIBUTE_NORMAL
);
3725 torture_assert(torture
, ok
, "setup file");
3727 /* check for FS sparse file support */
3728 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &src_h
,
3730 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3731 smb2_util_close(tree
, src_h
);
3733 torture_skip(torture
, "Sparse files not supported\n");
3736 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
3738 &src_h
, 0, /* src file */
3739 SEC_RIGHTS_FILE_ALL
,
3740 &dest_h
, 0, /* dest file */
3741 SEC_RIGHTS_FILE_ALL
,
3744 torture_assert(torture
, ok
, "setup copy chunk error");
3747 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, src_h
, true);
3748 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3750 /* start after dealloc_chunk_len, to create an unwritten sparse range */
3751 ok
= write_pattern(torture
, tree
, tmp_ctx
, src_h
,
3752 dealloc_chunk_len
, /* off */
3754 dealloc_chunk_len
); /* pattern offset */
3755 torture_assert(torture
, ok
, "write pattern");
3757 /* Skip test if 64k chunk is allocated - FS specific */
3758 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, src_h
,
3760 dealloc_chunk_len
+ 1024, /* len */
3763 torture_assert_ntstatus_ok(torture
, status
,
3764 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3765 torture_assert_u64_equal(torture
, far_count
, 1,
3766 "unexpected response len");
3767 if (far_rsp
[0].file_off
== 0) {
3768 torture_skip(torture
, "unwritten range fully allocated\n");
3771 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, dealloc_chunk_len
,
3772 "unexpected allocation");
3773 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 1024,
3774 "unexpected far len");
3776 /* copy-chunk unallocated + written ranges into non-sparse dest */
3778 cc_copy
.chunks
[0].source_off
= 0;
3779 cc_copy
.chunks
[0].target_off
= 0;
3780 cc_copy
.chunks
[0].length
= dealloc_chunk_len
+ 1024;
3782 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
3784 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3785 torture_assert_ndr_success(torture
, ndr_ret
,
3786 "ndr_push_srv_copychunk_copy");
3788 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3789 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
3791 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
3793 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3794 torture_assert_ndr_success(torture
, ndr_ret
,
3795 "ndr_pull_srv_copychunk_rsp");
3797 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
3798 1, /* chunks written */
3799 0, /* chunk bytes unsuccessfully written */
3800 dealloc_chunk_len
+ 1024); /* bytes written */
3801 torture_assert(torture
, ok
, "bad copy chunk response data");
3803 ok
= check_zero(torture
, tree
, tmp_ctx
, dest_h
, 0, dealloc_chunk_len
);
3804 torture_assert(torture
, ok
, "sparse zeroed range");
3806 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, dealloc_chunk_len
,
3807 1024, dealloc_chunk_len
);
3808 torture_assert(torture
, ok
, "copychunked range");
3810 /* copied range should be allocated in non-sparse dest */
3811 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, dest_h
,
3813 dealloc_chunk_len
+ 1024, /* len */
3816 torture_assert_ntstatus_ok(torture
, status
,
3817 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3818 torture_assert_u64_equal(torture
, far_count
, 1,
3819 "unexpected response len");
3820 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3821 "unexpected allocation");
3822 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
3823 dealloc_chunk_len
+ 1024,
3824 "unexpected far len");
3826 /* set dest as sparse */
3827 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, dest_h
, true);
3828 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
3830 /* zero (hole-punch) all data */
3831 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, dest_h
,
3833 dealloc_chunk_len
+ 1024);
3834 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3836 /* zeroed range might be deallocated */
3837 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, dest_h
,
3839 dealloc_chunk_len
+ 1024, /* len */
3842 torture_assert_ntstatus_ok(torture
, status
,
3843 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3844 if (far_count
== 0) {
3845 /* FS specific (e.g. NTFS) */
3846 torture_comment(torture
, "FS deallocates file on full-range "
3849 /* FS specific (e.g. EXT4) */
3850 torture_comment(torture
, "FS doesn't deallocate file on "
3851 "full-range punch\n");
3853 ok
= check_zero(torture
, tree
, tmp_ctx
, dest_h
, 0,
3854 dealloc_chunk_len
+ 1024);
3855 torture_assert(torture
, ok
, "punched zeroed range");
3857 /* copy-chunk again, this time with sparse dest */
3858 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
3859 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
3861 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
3863 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3864 torture_assert_ndr_success(torture
, ndr_ret
,
3865 "ndr_pull_srv_copychunk_rsp");
3867 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
3868 1, /* chunks written */
3869 0, /* chunk bytes unsuccessfully written */
3870 dealloc_chunk_len
+ 1024); /* bytes written */
3871 torture_assert(torture
, ok
, "bad copy chunk response data");
3873 ok
= check_zero(torture
, tree
, tmp_ctx
, dest_h
, 0, dealloc_chunk_len
);
3874 torture_assert(torture
, ok
, "sparse zeroed range");
3876 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, dealloc_chunk_len
,
3877 1024, dealloc_chunk_len
);
3878 torture_assert(torture
, ok
, "copychunked range");
3880 /* copied range may be allocated in sparse dest */
3881 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, dest_h
,
3883 dealloc_chunk_len
+ 1024, /* len */
3886 torture_assert_ntstatus_ok(torture
, status
,
3887 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3888 torture_assert_u64_equal(torture
, far_count
, 1,
3889 "unexpected response len");
3891 * FS specific: sparse region may be unallocated in dest if copy-chunk
3892 * is handled in a sparse preserving way - E.g. vfs_btrfs
3893 * with BTRFS_IOC_CLONE_RANGE.
3895 if (far_rsp
[0].file_off
== dealloc_chunk_len
) {
3896 torture_comment(torture
, "copy-chunk sparse range preserved\n");
3897 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 1024,
3898 "unexpected far len");
3900 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
3901 "unexpected allocation");
3902 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
3903 dealloc_chunk_len
+ 1024,
3904 "unexpected far len");
3907 smb2_util_close(tree
, src_h
);
3908 smb2_util_close(tree
, dest_h
);
3909 talloc_free(tmp_ctx
);
3913 static bool test_ioctl_sparse_punch_invalid(struct torture_context
*torture
,
3914 struct smb2_tree
*tree
)
3916 struct smb2_handle fh
;
3918 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
3923 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
3924 FNAME
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
3925 FILE_ATTRIBUTE_NORMAL
);
3926 torture_assert(torture
, ok
, "setup file");
3928 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
3930 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
3932 smb2_util_close(tree
, fh
);
3933 torture_skip(torture
, "Sparse files not supported\n");
3936 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
3937 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
3938 torture_assert(torture
, !is_sparse
, "sparse attr before set");
3940 /* loop twice, without and with sparse attrib */
3941 for (i
= 0; i
<= 1; i
++) {
3942 union smb_fileinfo io
;
3943 struct file_alloced_range_buf
*far_rsp
= NULL
;
3944 uint64_t far_count
= 0;
3946 /* get size before & after. zero data should never change it */
3948 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
3949 io
.generic
.in
.file
.handle
= fh
;
3950 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
3951 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
3952 torture_assert_int_equal(torture
, (int)io
.all_info2
.out
.size
,
3953 4096, "size after IO");
3955 /* valid 8 byte zero data, but after EOF */
3956 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3958 4104); /* beyond_final_zero */
3959 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3961 /* valid 8 byte zero data, but after EOF */
3962 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3964 8200); /* beyond_final_zero */
3965 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3968 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
3969 io
.generic
.in
.file
.handle
= fh
;
3970 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
3971 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
3972 torture_assert_int_equal(torture
, (int)io
.all_info2
.out
.size
,
3973 4096, "size after IO");
3975 /* valid 0 byte zero data, without sparse flag */
3976 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3978 4095); /* beyond_final_zero */
3979 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
3981 /* INVALID off is past beyond_final_zero */
3982 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
3984 4095); /* beyond_final_zero */
3985 torture_assert_ntstatus_equal(torture
, status
,
3986 NT_STATUS_INVALID_PARAMETER
,
3987 "invalid zero_data");
3989 /* zero length QAR - valid */
3990 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
3993 &far_rsp
, &far_count
);
3994 torture_assert_ntstatus_ok(torture
, status
,
3995 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
3996 torture_assert_u64_equal(torture
, far_count
, 0,
3997 "unexpected response len");
3999 /* QAR after EOF - valid */
4000 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4003 &far_rsp
, &far_count
);
4004 torture_assert_ntstatus_ok(torture
, status
,
4005 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4006 torture_assert_u64_equal(torture
, far_count
, 0,
4007 "unexpected response len");
4010 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
,
4012 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4015 smb2_util_close(tree
, fh
);
4016 talloc_free(tmp_ctx
);
4020 static bool test_ioctl_sparse_perms(struct torture_context
*torture
,
4021 struct smb2_tree
*tree
)
4023 struct smb2_handle fh
;
4025 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
4028 struct file_alloced_range_buf
*far_rsp
= NULL
;
4029 uint64_t far_count
= 0;
4031 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4032 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
4033 FILE_ATTRIBUTE_NORMAL
);
4034 torture_assert(torture
, ok
, "setup file");
4036 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
4038 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
4039 smb2_util_close(tree
, fh
);
4041 torture_skip(torture
, "Sparse files not supported\n");
4044 /* set sparse without WRITE_ATTR permission should succeed */
4045 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4047 (SEC_RIGHTS_FILE_WRITE
& ~(SEC_FILE_WRITE_ATTRIBUTE
4049 | SEC_FILE_WRITE_EA
)),
4050 FILE_ATTRIBUTE_NORMAL
);
4051 torture_assert(torture
, ok
, "setup file");
4053 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4054 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4055 smb2_util_close(tree
, fh
);
4057 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4058 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
4059 FILE_ATTRIBUTE_NORMAL
);
4060 torture_assert(torture
, ok
, "setup file");
4061 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4062 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4063 torture_assert(torture
, is_sparse
, "sparse after set");
4064 smb2_util_close(tree
, fh
);
4066 /* attempt get sparse without READ_DATA permission */
4067 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4069 (SEC_RIGHTS_FILE_READ
& ~SEC_FILE_READ_DATA
),
4070 FILE_ATTRIBUTE_NORMAL
);
4071 torture_assert(torture
, ok
, "setup file");
4073 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4074 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4075 torture_assert(torture
, !is_sparse
, "sparse set");
4076 smb2_util_close(tree
, fh
);
4078 /* attempt to set sparse with only WRITE_ATTR permission */
4079 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4081 SEC_FILE_WRITE_ATTRIBUTE
,
4082 FILE_ATTRIBUTE_NORMAL
);
4083 torture_assert(torture
, ok
, "setup file");
4085 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4086 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4087 smb2_util_close(tree
, fh
);
4089 /* attempt to set sparse with only WRITE_DATA permission */
4090 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4092 SEC_FILE_WRITE_DATA
,
4093 FILE_ATTRIBUTE_NORMAL
);
4094 torture_assert(torture
, ok
, "setup file");
4096 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4097 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4098 smb2_util_close(tree
, fh
);
4100 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4101 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
4102 FILE_ATTRIBUTE_NORMAL
);
4103 torture_assert(torture
, ok
, "setup file");
4104 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4105 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4106 torture_assert(torture
, is_sparse
, "sparse after set");
4107 smb2_util_close(tree
, fh
);
4109 /* attempt to set sparse with only APPEND_DATA permission */
4110 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4112 SEC_FILE_APPEND_DATA
,
4113 FILE_ATTRIBUTE_NORMAL
);
4114 torture_assert(torture
, ok
, "setup file");
4116 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4117 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4118 smb2_util_close(tree
, fh
);
4120 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4121 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
4122 FILE_ATTRIBUTE_NORMAL
);
4123 torture_assert(torture
, ok
, "setup file");
4124 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4125 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4126 torture_assert(torture
, is_sparse
, "sparse after set");
4127 smb2_util_close(tree
, fh
);
4129 /* attempt to set sparse with only WRITE_EA permission - should fail */
4130 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4133 FILE_ATTRIBUTE_NORMAL
);
4134 torture_assert(torture
, ok
, "setup file");
4136 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4137 torture_assert_ntstatus_equal(torture
, status
,
4138 NT_STATUS_ACCESS_DENIED
,
4139 "FSCTL_SET_SPARSE permission");
4140 smb2_util_close(tree
, fh
);
4142 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4143 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
4144 FILE_ATTRIBUTE_NORMAL
);
4145 torture_assert(torture
, ok
, "setup file");
4146 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4147 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4148 torture_assert(torture
, !is_sparse
, "sparse after set");
4149 smb2_util_close(tree
, fh
);
4151 /* attempt QAR with only READ_ATTR permission - should fail */
4152 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4153 FNAME
, &fh
, SEC_FILE_READ_ATTRIBUTE
,
4154 FILE_ATTRIBUTE_NORMAL
);
4155 torture_assert(torture
, ok
, "setup file");
4156 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4159 &far_rsp
, &far_count
);
4160 torture_assert_ntstatus_equal(torture
, status
,
4161 NT_STATUS_ACCESS_DENIED
,
4162 "FSCTL_QUERY_ALLOCATED_RANGES req passed");
4163 smb2_util_close(tree
, fh
);
4165 /* attempt QAR with only READ_DATA permission */
4166 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4167 FNAME
, &fh
, SEC_FILE_READ_DATA
,
4168 FILE_ATTRIBUTE_NORMAL
);
4169 torture_assert(torture
, ok
, "setup file");
4170 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4173 &far_rsp
, &far_count
);
4174 torture_assert_ntstatus_ok(torture
, status
,
4175 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4176 torture_assert_u64_equal(torture
, far_count
, 0,
4177 "unexpected response len");
4178 smb2_util_close(tree
, fh
);
4180 /* attempt QAR with only READ_EA permission - should fail */
4181 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4182 FNAME
, &fh
, SEC_FILE_READ_EA
,
4183 FILE_ATTRIBUTE_NORMAL
);
4184 torture_assert(torture
, ok
, "setup file");
4185 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4188 &far_rsp
, &far_count
);
4189 torture_assert_ntstatus_equal(torture
, status
,
4190 NT_STATUS_ACCESS_DENIED
,
4191 "FSCTL_QUERY_ALLOCATED_RANGES req passed");
4192 smb2_util_close(tree
, fh
);
4194 /* setup file for ZERO_DATA permissions tests */
4195 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4197 SEC_RIGHTS_FILE_ALL
,
4198 FILE_ATTRIBUTE_NORMAL
);
4199 torture_assert(torture
, ok
, "setup file");
4201 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4202 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4203 smb2_util_close(tree
, fh
);
4205 /* attempt ZERO_DATA with only WRITE_ATTR permission - should fail */
4206 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4207 FNAME
, &fh
, SEC_FILE_WRITE_ATTRIBUTE
,
4208 FILE_ATTRIBUTE_NORMAL
);
4209 torture_assert(torture
, ok
, "setup file");
4210 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4212 4096); /* beyond_final_zero */
4213 torture_assert_ntstatus_equal(torture
, status
,
4214 NT_STATUS_ACCESS_DENIED
,
4215 "zero_data permission");
4216 smb2_util_close(tree
, fh
);
4218 /* attempt ZERO_DATA with only WRITE_DATA permission */
4219 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4220 FNAME
, &fh
, SEC_FILE_WRITE_DATA
,
4221 FILE_ATTRIBUTE_NORMAL
);
4222 torture_assert(torture
, ok
, "setup file");
4223 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4225 4096); /* beyond_final_zero */
4226 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
4227 smb2_util_close(tree
, fh
);
4229 /* attempt ZERO_DATA with only APPEND_DATA permission - should fail */
4230 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4231 FNAME
, &fh
, SEC_FILE_APPEND_DATA
,
4232 FILE_ATTRIBUTE_NORMAL
);
4233 torture_assert(torture
, ok
, "setup file");
4234 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4236 4096); /* beyond_final_zero */
4237 torture_assert_ntstatus_equal(torture
, status
,
4238 NT_STATUS_ACCESS_DENIED
,
4239 "zero_data permission");
4240 smb2_util_close(tree
, fh
);
4242 /* attempt ZERO_DATA with only WRITE_EA permission - should fail */
4243 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
4244 FNAME
, &fh
, SEC_FILE_WRITE_EA
,
4245 FILE_ATTRIBUTE_NORMAL
);
4246 torture_assert(torture
, ok
, "setup file");
4247 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4249 4096); /* beyond_final_zero */
4250 torture_assert_ntstatus_equal(torture
, status
,
4251 NT_STATUS_ACCESS_DENIED
,
4252 "zero_data permission");
4253 smb2_util_close(tree
, fh
);
4255 talloc_free(tmp_ctx
);
4259 static bool test_ioctl_sparse_lck(struct torture_context
*torture
,
4260 struct smb2_tree
*tree
)
4262 struct smb2_handle fh
;
4263 struct smb2_handle fh2
;
4265 uint64_t dealloc_chunk_len
= 64 * 1024; /* Windows 2012 */
4266 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
4269 struct smb2_lock lck
;
4270 struct smb2_lock_element el
[1];
4271 struct file_alloced_range_buf
*far_rsp
= NULL
;
4272 uint64_t far_count
= 0;
4274 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
, FNAME
, &fh
,
4275 dealloc_chunk_len
, SEC_RIGHTS_FILE_ALL
,
4276 FILE_ATTRIBUTE_NORMAL
);
4277 torture_assert(torture
, ok
, "setup file");
4279 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
4281 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
4283 torture_skip(torture
, "Sparse files not supported\n");
4284 smb2_util_close(tree
, fh
);
4287 /* open and lock via separate fh2 */
4288 status
= torture_smb2_testfile(tree
, FNAME
, &fh2
);
4289 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
4291 lck
.in
.lock_count
= 0x0001;
4292 lck
.in
.lock_sequence
= 0x00000000;
4293 lck
.in
.file
.handle
= fh2
;
4296 el
[0].length
= dealloc_chunk_len
;
4298 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
4300 status
= smb2_lock(tree
, &lck
);
4301 torture_assert_ntstatus_ok(torture
, status
, "lock");
4303 /* set sparse while locked */
4304 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4305 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4307 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
4308 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
4309 torture_assert(torture
, is_sparse
, "sparse attr after set");
4311 /* zero data over locked range should fail */
4312 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4314 4096); /* beyond_final_zero */
4315 torture_assert_ntstatus_equal(torture
, status
,
4316 NT_STATUS_FILE_LOCK_CONFLICT
,
4317 "zero_data locked");
4319 /* QAR over locked range should pass */
4320 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4323 &far_rsp
, &far_count
);
4324 torture_assert_ntstatus_ok(torture
, status
,
4325 "FSCTL_QUERY_ALLOCATED_RANGES locked");
4326 torture_assert_u64_equal(torture
, far_count
, 1,
4327 "unexpected response len");
4328 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
4329 "unexpected allocation");
4330 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4332 "unexpected far len");
4334 /* zero data over range past EOF should pass */
4335 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4336 dealloc_chunk_len
, /* off */
4337 dealloc_chunk_len
+ 4096);
4338 torture_assert_ntstatus_ok(torture
, status
,
4339 "zero_data past EOF locked");
4341 /* QAR over range past EOF should pass */
4342 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4343 dealloc_chunk_len
, /* off */
4345 &far_rsp
, &far_count
);
4346 torture_assert_ntstatus_ok(torture
, status
,
4347 "FSCTL_QUERY_ALLOCATED_RANGES past EOF locked");
4348 torture_assert_u64_equal(torture
, far_count
, 0,
4349 "unexpected response len");
4351 lck
.in
.lock_count
= 0x0001;
4352 lck
.in
.lock_sequence
= 0x00000001;
4353 lck
.in
.file
.handle
= fh2
;
4356 el
[0].length
= dealloc_chunk_len
;
4358 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
4359 status
= smb2_lock(tree
, &lck
);
4360 torture_assert_ntstatus_ok(torture
, status
, "unlock");
4362 smb2_util_close(tree
, fh2
);
4363 smb2_util_close(tree
, fh
);
4364 talloc_free(tmp_ctx
);
4368 /* alleviate QAR off-by-one bug paranoia - help me ob1 */
4369 static bool test_ioctl_sparse_qar_ob1(struct torture_context
*torture
,
4370 struct smb2_tree
*tree
)
4372 struct smb2_handle fh
;
4374 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
4376 uint64_t dealloc_chunk_len
= 64 * 1024; /* Windows 2012 */
4377 struct file_alloced_range_buf
*far_rsp
= NULL
;
4378 uint64_t far_count
= 0;
4380 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
4381 FNAME
, &fh
, dealloc_chunk_len
* 2,
4382 SEC_RIGHTS_FILE_ALL
,
4383 FILE_ATTRIBUTE_NORMAL
);
4384 torture_assert(torture
, ok
, "setup file");
4386 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
4388 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
4390 torture_skip(torture
, "Sparse files not supported\n");
4391 smb2_util_close(tree
, fh
);
4394 /* non-sparse QAR with range one before EOF */
4395 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4397 dealloc_chunk_len
* 2 - 1, /* len */
4398 &far_rsp
, &far_count
);
4399 torture_assert_ntstatus_ok(torture
, status
,
4400 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4401 torture_assert_u64_equal(torture
, far_count
, 1,
4402 "unexpected response len");
4403 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
4404 "unexpected allocation");
4405 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4406 dealloc_chunk_len
* 2 - 1,
4407 "unexpected far len");
4409 /* non-sparse QAR with range one after EOF */
4410 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4412 dealloc_chunk_len
* 2 + 1, /* len */
4413 &far_rsp
, &far_count
);
4414 torture_assert_ntstatus_ok(torture
, status
,
4415 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4416 torture_assert_u64_equal(torture
, far_count
, 1,
4417 "unexpected response len");
4418 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
4419 "unexpected allocation");
4420 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4421 dealloc_chunk_len
* 2,
4422 "unexpected far len");
4424 /* non-sparse QAR with range one after EOF from off=1 */
4425 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4427 dealloc_chunk_len
* 2, /* len */
4428 &far_rsp
, &far_count
);
4429 torture_assert_ntstatus_ok(torture
, status
,
4430 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4431 torture_assert_u64_equal(torture
, far_count
, 1,
4432 "unexpected response len");
4433 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 1,
4434 "unexpected allocation");
4435 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4436 dealloc_chunk_len
* 2 - 1,
4437 "unexpected far len");
4439 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
4440 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
4442 /* punch out second chunk */
4443 status
= test_ioctl_zdata_req(torture
, tmp_ctx
, tree
, fh
,
4444 dealloc_chunk_len
, /* off */
4445 dealloc_chunk_len
* 2);
4446 torture_assert_ntstatus_ok(torture
, status
, "zero_data");
4448 /* sparse QAR with range one before hole */
4449 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4451 dealloc_chunk_len
- 1, /* len */
4452 &far_rsp
, &far_count
);
4453 torture_assert_ntstatus_ok(torture
, status
,
4454 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4455 torture_assert_u64_equal(torture
, far_count
, 1,
4456 "unexpected response len");
4457 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
4458 "unexpected allocation");
4459 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4460 dealloc_chunk_len
- 1,
4461 "unexpected far len");
4463 /* sparse QAR with range one after hole */
4464 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4466 dealloc_chunk_len
+ 1, /* len */
4467 &far_rsp
, &far_count
);
4468 torture_assert_ntstatus_ok(torture
, status
,
4469 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4470 torture_assert_u64_equal(torture
, far_count
, 1,
4471 "unexpected response len");
4472 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0,
4473 "unexpected allocation");
4474 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4476 "unexpected far len");
4478 /* sparse QAR with range one after hole from off=1 */
4479 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4481 dealloc_chunk_len
, /* len */
4482 &far_rsp
, &far_count
);
4483 torture_assert_ntstatus_ok(torture
, status
,
4484 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4485 torture_assert_u64_equal(torture
, far_count
, 1,
4486 "unexpected response len");
4487 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 1,
4488 "unexpected allocation");
4489 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4490 dealloc_chunk_len
- 1,
4491 "unexpected far len");
4493 /* sparse QAR with range one before EOF from off=chunk_len-1 */
4494 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4495 dealloc_chunk_len
- 1, /* off */
4496 dealloc_chunk_len
, /* len */
4497 &far_rsp
, &far_count
);
4498 torture_assert_ntstatus_ok(torture
, status
,
4499 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4500 torture_assert_u64_equal(torture
, far_count
, 1,
4501 "unexpected response len");
4502 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
,
4503 dealloc_chunk_len
- 1,
4504 "unexpected allocation");
4505 torture_assert_u64_equal(torture
, far_rsp
[0].len
,
4506 1, "unexpected far len");
4508 /* sparse QAR with range one after EOF from off=chunk_len+1 */
4509 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
4510 dealloc_chunk_len
+ 1, /* off */
4511 dealloc_chunk_len
, /* len */
4512 &far_rsp
, &far_count
);
4513 torture_assert_ntstatus_ok(torture
, status
,
4514 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
4515 torture_assert_u64_equal(torture
, far_count
, 0,
4516 "unexpected response len");
4517 smb2_util_close(tree
, fh
);
4518 talloc_free(tmp_ctx
);
4523 * basic testing of SMB2 ioctls
4525 struct torture_suite
*torture_smb2_ioctl_init(void)
4527 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "ioctl");
4529 torture_suite_add_1smb2_test(suite
, "shadow_copy",
4530 test_ioctl_get_shadow_copy
);
4531 torture_suite_add_1smb2_test(suite
, "req_resume_key",
4532 test_ioctl_req_resume_key
);
4533 torture_suite_add_1smb2_test(suite
, "copy_chunk_simple",
4534 test_ioctl_copy_chunk_simple
);
4535 torture_suite_add_1smb2_test(suite
, "copy_chunk_multi",
4536 test_ioctl_copy_chunk_multi
);
4537 torture_suite_add_1smb2_test(suite
, "copy_chunk_tiny",
4538 test_ioctl_copy_chunk_tiny
);
4539 torture_suite_add_1smb2_test(suite
, "copy_chunk_overwrite",
4540 test_ioctl_copy_chunk_over
);
4541 torture_suite_add_1smb2_test(suite
, "copy_chunk_append",
4542 test_ioctl_copy_chunk_append
);
4543 torture_suite_add_1smb2_test(suite
, "copy_chunk_limits",
4544 test_ioctl_copy_chunk_limits
);
4545 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_lock",
4546 test_ioctl_copy_chunk_src_lck
);
4547 torture_suite_add_1smb2_test(suite
, "copy_chunk_dest_lock",
4548 test_ioctl_copy_chunk_dest_lck
);
4549 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_key",
4550 test_ioctl_copy_chunk_bad_key
);
4551 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest",
4552 test_ioctl_copy_chunk_src_is_dest
);
4553 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest_overlap",
4554 test_ioctl_copy_chunk_src_is_dest_overlap
);
4555 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_access",
4556 test_ioctl_copy_chunk_bad_access
);
4557 torture_suite_add_1smb2_test(suite
, "copy_chunk_write_access",
4558 test_ioctl_copy_chunk_write_access
);
4559 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed",
4560 test_ioctl_copy_chunk_src_exceed
);
4561 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed_multi",
4562 test_ioctl_copy_chunk_src_exceed_multi
);
4563 torture_suite_add_1smb2_test(suite
, "copy_chunk_sparse_dest",
4564 test_ioctl_copy_chunk_sparse_dest
);
4565 torture_suite_add_1smb2_test(suite
, "copy_chunk_max_output_sz",
4566 test_ioctl_copy_chunk_max_output_sz
);
4567 torture_suite_add_1smb2_test(suite
, "copy_chunk_zero_length",
4568 test_ioctl_copy_chunk_zero_length
);
4569 torture_suite_add_1smb2_test(suite
, "compress_file_flag",
4570 test_ioctl_compress_file_flag
);
4571 torture_suite_add_1smb2_test(suite
, "compress_dir_inherit",
4572 test_ioctl_compress_dir_inherit
);
4573 torture_suite_add_1smb2_test(suite
, "compress_invalid_format",
4574 test_ioctl_compress_invalid_format
);
4575 torture_suite_add_1smb2_test(suite
, "compress_invalid_buf",
4576 test_ioctl_compress_invalid_buf
);
4577 torture_suite_add_1smb2_test(suite
, "compress_query_file_attr",
4578 test_ioctl_compress_query_file_attr
);
4579 torture_suite_add_1smb2_test(suite
, "compress_create_with_attr",
4580 test_ioctl_compress_create_with_attr
);
4581 torture_suite_add_1smb2_test(suite
, "compress_inherit_disable",
4582 test_ioctl_compress_inherit_disable
);
4583 torture_suite_add_1smb2_test(suite
, "compress_set_file_attr",
4584 test_ioctl_compress_set_file_attr
);
4585 torture_suite_add_1smb2_test(suite
, "compress_perms",
4586 test_ioctl_compress_perms
);
4587 torture_suite_add_1smb2_test(suite
, "network_interface_info",
4588 test_ioctl_network_interface_info
);
4589 torture_suite_add_1smb2_test(suite
, "sparse_file_flag",
4590 test_ioctl_sparse_file_flag
);
4591 torture_suite_add_1smb2_test(suite
, "sparse_file_attr",
4592 test_ioctl_sparse_file_attr
);
4593 torture_suite_add_1smb2_test(suite
, "sparse_dir_flag",
4594 test_ioctl_sparse_dir_flag
);
4595 torture_suite_add_1smb2_test(suite
, "sparse_set_nobuf",
4596 test_ioctl_sparse_set_nobuf
);
4597 torture_suite_add_1smb2_test(suite
, "sparse_set_oversize",
4598 test_ioctl_sparse_set_oversize
);
4599 torture_suite_add_1smb2_test(suite
, "sparse_qar",
4600 test_ioctl_sparse_qar
);
4601 torture_suite_add_1smb2_test(suite
, "sparse_qar_malformed",
4602 test_ioctl_sparse_qar_malformed
);
4603 torture_suite_add_1smb2_test(suite
, "sparse_punch",
4604 test_ioctl_sparse_punch
);
4605 torture_suite_add_1smb2_test(suite
, "sparse_hole_dealloc",
4606 test_ioctl_sparse_hole_dealloc
);
4607 torture_suite_add_1smb2_test(suite
, "sparse_compressed",
4608 test_ioctl_sparse_compressed
);
4609 torture_suite_add_1smb2_test(suite
, "sparse_copy_chunk",
4610 test_ioctl_sparse_copy_chunk
);
4611 torture_suite_add_1smb2_test(suite
, "sparse_punch_invalid",
4612 test_ioctl_sparse_punch_invalid
);
4613 torture_suite_add_1smb2_test(suite
, "sparse_perms",
4614 test_ioctl_sparse_perms
);
4615 torture_suite_add_1smb2_test(suite
, "sparse_lock",
4616 test_ioctl_sparse_lck
);
4617 torture_suite_add_1smb2_test(suite
, "sparse_qar_ob1",
4618 test_ioctl_sparse_qar_ob1
);
4620 suite
->description
= talloc_strdup(suite
, "SMB2-IOCTL tests");