The Samba-Bugzilla – Attachment 11134 Details for
Bug 11317
Implement OS X style copyfile in vfs_fruit
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for master
copyfile.patch (text/plain), 14.36 KB, created by
Ralph Böhme
on 2015-06-09 11:08:18 UTC
(
hide
)
Description:
Patch for master
Filename:
MIME Type:
Creator:
Ralph Böhme
Created:
2015-06-09 11:08:18 UTC
Size:
14.36 KB
patch
obsolete
>From 19c1720fc7f0c4377fc76ce9ad0c70089f21fd1f Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 27 Apr 2015 12:16:16 +0200 >Subject: [PATCH 1/2] s3:util: use pread/pwrite in transfer_file > >read/write aren't overloaded in the streams VFS modules, using >pread/pwrite instead this makes it possible to use transfer_file() with >named streams. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=11317 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/include/transfer_file.h | 4 ++-- > source3/lib/util_transfer_file.c | 23 +++++++++++++---------- > source3/smbd/vfs.c | 10 +++++----- > 3 files changed, 20 insertions(+), 17 deletions(-) > >diff --git a/source3/include/transfer_file.h b/source3/include/transfer_file.h >index 546104f..2f1bff4 100644 >--- a/source3/include/transfer_file.h >+++ b/source3/include/transfer_file.h >@@ -24,8 +24,8 @@ > ssize_t transfer_file_internal(void *in_file, > void *out_file, > size_t n, >- ssize_t (*read_fn)(void *, void *, size_t), >- ssize_t (*write_fn)(void *, const void *, size_t)); >+ ssize_t (*pread_fn)(void *, void *, size_t, off_t), >+ ssize_t (*pwrite_fn)(void *, const void *, size_t, off_t)); > > off_t transfer_file(int infd, int outfd, off_t n); > >diff --git a/source3/lib/util_transfer_file.c b/source3/lib/util_transfer_file.c >index d415d7f..91f4f6f 100644 >--- a/source3/lib/util_transfer_file.c >+++ b/source3/lib/util_transfer_file.c >@@ -36,8 +36,8 @@ > ssize_t transfer_file_internal(void *in_file, > void *out_file, > size_t n, >- ssize_t (*read_fn)(void *, void *, size_t), >- ssize_t (*write_fn)(void *, const void *, size_t)) >+ ssize_t (*pread_fn)(void *, void *, size_t, off_t), >+ ssize_t (*pwrite_fn)(void *, const void *, size_t, off_t)) > { > char *buf; > size_t total = 0; >@@ -45,6 +45,7 @@ ssize_t transfer_file_internal(void *in_file, > ssize_t write_ret; > size_t num_to_read_thistime; > size_t num_written = 0; >+ off_t offset = 0; > > if (n == 0) { > return 0; >@@ -57,7 +58,7 @@ ssize_t transfer_file_internal(void *in_file, > do { > num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE); > >- read_ret = (*read_fn)(in_file, buf, num_to_read_thistime); >+ read_ret = (*pread_fn)(in_file, buf, num_to_read_thistime, offset); > if (read_ret == -1) { > DEBUG(0,("transfer_file_internal: read failure. " > "Error = %s\n", strerror(errno) )); >@@ -71,8 +72,9 @@ ssize_t transfer_file_internal(void *in_file, > num_written = 0; > > while (num_written < read_ret) { >- write_ret = (*write_fn)(out_file, buf + num_written, >- read_ret - num_written); >+ write_ret = (*pwrite_fn)(out_file, buf + num_written, >+ read_ret - num_written, >+ offset + num_written); > > if (write_ret == -1) { > DEBUG(0,("transfer_file_internal: " >@@ -89,28 +91,29 @@ ssize_t transfer_file_internal(void *in_file, > } > > total += (size_t)read_ret; >+ offset += (off_t)read_ret; > } while (total < n); > > SAFE_FREE(buf); > return (ssize_t)total; > } > >-static ssize_t sys_read_fn(void *file, void *buf, size_t len) >+static ssize_t sys_pread_fn(void *file, void *buf, size_t len, off_t offset) > { > int *fd = (int *)file; > >- return sys_read(*fd, buf, len); >+ return sys_pread(*fd, buf, len, offset); > } > >-static ssize_t sys_write_fn(void *file, const void *buf, size_t len) >+static ssize_t sys_pwrite_fn(void *file, const void *buf, size_t len, off_t offset) > { > int *fd = (int *)file; > >- return sys_write(*fd, buf, len); >+ return sys_pwrite(*fd, buf, len, offset); > } > > off_t transfer_file(int infd, int outfd, off_t n) > { > return (off_t)transfer_file_internal(&infd, &outfd, (size_t)n, >- sys_read_fn, sys_write_fn); >+ sys_pread_fn, sys_pwrite_fn); > } >diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c >index 4ab7723..b267387 100644 >--- a/source3/smbd/vfs.c >+++ b/source3/smbd/vfs.c >@@ -756,24 +756,24 @@ int vfs_fill_sparse(files_struct *fsp, off_t len) > Transfer some data (n bytes) between two file_struct's. > ****************************************************************************/ > >-static ssize_t vfs_read_fn(void *file, void *buf, size_t len) >+static ssize_t vfs_pread_fn(void *file, void *buf, size_t len, off_t offset) > { > struct files_struct *fsp = (struct files_struct *)file; > >- return SMB_VFS_READ(fsp, buf, len); >+ return SMB_VFS_PREAD(fsp, buf, len, offset); > } > >-static ssize_t vfs_write_fn(void *file, const void *buf, size_t len) >+static ssize_t vfs_pwrite_fn(void *file, const void *buf, size_t len, off_t offset) > { > struct files_struct *fsp = (struct files_struct *)file; > >- return SMB_VFS_WRITE(fsp, buf, len); >+ return SMB_VFS_PWRITE(fsp, buf, len, offset); > } > > off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n) > { > return transfer_file_internal((void *)in, (void *)out, n, >- vfs_read_fn, vfs_write_fn); >+ vfs_pread_fn, vfs_pwrite_fn); > } > > /******************************************************************* >-- >2.1.0 > > >From 6cfc2657e958a920582eacb7e31028f3d2118525 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Apr 2015 22:29:16 +0200 >Subject: [PATCH 2/2] vfs:fruit: implement copyfile style copy_chunk > >Implement Apple's special copy_chunk ioctl that requests a copy of the >whole file along with all attached metadata. > >These copy_chunk requests have a chunk count of 0 that we translate to a >copy_chunk_send VFS call overloading the parameters src_off = dest_off = >num = 0. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=11317 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > docs-xml/manpages/vfs_fruit.8.xml | 10 ++ > source3/modules/vfs_fruit.c | 204 +++++++++++++++++++++++++++++++++++ > source3/smbd/smb2_ioctl_network_fs.c | 30 ++++++ > 3 files changed, 244 insertions(+) > >diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml >index e407b54..63cf925 100644 >--- a/docs-xml/manpages/vfs_fruit.8.xml >+++ b/docs-xml/manpages/vfs_fruit.8.xml >@@ -214,6 +214,16 @@ > </listitem> > </varlistentry> > >+ <varlistentry> >+ <term>fruit:copyfile = yes | no</term> >+ <listitem> >+ <para>Whether to enable OS X specific copychunk ioctl >+ that requests a copy of a whole file along with all >+ attached metadata.</para> >+ <para>The default is <emphasis>no</emphasis>.</para> >+ </listitem> >+ </varlistentry> >+ > </variablelist> > </refsect1> > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 2547838..7e3afc5 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -30,6 +30,7 @@ > #include "libcli/security/security.h" > #include "../libcli/smb/smb2_create_ctx.h" > #include "lib/sys_rw.h" >+#include "lib/util/tevent_ntstatus.h" > > /* > * Enhanced OS X and Netatalk compatibility >@@ -124,6 +125,7 @@ struct fruit_config_data { > enum fruit_locking locking; > enum fruit_encoding encoding; > bool use_aapl; >+ bool use_copyfile; > bool readdir_attr_enabled; > bool unix_info_enabled; > bool veto_appledouble; >@@ -1348,6 +1350,11 @@ static int init_fruit_config(vfs_handle_struct *handle) > config->unix_info_enabled = true; > } > >+ if (lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME, >+ "copyfile", false)) { >+ config->use_copyfile = true; >+ } >+ > if (lp_parm_bool(SNUM(handle->conn), > "readdir_attr", "aapl_rsize", true)) { > config->readdir_attr_rsize = true; >@@ -1837,6 +1844,10 @@ static NTSTATUS check_aapl(vfs_handle_struct *handle, > config->readdir_attr_enabled = true; > } > >+ if (config->use_copyfile) { >+ server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE; >+ } >+ > /* > * The client doesn't set the flag, so we can't check > * for it and just set it unconditionally >@@ -3462,6 +3473,197 @@ static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle, > return NT_STATUS_OK; > } > >+struct fruit_cc_state { >+ struct vfs_handle_struct *handle; >+ off_t copied; >+ struct files_struct *src_fsp; >+ struct files_struct *dst_fsp; >+}; >+ >+static void fruit_copy_chunk_done(struct tevent_req *subreq); >+static struct tevent_req *fruit_copy_chunk_send(struct vfs_handle_struct *handle, >+ TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct files_struct *src_fsp, >+ off_t src_off, >+ struct files_struct *dest_fsp, >+ off_t dest_off, >+ off_t num) >+{ >+ struct tevent_req *req, *subreq; >+ struct fruit_cc_state *fruit_cc_state; >+ NTSTATUS status; >+ struct fruit_config_data *config; >+ off_t to_copy = num; >+ >+ DEBUG(10,("%s: soff: %zd, doff: %zd, len: %zd\n", >+ __func__, src_off, dest_off, num)); >+ >+ SMB_VFS_HANDLE_GET_DATA(handle, config, >+ struct fruit_config_data, >+ return NULL); >+ >+ req = tevent_req_create(mem_ctx, &fruit_cc_state, struct fruit_cc_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ fruit_cc_state->handle = handle; >+ fruit_cc_state->src_fsp = src_fsp; >+ fruit_cc_state->dst_fsp = dest_fsp; >+ >+ /* >+ * Check if this a OS X copyfile style copychunk request with >+ * a requested chunk count of 0 that was translated to a >+ * copy_chunk_send VFS call overloading the parameters src_off >+ * = dest_off = num = 0. >+ */ >+ if ((src_off == 0) && (dest_off == 0) && (num == 0)) { >+ >+ if (!config->use_copyfile) { >+ tevent_req_error(req, EIO); >+ return tevent_req_post(req, ev); >+ } >+ >+ status = vfs_stat_fsp(src_fsp); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); >+ } >+ >+ to_copy = src_fsp->fsp_name->st.st_ex_size; >+ } >+ >+ subreq = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, >+ mem_ctx, >+ ev, >+ src_fsp, >+ src_off, >+ dest_fsp, >+ dest_off, >+ to_copy); >+ if (tevent_req_nomem(subreq, req)) { >+ return tevent_req_post(req, ev); >+ } >+ >+ tevent_req_set_callback(subreq, fruit_copy_chunk_done, req); >+ return req; >+} >+ >+static void fruit_copy_chunk_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct fruit_cc_state *state = tevent_req_data( >+ req, struct fruit_cc_state); >+ NTSTATUS status; >+ unsigned int num_streams = 0; >+ struct stream_struct *streams = NULL; >+ int i; >+ struct smb_filename *src_fname_tmp = NULL; >+ struct smb_filename *dst_fname_tmp = NULL; >+ >+ status = SMB_VFS_NEXT_COPY_CHUNK_RECV(state->handle, >+ subreq, >+ &state->copied); >+ TALLOC_FREE(subreq); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ >+ /* >+ * Now copy all reamining streams. We know the share supports >+ * streams, because we're in vfs_fruit. We don't do this async >+ * because streams are few and small. >+ */ >+ status = vfs_streaminfo(state->handle->conn, NULL, >+ state->src_fsp->fsp_name->base_name, >+ req, &num_streams, &streams); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ >+ if (num_streams == 1) { >+ /* There is always one stream, ::$DATA. */ >+ tevent_req_done(req); >+ return; >+ } >+ >+ for (i = 0; i < num_streams; i++) { >+ DEBUG(10, ("%s: stream: '%s'/%zd\n", >+ __func__, streams[i].name, streams[i].size)); >+ >+ src_fname_tmp = synthetic_smb_fname( >+ req, >+ state->src_fsp->fsp_name->base_name, >+ streams[i].name, >+ NULL); >+ if (src_fname_tmp == NULL) { >+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY); >+ return; >+ } >+ >+ if (is_ntfs_default_stream_smb_fname(src_fname_tmp)) { >+ TALLOC_FREE(src_fname_tmp); >+ continue; >+ } >+ >+ dst_fname_tmp = synthetic_smb_fname( >+ req, >+ state->dst_fsp->fsp_name->base_name, >+ streams[i].name, >+ NULL); >+ if (dst_fname_tmp == NULL) { >+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY); >+ return; >+ } >+ >+ status = copy_file(req, >+ state->handle->conn, >+ src_fname_tmp, >+ dst_fname_tmp, >+ OPENX_FILE_CREATE_IF_NOT_EXIST, >+ 0, false); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(1, ("%s: copy %s to %s failed: %s\n", __func__, >+ smb_fname_str_dbg(src_fname_tmp), >+ smb_fname_str_dbg(dst_fname_tmp), >+ nt_errstr(status))); >+ tevent_req_nterror(req, status); >+ return; >+ } >+ >+ TALLOC_FREE(src_fname_tmp); >+ TALLOC_FREE(dst_fname_tmp); >+ } >+ >+ TALLOC_FREE(streams); >+ TALLOC_FREE(src_fname_tmp); >+ TALLOC_FREE(dst_fname_tmp); >+ tevent_req_done(req); >+} >+ >+static NTSTATUS fruit_copy_chunk_recv(struct vfs_handle_struct *handle, >+ struct tevent_req *req, >+ off_t *copied) >+{ >+ struct fruit_cc_state *fruit_cc_state = tevent_req_data( >+ req, struct fruit_cc_state); >+ >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ DEBUG(1, ("server side copy chunk failed: %s\n", >+ nt_errstr(status))); >+ *copied = 0; >+ tevent_req_received(req); >+ return status; >+ } >+ >+ *copied = fruit_cc_state->copied; >+ tevent_req_received(req); >+ >+ return NT_STATUS_OK; >+} >+ > static struct vfs_fn_pointers vfs_fruit_fns = { > .connect_fn = fruit_connect, > >@@ -3483,6 +3685,8 @@ static struct vfs_fn_pointers vfs_fruit_fns = { > .fallocate_fn = fruit_fallocate, > .create_file_fn = fruit_create_file, > .readdir_attr_fn = fruit_readdir_attr, >+ .copy_chunk_send_fn = fruit_copy_chunk_send, >+ .copy_chunk_recv_fn = fruit_copy_chunk_recv, > > /* NT ACL operations */ > .fget_nt_acl_fn = fruit_fget_nt_acl, >diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c >index 5e70703..7d69c2b 100644 >--- a/source3/smbd/smb2_ioctl_network_fs.c >+++ b/source3/smbd/smb2_ioctl_network_fs.c >@@ -234,6 +234,36 @@ static struct tevent_req *fsctl_srv_copychunk_send(TALLOC_CTX *mem_ctx, > /* any errors from here onwards should carry copychunk response data */ > state->out_data = COPYCHUNK_OUT_RSP; > >+ if ((cc_copy.chunk_count == 0) && >+ (lp_parm_bool(-1, "fruit", "copyfile", false) == true)) { >+ /* >+ * Process as OS X copyfile request. Setting src_off = >+ * dst_off = 0 and a length of 0 is what must be used >+ * in the VFS to distinguish this from "normal" >+ * copychunk requests. I delibiretaly overload the >+ * params that way in order to avoid a VFS version >+ * bump. >+ */ >+ struct tevent_req *vfs_subreq; >+ vfs_subreq = SMB_VFS_COPY_CHUNK_SEND(dst_fsp->conn, >+ state, ev, >+ state->src_fsp, >+ 0, >+ state->dst_fsp, >+ 0, >+ 0); >+ if (vfs_subreq == NULL) { >+ DEBUG(1, ("VFS copy chunk send failed\n")); >+ state->status = NT_STATUS_NO_MEMORY; >+ tevent_req_nterror(req, state->status); >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_set_callback(vfs_subreq, >+ fsctl_srv_copychunk_vfs_done, req); >+ state->dispatch_count++; >+ return req; >+ } >+ > for (i = 0; i < cc_copy.chunk_count; i++) { > struct tevent_req *vfs_subreq; > chunk = &cc_copy.chunks[i]; >-- >2.1.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 11317
:
11133
|
11134
|
11143
|
11152
|
11156
|
11168
|
11324
|
11327