summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalph Boehme <slow@samba.org>2017-06-09 16:50:05 +0200
committerRalph Boehme <slow@samba.org>2017-07-03 19:59:08 +0200
commit74e018f476608429caa1c3594102485ccc17afce (patch)
tree7ac687febfd7e9e7b8c4fa08139cf7f8238fb068
parent2ad11c6920fada646cd174b53efa4cf590b80901 (diff)
downloadsamba-74e018f476608429caa1c3594102485ccc17afce.tar.gz
s3/smbd: redesign macOS copyfile copy-chunk
The copy-chunk request chunk_count can be 0 and Windows server just returns success saying number of copied chunks is 0. macOS client overload this after negotiating AAPL via their SMB2 extensions, meaning it's a so called copyfile request (copy whole file and all streams). We previously checked this at the SMB layer, with this patch we just send this down the VFS, if vfs_fruit is loaded it implements the macOS copyile semantics, otherwise we get Windows behavour.. No change in behaviour. Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
-rw-r--r--source3/modules/vfs_default.c6
-rw-r--r--source3/smbd/smb2_ioctl_network_fs.c76
2 files changed, 37 insertions, 45 deletions
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 291f39b60f2..9b86a905203 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1746,6 +1746,12 @@ static struct tevent_req *vfswrap_offload_write_send(
.remaining = to_copy,
.flags = flags,
};
+
+ if (to_copy == 0) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
state->buf = talloc_array(state, uint8_t, num);
if (tevent_req_nomem(state->buf, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c
index 98355e2d988..b528ff2346d 100644
--- a/source3/smbd/smb2_ioctl_network_fs.c
+++ b/source3/smbd/smb2_ioctl_network_fs.c
@@ -248,54 +248,35 @@ static NTSTATUS fsctl_srv_copychunk_loop(struct tevent_req *req)
struct fsctl_srv_copychunk_state *state = tevent_req_data(
req, struct fsctl_srv_copychunk_state);
struct tevent_req *subreq = NULL;
- struct srv_copychunk *chunk = NULL;
+ uint32_t length = 0;
+ off_t source_off = 0;
+ off_t target_off = 0;
- if (state->cc_copy.chunk_count == 0) {
- /*
- * Process as OS X copyfile request. This is currently
- * the only copychunk request with a chunk count of 0
- * we will process.
- */
- if (!state->src_fsp->aapl_copyfile_supported ||
- !state->dst_fsp->aapl_copyfile_supported)
- {
- /*
- * This must not produce an error but just return a
- * chunk count of 0 in the response.
- */
- tevent_req_done(req);
- tevent_req_post(req, state->ev);
- return NT_STATUS_OK;
- }
- state->aapl_copyfile = true;
-
- subreq = SMB_VFS_OFFLOAD_WRITE_SEND(state->dst_fsp->conn,
- state,
- state->ev,
- state->src_fsp,
- 0,
- state->dst_fsp,
- 0,
- 0,
- 0);
- if (subreq == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- tevent_req_set_callback(subreq,
- fsctl_srv_copychunk_vfs_done, req);
- return NT_STATUS_OK;
- }
+ /*
+ * chunk_count can be 0 which must either just do nothing returning
+ * success saying number of copied chunks is 0 (verified against
+ * Windows).
+ *
+ * Or it can be a special macOS copyfile request, so we send this into
+ * the VFS, vfs_fruit if loaded implements the macOS copyile semantics.
+ */
+ if (state->cc_copy.chunk_count > 0) {
+ struct srv_copychunk *chunk = NULL;
- chunk = &state->cc_copy.chunks[state->current_chunk];
+ chunk = &state->cc_copy.chunks[state->current_chunk];
+ length = chunk->length;
+ source_off = chunk->source_off;
+ target_off = chunk->target_off;
+ }
subreq = SMB_VFS_OFFLOAD_WRITE_SEND(state->dst_fsp->conn,
state,
state->ev,
state->src_fsp,
- chunk->source_off,
+ source_off,
state->dst_fsp,
- chunk->target_off,
- chunk->length,
+ target_off,
+ length,
0);
if (tevent_req_nomem(subreq, req)) {
return NT_STATUS_NO_MEMORY;
@@ -331,6 +312,15 @@ static void fsctl_srv_copychunk_vfs_done(struct tevent_req *subreq)
(unsigned int)state->cc_copy.chunk_count);
state->total_written += chunk_nwritten;
+ if (state->cc_copy.chunk_count == 0) {
+ /*
+ * This must not produce an error but just return a chunk count
+ * of 0 in the response.
+ */
+ tevent_req_done(req);
+ return;
+ }
+
state->current_chunk++;
if (state->current_chunk == state->cc_copy.chunk_count) {
tevent_req_done(req);
@@ -361,11 +351,7 @@ static NTSTATUS fsctl_srv_copychunk_recv(struct tevent_req *req,
*pack_rsp = true;
break;
case COPYCHUNK_OUT_RSP:
- if (state->aapl_copyfile == true) {
- cc_rsp->chunks_written = 0;
- } else {
- cc_rsp->chunks_written = state->current_chunk;
- }
+ cc_rsp->chunks_written = state->current_chunk;
cc_rsp->chunk_bytes_written = 0;
cc_rsp->total_bytes_written = state->total_written;
*pack_rsp = true;