From bfe1cc402dcdec3df9f149f6635998c7a31c9fab Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 10 Oct 2011 14:31:55 +0200 Subject: [PATCH] s3-vfs: add copy_chunk vfs hooks 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 | 2 + examples/VFS/skel_opaque.c | 21 +++++++ examples/VFS/skel_transparent.c | 22 +++++++ source3/include/vfs.h | 25 +++++++- source3/include/vfs_macros.h | 10 ++++ source3/modules/vfs_default.c | 64 +++++++++++++++++++++ source3/modules/vfs_full_audit.c | 38 ++++++++++++ source3/modules/vfs_time_audit.c | 80 ++++++++++++++++++++++++++ source3/smbd/vfs.c | 26 ++++++++- 9 files changed, 285 insertions(+), 3 deletions(-) diff --git a/docs-xml/manpages/vfs_full_audit.8.xml b/docs-xml/manpages/vfs_full_audit.8.xml index a44924a8f64..312bc25078d 100644 --- a/docs-xml/manpages/vfs_full_audit.8.xml +++ b/docs-xml/manpages/vfs_full_audit.8.xml @@ -46,6 +46,8 @@ close closedir connect + copy_chunk_send + copy_chunk_recv disconnect disk_free fchmod diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index a786a234d40..8d7a0945119 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -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, diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index 02a994c07f7..9aa8d72f5fc 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -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, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index c83e7ed54b8..f360eb160be 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -146,6 +146,7 @@ /* 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, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 4eca1b07484..67b5af526f4 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -399,6 +399,16 @@ #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) \ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 8392feb8c43..cb988dca13a 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -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. */ diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 392baeadd0a..998a623ef6b 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -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, diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 7571b2f3403..a73e4a66c1e 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -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, diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index fe99ee29e99..b8d90df77cc 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -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, -- 2.34.1