2 Unix SMB/CIFS implementation.
4 test suite for SMB2 ioctl operations
6 Copyright (C) David Disseldorp 2011-2013
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 buf_off
= 0;
136 buf
= talloc_zero_size(mem_ctx
, len
);
137 torture_assert(torture
, (buf
!= NULL
), "no memory for file data buf");
139 for (i
= 0; i
<= len
- 8; i
+= 8) {
140 SBVAL(buf
, i
, patt_hash(patt_off
));
145 uint64_t io_sz
= MIN(1024 * 1024, len
);
146 status
= smb2_util_write(tree
, h
,
147 buf
+ buf_off
, off
, io_sz
);
148 torture_assert_ntstatus_ok(torture
, status
, "file write");
158 static bool check_pattern(struct torture_context
*torture
,
159 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
160 struct smb2_handle h
, uint64_t off
, uint64_t len
,
168 r
.in
.file
.handle
= h
;
171 status
= smb2_read(tree
, mem_ctx
, &r
);
172 torture_assert_ntstatus_ok(torture
, status
, "read");
174 torture_assert_u64_equal(torture
, r
.out
.data
.length
, len
,
175 "read data len mismatch");
177 for (i
= 0; i
<= len
- 8; i
+= 8, patt_off
+= 8) {
178 uint64_t data
= BVAL(r
.out
.data
.data
, i
);
179 torture_assert_u64_equal(torture
, data
, patt_hash(patt_off
),
180 talloc_asprintf(torture
, "read data "
181 "pattern bad at %llu\n",
182 (unsigned long long)i
));
185 talloc_free(r
.out
.data
.data
);
189 static bool test_setup_open(struct torture_context
*torture
,
190 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
192 struct smb2_handle
*fh
,
193 uint32_t desired_access
,
194 uint32_t file_attributes
)
196 struct smb2_create io
;
200 io
.in
.desired_access
= desired_access
;
201 io
.in
.file_attributes
= file_attributes
;
202 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
204 NTCREATEX_SHARE_ACCESS_DELETE
|
205 NTCREATEX_SHARE_ACCESS_READ
|
206 NTCREATEX_SHARE_ACCESS_WRITE
;
207 if (file_attributes
& FILE_ATTRIBUTE_DIRECTORY
) {
208 io
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
212 status
= smb2_create(tree
, mem_ctx
, &io
);
213 torture_assert_ntstatus_ok(torture
, status
, "file create");
215 *fh
= io
.out
.file
.handle
;
220 static bool test_setup_create_fill(struct torture_context
*torture
,
221 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
223 struct smb2_handle
*fh
,
225 uint32_t desired_access
,
226 uint32_t file_attributes
)
230 smb2_util_unlink(tree
, fname
);
232 ok
= test_setup_open(torture
, tree
, mem_ctx
,
237 torture_assert(torture
, ok
, "file open");
240 ok
= write_pattern(torture
, tree
, mem_ctx
, *fh
, 0, size
, 0);
241 torture_assert(torture
, ok
, "write pattern");
246 static bool test_setup_copy_chunk(struct torture_context
*torture
,
247 struct smb2_tree
*tree
, TALLOC_CTX
*mem_ctx
,
249 struct smb2_handle
*src_h
,
251 uint32_t src_desired_access
,
252 struct smb2_handle
*dest_h
,
254 uint32_t dest_desired_access
,
255 struct srv_copychunk_copy
*cc_copy
,
256 union smb_ioctl
*ioctl
)
258 struct req_resume_key_rsp res_key
;
261 enum ndr_err_code ndr_ret
;
263 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME
,
264 src_h
, src_size
, src_desired_access
,
265 FILE_ATTRIBUTE_NORMAL
);
266 torture_assert(torture
, ok
, "src file create fill");
268 ok
= test_setup_create_fill(torture
, tree
, mem_ctx
, FNAME2
,
269 dest_h
, dest_size
, dest_desired_access
,
270 FILE_ATTRIBUTE_NORMAL
);
271 torture_assert(torture
, ok
, "dest file create fill");
273 ZERO_STRUCTPN(ioctl
);
274 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
275 ioctl
->smb2
.in
.file
.handle
= *src_h
;
276 ioctl
->smb2
.in
.function
= FSCTL_SRV_REQUEST_RESUME_KEY
;
277 /* Allow for Key + ContextLength + Context */
278 ioctl
->smb2
.in
.max_response_size
= 32;
279 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
281 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
->smb2
);
282 torture_assert_ntstatus_ok(torture
, status
,
283 "FSCTL_SRV_REQUEST_RESUME_KEY");
285 ndr_ret
= ndr_pull_struct_blob(&ioctl
->smb2
.out
.out
, mem_ctx
, &res_key
,
286 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
288 torture_assert_ndr_success(torture
, ndr_ret
,
289 "ndr_pull_req_resume_key_rsp");
291 ZERO_STRUCTPN(ioctl
);
292 ioctl
->smb2
.level
= RAW_IOCTL_SMB2
;
293 ioctl
->smb2
.in
.file
.handle
= *dest_h
;
294 ioctl
->smb2
.in
.function
= FSCTL_SRV_COPYCHUNK
;
295 ioctl
->smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
);
296 ioctl
->smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
298 ZERO_STRUCTPN(cc_copy
);
299 memcpy(cc_copy
->source_key
, res_key
.resume_key
, ARRAY_SIZE(cc_copy
->source_key
));
300 cc_copy
->chunk_count
= nchunks
;
301 cc_copy
->chunks
= talloc_zero_array(mem_ctx
, struct srv_copychunk
, nchunks
);
302 torture_assert(torture
, (cc_copy
->chunks
!= NULL
), "no memory for chunks");
308 static bool check_copy_chunk_rsp(struct torture_context
*torture
,
309 struct srv_copychunk_rsp
*cc_rsp
,
310 uint32_t ex_chunks_written
,
311 uint32_t ex_chunk_bytes_written
,
312 uint32_t ex_total_bytes_written
)
314 torture_assert_int_equal(torture
, cc_rsp
->chunks_written
,
315 ex_chunks_written
, "num chunks");
316 torture_assert_int_equal(torture
, cc_rsp
->chunk_bytes_written
,
317 ex_chunk_bytes_written
, "chunk bytes written");
318 torture_assert_int_equal(torture
, cc_rsp
->total_bytes_written
,
319 ex_total_bytes_written
, "chunk total bytes");
323 static bool test_ioctl_copy_chunk_simple(struct torture_context
*torture
,
324 struct smb2_tree
*tree
)
326 struct smb2_handle src_h
;
327 struct smb2_handle dest_h
;
329 union smb_ioctl ioctl
;
330 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
331 struct srv_copychunk_copy cc_copy
;
332 struct srv_copychunk_rsp cc_rsp
;
333 enum ndr_err_code ndr_ret
;
336 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
338 &src_h
, 4096, /* fill 4096 byte src file */
340 &dest_h
, 0, /* 0 byte dest file */
345 torture_fail(torture
, "setup copy chunk error");
348 /* copy all src file data (via a single chunk desc) */
349 cc_copy
.chunks
[0].source_off
= 0;
350 cc_copy
.chunks
[0].target_off
= 0;
351 cc_copy
.chunks
[0].length
= 4096;
353 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
355 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
356 torture_assert_ndr_success(torture
, ndr_ret
,
357 "ndr_push_srv_copychunk_copy");
359 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
360 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
362 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
364 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
365 torture_assert_ndr_success(torture
, ndr_ret
,
366 "ndr_pull_srv_copychunk_rsp");
368 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
369 1, /* chunks written */
370 0, /* chunk bytes unsuccessfully written */
371 4096); /* total bytes written */
373 torture_fail(torture
, "bad copy chunk response data");
376 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
378 torture_fail(torture
, "inconsistent file data");
381 smb2_util_close(tree
, src_h
);
382 smb2_util_close(tree
, dest_h
);
383 talloc_free(tmp_ctx
);
387 static bool test_ioctl_copy_chunk_multi(struct torture_context
*torture
,
388 struct smb2_tree
*tree
)
390 struct smb2_handle src_h
;
391 struct smb2_handle dest_h
;
393 union smb_ioctl ioctl
;
394 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
395 struct srv_copychunk_copy cc_copy
;
396 struct srv_copychunk_rsp cc_rsp
;
397 enum ndr_err_code ndr_ret
;
400 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
402 &src_h
, 8192, /* src file */
404 &dest_h
, 0, /* dest file */
409 torture_fail(torture
, "setup copy chunk error");
412 /* copy all src file data via two chunks */
413 cc_copy
.chunks
[0].source_off
= 0;
414 cc_copy
.chunks
[0].target_off
= 0;
415 cc_copy
.chunks
[0].length
= 4096;
417 cc_copy
.chunks
[1].source_off
= 4096;
418 cc_copy
.chunks
[1].target_off
= 4096;
419 cc_copy
.chunks
[1].length
= 4096;
421 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
423 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
424 torture_assert_ndr_success(torture
, ndr_ret
,
425 "ndr_push_srv_copychunk_copy");
427 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
428 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
430 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
432 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
433 torture_assert_ndr_success(torture
, ndr_ret
,
434 "ndr_pull_srv_copychunk_rsp");
436 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
437 2, /* chunks written */
438 0, /* chunk bytes unsuccessfully written */
439 8192); /* total bytes written */
441 torture_fail(torture
, "bad copy chunk response data");
444 smb2_util_close(tree
, src_h
);
445 smb2_util_close(tree
, dest_h
);
446 talloc_free(tmp_ctx
);
450 static bool test_ioctl_copy_chunk_tiny(struct torture_context
*torture
,
451 struct smb2_tree
*tree
)
453 struct smb2_handle src_h
;
454 struct smb2_handle dest_h
;
456 union smb_ioctl ioctl
;
457 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
458 struct srv_copychunk_copy cc_copy
;
459 struct srv_copychunk_rsp cc_rsp
;
460 enum ndr_err_code ndr_ret
;
463 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
465 &src_h
, 100, /* src file */
467 &dest_h
, 0, /* dest file */
472 torture_fail(torture
, "setup copy chunk error");
475 /* copy all src file data via two chunks, sub block size chunks */
476 cc_copy
.chunks
[0].source_off
= 0;
477 cc_copy
.chunks
[0].target_off
= 0;
478 cc_copy
.chunks
[0].length
= 50;
480 cc_copy
.chunks
[1].source_off
= 50;
481 cc_copy
.chunks
[1].target_off
= 50;
482 cc_copy
.chunks
[1].length
= 50;
484 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
486 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
487 torture_assert_ndr_success(torture
, ndr_ret
,
488 "ndr_push_srv_copychunk_copy");
490 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
491 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
493 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
495 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
496 torture_assert_ndr_success(torture
, ndr_ret
,
497 "ndr_pull_srv_copychunk_rsp");
499 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
500 2, /* chunks written */
501 0, /* chunk bytes unsuccessfully written */
502 100); /* total bytes written */
504 torture_fail(torture
, "bad copy chunk response data");
507 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 100, 0);
509 torture_fail(torture
, "inconsistent file data");
512 smb2_util_close(tree
, src_h
);
513 smb2_util_close(tree
, dest_h
);
514 talloc_free(tmp_ctx
);
518 static bool test_ioctl_copy_chunk_over(struct torture_context
*torture
,
519 struct smb2_tree
*tree
)
521 struct smb2_handle src_h
;
522 struct smb2_handle dest_h
;
524 union smb_ioctl ioctl
;
525 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
526 struct srv_copychunk_copy cc_copy
;
527 struct srv_copychunk_rsp cc_rsp
;
528 enum ndr_err_code ndr_ret
;
531 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
533 &src_h
, 8192, /* src file */
535 &dest_h
, 4096, /* dest file */
540 torture_fail(torture
, "setup copy chunk error");
543 /* first chunk overwrites existing dest data */
544 cc_copy
.chunks
[0].source_off
= 0;
545 cc_copy
.chunks
[0].target_off
= 0;
546 cc_copy
.chunks
[0].length
= 4096;
548 /* second chunk overwrites the first */
549 cc_copy
.chunks
[1].source_off
= 4096;
550 cc_copy
.chunks
[1].target_off
= 0;
551 cc_copy
.chunks
[1].length
= 4096;
553 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
555 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
556 torture_assert_ndr_success(torture
, ndr_ret
,
557 "ndr_push_srv_copychunk_copy");
559 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
560 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
562 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
564 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
565 torture_assert_ndr_success(torture
, ndr_ret
,
566 "ndr_pull_srv_copychunk_rsp");
568 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
569 2, /* chunks written */
570 0, /* chunk bytes unsuccessfully written */
571 8192); /* total bytes written */
573 torture_fail(torture
, "bad copy chunk response data");
576 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 4096);
578 torture_fail(torture
, "inconsistent file data");
581 smb2_util_close(tree
, src_h
);
582 smb2_util_close(tree
, dest_h
);
583 talloc_free(tmp_ctx
);
587 static bool test_ioctl_copy_chunk_append(struct torture_context
*torture
,
588 struct smb2_tree
*tree
)
590 struct smb2_handle src_h
;
591 struct smb2_handle dest_h
;
593 union smb_ioctl ioctl
;
594 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
595 struct srv_copychunk_copy cc_copy
;
596 struct srv_copychunk_rsp cc_rsp
;
597 enum ndr_err_code ndr_ret
;
600 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
602 &src_h
, 4096, /* src file */
604 &dest_h
, 0, /* dest file */
609 torture_fail(torture
, "setup copy chunk error");
612 cc_copy
.chunks
[0].source_off
= 0;
613 cc_copy
.chunks
[0].target_off
= 0;
614 cc_copy
.chunks
[0].length
= 4096;
616 /* second chunk appends the same data to the first */
617 cc_copy
.chunks
[1].source_off
= 0;
618 cc_copy
.chunks
[1].target_off
= 4096;
619 cc_copy
.chunks
[1].length
= 4096;
621 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
623 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
624 torture_assert_ndr_success(torture
, ndr_ret
,
625 "ndr_push_srv_copychunk_copy");
627 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
628 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
630 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
632 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
633 torture_assert_ndr_success(torture
, ndr_ret
,
634 "ndr_pull_srv_copychunk_rsp");
636 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
637 2, /* chunks written */
638 0, /* chunk bytes unsuccessfully written */
639 8192); /* total bytes written */
641 torture_fail(torture
, "bad copy chunk response data");
644 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
646 torture_fail(torture
, "inconsistent file data");
649 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
651 torture_fail(torture
, "inconsistent file data");
654 smb2_util_close(tree
, src_h
);
655 smb2_util_close(tree
, dest_h
);
656 talloc_free(tmp_ctx
);
660 static bool test_ioctl_copy_chunk_limits(struct torture_context
*torture
,
661 struct smb2_tree
*tree
)
663 struct smb2_handle src_h
;
664 struct smb2_handle dest_h
;
666 union smb_ioctl ioctl
;
667 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
668 struct srv_copychunk_copy cc_copy
;
669 struct srv_copychunk_rsp cc_rsp
;
670 enum ndr_err_code ndr_ret
;
673 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
675 &src_h
, 4096, /* src file */
677 &dest_h
, 0, /* dest file */
682 torture_fail(torture
, "setup copy chunk error");
685 /* send huge chunk length request */
686 cc_copy
.chunks
[0].source_off
= 0;
687 cc_copy
.chunks
[0].target_off
= 0;
688 cc_copy
.chunks
[0].length
= UINT_MAX
;
690 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
692 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
693 torture_assert_ndr_success(torture
, ndr_ret
, "marshalling request");
695 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
696 torture_assert_ntstatus_equal(torture
, status
,
697 NT_STATUS_INVALID_PARAMETER
,
698 "bad oversize chunk response");
700 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
702 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
703 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
705 torture_comment(torture
, "limit max chunks, got %u\n",
706 cc_rsp
.chunks_written
);
707 torture_comment(torture
, "limit max chunk len, got %u\n",
708 cc_rsp
.chunk_bytes_written
);
709 torture_comment(torture
, "limit max total bytes, got %u\n",
710 cc_rsp
.total_bytes_written
);
712 smb2_util_close(tree
, src_h
);
713 smb2_util_close(tree
, dest_h
);
714 talloc_free(tmp_ctx
);
718 static bool test_ioctl_copy_chunk_src_lck(struct torture_context
*torture
,
719 struct smb2_tree
*tree
)
721 struct smb2_handle src_h
;
722 struct smb2_handle src_h2
;
723 struct smb2_handle dest_h
;
725 union smb_ioctl ioctl
;
726 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
727 struct srv_copychunk_copy cc_copy
;
728 struct srv_copychunk_rsp cc_rsp
;
729 enum ndr_err_code ndr_ret
;
731 struct smb2_lock lck
;
732 struct smb2_lock_element el
[1];
734 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
736 &src_h
, 4096, /* src file */
738 &dest_h
, 0, /* dest file */
743 torture_fail(torture
, "setup copy chunk error");
746 cc_copy
.chunks
[0].source_off
= 0;
747 cc_copy
.chunks
[0].target_off
= 0;
748 cc_copy
.chunks
[0].length
= 4096;
750 /* open and lock the copychunk src file */
751 status
= torture_smb2_testfile(tree
, FNAME
, &src_h2
);
752 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
754 lck
.in
.lock_count
= 0x0001;
755 lck
.in
.lock_sequence
= 0x00000000;
756 lck
.in
.file
.handle
= src_h2
;
758 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
759 el
[0].length
= cc_copy
.chunks
[0].length
;
761 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
763 status
= smb2_lock(tree
, &lck
);
764 torture_assert_ntstatus_ok(torture
, status
, "lock");
766 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
768 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
769 torture_assert_ndr_success(torture
, ndr_ret
,
770 "ndr_push_srv_copychunk_copy");
772 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
774 * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
776 * Edgar Olougouna @ MS wrote:
777 * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
778 * discrepancy observed between Windows versions, we confirm that the
779 * behavior change is expected.
781 * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
782 * to move the chunks from the source to the destination.
783 * These ReadFile/WriteFile APIs go through the byte-range lock checks,
784 * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
786 * Prior to Windows Server 2012, CopyChunk used mapped sections to move
787 * the data. And byte range locks are not enforced on mapped I/O, and
788 * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
790 torture_assert_ntstatus_equal(torture
, status
,
791 NT_STATUS_FILE_LOCK_CONFLICT
,
792 "FSCTL_SRV_COPYCHUNK locked");
794 /* should get cc response data with the lock conflict status */
795 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
797 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
798 torture_assert_ndr_success(torture
, ndr_ret
,
799 "ndr_pull_srv_copychunk_rsp");
800 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
801 0, /* chunks written */
802 0, /* chunk bytes unsuccessfully written */
803 0); /* total bytes written */
805 lck
.in
.lock_count
= 0x0001;
806 lck
.in
.lock_sequence
= 0x00000001;
807 lck
.in
.file
.handle
= src_h2
;
809 el
[0].offset
= cc_copy
.chunks
[0].source_off
;
810 el
[0].length
= cc_copy
.chunks
[0].length
;
812 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
813 status
= smb2_lock(tree
, &lck
);
814 torture_assert_ntstatus_ok(torture
, status
, "unlock");
816 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
817 torture_assert_ntstatus_ok(torture
, status
,
818 "FSCTL_SRV_COPYCHUNK unlocked");
820 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
822 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
823 torture_assert_ndr_success(torture
, ndr_ret
,
824 "ndr_pull_srv_copychunk_rsp");
826 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
827 1, /* chunks written */
828 0, /* chunk bytes unsuccessfully written */
829 4096); /* total bytes written */
831 torture_fail(torture
, "bad copy chunk response data");
834 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
836 torture_fail(torture
, "inconsistent file data");
839 smb2_util_close(tree
, src_h2
);
840 smb2_util_close(tree
, src_h
);
841 smb2_util_close(tree
, dest_h
);
842 talloc_free(tmp_ctx
);
846 static bool test_ioctl_copy_chunk_dest_lck(struct torture_context
*torture
,
847 struct smb2_tree
*tree
)
849 struct smb2_handle src_h
;
850 struct smb2_handle dest_h
;
851 struct smb2_handle dest_h2
;
853 union smb_ioctl ioctl
;
854 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
855 struct srv_copychunk_copy cc_copy
;
856 struct srv_copychunk_rsp cc_rsp
;
857 enum ndr_err_code ndr_ret
;
859 struct smb2_lock lck
;
860 struct smb2_lock_element el
[1];
862 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
864 &src_h
, 4096, /* src file */
866 &dest_h
, 4096, /* dest file */
871 torture_fail(torture
, "setup copy chunk error");
874 cc_copy
.chunks
[0].source_off
= 0;
875 cc_copy
.chunks
[0].target_off
= 0;
876 cc_copy
.chunks
[0].length
= 4096;
878 /* open and lock the copychunk dest file */
879 status
= torture_smb2_testfile(tree
, FNAME2
, &dest_h2
);
880 torture_assert_ntstatus_ok(torture
, status
, "2nd src open");
882 lck
.in
.lock_count
= 0x0001;
883 lck
.in
.lock_sequence
= 0x00000000;
884 lck
.in
.file
.handle
= dest_h2
;
886 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
887 el
[0].length
= cc_copy
.chunks
[0].length
;
889 el
[0].flags
= SMB2_LOCK_FLAG_EXCLUSIVE
;
891 status
= smb2_lock(tree
, &lck
);
892 torture_assert_ntstatus_ok(torture
, status
, "lock");
894 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
896 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
897 torture_assert_ndr_success(torture
, ndr_ret
,
898 "ndr_push_srv_copychunk_copy");
900 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
901 torture_assert_ntstatus_equal(torture
, status
,
902 NT_STATUS_FILE_LOCK_CONFLICT
,
903 "FSCTL_SRV_COPYCHUNK locked");
905 lck
.in
.lock_count
= 0x0001;
906 lck
.in
.lock_sequence
= 0x00000001;
907 lck
.in
.file
.handle
= dest_h2
;
909 el
[0].offset
= cc_copy
.chunks
[0].target_off
;
910 el
[0].length
= cc_copy
.chunks
[0].length
;
912 el
[0].flags
= SMB2_LOCK_FLAG_UNLOCK
;
913 status
= smb2_lock(tree
, &lck
);
914 torture_assert_ntstatus_ok(torture
, status
, "unlock");
916 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
917 torture_assert_ntstatus_ok(torture
, status
,
918 "FSCTL_SRV_COPYCHUNK unlocked");
920 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
922 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
923 torture_assert_ndr_success(torture
, ndr_ret
,
924 "ndr_pull_srv_copychunk_rsp");
926 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
927 1, /* chunks written */
928 0, /* chunk bytes unsuccessfully written */
929 4096); /* total bytes written */
931 torture_fail(torture
, "bad copy chunk response data");
934 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
936 torture_fail(torture
, "inconsistent file data");
939 smb2_util_close(tree
, dest_h2
);
940 smb2_util_close(tree
, src_h
);
941 smb2_util_close(tree
, dest_h
);
942 talloc_free(tmp_ctx
);
946 static bool test_ioctl_copy_chunk_bad_key(struct torture_context
*torture
,
947 struct smb2_tree
*tree
)
949 struct smb2_handle src_h
;
950 struct smb2_handle dest_h
;
952 union smb_ioctl ioctl
;
953 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
954 struct srv_copychunk_copy cc_copy
;
955 enum ndr_err_code ndr_ret
;
958 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
967 torture_fail(torture
, "setup copy chunk error");
970 /* overwrite the resume key with a bogus value */
971 memcpy(cc_copy
.source_key
, "deadbeefdeadbeefdeadbeef", 24);
973 cc_copy
.chunks
[0].source_off
= 0;
974 cc_copy
.chunks
[0].target_off
= 0;
975 cc_copy
.chunks
[0].length
= 4096;
977 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
979 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
980 torture_assert_ndr_success(torture
, ndr_ret
,
981 "ndr_push_srv_copychunk_copy");
983 /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
984 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
985 torture_assert_ntstatus_equal(torture
, status
,
986 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
987 "FSCTL_SRV_COPYCHUNK");
989 smb2_util_close(tree
, src_h
);
990 smb2_util_close(tree
, dest_h
);
991 talloc_free(tmp_ctx
);
995 static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context
*torture
,
996 struct smb2_tree
*tree
)
998 struct smb2_handle src_h
;
999 struct smb2_handle dest_h
;
1001 union smb_ioctl ioctl
;
1002 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1003 struct srv_copychunk_copy cc_copy
;
1004 struct srv_copychunk_rsp cc_rsp
;
1005 enum ndr_err_code ndr_ret
;
1008 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1011 SEC_RIGHTS_FILE_ALL
,
1013 SEC_RIGHTS_FILE_ALL
,
1017 torture_fail(torture
, "setup copy chunk error");
1020 /* the source is also the destination */
1021 ioctl
.smb2
.in
.file
.handle
= src_h
;
1023 /* non-overlapping */
1024 cc_copy
.chunks
[0].source_off
= 0;
1025 cc_copy
.chunks
[0].target_off
= 4096;
1026 cc_copy
.chunks
[0].length
= 4096;
1028 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1030 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1031 torture_assert_ndr_success(torture
, ndr_ret
,
1032 "ndr_push_srv_copychunk_copy");
1034 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1035 torture_assert_ntstatus_ok(torture
, status
,
1036 "FSCTL_SRV_COPYCHUNK");
1038 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1040 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1041 torture_assert_ndr_success(torture
, ndr_ret
,
1042 "ndr_pull_srv_copychunk_rsp");
1044 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1045 1, /* chunks written */
1046 0, /* chunk bytes unsuccessfully written */
1047 4096); /* total bytes written */
1049 torture_fail(torture
, "bad copy chunk response data");
1052 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 4096, 0);
1054 torture_fail(torture
, "inconsistent file data");
1056 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 4096, 4096, 0);
1058 torture_fail(torture
, "inconsistent file data");
1061 smb2_util_close(tree
, src_h
);
1062 smb2_util_close(tree
, dest_h
);
1063 talloc_free(tmp_ctx
);
1068 * Test a single-chunk copychunk request, where the source and target ranges
1069 * overlap, and the SourceKey refers to the same target file. E.g:
1073 * File: src_and_dest
1074 * Offset: 0123456789
1079 * FSCTL_SRV_COPYCHUNK(src_and_dest)
1080 * SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
1082 * Chunks[0].SourceOffset = 0
1083 * Chunks[0].TargetOffset = 4
1084 * Chunks[0].Length = 6
1088 * File: src_and_dest
1089 * Offset: 0123456789
1092 * The resultant contents of src_and_dest is dependent on the server's
1093 * copy algorithm. In the above example, the server uses an IO buffer
1094 * large enough to hold the entire six-byte source data before writing
1095 * to TargetOffset. If the server were to use a four-byte IO buffer and
1096 * started reads/writes from the lowest offset, then the two overlapping
1097 * bytes in the above example would be overwritten before being read. The
1098 * resultant file contents would be abcdabcdab.
1100 * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
1101 * after this offset are written before being read. Windows 2012 on the
1102 * other hand appears to use a buffer large enough to hold its maximum
1103 * supported chunk size (1M). Samba currently uses a 64k copy buffer by
1104 * default (vfs_cc_state.buf).
1106 * This test uses an 8-byte overlap at 2040-2048, so that it passes against
1107 * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
1108 * to use a different copy algorithm to 2008r2.
1111 test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context
*torture
,
1112 struct smb2_tree
*tree
)
1114 struct smb2_handle src_h
;
1115 struct smb2_handle dest_h
;
1117 union smb_ioctl ioctl
;
1118 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1119 struct srv_copychunk_copy cc_copy
;
1120 struct srv_copychunk_rsp cc_rsp
;
1121 enum ndr_err_code ndr_ret
;
1124 /* exceed the vfs_default copy buffer */
1125 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1128 SEC_RIGHTS_FILE_ALL
,
1130 SEC_RIGHTS_FILE_ALL
,
1134 torture_fail(torture
, "setup copy chunk error");
1137 /* the source is also the destination */
1138 ioctl
.smb2
.in
.file
.handle
= src_h
;
1140 /* 8 bytes overlap between source and target ranges */
1141 cc_copy
.chunks
[0].source_off
= 0;
1142 cc_copy
.chunks
[0].target_off
= 2048 - 8;
1143 cc_copy
.chunks
[0].length
= 2048;
1145 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1147 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1148 torture_assert_ndr_success(torture
, ndr_ret
,
1149 "ndr_push_srv_copychunk_copy");
1151 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1152 torture_assert_ntstatus_ok(torture
, status
,
1153 "FSCTL_SRV_COPYCHUNK");
1155 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1157 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1158 torture_assert_ndr_success(torture
, ndr_ret
,
1159 "ndr_pull_srv_copychunk_rsp");
1161 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1162 1, /* chunks written */
1163 0, /* chunk bytes unsuccessfully written */
1164 2048); /* total bytes written */
1166 torture_fail(torture
, "bad copy chunk response data");
1169 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 0, 2048 - 8, 0);
1171 torture_fail(torture
, "inconsistent file data");
1173 ok
= check_pattern(torture
, tree
, tmp_ctx
, src_h
, 2048 - 8, 2048, 0);
1175 torture_fail(torture
, "inconsistent file data");
1178 smb2_util_close(tree
, src_h
);
1179 smb2_util_close(tree
, dest_h
);
1180 talloc_free(tmp_ctx
);
1184 static bool test_ioctl_copy_chunk_bad_access(struct torture_context
*torture
,
1185 struct smb2_tree
*tree
)
1187 struct smb2_handle src_h
;
1188 struct smb2_handle dest_h
;
1190 union smb_ioctl ioctl
;
1191 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1192 struct srv_copychunk_copy cc_copy
;
1193 enum ndr_err_code ndr_ret
;
1196 /* no read permission on src */
1197 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1199 &src_h
, 4096, /* fill 4096 byte src file */
1200 SEC_RIGHTS_FILE_WRITE
,
1201 &dest_h
, 0, /* 0 byte dest file */
1202 SEC_RIGHTS_FILE_ALL
,
1206 torture_fail(torture
, "setup copy chunk error");
1209 cc_copy
.chunks
[0].source_off
= 0;
1210 cc_copy
.chunks
[0].target_off
= 0;
1211 cc_copy
.chunks
[0].length
= 4096;
1213 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1215 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1216 torture_assert_ndr_success(torture
, ndr_ret
,
1217 "ndr_push_srv_copychunk_copy");
1219 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1220 torture_assert_ntstatus_equal(torture
, status
,
1221 NT_STATUS_ACCESS_DENIED
,
1222 "FSCTL_SRV_COPYCHUNK");
1224 smb2_util_close(tree
, src_h
);
1225 smb2_util_close(tree
, dest_h
);
1227 /* no write permission on dest */
1228 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1230 &src_h
, 4096, /* fill 4096 byte src file */
1231 SEC_RIGHTS_FILE_ALL
,
1232 &dest_h
, 0, /* 0 byte dest file */
1233 (SEC_RIGHTS_FILE_READ
1234 | SEC_RIGHTS_FILE_EXECUTE
),
1238 torture_fail(torture
, "setup copy chunk error");
1241 cc_copy
.chunks
[0].source_off
= 0;
1242 cc_copy
.chunks
[0].target_off
= 0;
1243 cc_copy
.chunks
[0].length
= 4096;
1245 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1247 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1248 torture_assert_ndr_success(torture
, ndr_ret
,
1249 "ndr_push_srv_copychunk_copy");
1251 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1252 torture_assert_ntstatus_equal(torture
, status
,
1253 NT_STATUS_ACCESS_DENIED
,
1254 "FSCTL_SRV_COPYCHUNK");
1256 smb2_util_close(tree
, src_h
);
1257 smb2_util_close(tree
, dest_h
);
1259 /* no read permission on dest */
1260 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1262 &src_h
, 4096, /* fill 4096 byte src file */
1263 SEC_RIGHTS_FILE_ALL
,
1264 &dest_h
, 0, /* 0 byte dest file */
1265 (SEC_RIGHTS_FILE_WRITE
1266 | SEC_RIGHTS_FILE_EXECUTE
),
1270 torture_fail(torture
, "setup copy chunk error");
1273 cc_copy
.chunks
[0].source_off
= 0;
1274 cc_copy
.chunks
[0].target_off
= 0;
1275 cc_copy
.chunks
[0].length
= 4096;
1277 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1279 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1280 torture_assert_ndr_success(torture
, ndr_ret
,
1281 "ndr_push_srv_copychunk_copy");
1284 * FSCTL_SRV_COPYCHUNK requires read permission on dest,
1285 * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
1287 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1288 torture_assert_ntstatus_equal(torture
, status
,
1289 NT_STATUS_ACCESS_DENIED
,
1290 "FSCTL_SRV_COPYCHUNK");
1292 smb2_util_close(tree
, src_h
);
1293 smb2_util_close(tree
, dest_h
);
1294 talloc_free(tmp_ctx
);
1299 static bool test_ioctl_copy_chunk_write_access(struct torture_context
*torture
,
1300 struct smb2_tree
*tree
)
1302 struct smb2_handle src_h
;
1303 struct smb2_handle dest_h
;
1305 union smb_ioctl ioctl
;
1306 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1307 struct srv_copychunk_copy cc_copy
;
1308 enum ndr_err_code ndr_ret
;
1311 /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
1312 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1314 &src_h
, 4096, /* fill 4096 byte src file */
1315 SEC_RIGHTS_FILE_ALL
,
1316 &dest_h
, 0, /* 0 byte dest file */
1317 (SEC_RIGHTS_FILE_WRITE
1318 | SEC_RIGHTS_FILE_EXECUTE
),
1322 torture_fail(torture
, "setup copy chunk error");
1325 ioctl
.smb2
.in
.function
= FSCTL_SRV_COPYCHUNK_WRITE
;
1326 cc_copy
.chunks
[0].source_off
= 0;
1327 cc_copy
.chunks
[0].target_off
= 0;
1328 cc_copy
.chunks
[0].length
= 4096;
1330 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1332 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1333 torture_assert_ndr_success(torture
, ndr_ret
,
1334 "ndr_push_srv_copychunk_copy");
1336 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1337 torture_assert_ntstatus_ok(torture
, status
,
1338 "FSCTL_SRV_COPYCHUNK_WRITE");
1340 smb2_util_close(tree
, src_h
);
1341 smb2_util_close(tree
, dest_h
);
1342 talloc_free(tmp_ctx
);
1347 static bool test_ioctl_copy_chunk_src_exceed(struct torture_context
*torture
,
1348 struct smb2_tree
*tree
)
1350 struct smb2_handle src_h
;
1351 struct smb2_handle dest_h
;
1353 union smb_ioctl ioctl
;
1354 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1355 struct srv_copychunk_copy cc_copy
;
1356 struct srv_copychunk_rsp cc_rsp
;
1357 enum ndr_err_code ndr_ret
;
1360 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1362 &src_h
, 4096, /* fill 4096 byte src file */
1363 SEC_RIGHTS_FILE_ALL
,
1364 &dest_h
, 0, /* 0 byte dest file */
1365 SEC_RIGHTS_FILE_ALL
,
1369 torture_fail(torture
, "setup copy chunk error");
1372 /* Request copy where off + length exceeds size of src */
1373 cc_copy
.chunks
[0].source_off
= 1024;
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_equal(torture
, status
,
1385 NT_STATUS_INVALID_VIEW_SIZE
,
1386 "FSCTL_SRV_COPYCHUNK oversize");
1388 /* Request copy where length exceeds size of src */
1389 cc_copy
.chunks
[0].source_off
= 1024;
1390 cc_copy
.chunks
[0].target_off
= 0;
1391 cc_copy
.chunks
[0].length
= 3072;
1393 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1395 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1396 torture_assert_ndr_success(torture
, ndr_ret
,
1397 "ndr_push_srv_copychunk_copy");
1399 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1400 torture_assert_ntstatus_ok(torture
, status
,
1401 "FSCTL_SRV_COPYCHUNK just right");
1403 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1405 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1406 torture_assert_ndr_success(torture
, ndr_ret
,
1407 "ndr_pull_srv_copychunk_rsp");
1409 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1410 1, /* chunks written */
1411 0, /* chunk bytes unsuccessfully written */
1412 3072); /* total bytes written */
1414 torture_fail(torture
, "bad copy chunk response data");
1417 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 3072, 1024);
1419 torture_fail(torture
, "inconsistent file data");
1422 smb2_util_close(tree
, src_h
);
1423 smb2_util_close(tree
, dest_h
);
1424 talloc_free(tmp_ctx
);
1429 test_ioctl_copy_chunk_src_exceed_multi(struct torture_context
*torture
,
1430 struct smb2_tree
*tree
)
1432 struct smb2_handle src_h
;
1433 struct smb2_handle dest_h
;
1435 union smb_ioctl ioctl
;
1436 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1437 struct srv_copychunk_copy cc_copy
;
1438 struct srv_copychunk_rsp cc_rsp
;
1439 enum ndr_err_code ndr_ret
;
1442 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1444 &src_h
, 8192, /* fill 8192 byte src file */
1445 SEC_RIGHTS_FILE_ALL
,
1446 &dest_h
, 0, /* 0 byte dest file */
1447 SEC_RIGHTS_FILE_ALL
,
1451 torture_fail(torture
, "setup copy chunk error");
1454 /* Request copy where off + length exceeds size of src */
1455 cc_copy
.chunks
[0].source_off
= 0;
1456 cc_copy
.chunks
[0].target_off
= 0;
1457 cc_copy
.chunks
[0].length
= 4096;
1459 cc_copy
.chunks
[1].source_off
= 4096;
1460 cc_copy
.chunks
[1].target_off
= 4096;
1461 cc_copy
.chunks
[1].length
= 8192;
1463 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1465 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1466 torture_assert_ndr_success(torture
, ndr_ret
,
1467 "ndr_push_srv_copychunk_copy");
1469 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1470 torture_assert_ntstatus_equal(torture
, status
,
1471 NT_STATUS_INVALID_VIEW_SIZE
,
1472 "FSCTL_SRV_COPYCHUNK oversize");
1473 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1475 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1476 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1478 /* first chunk should still be written */
1479 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1480 1, /* chunks written */
1481 0, /* chunk bytes unsuccessfully written */
1482 4096); /* total bytes written */
1484 torture_fail(torture
, "bad copy chunk response data");
1486 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 0, 4096, 0);
1488 torture_fail(torture
, "inconsistent file data");
1491 smb2_util_close(tree
, src_h
);
1492 smb2_util_close(tree
, dest_h
);
1493 talloc_free(tmp_ctx
);
1497 static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context
*torture
,
1498 struct smb2_tree
*tree
)
1500 struct smb2_handle src_h
;
1501 struct smb2_handle dest_h
;
1503 union smb_ioctl ioctl
;
1505 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1506 struct srv_copychunk_copy cc_copy
;
1507 struct srv_copychunk_rsp cc_rsp
;
1508 enum ndr_err_code ndr_ret
;
1512 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1514 &src_h
, 4096, /* fill 4096 byte src file */
1515 SEC_RIGHTS_FILE_ALL
,
1516 &dest_h
, 0, /* 0 byte dest file */
1517 SEC_RIGHTS_FILE_ALL
,
1521 torture_fail(torture
, "setup copy chunk error");
1524 /* copy all src file data (via a single chunk desc) */
1525 cc_copy
.chunks
[0].source_off
= 0;
1526 cc_copy
.chunks
[0].target_off
= 4096;
1527 cc_copy
.chunks
[0].length
= 4096;
1529 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1531 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1532 torture_assert_ndr_success(torture
, ndr_ret
,
1533 "ndr_push_srv_copychunk_copy");
1535 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1536 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SRV_COPYCHUNK");
1538 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1540 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1541 torture_assert_ndr_success(torture
, ndr_ret
,
1542 "ndr_pull_srv_copychunk_rsp");
1544 ok
= check_copy_chunk_rsp(torture
, &cc_rsp
,
1545 1, /* chunks written */
1546 0, /* chunk bytes unsuccessfully written */
1547 4096); /* total bytes written */
1549 torture_fail(torture
, "bad copy chunk response data");
1552 /* check for zeros in first 4k */
1554 r
.in
.file
.handle
= dest_h
;
1557 status
= smb2_read(tree
, tmp_ctx
, &r
);
1558 torture_assert_ntstatus_ok(torture
, status
, "read");
1560 torture_assert_u64_equal(torture
, r
.out
.data
.length
, 4096,
1561 "read data len mismatch");
1563 for (i
= 0; i
< 4096; i
++) {
1564 torture_assert(torture
, (r
.out
.data
.data
[i
] == 0),
1565 "sparse did not pass class");
1568 ok
= check_pattern(torture
, tree
, tmp_ctx
, dest_h
, 4096, 4096, 0);
1570 torture_fail(torture
, "inconsistent file data");
1573 smb2_util_close(tree
, src_h
);
1574 smb2_util_close(tree
, dest_h
);
1575 talloc_free(tmp_ctx
);
1580 * set the ioctl MaxOutputResponse size to less than
1581 * sizeof(struct srv_copychunk_rsp)
1583 static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context
*torture
,
1584 struct smb2_tree
*tree
)
1586 struct smb2_handle src_h
;
1587 struct smb2_handle dest_h
;
1589 union smb_ioctl ioctl
;
1590 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1591 struct srv_copychunk_copy cc_copy
;
1592 enum ndr_err_code ndr_ret
;
1595 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1597 &src_h
, 4096, /* fill 4096 byte src file */
1598 SEC_RIGHTS_FILE_ALL
,
1599 &dest_h
, 0, /* 0 byte dest file */
1600 SEC_RIGHTS_FILE_ALL
,
1604 torture_fail(torture
, "setup copy chunk error");
1607 cc_copy
.chunks
[0].source_off
= 0;
1608 cc_copy
.chunks
[0].target_off
= 0;
1609 cc_copy
.chunks
[0].length
= 4096;
1610 /* req is valid, but use undersize max_response_size */
1611 ioctl
.smb2
.in
.max_response_size
= sizeof(struct srv_copychunk_rsp
) - 1;
1613 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1615 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1616 torture_assert_ndr_success(torture
, ndr_ret
,
1617 "ndr_push_srv_copychunk_copy");
1619 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1620 torture_assert_ntstatus_equal(torture
, status
,
1621 NT_STATUS_INVALID_PARAMETER
,
1622 "FSCTL_SRV_COPYCHUNK");
1624 smb2_util_close(tree
, src_h
);
1625 smb2_util_close(tree
, dest_h
);
1626 talloc_free(tmp_ctx
);
1630 static bool test_ioctl_copy_chunk_zero_length(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 union smb_fileinfo q
;
1638 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1639 struct srv_copychunk_copy cc_copy
;
1640 struct srv_copychunk_rsp cc_rsp
;
1641 enum ndr_err_code ndr_ret
;
1644 ok
= test_setup_copy_chunk(torture
, tree
, tmp_ctx
,
1646 &src_h
, 4096, /* fill 4096 byte src file */
1647 SEC_RIGHTS_FILE_ALL
,
1648 &dest_h
, 0, /* 0 byte dest file */
1649 SEC_RIGHTS_FILE_ALL
,
1653 torture_fail(torture
, "setup copy chunk error");
1656 /* zero length server-side copy (via a single chunk desc) */
1657 cc_copy
.chunks
[0].source_off
= 0;
1658 cc_copy
.chunks
[0].target_off
= 0;
1659 cc_copy
.chunks
[0].length
= 0;
1661 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
1663 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
1664 torture_assert_ndr_success(torture
, ndr_ret
,
1665 "ndr_push_srv_copychunk_copy");
1667 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1668 torture_assert_ntstatus_equal(torture
, status
,
1669 NT_STATUS_INVALID_PARAMETER
,
1670 "bad zero-length chunk response");
1672 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
1674 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
1675 torture_assert_ndr_success(torture
, ndr_ret
, "unmarshalling response");
1678 q
.all_info2
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
1679 q
.all_info2
.in
.file
.handle
= dest_h
;
1680 status
= smb2_getinfo_file(tree
, torture
, &q
);
1681 torture_assert_ntstatus_ok(torture
, status
, "getinfo");
1683 torture_assert_int_equal(torture
, q
.all_info2
.out
.size
, 0,
1684 "size after zero len clone");
1686 smb2_util_close(tree
, src_h
);
1687 smb2_util_close(tree
, dest_h
);
1688 talloc_free(tmp_ctx
);
1692 static NTSTATUS
test_ioctl_compress_fs_supported(struct torture_context
*torture
,
1693 struct smb2_tree
*tree
,
1694 TALLOC_CTX
*mem_ctx
,
1695 struct smb2_handle
*fh
,
1696 bool *compress_support
)
1699 union smb_fsinfo info
;
1702 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
1703 info
.generic
.handle
= *fh
;
1704 status
= smb2_getinfo_fs(tree
, tree
, &info
);
1705 if (!NT_STATUS_IS_OK(status
)) {
1709 if (info
.attribute_info
.out
.fs_attr
& FILE_FILE_COMPRESSION
) {
1710 *compress_support
= true;
1712 *compress_support
= false;
1714 return NT_STATUS_OK
;
1717 static NTSTATUS
test_ioctl_compress_get(struct torture_context
*torture
,
1718 TALLOC_CTX
*mem_ctx
,
1719 struct smb2_tree
*tree
,
1720 struct smb2_handle fh
,
1721 uint16_t *_compression_fmt
)
1723 union smb_ioctl ioctl
;
1724 struct compression_state cmpr_state
;
1725 enum ndr_err_code ndr_ret
;
1729 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1730 ioctl
.smb2
.in
.file
.handle
= fh
;
1731 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1732 ioctl
.smb2
.in
.max_response_size
= sizeof(struct compression_state
);
1733 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1735 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1736 if (!NT_STATUS_IS_OK(status
)) {
1740 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, mem_ctx
,
1742 (ndr_pull_flags_fn_t
)ndr_pull_compression_state
);
1744 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1745 return NT_STATUS_INTERNAL_ERROR
;
1748 *_compression_fmt
= cmpr_state
.format
;
1749 return NT_STATUS_OK
;
1752 static NTSTATUS
test_ioctl_compress_set(struct torture_context
*torture
,
1753 TALLOC_CTX
*mem_ctx
,
1754 struct smb2_tree
*tree
,
1755 struct smb2_handle fh
,
1756 uint16_t compression_fmt
)
1758 union smb_ioctl ioctl
;
1759 struct compression_state cmpr_state
;
1760 enum ndr_err_code ndr_ret
;
1764 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1765 ioctl
.smb2
.in
.file
.handle
= fh
;
1766 ioctl
.smb2
.in
.function
= FSCTL_SET_COMPRESSION
;
1767 ioctl
.smb2
.in
.max_response_size
= 0;
1768 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1770 cmpr_state
.format
= compression_fmt
;
1771 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, mem_ctx
,
1773 (ndr_push_flags_fn_t
)ndr_push_compression_state
);
1774 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
1775 return NT_STATUS_INTERNAL_ERROR
;
1778 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
1782 static bool test_ioctl_compress_file_flag(struct torture_context
*torture
,
1783 struct smb2_tree
*tree
)
1785 struct smb2_handle fh
;
1787 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1789 uint16_t compression_fmt
;
1791 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1792 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1793 FILE_ATTRIBUTE_NORMAL
);
1794 torture_assert(torture
, ok
, "setup compression file");
1796 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1798 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1800 smb2_util_close(tree
, fh
);
1801 torture_skip(torture
, "FS compression not supported\n");
1804 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1806 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1808 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1809 "initial compression state not NONE");
1811 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1812 COMPRESSION_FORMAT_DEFAULT
);
1813 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1815 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1817 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1819 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1820 "invalid compression state after set");
1822 smb2_util_close(tree
, fh
);
1823 talloc_free(tmp_ctx
);
1827 static bool test_ioctl_compress_dir_inherit(struct torture_context
*torture
,
1828 struct smb2_tree
*tree
)
1830 struct smb2_handle dirh
;
1831 struct smb2_handle fh
;
1833 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1834 uint16_t compression_fmt
;
1836 char path_buf
[PATH_MAX
];
1838 smb2_deltree(tree
, DNAME
);
1839 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1840 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
1841 FILE_ATTRIBUTE_DIRECTORY
);
1842 torture_assert(torture
, ok
, "setup compression directory");
1844 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
1846 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1848 smb2_util_close(tree
, dirh
);
1849 smb2_deltree(tree
, DNAME
);
1850 torture_skip(torture
, "FS compression not supported\n");
1853 /* set compression on parent dir, then check for inheritance */
1854 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1855 COMPRESSION_FORMAT_LZNT1
);
1856 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1858 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
1860 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1862 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1863 "invalid compression state after set");
1865 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
1866 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1867 path_buf
, &fh
, 4096, SEC_RIGHTS_FILE_ALL
,
1868 FILE_ATTRIBUTE_NORMAL
);
1869 torture_assert(torture
, ok
, "setup compression file");
1871 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1873 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1875 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1876 "compression attr not inherited by new file");
1878 /* check compressed data is consistent */
1879 ok
= check_pattern(torture
, tree
, tmp_ctx
, fh
, 0, 4096, 0);
1881 /* disable dir compression attr, file should remain compressed */
1882 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
1883 COMPRESSION_FORMAT_NONE
);
1884 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
1886 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1888 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1890 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
1891 "file compression attr removed after dir change");
1892 smb2_util_close(tree
, fh
);
1894 /* new files should no longer inherit compression attr */
1895 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
1896 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1897 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1898 FILE_ATTRIBUTE_NORMAL
);
1899 torture_assert(torture
, ok
, "setup file");
1901 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1903 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1905 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1906 "compression attr present on new file");
1908 smb2_util_close(tree
, fh
);
1909 smb2_util_close(tree
, dirh
);
1910 smb2_deltree(tree
, DNAME
);
1911 talloc_free(tmp_ctx
);
1915 static bool test_ioctl_compress_invalid_format(struct torture_context
*torture
,
1916 struct smb2_tree
*tree
)
1918 struct smb2_handle fh
;
1920 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1922 uint16_t compression_fmt
;
1924 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1925 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1926 FILE_ATTRIBUTE_NORMAL
);
1927 torture_assert(torture
, ok
, "setup compression file");
1929 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1931 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1933 smb2_util_close(tree
, fh
);
1934 torture_skip(torture
, "FS compression not supported\n");
1937 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
1938 0x0042); /* bogus */
1939 torture_assert_ntstatus_equal(torture
, status
,
1940 NT_STATUS_INVALID_PARAMETER
,
1941 "invalid FSCTL_SET_COMPRESSION");
1943 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
1945 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
1947 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
1948 "initial compression state not NONE");
1950 smb2_util_close(tree
, fh
);
1951 talloc_free(tmp_ctx
);
1955 static bool test_ioctl_compress_invalid_buf(struct torture_context
*torture
,
1956 struct smb2_tree
*tree
)
1958 struct smb2_handle fh
;
1960 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
1962 union smb_ioctl ioctl
;
1964 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
1965 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
1966 FILE_ATTRIBUTE_NORMAL
);
1967 torture_assert(torture
, ok
, "setup compression file");
1969 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
1971 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
1973 smb2_util_close(tree
, fh
);
1974 torture_skip(torture
, "FS compression not supported\n");
1978 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
1979 ioctl
.smb2
.in
.file
.handle
= fh
;
1980 ioctl
.smb2
.in
.function
= FSCTL_GET_COMPRESSION
;
1981 ioctl
.smb2
.in
.max_response_size
= 0; /* no room for rsp data */
1982 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
1984 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
1985 if (!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_USER_BUFFER
)
1986 && !NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1987 /* neither Server 2k12 nor 2k8r2 response status */
1988 torture_assert(torture
, true,
1989 "invalid FSCTL_SET_COMPRESSION");
1992 smb2_util_close(tree
, fh
);
1993 talloc_free(tmp_ctx
);
1997 static bool test_ioctl_compress_query_file_attr(struct torture_context
*torture
,
1998 struct smb2_tree
*tree
)
2000 struct smb2_handle fh
;
2001 union smb_fileinfo io
;
2003 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2006 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2007 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2008 FILE_ATTRIBUTE_NORMAL
);
2009 torture_assert(torture
, ok
, "setup compression file");
2011 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2013 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2015 smb2_util_close(tree
, fh
);
2016 torture_skip(torture
, "FS compression not supported\n");
2020 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2021 io
.generic
.in
.file
.handle
= fh
;
2022 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2023 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2025 torture_assert(torture
,
2026 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2027 "compression attr before set");
2029 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2030 COMPRESSION_FORMAT_DEFAULT
);
2031 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2034 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2035 io
.generic
.in
.file
.handle
= fh
;
2036 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2037 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2039 torture_assert(torture
,
2040 (io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2041 "no compression attr after set");
2043 smb2_util_close(tree
, fh
);
2044 talloc_free(tmp_ctx
);
2049 * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
2052 static bool test_ioctl_compress_create_with_attr(struct torture_context
*torture
,
2053 struct smb2_tree
*tree
)
2055 struct smb2_handle fh2
;
2056 union smb_fileinfo io
;
2058 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2059 uint16_t compression_fmt
;
2062 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2063 FNAME2
, &fh2
, 0, SEC_RIGHTS_FILE_ALL
,
2064 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_COMPRESSED
));
2065 torture_assert(torture
, ok
, "setup compression file");
2067 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh2
,
2069 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2071 smb2_util_close(tree
, fh2
);
2072 torture_skip(torture
, "FS compression not supported\n");
2075 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh2
,
2077 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2079 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2080 "initial compression state not NONE");
2083 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2084 io
.generic
.in
.file
.handle
= fh2
;
2085 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2086 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2088 torture_assert(torture
,
2089 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2090 "incorrect compression attr");
2092 smb2_util_close(tree
, fh2
);
2093 talloc_free(tmp_ctx
);
2097 static bool test_ioctl_compress_inherit_disable(struct torture_context
*torture
,
2098 struct smb2_tree
*tree
)
2100 struct smb2_handle fh
;
2101 struct smb2_handle dirh
;
2102 char path_buf
[PATH_MAX
];
2104 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2106 uint16_t compression_fmt
;
2108 struct smb2_create io
;
2110 smb2_deltree(tree
, DNAME
);
2111 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2112 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2113 FILE_ATTRIBUTE_DIRECTORY
);
2114 torture_assert(torture
, ok
, "setup compression directory");
2116 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2118 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2120 smb2_util_close(tree
, dirh
);
2121 smb2_deltree(tree
, DNAME
);
2122 torture_skip(torture
, "FS compression not supported\n");
2125 /* set compression on parent dir, then check for inheritance */
2126 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, dirh
,
2127 COMPRESSION_FORMAT_LZNT1
);
2128 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2130 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2132 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2134 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2135 "invalid compression state after set");
2136 smb2_util_close(tree
, dirh
);
2138 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME
);
2139 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2140 path_buf
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2141 FILE_ATTRIBUTE_NORMAL
);
2142 torture_assert(torture
, ok
, "setup compression file");
2144 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2146 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2148 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_LZNT1
),
2149 "compression attr not inherited by new file");
2150 smb2_util_close(tree
, fh
);
2152 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, FNAME2
);
2154 /* NO_COMPRESSION option should block inheritance */
2156 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2157 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2158 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2159 io
.in
.create_options
= NTCREATEX_OPTIONS_NO_COMPRESSION
;
2160 io
.in
.share_access
=
2161 NTCREATEX_SHARE_ACCESS_DELETE
|
2162 NTCREATEX_SHARE_ACCESS_READ
|
2163 NTCREATEX_SHARE_ACCESS_WRITE
;
2164 io
.in
.fname
= path_buf
;
2166 status
= smb2_create(tree
, tmp_ctx
, &io
);
2167 torture_assert_ntstatus_ok(torture
, status
, "file create");
2169 fh
= io
.out
.file
.handle
;
2171 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2173 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2175 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2176 "compression attr inherited by NO_COMPRESSION file");
2177 smb2_util_close(tree
, fh
);
2180 snprintf(path_buf
, PATH_MAX
, "%s\\%s", DNAME
, DNAME
);
2182 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
2183 io
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
2184 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2185 io
.in
.create_options
= (NTCREATEX_OPTIONS_NO_COMPRESSION
2186 | NTCREATEX_OPTIONS_DIRECTORY
);
2187 io
.in
.share_access
=
2188 NTCREATEX_SHARE_ACCESS_DELETE
|
2189 NTCREATEX_SHARE_ACCESS_READ
|
2190 NTCREATEX_SHARE_ACCESS_WRITE
;
2191 io
.in
.fname
= path_buf
;
2193 status
= smb2_create(tree
, tmp_ctx
, &io
);
2194 torture_assert_ntstatus_ok(torture
, status
, "dir create");
2196 dirh
= io
.out
.file
.handle
;
2198 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2200 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2202 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2203 "compression attr inherited by NO_COMPRESSION dir");
2204 smb2_util_close(tree
, dirh
);
2205 smb2_deltree(tree
, DNAME
);
2207 talloc_free(tmp_ctx
);
2211 /* attempting to set compression via SetInfo should not stick */
2212 static bool test_ioctl_compress_set_file_attr(struct torture_context
*torture
,
2213 struct smb2_tree
*tree
)
2215 struct smb2_handle fh
;
2216 struct smb2_handle dirh
;
2217 union smb_fileinfo io
;
2218 union smb_setfileinfo set_io
;
2219 uint16_t compression_fmt
;
2221 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2224 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2225 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2226 FILE_ATTRIBUTE_NORMAL
);
2227 torture_assert(torture
, ok
, "setup compression file");
2229 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2231 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2233 smb2_util_close(tree
, fh
);
2234 torture_skip(torture
, "FS compression not supported\n");
2238 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2239 io
.generic
.in
.file
.handle
= fh
;
2240 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2241 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2243 torture_assert(torture
,
2244 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2245 "compression attr before set");
2247 ZERO_STRUCT(set_io
);
2248 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2249 set_io
.basic_info
.in
.file
.handle
= fh
;
2250 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2251 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2252 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2253 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2254 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2255 | FILE_ATTRIBUTE_COMPRESSED
);
2256 status
= smb2_setinfo_file(tree
, &set_io
);
2257 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2260 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2261 io
.generic
.in
.file
.handle
= fh
;
2262 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2263 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2265 torture_assert(torture
,
2266 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2267 "compression attr after set");
2269 smb2_util_close(tree
, fh
);
2270 smb2_deltree(tree
, DNAME
);
2271 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2272 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2273 FILE_ATTRIBUTE_DIRECTORY
);
2274 torture_assert(torture
, ok
, "setup compression directory");
2277 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2278 io
.generic
.in
.file
.handle
= dirh
;
2279 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2280 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2282 torture_assert(torture
,
2283 ((io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
) == 0),
2284 "compression attr before set");
2286 ZERO_STRUCT(set_io
);
2287 set_io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2288 set_io
.basic_info
.in
.file
.handle
= dirh
;
2289 set_io
.basic_info
.in
.create_time
= io
.basic_info
.out
.create_time
;
2290 set_io
.basic_info
.in
.access_time
= io
.basic_info
.out
.access_time
;
2291 set_io
.basic_info
.in
.write_time
= io
.basic_info
.out
.write_time
;
2292 set_io
.basic_info
.in
.change_time
= io
.basic_info
.out
.change_time
;
2293 set_io
.basic_info
.in
.attrib
= (io
.basic_info
.out
.attrib
2294 | FILE_ATTRIBUTE_COMPRESSED
);
2295 status
= smb2_setinfo_file(tree
, &set_io
);
2296 torture_assert_ntstatus_ok(torture
, status
, "SMB2_SETINFO_FILE");
2298 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, dirh
,
2300 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2302 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2303 "dir compression set after SetInfo");
2305 smb2_util_close(tree
, dirh
);
2306 talloc_free(tmp_ctx
);
2310 static bool test_ioctl_compress_perms(struct torture_context
*torture
,
2311 struct smb2_tree
*tree
)
2313 struct smb2_handle fh
;
2314 uint16_t compression_fmt
;
2315 union smb_fileinfo io
;
2317 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2320 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2321 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2322 FILE_ATTRIBUTE_NORMAL
);
2323 torture_assert(torture
, ok
, "setup compression file");
2325 status
= test_ioctl_compress_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2327 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2328 smb2_util_close(tree
, fh
);
2330 torture_skip(torture
, "FS compression not supported\n");
2333 /* attempt get compression without READ_ATTR permission */
2334 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2336 (SEC_RIGHTS_FILE_READ
& ~(SEC_FILE_READ_ATTRIBUTE
2337 | SEC_STD_READ_CONTROL
2338 | SEC_FILE_READ_EA
)),
2339 FILE_ATTRIBUTE_NORMAL
);
2340 torture_assert(torture
, ok
, "setup compression file");
2342 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2344 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2345 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2346 "compression set after create");
2347 smb2_util_close(tree
, fh
);
2349 /* set compression without WRITE_ATTR permission should succeed */
2350 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2352 (SEC_RIGHTS_FILE_WRITE
& ~(SEC_FILE_WRITE_ATTRIBUTE
2354 | SEC_FILE_WRITE_EA
)),
2355 FILE_ATTRIBUTE_NORMAL
);
2356 torture_assert(torture
, ok
, "setup compression file");
2358 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2359 COMPRESSION_FORMAT_DEFAULT
);
2360 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_COMPRESSION");
2361 smb2_util_close(tree
, fh
);
2363 ok
= test_setup_open(torture
, tree
, tmp_ctx
,
2364 FNAME
, &fh
, SEC_RIGHTS_FILE_ALL
,
2365 FILE_ATTRIBUTE_NORMAL
);
2366 torture_assert(torture
, ok
, "setup compression file");
2368 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2369 io
.generic
.in
.file
.handle
= fh
;
2370 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2371 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2373 torture_assert(torture
,
2374 (io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_COMPRESSED
),
2375 "incorrect compression attr");
2376 smb2_util_close(tree
, fh
);
2378 /* attempt get compression without READ_DATA permission */
2379 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2381 (SEC_RIGHTS_FILE_READ
& ~SEC_FILE_READ_DATA
),
2382 FILE_ATTRIBUTE_NORMAL
);
2383 torture_assert(torture
, ok
, "setup compression file");
2385 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2387 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2388 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2389 "compression enabled after set");
2390 smb2_util_close(tree
, fh
);
2392 /* attempt get compression with only SYNCHRONIZE permission */
2393 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2395 SEC_STD_SYNCHRONIZE
,
2396 FILE_ATTRIBUTE_NORMAL
);
2397 torture_assert(torture
, ok
, "setup compression file");
2399 status
= test_ioctl_compress_get(torture
, tmp_ctx
, tree
, fh
,
2401 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_GET_COMPRESSION");
2402 torture_assert(torture
, (compression_fmt
== COMPRESSION_FORMAT_NONE
),
2403 "compression not enabled after set");
2404 smb2_util_close(tree
, fh
);
2406 /* attempt to set compression without WRITE_DATA permission */
2407 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2409 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2410 FILE_ATTRIBUTE_NORMAL
);
2411 torture_assert(torture
, ok
, "setup compression file");
2413 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2414 COMPRESSION_FORMAT_DEFAULT
);
2415 torture_assert_ntstatus_equal(torture
, status
,
2416 NT_STATUS_ACCESS_DENIED
,
2417 "FSCTL_SET_COMPRESSION permission");
2418 smb2_util_close(tree
, fh
);
2420 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2422 (SEC_RIGHTS_FILE_WRITE
& (~SEC_FILE_WRITE_DATA
)),
2423 FILE_ATTRIBUTE_NORMAL
);
2424 torture_assert(torture
, ok
, "setup compression file");
2426 status
= test_ioctl_compress_set(torture
, tmp_ctx
, tree
, fh
,
2427 COMPRESSION_FORMAT_NONE
);
2428 torture_assert_ntstatus_equal(torture
, status
,
2429 NT_STATUS_ACCESS_DENIED
,
2430 "FSCTL_SET_COMPRESSION permission");
2431 smb2_util_close(tree
, fh
);
2433 talloc_free(tmp_ctx
);
2438 basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
2440 static bool test_ioctl_network_interface_info(struct torture_context
*torture
,
2441 struct smb2_tree
*tree
)
2443 union smb_ioctl ioctl
;
2444 struct smb2_handle fh
;
2446 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2447 struct fsctl_net_iface_info net_iface
;
2448 enum ndr_err_code ndr_ret
;
2451 caps
= smb2cli_conn_server_capabilities(tree
->session
->transport
->conn
);
2452 if (!(caps
& SMB2_CAP_MULTI_CHANNEL
)) {
2453 torture_skip(torture
, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
2457 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2458 fh
.data
[0] = UINT64_MAX
;
2459 fh
.data
[1] = UINT64_MAX
;
2460 ioctl
.smb2
.in
.file
.handle
= fh
;
2461 ioctl
.smb2
.in
.function
= FSCTL_QUERY_NETWORK_INTERFACE_INFO
;
2462 ioctl
.smb2
.in
.max_response_size
= 0x10000; /* Windows client sets this to 64KiB */
2463 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2465 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2466 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
2468 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
, &net_iface
,
2469 (ndr_pull_flags_fn_t
)ndr_pull_fsctl_net_iface_info
);
2470 torture_assert_ndr_success(torture
, ndr_ret
,
2471 "ndr_pull_fsctl_net_iface_info");
2473 ndr_print_debug((ndr_print_fn_t
)ndr_print_fsctl_net_iface_info
,
2474 "Network Interface Info", &net_iface
);
2476 talloc_free(tmp_ctx
);
2480 static NTSTATUS
test_ioctl_sparse_fs_supported(struct torture_context
*torture
,
2481 struct smb2_tree
*tree
,
2482 TALLOC_CTX
*mem_ctx
,
2483 struct smb2_handle
*fh
,
2484 bool *sparse_support
)
2487 union smb_fsinfo info
;
2490 info
.generic
.level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
2491 info
.generic
.handle
= *fh
;
2492 status
= smb2_getinfo_fs(tree
, tree
, &info
);
2493 if (!NT_STATUS_IS_OK(status
)) {
2497 if (info
.attribute_info
.out
.fs_attr
& FILE_SUPPORTS_SPARSE_FILES
) {
2498 *sparse_support
= true;
2500 *sparse_support
= false;
2502 return NT_STATUS_OK
;
2505 static NTSTATUS
test_ioctl_sparse_req(struct torture_context
*torture
,
2506 TALLOC_CTX
*mem_ctx
,
2507 struct smb2_tree
*tree
,
2508 struct smb2_handle fh
,
2511 union smb_ioctl ioctl
;
2516 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2517 ioctl
.smb2
.in
.file
.handle
= fh
;
2518 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2519 ioctl
.smb2
.in
.max_response_size
= 0;
2520 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2521 set_sparse
= (set
? 0xFF : 0x0);
2522 ioctl
.smb2
.in
.out
.data
= &set_sparse
;
2523 ioctl
.smb2
.in
.out
.length
= sizeof(set_sparse
);
2525 status
= smb2_ioctl(tree
, mem_ctx
, &ioctl
.smb2
);
2529 static NTSTATUS
test_sparse_get(struct torture_context
*torture
,
2530 TALLOC_CTX
*mem_ctx
,
2531 struct smb2_tree
*tree
,
2532 struct smb2_handle fh
,
2535 union smb_fileinfo io
;
2539 io
.generic
.level
= RAW_FILEINFO_BASIC_INFORMATION
;
2540 io
.generic
.in
.file
.handle
= fh
;
2541 status
= smb2_getinfo_file(tree
, mem_ctx
, &io
);
2542 if (!NT_STATUS_IS_OK(status
)) {
2545 *_is_sparse
= !!(io
.basic_info
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
);
2550 static bool test_ioctl_sparse_file_flag(struct torture_context
*torture
,
2551 struct smb2_tree
*tree
)
2553 struct smb2_handle fh
;
2554 union smb_fileinfo io
;
2556 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2560 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2561 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2562 FILE_ATTRIBUTE_NORMAL
);
2563 torture_assert(torture
, ok
, "setup file");
2565 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2567 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2569 smb2_util_close(tree
, fh
);
2570 torture_skip(torture
, "Sparse files not supported\n");
2574 io
.generic
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
2575 io
.generic
.in
.file
.handle
= fh
;
2576 status
= smb2_getinfo_file(tree
, tmp_ctx
, &io
);
2577 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FILE");
2579 torture_assert(torture
,
2580 ((io
.all_info2
.out
.attrib
& FILE_ATTRIBUTE_SPARSE
) == 0),
2581 "sparse attr before set");
2583 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
2584 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2586 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2587 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2588 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2590 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
2591 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2593 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2594 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2595 torture_assert(torture
, !is_sparse
, "sparse attr after unset");
2597 smb2_util_close(tree
, fh
);
2598 talloc_free(tmp_ctx
);
2602 static bool test_ioctl_sparse_file_attr(struct torture_context
*torture
,
2603 struct smb2_tree
*tree
)
2605 struct smb2_handle fh
;
2607 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2611 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2612 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2613 (FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_SPARSE
));
2614 torture_assert(torture
, ok
, "setup file");
2616 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2618 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2620 smb2_util_close(tree
, fh
);
2621 torture_skip(torture
, "Sparse files not supported\n");
2624 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2625 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2626 torture_assert(torture
, !is_sparse
, "sparse attr on open");
2628 smb2_util_close(tree
, fh
);
2629 talloc_free(tmp_ctx
);
2633 static bool test_ioctl_sparse_dir_flag(struct torture_context
*torture
,
2634 struct smb2_tree
*tree
)
2636 struct smb2_handle dirh
;
2638 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2641 smb2_deltree(tree
, DNAME
);
2642 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2643 DNAME
, &dirh
, 0, SEC_RIGHTS_FILE_ALL
,
2644 FILE_ATTRIBUTE_DIRECTORY
);
2645 torture_assert(torture
, ok
, "setup sparse directory");
2647 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &dirh
,
2649 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2651 smb2_util_close(tree
, dirh
);
2652 smb2_deltree(tree
, DNAME
);
2653 torture_skip(torture
, "Sparse files not supported\n");
2656 /* set sparse dir should fail, check for 2k12 & 2k8 response */
2657 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, dirh
, true);
2658 torture_assert_ntstatus_equal(torture
, status
,
2659 NT_STATUS_INVALID_PARAMETER
,
2660 "dir FSCTL_SET_SPARSE status");
2662 smb2_util_close(tree
, dirh
);
2663 smb2_deltree(tree
, DNAME
);
2664 talloc_free(tmp_ctx
);
2669 * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse
2670 * buffer to indicate whether the flag should be set or cleared. When sent
2671 * without a buffer, it must be handled as if SetSparse=TRUE.
2673 static bool test_ioctl_sparse_set_nobuf(struct torture_context
*torture
,
2674 struct smb2_tree
*tree
)
2676 struct smb2_handle fh
;
2677 union smb_ioctl ioctl
;
2679 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2683 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2684 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2685 FILE_ATTRIBUTE_NORMAL
);
2686 torture_assert(torture
, ok
, "setup file");
2688 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2690 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2692 smb2_util_close(tree
, fh
);
2693 torture_skip(torture
, "Sparse files not supported\n");
2696 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2697 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2698 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2701 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2702 ioctl
.smb2
.in
.file
.handle
= fh
;
2703 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2704 ioctl
.smb2
.in
.max_response_size
= 0;
2705 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2706 /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */
2708 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2709 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2711 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2712 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2713 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2715 /* second non-SetSparse request shouldn't toggle sparse */
2717 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2718 ioctl
.smb2
.in
.file
.handle
= fh
;
2719 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2720 ioctl
.smb2
.in
.max_response_size
= 0;
2721 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2723 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2724 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2726 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2727 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2728 torture_assert(torture
, is_sparse
, "no sparse attr after 2nd set");
2730 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, false);
2731 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2733 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2734 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2735 torture_assert(torture
, !is_sparse
, "sparse attr after unset");
2737 smb2_util_close(tree
, fh
);
2738 talloc_free(tmp_ctx
);
2742 static bool test_ioctl_sparse_set_oversize(struct torture_context
*torture
,
2743 struct smb2_tree
*tree
)
2745 struct smb2_handle fh
;
2746 union smb_ioctl ioctl
;
2748 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2753 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2754 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2755 FILE_ATTRIBUTE_NORMAL
);
2756 torture_assert(torture
, ok
, "setup file");
2758 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2760 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2762 smb2_util_close(tree
, fh
);
2763 torture_skip(torture
, "Sparse files not supported\n");
2766 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2767 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2768 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2771 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2772 ioctl
.smb2
.in
.file
.handle
= fh
;
2773 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2774 ioctl
.smb2
.in
.max_response_size
= 0;
2775 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2778 * Attach a request buffer larger than FILE_SET_SPARSE_BUFFER
2779 * Windows still successfully processes the request.
2782 buf
[0] = 0xFF; /* attempt to set sparse */
2783 ioctl
.smb2
.in
.out
.data
= buf
;
2784 ioctl
.smb2
.in
.out
.length
= ARRAY_SIZE(buf
);
2786 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2787 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2789 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2790 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2791 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2794 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2795 ioctl
.smb2
.in
.file
.handle
= fh
;
2796 ioctl
.smb2
.in
.function
= FSCTL_SET_SPARSE
;
2797 ioctl
.smb2
.in
.max_response_size
= 0;
2798 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2800 ZERO_ARRAY(buf
); /* clear sparse */
2801 ioctl
.smb2
.in
.out
.data
= buf
;
2802 ioctl
.smb2
.in
.out
.length
= ARRAY_SIZE(buf
);
2804 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2805 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2807 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2808 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2809 torture_assert(torture
, !is_sparse
, "sparse attr after clear");
2811 smb2_util_close(tree
, fh
);
2812 talloc_free(tmp_ctx
);
2816 static NTSTATUS
test_ioctl_qar_req(struct torture_context
*torture
,
2817 TALLOC_CTX
*mem_ctx
,
2818 struct smb2_tree
*tree
,
2819 struct smb2_handle fh
,
2822 struct file_alloced_range_buf
**_rsp
,
2823 uint64_t *_rsp_count
)
2825 union smb_ioctl ioctl
;
2827 enum ndr_err_code ndr_ret
;
2828 struct file_alloced_range_buf far_buf
;
2829 struct file_alloced_range_buf
*far_rsp
= NULL
;
2830 uint64_t far_count
= 0;
2832 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
2833 if (tmp_ctx
== NULL
) {
2834 return NT_STATUS_NO_MEMORY
;
2838 ioctl
.smb2
.level
= RAW_IOCTL_SMB2
;
2839 ioctl
.smb2
.in
.file
.handle
= fh
;
2840 ioctl
.smb2
.in
.function
= FSCTL_QUERY_ALLOCATED_RANGES
;
2841 ioctl
.smb2
.in
.max_response_size
= 1024;
2842 ioctl
.smb2
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
2844 far_buf
.file_off
= req_off
;
2845 far_buf
.len
= req_len
;
2847 ndr_ret
= ndr_push_struct_blob(&ioctl
.smb2
.in
.out
, tmp_ctx
,
2849 (ndr_push_flags_fn_t
)ndr_push_file_alloced_range_buf
);
2850 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2851 status
= NT_STATUS_UNSUCCESSFUL
;
2855 status
= smb2_ioctl(tree
, tmp_ctx
, &ioctl
.smb2
);
2856 if (!NT_STATUS_IS_OK(status
)) {
2860 if (ioctl
.smb2
.out
.out
.length
== 0) {
2864 if ((ioctl
.smb2
.out
.out
.length
% sizeof(far_buf
)) != 0) {
2865 torture_comment(torture
, "invalid qry_alloced rsp len: %zd:",
2866 ioctl
.smb2
.out
.out
.length
);
2867 status
= NT_STATUS_INVALID_VIEW_SIZE
;
2871 far_count
= (ioctl
.smb2
.out
.out
.length
/ sizeof(far_buf
));
2872 far_rsp
= talloc_array(mem_ctx
, struct file_alloced_range_buf
,
2874 if (far_rsp
== NULL
) {
2875 status
= NT_STATUS_NO_MEMORY
;
2879 for (i
= 0; i
< far_count
; i
++) {
2880 ndr_ret
= ndr_pull_struct_blob(&ioctl
.smb2
.out
.out
, tmp_ctx
,
2882 (ndr_pull_flags_fn_t
)ndr_pull_file_alloced_range_buf
);
2883 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2884 status
= NT_STATUS_UNSUCCESSFUL
;
2891 *_rsp_count
= far_count
;
2892 status
= NT_STATUS_OK
;
2894 talloc_free(tmp_ctx
);
2898 static bool test_ioctl_sparse_qar(struct torture_context
*torture
,
2899 struct smb2_tree
*tree
)
2901 struct smb2_handle fh
;
2903 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
2906 struct file_alloced_range_buf
*far_rsp
= NULL
;
2907 uint64_t far_count
= 0;
2909 /* zero length file, shouldn't have any ranges */
2910 ok
= test_setup_create_fill(torture
, tree
, tmp_ctx
,
2911 FNAME
, &fh
, 0, SEC_RIGHTS_FILE_ALL
,
2912 FILE_ATTRIBUTE_NORMAL
);
2913 torture_assert(torture
, ok
, "setup file");
2915 status
= test_ioctl_sparse_fs_supported(torture
, tree
, tmp_ctx
, &fh
,
2917 torture_assert_ntstatus_ok(torture
, status
, "SMB2_GETINFO_FS");
2919 smb2_util_close(tree
, fh
);
2920 torture_skip(torture
, "Sparse files not supported\n");
2923 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2924 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2925 torture_assert(torture
, !is_sparse
, "sparse attr before set");
2927 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2932 torture_assert_ntstatus_ok(torture
, status
,
2933 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2934 torture_assert_u64_equal(torture
, far_count
, 0,
2935 "unexpected response len");
2937 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2942 torture_assert_ntstatus_ok(torture
, status
,
2943 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2944 torture_assert_u64_equal(torture
, far_count
, 0,
2945 "unexpected response len");
2947 status
= test_ioctl_sparse_req(torture
, tmp_ctx
, tree
, fh
, true);
2948 torture_assert_ntstatus_ok(torture
, status
, "FSCTL_SET_SPARSE");
2950 status
= test_sparse_get(torture
, tmp_ctx
, tree
, fh
, &is_sparse
);
2951 torture_assert_ntstatus_ok(torture
, status
, "test_sparse_get");
2952 torture_assert(torture
, is_sparse
, "no sparse attr after set");
2954 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2959 torture_assert_ntstatus_ok(torture
, status
,
2960 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2961 torture_assert_u64_equal(torture
, far_count
, 0,
2962 "unexpected response len");
2964 /* write into the (now) sparse file at 4k offset */
2965 ok
= write_pattern(torture
, tree
, tmp_ctx
, fh
,
2968 4096); /* pattern offset */
2969 torture_assert(torture
, ok
, "write pattern");
2971 /* query range before write off, it should be alloced */
2972 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2977 torture_assert_ntstatus_ok(torture
, status
,
2978 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2979 torture_assert_u64_equal(torture
, far_count
, 1,
2980 "unexpected response len");
2981 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0, "far offset");
2982 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 4096, "far len");
2985 * Query range before and past write, it should be allocated up to the
2988 status
= test_ioctl_qar_req(torture
, tmp_ctx
, tree
, fh
,
2993 torture_assert_ntstatus_ok(torture
, status
,
2994 "FSCTL_QUERY_ALLOCATED_RANGES req failed");
2995 torture_assert_u64_equal(torture
, far_count
, 1,
2996 "unexpected response len");
2997 torture_assert_u64_equal(torture
, far_rsp
[0].file_off
, 0, "far offset");
2998 torture_assert_u64_equal(torture
, far_rsp
[0].len
, 5120, "far len");
3000 smb2_util_close(tree
, fh
);
3001 talloc_free(tmp_ctx
);
3006 * basic testing of SMB2 ioctls
3008 struct torture_suite
*torture_smb2_ioctl_init(void)
3010 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "ioctl");
3012 torture_suite_add_1smb2_test(suite
, "shadow_copy",
3013 test_ioctl_get_shadow_copy
);
3014 torture_suite_add_1smb2_test(suite
, "req_resume_key",
3015 test_ioctl_req_resume_key
);
3016 torture_suite_add_1smb2_test(suite
, "copy_chunk_simple",
3017 test_ioctl_copy_chunk_simple
);
3018 torture_suite_add_1smb2_test(suite
, "copy_chunk_multi",
3019 test_ioctl_copy_chunk_multi
);
3020 torture_suite_add_1smb2_test(suite
, "copy_chunk_tiny",
3021 test_ioctl_copy_chunk_tiny
);
3022 torture_suite_add_1smb2_test(suite
, "copy_chunk_overwrite",
3023 test_ioctl_copy_chunk_over
);
3024 torture_suite_add_1smb2_test(suite
, "copy_chunk_append",
3025 test_ioctl_copy_chunk_append
);
3026 torture_suite_add_1smb2_test(suite
, "copy_chunk_limits",
3027 test_ioctl_copy_chunk_limits
);
3028 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_lock",
3029 test_ioctl_copy_chunk_src_lck
);
3030 torture_suite_add_1smb2_test(suite
, "copy_chunk_dest_lock",
3031 test_ioctl_copy_chunk_dest_lck
);
3032 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_key",
3033 test_ioctl_copy_chunk_bad_key
);
3034 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest",
3035 test_ioctl_copy_chunk_src_is_dest
);
3036 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_is_dest_overlap",
3037 test_ioctl_copy_chunk_src_is_dest_overlap
);
3038 torture_suite_add_1smb2_test(suite
, "copy_chunk_bad_access",
3039 test_ioctl_copy_chunk_bad_access
);
3040 torture_suite_add_1smb2_test(suite
, "copy_chunk_write_access",
3041 test_ioctl_copy_chunk_write_access
);
3042 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed",
3043 test_ioctl_copy_chunk_src_exceed
);
3044 torture_suite_add_1smb2_test(suite
, "copy_chunk_src_exceed_multi",
3045 test_ioctl_copy_chunk_src_exceed_multi
);
3046 torture_suite_add_1smb2_test(suite
, "copy_chunk_sparse_dest",
3047 test_ioctl_copy_chunk_sparse_dest
);
3048 torture_suite_add_1smb2_test(suite
, "copy_chunk_max_output_sz",
3049 test_ioctl_copy_chunk_max_output_sz
);
3050 torture_suite_add_1smb2_test(suite
, "copy_chunk_zero_length",
3051 test_ioctl_copy_chunk_zero_length
);
3052 torture_suite_add_1smb2_test(suite
, "compress_file_flag",
3053 test_ioctl_compress_file_flag
);
3054 torture_suite_add_1smb2_test(suite
, "compress_dir_inherit",
3055 test_ioctl_compress_dir_inherit
);
3056 torture_suite_add_1smb2_test(suite
, "compress_invalid_format",
3057 test_ioctl_compress_invalid_format
);
3058 torture_suite_add_1smb2_test(suite
, "compress_invalid_buf",
3059 test_ioctl_compress_invalid_buf
);
3060 torture_suite_add_1smb2_test(suite
, "compress_query_file_attr",
3061 test_ioctl_compress_query_file_attr
);
3062 torture_suite_add_1smb2_test(suite
, "compress_create_with_attr",
3063 test_ioctl_compress_create_with_attr
);
3064 torture_suite_add_1smb2_test(suite
, "compress_inherit_disable",
3065 test_ioctl_compress_inherit_disable
);
3066 torture_suite_add_1smb2_test(suite
, "compress_set_file_attr",
3067 test_ioctl_compress_set_file_attr
);
3068 torture_suite_add_1smb2_test(suite
, "compress_perms",
3069 test_ioctl_compress_perms
);
3070 torture_suite_add_1smb2_test(suite
, "network_interface_info",
3071 test_ioctl_network_interface_info
);
3072 torture_suite_add_1smb2_test(suite
, "sparse_file_flag",
3073 test_ioctl_sparse_file_flag
);
3074 torture_suite_add_1smb2_test(suite
, "sparse_file_attr",
3075 test_ioctl_sparse_file_attr
);
3076 torture_suite_add_1smb2_test(suite
, "sparse_dir_flag",
3077 test_ioctl_sparse_dir_flag
);
3078 torture_suite_add_1smb2_test(suite
, "sparse_set_nobuf",
3079 test_ioctl_sparse_set_nobuf
);
3080 torture_suite_add_1smb2_test(suite
, "sparse_set_oversize",
3081 test_ioctl_sparse_set_oversize
);
3082 torture_suite_add_1smb2_test(suite
, "sparse_qar",
3083 test_ioctl_sparse_qar
);
3085 suite
->description
= talloc_strdup(suite
, "SMB2-IOCTL tests");