s3-vfs: add copy_chunk vfs hooks
authorDavid Disseldorp <ddiss@suse.de>
Mon, 10 Oct 2011 12:31:55 +0000 (14:31 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Wed, 19 Sep 2012 03:59:03 +0000 (05:59 +0200)
copy_chunk copies n bytes from a source file at a specific offset to a
destination file at a given offset. This interface will be used in
handling smb2 FSCTL_SRV_COPYCHUNK ioctl requests.

Provide send and receive hooks for copy chunk VFS interface, allowing
asynchronous behaviour.

docs-xml/manpages/vfs_full_audit.8.xml
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/modules/vfs_full_audit.c
source3/modules/vfs_time_audit.c
source3/smbd/vfs.c

index a44924a8f64293c439e09d680e5f76ef6d17ba4d..312bc25078d00e38c0189db12493a66cb9d67b96 100644 (file)
@@ -46,6 +46,8 @@
         <member>close</member>
         <member>closedir</member>
         <member>connect</member>
+       <member>copy_chunk_send</member>
+       <member>copy_chunk_recv</member>
         <member>disconnect</member>
         <member>disk_free</member>
         <member>fchmod</member>
index a786a234d40a144d9e98980aa5bf01ba71175feb..8d7a0945119d28a795a2bd48d9af004a7c34be04 100644 (file)
@@ -452,6 +452,25 @@ static struct file_id skel_file_id_create(vfs_handle_struct *handle,
        return id;
 }
 
+static struct tevent_req *skel_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)
+{
+       return NULL;
+}
+
+static NTSTATUS skel_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                    struct tevent_req *req,
+                                    off_t *copied)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
 static NTSTATUS skel_streaminfo(struct vfs_handle_struct *handle,
                                struct files_struct *fsp,
                                const char *fname,
@@ -758,6 +777,8 @@ struct vfs_fn_pointers skel_opaque_fns = {
        .notify_watch_fn = skel_notify_watch,
        .chflags_fn = skel_chflags,
        .file_id_create_fn = skel_file_id_create,
+       .copy_chunk_send_fn = skel_copy_chunk_send,
+       .copy_chunk_recv_fn = skel_copy_chunk_recv,
 
        .streaminfo_fn = skel_streaminfo,
        .get_real_filename_fn = skel_get_real_filename,
index 02a994c07f7923dcb733c616b67d0025a189c8f9..9aa8d72f5fc7ab8a09d22c39c850ae4ae7d8c3be 100644 (file)
@@ -541,6 +541,26 @@ static struct file_id skel_file_id_create(vfs_handle_struct *handle,
        return SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
 }
 
+static struct tevent_req *skel_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)
+{
+       return SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, mem_ctx, ev, src_fsp, src_off,
+                                           dest_fsp, dest_off, num);
+}
+
+static NTSTATUS skel_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                    struct tevent_req *req,
+                                    off_t *copied)
+{
+       return SMB_VFS_NEXT_COPY_CHUNK_RECV(handle, req, copied);
+}
+
 static NTSTATUS skel_streaminfo(struct vfs_handle_struct *handle,
                                struct files_struct *fsp,
                                const char *fname,
@@ -860,6 +880,8 @@ struct vfs_fn_pointers skel_transparent_fns = {
        .notify_watch_fn = skel_notify_watch,
        .chflags_fn = skel_chflags,
        .file_id_create_fn = skel_file_id_create,
+       .copy_chunk_send_fn = skel_copy_chunk_send,
+       .copy_chunk_recv_fn = skel_copy_chunk_recv,
 
        .streaminfo_fn = skel_streaminfo,
        .get_real_filename_fn = skel_get_real_filename,
index c83e7ed54b8fe17eb9c886ff98b63d237382d3ae..f360eb160bed1c89c84bd6428a7ec478704e9b34 100644 (file)
 /* Leave at 29 - not yet released. Added sys_acl_blob_get_file and sys_acl_blob_get_fd */
 /* Bump to version 30 - Samba 4.0.0 will ship with interface version 30 */
 /* Leave at 30 - not yet released. Added conn->cwd to save vfs_GetWd() calls. */
+/* Leave at 30 - not yet released. add SMB_VFS_COPY_CHUNK() */
 #define SMB_VFS_INTERFACE_VERSION 30
 
 /*
@@ -608,6 +609,17 @@ struct vfs_fn_pointers {
        int (*chflags_fn)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
        struct file_id (*file_id_create_fn)(struct vfs_handle_struct *handle,
                                            const SMB_STRUCT_STAT *sbuf);
+       struct tevent_req *(*copy_chunk_send_fn)(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);
+       NTSTATUS (*copy_chunk_recv_fn)(struct vfs_handle_struct *handle,
+                                      struct tevent_req *req,
+                                      off_t *copied);
 
        NTSTATUS (*streaminfo_fn)(struct vfs_handle_struct *handle,
                                  struct files_struct *fsp,
@@ -1070,7 +1082,18 @@ NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
                            uint32_t in_len,
                            uint8_t **_out_data,
                            uint32_t max_out_len,
-                           uint32_t *out_len); 
+                           uint32_t *out_len);
+struct tevent_req *smb_vfs_call_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);
+NTSTATUS smb_vfs_call_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                     struct tevent_req *req,
+                                     off_t *copied);
 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
                                  struct files_struct *fsp,
                                  uint32 security_info,
index 4eca1b074841bf2bae2935e26d04bfc2a923ce18..67b5af526f453447faf5dfe6d0eb7465ebf53879 100644 (file)
 #define SMB_VFS_NEXT_FSCTL(handle, fsp, ctx, function, req_flags, in_data, in_len, out_data, max_out_len, out_len) \
        smb_vfs_call_fsctl((handle)->next, (fsp), (ctx), (function), (req_flags), (in_data), (in_len), (out_data), (max_out_len), (out_len))
 
+#define SMB_VFS_COPY_CHUNK_SEND(conn, mem_ctx, ev, src_fsp, src_off, dest_fsp, dest_off, num) \
+       smb_vfs_call_copy_chunk_send((conn)->vfs_handles, (mem_ctx), (ev), (src_fsp), (src_off), (dest_fsp), (dest_off), (num))
+#define SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, mem_ctx, ev, src_fsp, src_off, dest_fsp, dest_off, num) \
+       smb_vfs_call_copy_chunk_send((handle)->next, (mem_ctx), (ev), (src_fsp), (src_off), (dest_fsp), (dest_off), (num))
+
+#define SMB_VFS_COPY_CHUNK_RECV(conn, req, copied) \
+       smb_vfs_call_copy_chunk_recv((conn)->vfs_handles, (req), (copied))
+#define SMB_VFS_NEXT_COPY_CHUNK_RECV(handle, req, copied) \
+       smb_vfs_call_copy_chunk_recv((handle)->next, (req), (copied))
+
 #define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) \
        smb_vfs_call_fget_nt_acl((fsp)->conn->vfs_handles, (fsp), (security_info), (ppdesc))
 #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) \
index 8392feb8c43261e5f8939ef600654d37b00b672f..cb988dca13affb54af09dd59e48b1a8092dec29d 100644 (file)
@@ -31,6 +31,7 @@
 #include "librpc/gen_ndr/ndr_dfsblobs.h"
 #include "lib/util/tevent_unix.h"
 #include "lib/asys/asys.h"
+#include "lib/util/tevent_ntstatus.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -1306,6 +1307,67 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
        return NT_STATUS_NOT_SUPPORTED;
 }
 
+struct vfs_cc_state {
+       off_t copied;
+       NTSTATUS status;
+};
+
+static struct tevent_req *vfswrap_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;
+       struct vfs_cc_state *vfs_cc_state;
+
+       DEBUG(10,("performing server side copy chunk of length %lu\n", num));
+
+       req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       /* everything is done synchronously for now */
+       if (SMB_VFS_LSEEK(src_fsp, src_off, SEEK_SET) != src_off) {
+               vfs_cc_state->status = map_nt_error_from_unix(errno);
+               goto err_out;
+       }
+       if (SMB_VFS_LSEEK(dest_fsp, dest_off, SEEK_SET) != dest_off) {
+               vfs_cc_state->status = map_nt_error_from_unix(errno);
+               goto err_out;
+       }
+
+       vfs_cc_state->copied = vfs_transfer_file(src_fsp, dest_fsp, num);
+       if (vfs_cc_state->copied == -1) {
+               vfs_cc_state->status = map_nt_error_from_unix(errno);
+               goto err_out;
+       }
+       vfs_cc_state->status = NT_STATUS_OK;
+
+err_out:
+       if (!tevent_req_nterror(req, vfs_cc_state->status)) {
+               tevent_req_done(req);
+       }
+       return tevent_req_post(req, ev);
+}
+
+static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                       struct tevent_req *req,
+                                       off_t *copied)
+{
+       struct vfs_cc_state *vfs_cc_state = tevent_req_data(req,
+                                                       struct vfs_cc_state);
+
+       *copied = vfs_cc_state->copied;
+       DEBUG(10,("server side copy chunk copied %lu\n", *copied));
+
+       return vfs_cc_state->status;
+}
+
 /********************************************************************
  Given a stat buffer return the allocated size on disk, taking into
  account sparse files.
@@ -2341,6 +2403,8 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .strict_unlock_fn = vfswrap_strict_unlock,
        .translate_name_fn = vfswrap_translate_name,
        .fsctl_fn = vfswrap_fsctl,
+       .copy_chunk_send_fn = vfswrap_copy_chunk_send,
+       .copy_chunk_recv_fn = vfswrap_copy_chunk_recv,
 
        /* NT ACL operations. */
 
