[PATCH] Fix the new async copy-chunk for streams
Ralph Böhme
slow at samba.org
Tue May 16 11:37:46 UTC 2017
On Mon, May 15, 2017 at 08:29:00PM +0200, Ralph Böhme via samba-technical wrote:
> Nevertheless I agree that it makes sense to add a basic test to smb2.ioctl
> itself. I will post an updated patchset.
attached.
Fwiw, I tried to consolidate test_setup_copy_chunk() and make it a public
utility function but I failed miserably to figure out the required headers and
deps.
-slow
-------------- next part --------------
From 48981924657018db9379251ad8edaec5a8c999e5 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 12 May 2017 07:58:01 +0200
Subject: [PATCH 1/7] vfs_streams_xattr: add pread_send/recv and
pwrite_send/recv
This is needed to support copy-chunk of streams. vfs_default issues
calls to async pread and pwrite (send/recv versions) since commit
60e45a2d25401eaf9a15a86d19114670ccfde259.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: David Disseldorp <ddiss at samba.org>
---
source3/modules/vfs_streams_xattr.c | 165 ++++++++++++++++++++++++++++++++++++
1 file changed, 165 insertions(+)
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index 2943e52..f481f27 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -25,6 +25,7 @@
#include "smbd/smbd.h"
#include "system/filesys.h"
#include "../lib/crypto/md5.h"
+#include "lib/util/tevent_unix.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
@@ -1048,6 +1049,166 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
return overlap;
}
+struct streams_xattr_pread_state {
+ ssize_t nread;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void streams_xattr_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *streams_xattr_pread_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ void *data,
+ size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct streams_xattr_pread_state *state = NULL;
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct streams_xattr_pread_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (sio == NULL) {
+ subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
+ data, n, offset);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, streams_xattr_pread_done, req);
+ return req;
+ }
+
+ state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
+ if (state->nread != n) {
+ if (state->nread != -1) {
+ errno = EIO;
+ }
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static void streams_xattr_pread_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct streams_xattr_pread_state *state = tevent_req_data(
+ req, struct streams_xattr_pread_state);
+
+ state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+
+ if (tevent_req_error(req, state->vfs_aio_state.error)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t streams_xattr_pread_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct streams_xattr_pread_state *state = tevent_req_data(
+ req, struct streams_xattr_pread_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->nread;
+}
+
+struct streams_xattr_pwrite_state {
+ ssize_t nwritten;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void streams_xattr_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *streams_xattr_pwrite_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ const void *data,
+ size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct streams_xattr_pwrite_state *state = NULL;
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct streams_xattr_pwrite_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (sio == NULL) {
+ subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
+ data, n, offset);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, streams_xattr_pwrite_done, req);
+ return req;
+ }
+
+ state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
+ if (state->nwritten != n) {
+ if (state->nwritten != -1) {
+ errno = EIO;
+ }
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static void streams_xattr_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct streams_xattr_pwrite_state *state = tevent_req_data(
+ req, struct streams_xattr_pwrite_state);
+
+ state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+
+ if (tevent_req_error(req, state->vfs_aio_state.error)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t streams_xattr_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct streams_xattr_pwrite_state *state = tevent_req_data(
+ req, struct streams_xattr_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->nwritten;
+}
+
static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
struct files_struct *fsp,
off_t offset)
@@ -1151,6 +1312,10 @@ static struct vfs_fn_pointers vfs_streams_xattr_fns = {
.lstat_fn = streams_xattr_lstat,
.pread_fn = streams_xattr_pread,
.pwrite_fn = streams_xattr_pwrite,
+ .pread_send_fn = streams_xattr_pread_send,
+ .pread_recv_fn = streams_xattr_pread_recv,
+ .pwrite_send_fn = streams_xattr_pwrite_send,
+ .pwrite_recv_fn = streams_xattr_pwrite_recv,
.unlink_fn = streams_xattr_unlink,
.rename_fn = streams_xattr_rename,
.ftruncate_fn = streams_xattr_ftruncate,
--
2.9.3
From 164faa37d3295a377aba0adfc27dede107c0fd68 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 12 May 2017 14:40:03 +0200
Subject: [PATCH 2/7] vfs_fruit: add pread_send/recv and pwrite_send/recv
This is needed to support copy-chunk of streams. vfs_default issues
calls to async pread and pwrite (send/recv versions) since
commit60e45a2d25401eaf9a15a86d19114670ccfde259.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: David Disseldorp <ddiss at samba.org>
---
source3/modules/vfs_fruit.c | 182 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 182 insertions(+)
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 273540e..63acdf8 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -31,6 +31,7 @@
#include "../libcli/smb/smb2_create_ctx.h"
#include "lib/util/sys_rw.h"
#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/tevent_unix.h"
/*
* Enhanced OS X and Netatalk compatibility
@@ -3755,6 +3756,105 @@ static ssize_t fruit_pread(vfs_handle_struct *handle,
return nread;
}
+static bool fruit_must_handle_aio_stream(struct fio *fio)
+{
+ if (fio == NULL) {
+ return false;
+ };
+
+ if ((fio->type == ADOUBLE_META) &&
+ (fio->config->meta == FRUIT_META_NETATALK))
+ {
+ return true;
+ }
+
+ if ((fio->type == ADOUBLE_RSRC) &&
+ (fio->config->rsrc == FRUIT_RSRC_ADFILE))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+struct fruit_pread_state {
+ ssize_t nread;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void fruit_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *fruit_pread_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ void *data,
+ size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct fruit_pread_state *state = NULL;
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct fruit_pread_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (fruit_must_handle_aio_stream(fio)) {
+ state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
+ if (state->nread != n) {
+ if (state->nread != -1) {
+ errno = EIO;
+ }
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
+ data, n, offset);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, fruit_pread_done, req);
+ return req;
+}
+
+static void fruit_pread_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct fruit_pread_state *state = tevent_req_data(
+ req, struct fruit_pread_state);
+
+ state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+
+ if (tevent_req_error(req, state->vfs_aio_state.error)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t fruit_pread_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct fruit_pread_state *state = tevent_req_data(
+ req, struct fruit_pread_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->nread;
+}
+
static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
files_struct *fsp, const void *data,
size_t n, off_t offset)
@@ -3979,6 +4079,84 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle,
return nwritten;
}
+struct fruit_pwrite_state {
+ ssize_t nwritten;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void fruit_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *fruit_pwrite_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ const void *data,
+ size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct fruit_pwrite_state *state = NULL;
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct fruit_pwrite_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (fruit_must_handle_aio_stream(fio)) {
+ state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
+ if (state->nwritten != n) {
+ if (state->nwritten != -1) {
+ errno = EIO;
+ }
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
+ data, n, offset);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, fruit_pwrite_done, req);
+ return req;
+}
+
+static void fruit_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct fruit_pwrite_state *state = tevent_req_data(
+ req, struct fruit_pwrite_state);
+
+ state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+
+ if (tevent_req_error(req, state->vfs_aio_state.error)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t fruit_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct fruit_pwrite_state *state = tevent_req_data(
+ req, struct fruit_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->nwritten;
+}
+
/**
* Helper to stat/lstat the base file of an smb_fname.
*/
@@ -5427,6 +5605,10 @@ static struct vfs_fn_pointers vfs_fruit_fns = {
.open_fn = fruit_open,
.pread_fn = fruit_pread,
.pwrite_fn = fruit_pwrite,
+ .pread_send_fn = fruit_pread_send,
+ .pread_recv_fn = fruit_pread_recv,
+ .pwrite_send_fn = fruit_pwrite_send,
+ .pwrite_recv_fn = fruit_pwrite_recv,
.stat_fn = fruit_stat,
.lstat_fn = fruit_lstat,
.fstat_fn = fruit_fstat,
--
2.9.3
From f4fa85425440a11bb7dc777a97868f608bf0f117 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 12 May 2017 17:09:08 +0200
Subject: [PATCH 3/7] lib/torture: add two more ndr assert macros
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: David Disseldorp <ddiss at samba.org>
---
lib/torture/torture.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
index 668458a..6b373a9 100644
--- a/lib/torture/torture.h
+++ b/lib/torture/torture.h
@@ -293,6 +293,15 @@ void torture_result(struct torture_context *test,
}\
} while(0)
+#define torture_assert_ndr_err_equal_goto(torture_ctx,got,expected,ret,label,cmt) \
+ do { enum ndr_err_code __got = got, __expected = expected; \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d (%s), expected %d (%s): %s", __got, ndr_errstr(__got), __expected, __STRING(expected), cmt); \
+ ret = false; \
+ goto label; \
+ }\
+ } while(0)
+
#define torture_assert_hresult_equal(torture_ctx, got, expected, cmt) \
do { HRESULT __got = got, __expected = expected; \
if (!HRES_IS_EQUAL(__got, __expected)) { \
@@ -647,6 +656,9 @@ static inline void torture_dump_data_str_cb(const char *buf, void *private_data)
#define torture_assert_ndr_success(torture_ctx,expr,cmt) \
torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt)
+#define torture_assert_ndr_success_goto(torture_ctx,expr,ret,label,cmt) \
+ torture_assert_ndr_err_equal_goto(torture_ctx,expr,NDR_ERR_SUCCESS,ret,label,cmt)
+
#define torture_assert_hresult_ok(torture_ctx,expr,cmt) \
torture_assert_hresult_equal(torture_ctx,expr,HRES_ERROR(0), cmt)
--
2.9.3
From f239d98b3d299d5f71127ddc46f34814cc4ba5a9 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 16 May 2017 13:13:08 +0200
Subject: [PATCH 4/7] s4/torture: smb2.ioctl: add src and dst path args to
test_setup_copy_chunk
Just let the caller pass in the paths, no change in behaviour. A new
test in a subsequent commit will use it to pass paths to streams.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source4/torture/smb2/ioctl.c | 62 +++++++++++++++++++++++++++++++++++---------
1 file changed, 50 insertions(+), 12 deletions(-)
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
index 53476fa..c9fc121 100644
--- a/source4/torture/smb2/ioctl.c
+++ b/source4/torture/smb2/ioctl.c
@@ -309,9 +309,11 @@ static bool test_setup_create_fill(struct torture_context *torture,
static bool test_setup_copy_chunk(struct torture_context *torture,
struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
uint32_t nchunks,
+ const char *src_name,
struct smb2_handle *src_h,
uint64_t src_size,
uint32_t src_desired_access,
+ const char *dst_name,
struct smb2_handle *dest_h,
uint64_t dest_size,
uint32_t dest_desired_access,
@@ -323,12 +325,12 @@ static bool test_setup_copy_chunk(struct torture_context *torture,
NTSTATUS status;
enum ndr_err_code ndr_ret;
- ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME,
+ ok = test_setup_create_fill(torture, tree, mem_ctx, src_name,
src_h, src_size, src_desired_access,
FILE_ATTRIBUTE_NORMAL);
torture_assert(torture, ok, "src file create fill");
- ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME2,
+ ok = test_setup_create_fill(torture, tree, mem_ctx, dst_name,
dest_h, dest_size, dest_desired_access,
FILE_ATTRIBUTE_NORMAL);
torture_assert(torture, ok, "dest file create fill");
@@ -398,8 +400,10 @@ static bool test_ioctl_copy_chunk_simple(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -462,8 +466,10 @@ static bool test_ioctl_copy_chunk_multi(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
+ FNAME,
&src_h, 8192, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -525,8 +531,10 @@ static bool test_ioctl_copy_chunk_tiny(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
+ FNAME,
&src_h, 96, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -593,8 +601,10 @@ static bool test_ioctl_copy_chunk_over(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
+ FNAME,
&src_h, 8192, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 4096, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -662,8 +672,10 @@ static bool test_ioctl_copy_chunk_append(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* chunks */
+ FNAME,
&src_h, 4096, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -735,8 +747,10 @@ static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* chunks */
+ FNAME,
&src_h, 4096, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -796,8 +810,10 @@ static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* chunks */
+ FNAME,
&src_h, 4096, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -924,8 +940,10 @@ static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* chunks */
+ FNAME,
&src_h, 4096, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 4096, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1020,8 +1038,10 @@ static bool test_ioctl_copy_chunk_bad_key(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1,
+ FNAME,
&src_h, 4096,
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0,
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1070,8 +1090,10 @@ static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1,
+ FNAME,
&src_h, 8192,
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0,
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1187,8 +1209,10 @@ test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context *torture,
/* exceed the vfs_default copy buffer */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1,
+ FNAME,
&src_h, 2048 * 2,
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0,
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1257,9 +1281,9 @@ static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
bool ok;
/* read permission on src */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
- &src_h, 4096, /* fill 4096 byte src file */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
- &dest_h, 0, /* 0 byte dest file */
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
if (!ok) {
torture_fail(torture, "setup copy chunk error");
@@ -1284,9 +1308,9 @@ static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
/* execute permission on src */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
- &src_h, 4096, /* fill 4096 byte src file */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
- &dest_h, 0, /* 0 byte dest file */
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
if (!ok) {
torture_fail(torture, "setup copy chunk error");
@@ -1311,8 +1335,8 @@ static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
/* neither read nor execute permission on src */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
- &src_h, 4096, /* fill 4096 byte src file */
- SEC_FILE_READ_ATTRIBUTE, &dest_h,
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
if (!ok) {
@@ -1340,8 +1364,8 @@ static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
/* no write permission on dest */
ok = test_setup_copy_chunk(
torture, tree, tmp_ctx, 1, /* 1 chunk */
- &src_h, 4096, /* fill 4096 byte src file */
- SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE, &dest_h,
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
0, /* 0 byte dest file */
(SEC_RIGHTS_FILE_ALL &
~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)),
@@ -1370,9 +1394,9 @@ static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
/* no read permission on dest */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 1, /* 1 chunk */
- &src_h, 4096, /* fill 4096 byte src file */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
- &dest_h, 0, /* 0 byte dest file */
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
(SEC_RIGHTS_FILE_ALL & ~SEC_FILE_READ_DATA),
&cc_copy, &ioctl);
if (!ok) {
@@ -1420,8 +1444,10 @@ static bool test_ioctl_copy_chunk_write_access(struct torture_context *torture,
/* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
(SEC_RIGHTS_FILE_WRITE
| SEC_RIGHTS_FILE_EXECUTE),
@@ -1468,8 +1494,10 @@ static bool test_ioctl_copy_chunk_src_exceed(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1550,8 +1578,10 @@ test_ioctl_copy_chunk_src_exceed_multi(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
2, /* 2 chunks */
+ FNAME,
&src_h, 8192, /* fill 8192 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1620,8 +1650,10 @@ static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1703,8 +1735,10 @@ static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -1752,8 +1786,10 @@ static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* 1 chunk */
+ FNAME,
&src_h, 4096, /* fill 4096 byte src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* 0 byte dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
@@ -3885,8 +3921,10 @@ static bool test_ioctl_sparse_copy_chunk(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
1, /* chunks */
+ FNAME,
&src_h, 0, /* src file */
SEC_RIGHTS_FILE_ALL,
+ FNAME2,
&dest_h, 0, /* dest file */
SEC_RIGHTS_FILE_ALL,
&cc_copy,
--
2.9.3
From 2371d487d2abd54c9a1f1139737fce425a7aaa44 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 16 May 2017 13:14:16 +0200
Subject: [PATCH 5/7] s4/torture: smb2.ioctl: add copy-chunk test with stream
to smb2.ioctl
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
---
selftest/knownfail | 1 +
source4/torture/smb2/ioctl.c | 150 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 151 insertions(+)
diff --git a/selftest/knownfail b/selftest/knownfail
index 2cc9c70..b16ff52 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -157,6 +157,7 @@
^samba3.smb2.durable-v2-open.reopen1a-lease\(ad_dc\)$
^samba4.smb2.ioctl.req_resume_key\(ad_dc_ntvfs\) # not supported by s4 ntvfs server
^samba4.smb2.ioctl.copy_chunk_\w*\(ad_dc_ntvfs\) # not supported by s4 ntvfs server
+^samba4.smb2.ioctl.copy-chunk streams\(ad_dc_ntvfs\) # not supported by s4 ntvfs server
^samba3.smb2.dir.one
^samba3.smb2.dir.modify
^samba3.smb2.oplock.batch20
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
index c9fc121..f81c027 100644
--- a/source4/torture/smb2/ioctl.c
+++ b/source4/torture/smb2/ioctl.c
@@ -1834,6 +1834,154 @@ static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
return true;
}
+static bool copy_one_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_sname,
+ const char *dst_sname)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok = false;
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_sname,
+ &src_h, 256, /* fill 256 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_sname,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 256;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 256); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+/**
+ * Create a file
+ **/
+static bool torture_setup_file(TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ const char *name)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, name);
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = name;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_copy_chunk_streams(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *src_name = "src";
+ const char *dst_name = "dst";
+ struct names {
+ const char *src_sname;
+ const char *dst_sname;
+ } names[] = {
+ { "src:foo", "dst:foo" }
+ };
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok = false;
+
+ tmp_ctx = talloc_new(tree);
+ torture_assert_not_null_goto(torture, tmp_ctx, ok, done,
+ "torture_setup_file\n");
+
+ ok = torture_setup_file(torture, tree, src_name);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+ ok = torture_setup_file(torture, tree, dst_name);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ ok = copy_one_stream(torture, tree, tmp_ctx,
+ names[i].src_sname,
+ names[i].dst_sname);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_one_stream failed\n");
+ }
+
+done:
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+ talloc_free(tmp_ctx);
+ return ok;
+}
+
static NTSTATUS test_ioctl_compress_fs_supported(struct torture_context *torture,
struct smb2_tree *tree,
TALLOC_CTX *mem_ctx,
@@ -6270,6 +6418,8 @@ struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
test_ioctl_copy_chunk_max_output_sz);
torture_suite_add_1smb2_test(suite, "copy_chunk_zero_length",
test_ioctl_copy_chunk_zero_length);
+ torture_suite_add_1smb2_test(suite, "copy-chunk streams",
+ test_copy_chunk_streams);
torture_suite_add_1smb2_test(suite, "compress_file_flag",
test_ioctl_compress_file_flag);
torture_suite_add_1smb2_test(suite, "compress_dir_inherit",
--
2.9.3
From 765c4ffe688425b14e87a2e52d57dc3799ddea10 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 12 May 2017 14:56:53 +0200
Subject: [PATCH 6/7] s4/torture: vfs_fruit: add src and dst path args to
test_setup_copy_chunk
Just let the caller pass in the paths, no change in behaviour. A new
test in a subsequent commit will use it to pass paths to streams.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source4/torture/vfs/fruit.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
index 96edec2..7d59fee 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -2353,9 +2353,11 @@ static bool test_setup_create_fill(struct torture_context *torture,
static bool test_setup_copy_chunk(struct torture_context *torture,
struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
uint32_t nchunks,
+ const char *src_name,
struct smb2_handle *src_h,
uint64_t src_size,
uint32_t src_desired_access,
+ const char *dst_name,
struct smb2_handle *dest_h,
uint64_t dest_size,
uint32_t dest_desired_access,
@@ -2367,12 +2369,12 @@ static bool test_setup_copy_chunk(struct torture_context *torture,
NTSTATUS status;
enum ndr_err_code ndr_ret;
- ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME_CC_SRC,
+ ok = test_setup_create_fill(torture, tree, mem_ctx, src_name,
src_h, src_size, src_desired_access,
FILE_ATTRIBUTE_NORMAL);
torture_assert(torture, ok, "src file create fill");
- ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME_CC_DST,
+ ok = test_setup_create_fill(torture, tree, mem_ctx, dst_name,
dest_h, dest_size, dest_desired_access,
FILE_ATTRIBUTE_NORMAL);
torture_assert(torture, ok, "dest file create fill");
@@ -2533,8 +2535,10 @@ static bool test_copyfile(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
0, /* 0 chunks, copyfile semantics */
+ FNAME_CC_SRC,
&src_h, 4096, /* fill 4096 byte src file */
SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ FNAME_CC_DST,
&dest_h, 0, /* 0 byte dest file */
SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
&cc_copy,
@@ -2600,8 +2604,10 @@ static bool test_copyfile(struct torture_context *torture,
ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
0, /* 0 chunks, copyfile semantics */
+ FNAME_CC_SRC,
&src_h, 4096, /* fill 4096 byte src file */
SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ FNAME_CC_DST,
&dest_h, 0, /* 0 byte dest file */
SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
&cc_copy,
--
2.9.3
From 98cc3445816c39f592e3c679aa253c38fff197e3 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 12 May 2017 17:10:07 +0200
Subject: [PATCH 7/7] s4/torture: vfs_fruit: test copy-chunk on streams
Bug: https://bugzilla.samba.org/show_bug.cgi?id=12787
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source4/torture/vfs/fruit.c | 225 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 225 insertions(+)
diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
index 7d59fee..2ab153a 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -4048,6 +4048,230 @@ done:
return ret;
}
+static bool copy_one_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_sname,
+ const char *dst_sname)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok = false;
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_sname,
+ &src_h, 256, /* fill 256 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_sname,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 256;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 256); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+static bool copy_finderinfo_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_name,
+ const char *dst_name)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ const char *src_name_afpinfo = NULL;
+ const char *dst_name_afpinfo = NULL;
+ bool ok = false;
+
+ src_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", src_name,
+ AFPINFO_STREAM);
+ torture_assert_not_null_goto(torture, src_name_afpinfo, ok, done,
+ "talloc_asprintf failed\n");
+
+ dst_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", dst_name,
+ AFPINFO_STREAM);
+ torture_assert_not_null_goto(torture, dst_name_afpinfo, ok, done,
+ "talloc_asprintf failed\n");
+
+ info = torture_afpinfo_new(tmp_ctx);
+ torture_assert_not_null_goto(torture, info, ok, done,
+ "torture_afpinfo_new failed\n");
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ok = torture_write_afpinfo(tree, torture, tmp_ctx, src_name, info);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "torture_write_afpinfo failed\n");
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_name_afpinfo,
+ &src_h, 0,
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_name_afpinfo,
+ &dest_h, 0,
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 60;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ smb2_util_close(tree, src_h);
+ ZERO_STRUCT(src_h);
+ smb2_util_close(tree, dest_h);
+ ZERO_STRUCT(dest_h);
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 60); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_stream(tree, __location__, torture, tmp_ctx,
+ dst_name, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n");
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+static bool test_copy_chunk_streams(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *src_name = "src";
+ const char *dst_name = "dst";
+ struct names {
+ const char *src_sname;
+ const char *dst_sname;
+ } names[] = {
+ { "src:foo", "dst:foo" },
+ { "src" AFPRESOURCE_STREAM, "dst" AFPRESOURCE_STREAM }
+ };
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok = false;
+
+ tmp_ctx = talloc_new(tree);
+ torture_assert_not_null_goto(torture, tmp_ctx, ok, done,
+ "torture_setup_file\n");
+
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+
+ ok = torture_setup_file(torture, tree, src_name, false);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+ ok = torture_setup_file(torture, tree, dst_name, false);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ ok = copy_one_stream(torture, tree, tmp_ctx,
+ names[i].src_sname,
+ names[i].dst_sname);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_one_stream failed\n");
+ }
+
+ ok = copy_finderinfo_stream(torture, tree, tmp_ctx,
+ src_name, dst_name);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_finderinfo_stream failed\n");
+
+done:
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+ talloc_free(tmp_ctx);
+ return ok;
+}
+
/*
* Note: This test depends on "vfs objects = catia fruit streams_xattr". For
* some tests torture must be run on the host it tests and takes an additional
@@ -4086,6 +4310,7 @@ struct torture_suite *torture_vfs_fruit(TALLOC_CTX *ctx)
torture_suite_add_1smb2_test(suite, "readdir_attr with names with illegal ntfs characters", test_readdir_attr_illegal_ntfs);
torture_suite_add_2ns_smb2_test(suite, "invalid AFP_AfpInfo", test_invalid_afpinfo);
torture_suite_add_1smb2_test(suite, "creating rsrc with read-only access", test_rfork_create_ro);
+ torture_suite_add_1smb2_test(suite, "copy-chunk streams", test_copy_chunk_streams);
return suite;
}
--
2.9.3
More information about the samba-technical
mailing list