smb2_util_unlink(tree, FNAME);
status = torture_smb2_testfile(tree, FNAME, &h);
- if (!NT_STATUS_IS_OK(status)) {
- printf("create write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "create write");
ZERO_ARRAY(buf);
status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
- if (!NT_STATUS_IS_OK(status)) {
- printf("failed write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "write");
ZERO_STRUCT(ioctl);
ioctl.smb2.level = RAW_IOCTL_SMB2;
ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_ENUM_SNAPS failed\n");
- return false;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)
+ || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) {
+ torture_comment(torture,
+ "FSCTL_SRV_ENUM_SNAPS not supported, skipping\n");
+ return true;
}
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_ENUM_SNAPS");
return true;
}
smb2_util_unlink(tree, FNAME);
status = torture_smb2_testfile(tree, FNAME, &h);
- if (!NT_STATUS_IS_OK(status)) {
- printf("create write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "create write");
ZERO_ARRAY(buf);
status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
- if (!NT_STATUS_IS_OK(status)) {
- printf("failed write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "write");
ZERO_STRUCT(ioctl);
ioctl.smb2.level = RAW_IOCTL_SMB2;
ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_REQUEST_RESUME_KEY failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
(ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
ndr_print_debug((ndr_print_fn_t)ndr_print_req_resume_key_rsp, "yo", &res_key);
return true;
}
-static bool test_setup_copy_chunk(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+static uint64_t patt_hash(uint64_t off)
+{
+ return off;
+}
+
+static bool check_pattern(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len,
+ uint64_t patt_off)
+{
+ uint64_t i;
+ struct smb2_read r;
+ NTSTATUS status;
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = len;
+ r.in.offset = off;
+ status = smb2_read(tree, mem_ctx, &r);
+ torture_assert_ntstatus_ok(torture, status, "read");
+
+ torture_assert_u64_equal(torture, r.out.data.length, len,
+ "read data len mismatch");
+
+ for (i = 0; i <= len - 8; i += 8, patt_off += 8) {
+ uint64_t data = BVAL(r.out.data.data, i);
+ torture_assert_u64_equal(torture, data, patt_hash(patt_off),
+ talloc_asprintf(torture, "read data "
+ "pattern bad at %llu\n",
+ (unsigned long long)i));
+ }
+
+ talloc_free(r.out.data.data);
+ return true;
+}
+
+static bool test_setup_copy_chunk(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
uint32_t nchunks,
struct smb2_handle *src_h,
uint64_t src_size,
struct req_resume_key_rsp res_key;
NTSTATUS status;
enum ndr_err_code ndr_ret;
+ uint64_t i;
uint8_t *buf = talloc_zero_size(mem_ctx, MAX(src_size, dest_size));
if (buf == NULL) {
printf("no mem for file data buffer\n");
smb2_util_unlink(tree, FNAME2);
status = torture_smb2_testfile(tree, FNAME, src_h);
- if (!NT_STATUS_IS_OK(status)) {
- printf("create write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "create write");
if (src_size > 0) {
- status = smb2_util_write(tree, *src_h, buf, 0, src_size);
- if (!NT_STATUS_IS_OK(status)) {
- printf("failed src write\n");
- return false;
+ for (i = 0; i <= src_size - 8; i += 8) {
+ SBVAL(buf, i, patt_hash(i));
}
+ status = smb2_util_write(tree, *src_h, buf, 0, src_size);
+ torture_assert_ntstatus_ok(torture, status, "src write");
}
status = torture_smb2_testfile(tree, FNAME2, dest_h);
- if (!NT_STATUS_IS_OK(status)) {
- printf("create write\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "create write");
if (dest_size > 0) {
- status = smb2_util_write(tree, *dest_h, buf, 0, dest_size);
- if (!NT_STATUS_IS_OK(status)) {
- printf("failed dest write\n");
- return false;
+ for (i = 0; i <= dest_size - 8; i += 8) {
+ SBVAL(buf, i, patt_hash(i));
}
+ status = smb2_util_write(tree, *dest_h, buf, 0, dest_size);
+ torture_assert_ntstatus_ok(torture, status, "dest write");
}
ZERO_STRUCTPN(ioctl);
ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
status = smb2_ioctl(tree, mem_ctx, &ioctl->smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_REQUEST_RESUME_KEY failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_REQUEST_RESUME_KEY");
+
ndr_ret = ndr_pull_struct_blob(&ioctl->smb2.out.out, mem_ctx, &res_key,
(ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
ZERO_STRUCTPN(ioctl);
ioctl->smb2.level = RAW_IOCTL_SMB2;
}
-static bool check_copy_chunk_rsp(struct srv_copychunk_rsp *cc_rsp,
+static bool check_copy_chunk_rsp(struct torture_context *torture,
+ struct srv_copychunk_rsp *cc_rsp,
uint32_t ex_chunks_written,
uint32_t ex_chunk_bytes_written,
uint32_t ex_total_bytes_written)
{
- if (cc_rsp->chunks_written != ex_chunks_written) {
- printf("expected %u chunks, got %u\n",
- ex_chunks_written, cc_rsp->chunks_written);
- return false;
- }
- if (cc_rsp->chunk_bytes_written != ex_chunk_bytes_written) {
- printf("expected %u chunk bytes remaining, got %u\n",
- ex_chunk_bytes_written, cc_rsp->chunk_bytes_written);
- return false;
- }
- if (cc_rsp->total_bytes_written != ex_total_bytes_written) {
- printf("expected %u total bytes, got %u\n",
- ex_total_bytes_written, cc_rsp->total_bytes_written);
- return false;
- }
+ torture_assert_int_equal(torture, cc_rsp->chunks_written,
+ ex_chunks_written, "num chunks");
+ torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written,
+ ex_chunk_bytes_written, "chunk bytes written");
+ torture_assert_int_equal(torture, cc_rsp->total_bytes_written,
+ ex_total_bytes_written, "chunk total bytes");
return true;
}
enum ndr_err_code ndr_ret;
bool ok;
- ok = test_setup_copy_chunk(tree, tmp_ctx,
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
&src_h, 4096, /* fill 4096 byte src file */
&dest_h, 0, /* 0 byte dest file */
ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
&cc_copy,
(ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_COPYCHUNK failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
&cc_rsp,
(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
- ok = check_copy_chunk_rsp(&cc_rsp,
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
1, /* chunks written */
0, /* chunk bytes unsuccessfully written */
4096); /* total bytes written */
return false;
}
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ return false;
+ }
+
smb2_util_close(tree, src_h);
smb2_util_close(tree, dest_h);
talloc_free(tmp_ctx);
enum ndr_err_code ndr_ret;
bool ok;
- ok = test_setup_copy_chunk(tree, tmp_ctx,
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
&src_h, 8192, /* src file */
&dest_h, 0, /* dest file */
ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
&cc_copy,
(ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_COPYCHUNK failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
&cc_rsp,
(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
- ok = check_copy_chunk_rsp(&cc_rsp,
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
2, /* chunks written */
0, /* chunk bytes unsuccessfully written */
8192); /* total bytes written */
enum ndr_err_code ndr_ret;
bool ok;
- ok = test_setup_copy_chunk(tree, tmp_ctx,
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
&src_h, 100, /* src file */
&dest_h, 0, /* dest file */
ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
&cc_copy,
(ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_COPYCHUNK failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
&cc_rsp,
(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
- ok = check_copy_chunk_rsp(&cc_rsp,
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
2, /* chunks written */
0, /* chunk bytes unsuccessfully written */
100); /* total bytes written */
return false;
}
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 100, 0);
+ if (!ok) {
+ return false;
+ }
+
smb2_util_close(tree, src_h);
smb2_util_close(tree, dest_h);
talloc_free(tmp_ctx);
enum ndr_err_code ndr_ret;
bool ok;
- ok = test_setup_copy_chunk(tree, tmp_ctx,
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
&src_h, 8192, /* src file */
&dest_h, 4096, /* dest file */
ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
&cc_copy,
(ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_COPYCHUNK failed\n");
- return false;
- }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
&cc_rsp,
(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- return false;
- }
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
- ok = check_copy_chunk_rsp(&cc_rsp,
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
2, /* chunks written */
0, /* chunk bytes unsuccessfully written */
8192); /* total bytes written */
return false;
}
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 4096);
+ if (!ok) {
+ return false;
+ }
+
smb2_util_close(tree, src_h);
smb2_util_close(tree, dest_h);
talloc_free(tmp_ctx);
enum ndr_err_code ndr_ret;
bool ok;
- ok = test_setup_copy_chunk(tree, tmp_ctx,
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
&src_h, 4096, /* src file */
&dest_h, 0, /* dest file */
ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
&cc_copy,
(ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
- if (ndr_ret != NDR_ERR_SUCCESS) {
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 8192); /* total bytes written */
+ if (!ok) {
+ return false;
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
return false;
}
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
+ if (!ok) {
+ return false;
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* chunks */
+ &src_h, 4096, /* src file */
+ &dest_h, 0, /* dest file */
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ return false;
+ }
+
+ /* send huge chunk length request */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = UINT_MAX;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret, "marshalling request");
+
status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
- if (!NT_STATUS_IS_OK(status)) {
- printf("FSCTL_SRV_COPYCHUNK failed\n");
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "bad oversize chunk response");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
+
+ torture_comment(torture, "limit max chunks, got %u\n",
+ cc_rsp.chunks_written);
+ torture_comment(torture, "limit max chunk len, got %u\n",
+ cc_rsp.chunk_bytes_written);
+ torture_comment(torture, "limit max total bytes, got %u\n",
+ cc_rsp.total_bytes_written);
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle src_h2;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* chunks */
+ &src_h, 4096, /* src file */
+ &dest_h, 0, /* dest file */
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
return false;
}
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* open and lock the copychunk src file */
+ status = torture_smb2_testfile(tree, FNAME, &src_h2);
+ torture_assert_ntstatus_ok(torture, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].source_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "lock");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ /*
+ * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
+ *
+ * Edgar Olougouna @ MS wrote:
+ * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
+ * discrepancy observed between Windows versions, we confirm that the
+ * behavior change is expected.
+ *
+ * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
+ * to move the chunks from the source to the destination.
+ * These ReadFile/WriteFile APIs go through the byte-range lock checks,
+ * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
+ *
+ * Prior to Windows Server 2012, CopyChunk used mapped sections to move
+ * the data. And byte range locks are not enforced on mapped I/O, and
+ * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
+ */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_FILE_LOCK_CONFLICT,
+ "FSCTL_SRV_COPYCHUNK locked");
+
+ /* should get cc response data with the lock conflict status */
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 0, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 0); /* total bytes written */
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].source_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK unlocked");
+
ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
&cc_rsp,
(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
return false;
}
- ok = check_copy_chunk_rsp(&cc_rsp,
- 2, /* chunks written */
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ return false;
+ }
+
+ smb2_util_close(tree, src_h2);
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ struct smb2_handle dest_h2;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* chunks */
+ &src_h, 4096, /* src file */
+ &dest_h, 4096, /* dest file */
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ return false;
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* open and lock the copychunk dest file */
+ status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
+ torture_assert_ntstatus_ok(torture, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].target_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "lock");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_FILE_LOCK_CONFLICT,
+ "FSCTL_SRV_COPYCHUNK locked");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].target_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK unlocked");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
0, /* chunk bytes unsuccessfully written */
- 8192); /* total bytes written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ return false;
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
if (!ok) {
return false;
}
+ smb2_util_close(tree, dest_h2);
smb2_util_close(tree, src_h);
smb2_util_close(tree, dest_h);
talloc_free(tmp_ctx);
test_ioctl_copy_chunk_over);
torture_suite_add_1smb2_test(suite, "copy_chunk_append",
test_ioctl_copy_chunk_append);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_limits",
+ test_ioctl_copy_chunk_limits);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_lock",
+ test_ioctl_copy_chunk_src_lck);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_dest_lock",
+ test_ioctl_copy_chunk_dest_lck);
suite->description = talloc_strdup(suite, "SMB2-IOCTL tests");