index 392baeadd0a299cf238c0c7b9585f1ba5bc63d8c..998a623ef6b502126d583c9556d0247b1de19983 100644 (file)
@@ -161,6 +161,8 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_STRICT_LOCK,
        SMB_VFS_OP_STRICT_UNLOCK,
        SMB_VFS_OP_TRANSLATE_NAME,
+       SMB_VFS_OP_COPY_CHUNK_SEND,
+       SMB_VFS_OP_COPY_CHUNK_RECV,
 
        /* NT ACL operations. */
 
@@ -279,6 +281,8 @@ static struct {
        { SMB_VFS_OP_STRICT_LOCK, "strict_lock" },
        { SMB_VFS_OP_STRICT_UNLOCK, "strict_unlock" },
        { SMB_VFS_OP_TRANSLATE_NAME,    "translate_name" },
+       { SMB_VFS_OP_COPY_CHUNK_SEND,   "copy_chunk_send" },
+       { SMB_VFS_OP_COPY_CHUNK_RECV,   "copy_chunk_recv" },
        { SMB_VFS_OP_FGET_NT_ACL,       "fget_nt_acl" },
        { SMB_VFS_OP_GET_NT_ACL,        "get_nt_acl" },
        { SMB_VFS_OP_FSET_NT_ACL,       "fset_nt_acl" },
@@ -1729,6 +1733,38 @@ static NTSTATUS smb_full_audit_translate_name(struct vfs_handle_struct *handle,
        return result;
 }
 
+static struct tevent_req *smb_full_audit_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;
+
+       req = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, mem_ctx, ev, src_fsp,
+                                          src_off, dest_fsp, dest_off, num);
+
+       do_log(SMB_VFS_OP_COPY_CHUNK_SEND, req, handle, "");
+
+       return req;
+}
+
+static NTSTATUS smb_full_audit_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                              struct tevent_req *req,
+                                              off_t *copied)
+{
+       NTSTATUS result;
+
+       result = SMB_VFS_NEXT_COPY_CHUNK_RECV(handle, req, copied);
+
+       do_log(SMB_VFS_OP_COPY_CHUNK_RECV, NT_STATUS_IS_OK(result), handle, "");
+
+       return result;
+}
+
 static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
                                uint32 security_info,
                                struct security_descriptor **ppdesc)
@@ -2124,6 +2160,8 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .strict_lock_fn = smb_full_audit_strict_lock,
        .strict_unlock_fn = smb_full_audit_strict_unlock,
        .translate_name_fn = smb_full_audit_translate_name,
+       .copy_chunk_send_fn = smb_full_audit_copy_chunk_send,
+       .copy_chunk_recv_fn = smb_full_audit_copy_chunk_recv,
        .fget_nt_acl_fn = smb_full_audit_fget_nt_acl,
        .get_nt_acl_fn = smb_full_audit_get_nt_acl,
        .fset_nt_acl_fn = smb_full_audit_fset_nt_acl,
index 7571b2f3403f6ae4cc1dd9b1d76e7d0f5158f67c..a73e4a66c1e3b5d6e95b815dc3e5a01045f30bf0 100644 (file)
@@ -29,6 +29,7 @@
 #include "smbd/smbd.h"
 #include "ntioctl.h"
 #include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -1668,6 +1669,83 @@ static NTSTATUS smb_time_audit_translate_name(struct vfs_handle_struct *handle,
        return result;
 }
 
+struct time_audit_cc_state {
+       struct timespec ts_send;
+       struct vfs_handle_struct *handle;
+       off_t copied;
+       NTSTATUS status;
+       struct tevent_req *subreq;
+};
+static void smb_time_audit_copy_chunk_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb_time_audit_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;
+       struct time_audit_cc_state *cc_state;
+
+       req = tevent_req_create(mem_ctx, &cc_state, struct time_audit_cc_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       cc_state->handle = handle;
+       cc_state->status = NT_STATUS_OK;
+       clock_gettime_mono(&cc_state->ts_send);
+       cc_state->subreq = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, mem_ctx, ev,
+                                                       src_fsp, src_off,
+                                                       dest_fsp, dest_off,
+                                                       num);
+       if (tevent_req_nomem(cc_state->subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(cc_state->subreq,
+                               smb_time_audit_copy_chunk_done,
+                               req);
+       return req;
+}
+
+static void smb_time_audit_copy_chunk_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct time_audit_cc_state *cc_state
+                       = tevent_req_data(req, struct time_audit_cc_state);
+
+       cc_state->status = SMB_VFS_NEXT_COPY_CHUNK_RECV(cc_state->handle,
+                                                       cc_state->subreq, &cc_state->copied);
+       if (tevent_req_nterror(req, cc_state->status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static NTSTATUS smb_time_audit_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                              struct tevent_req *req,
+                                              off_t *copied)
+{
+       struct time_audit_cc_state *cc_state
+                       = tevent_req_data(req, struct time_audit_cc_state);
+       struct timespec ts_recv;
+       double timediff;
+
+       clock_gettime_mono(&ts_recv);
+       timediff = nsec_time_diff(&ts_recv, &cc_state->ts_send)*1.0e-9;
+       if (timediff > audit_timeout) {
+               smb_time_audit_log("copy_chunk", timediff);
+       }
+
+       *copied = cc_state->copied;
+       return cc_state->status;
+}
+
 static NTSTATUS smb_time_audit_fget_nt_acl(vfs_handle_struct *handle,
                                           files_struct *fsp,
                                           uint32 security_info,
@@ -2174,6 +2252,8 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .strict_lock_fn = smb_time_audit_strict_lock,
        .strict_unlock_fn = smb_time_audit_strict_unlock,
        .translate_name_fn = smb_time_audit_translate_name,
+       .copy_chunk_send_fn = smb_time_audit_copy_chunk_send,
+       .copy_chunk_recv_fn = smb_time_audit_copy_chunk_recv,
        .fget_nt_acl_fn = smb_time_audit_fget_nt_acl,
        .get_nt_acl_fn = smb_time_audit_get_nt_acl,
        .fset_nt_acl_fn = smb_time_audit_fset_nt_acl,
index fe99ee29e99a2e9e640042019d8da185e9651c63..b8d90df77cca6a132ee6a3a07db0c7e3a77511f5 100644 (file)
@@ -2157,11 +2157,33 @@ NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
                            uint32_t *out_len)
 {
        VFS_FIND(fsctl);
-       return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags, 
-                                    in_data, in_len, out_data, max_out_len, 
+       return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags,
+                                    in_data, in_len, out_data, max_out_len,
                                     out_len);
 }
 
+struct tevent_req *smb_vfs_call_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)
+{
+       VFS_FIND(copy_chunk_send);
+       return handle->fns->copy_chunk_send_fn(handle, mem_ctx, ev, src_fsp,
+                                              src_off, dest_fsp, dest_off, num);
+}
+
+NTSTATUS smb_vfs_call_copy_chunk_recv(struct vfs_handle_struct *handle,
+                                     struct tevent_req *req,
+                                     off_t *copied)
+{
+       VFS_FIND(copy_chunk_recv);
+       return handle->fns->copy_chunk_recv_fn(handle, req, copied);
+}
+
 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
                                  struct files_struct *fsp,
                                  uint32 security_info,