Skip to content

Commit

Permalink
s3-vfs: add copy_chunk vfs hooks
Browse files Browse the repository at this point in the history
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.

Use a pread/pwrite loop in vfs_default, so that requests referring to
the same src and dest file are possible.

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

Check whether the request source offset + length exceeds the current
size. Return STATUS_INVALID_VIEW_SIZE under such a condition, matching
Windows server behaviour.

Reviewed by: Jeremy Allison <[email protected]>
  • Loading branch information
ddiss authored and jrasamba committed Jan 16, 2013
1 parent 2bde963 commit ef00eb9
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs-xml/manpages/vfs_full_audit.8.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
42 changes: 42 additions & 0 deletions examples/VFS/skel_opaque.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

#include "../source3/include/includes.h"
#include "lib/util/tevent_ntstatus.h"

/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE
SAMBA DEVELOPERS GUIDE!!!!!!
Expand Down Expand Up @@ -488,6 +489,45 @@ static struct file_id skel_file_id_create(vfs_handle_struct *handle,
return id;
}

struct skel_cc_state {
uint64_t unused;
};
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)
{
struct tevent_req *req;
struct skel_cc_state *cc_state;

req = tevent_req_create(mem_ctx, &cc_state, struct skel_cc_state);
if (req == NULL) {
return NULL;
}

tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
return tevent_req_post(req, ev);
}

static NTSTATUS skel_copy_chunk_recv(struct vfs_handle_struct *handle,
struct tevent_req *req,
off_t *copied)
{
NTSTATUS status;

if (tevent_req_is_nterror(req, &status)) {
tevent_req_received(req);
return status;
}
tevent_req_received(req);

return NT_STATUS_OK;
}

static NTSTATUS skel_streaminfo(struct vfs_handle_struct *handle,
struct files_struct *fsp,
const char *fname,
Expand Down Expand Up @@ -825,6 +865,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,
Expand Down
75 changes: 75 additions & 0 deletions examples/VFS/skel_transparent.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "../source3/include/includes.h"
#include "lib/util/tevent_unix.h"
#include "lib/util/tevent_ntstatus.h"

/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE
SAMBA DEVELOPERS GUIDE!!!!!!
Expand Down Expand Up @@ -572,6 +573,78 @@ static struct file_id skel_file_id_create(vfs_handle_struct *handle,
return SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
}

struct skel_cc_state {
struct vfs_handle_struct *handle;
off_t copied;
};
static void skel_copy_chunk_done(struct tevent_req *subreq);

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)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct skel_cc_state *cc_state;

req = tevent_req_create(mem_ctx, &cc_state, struct skel_cc_state);
if (req == NULL) {
return NULL;
}

cc_state->handle = handle;
subreq = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, cc_state, ev,
src_fsp, src_off,
dest_fsp, dest_off, num);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}

tevent_req_set_callback(subreq, skel_copy_chunk_done, req);
return req;
}

static void skel_copy_chunk_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct skel_cc_state *cc_state
= tevent_req_data(req, struct skel_cc_state);
NTSTATUS status;

status = SMB_VFS_NEXT_COPY_CHUNK_RECV(cc_state->handle,
subreq,
&cc_state->copied);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
tevent_req_done(req);
}

static NTSTATUS skel_copy_chunk_recv(struct vfs_handle_struct *handle,
struct tevent_req *req,
off_t *copied)
{
struct skel_cc_state *cc_state
= tevent_req_data(req, struct skel_cc_state);
NTSTATUS status;

*copied = cc_state->copied;
if (tevent_req_is_nterror(req, &status)) {
tevent_req_received(req);
return status;
}

tevent_req_received(req);
return NT_STATUS_OK;
}

static NTSTATUS skel_streaminfo(struct vfs_handle_struct *handle,
struct files_struct *fsp,
const char *fname,
Expand Down Expand Up @@ -898,6 +971,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,
Expand Down
25 changes: 24 additions & 1 deletion source3/include/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
/* Leave at 31 - not yet released. Make struct vuid_cache_entry in
connection_struct a pointer. */
/* Leave at 31 - not yet released. Add share_access to vuid_cache_entry. */
/* Leave at 31 - not yet released. add SMB_VFS_COPY_CHUNK() */

#define SMB_VFS_INTERFACE_VERSION 31

Expand Down Expand Up @@ -615,6 +616,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,
Expand Down Expand Up @@ -1086,7 +1098,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,
Expand Down
10 changes: 10 additions & 0 deletions source3/include/vfs_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, mem_ctx, ppdesc) \
smb_vfs_call_fget_nt_acl((fsp)->conn->vfs_handles, (fsp), (security_info), (mem_ctx), (ppdesc))
#define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, mem_ctx, ppdesc) \
Expand Down
111 changes: 111 additions & 0 deletions source3/modules/vfs_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1323,6 +1324,114 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
return NT_STATUS_NOT_SUPPORTED;
}

struct vfs_cc_state {
off_t copied;
uint8_t buf[65536];
};

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;
NTSTATUS status;

DEBUG(10, ("performing server side copy chunk of length %lu\n",
(unsigned long)num));

req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
if (req == NULL) {
return NULL;
}

status = vfs_stat_fsp(src_fsp);
if (tevent_req_nterror(req, status)) {
return tevent_req_post(req, ev);
}

if (src_fsp->fsp_name->st.st_ex_size < src_off + num) {
/*
* [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
* If the SourceOffset or SourceOffset + Length extends beyond
* the end of file, the server SHOULD<240> treat this as a
* STATUS_END_OF_FILE error.
* ...
* <240> Section 3.3.5.15.6: Windows servers will return
* STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
*/
tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
return tevent_req_post(req, ev);
}

/* could use 2.6.33+ sendfile here to do this in kernel */
while (vfs_cc_state->copied < num) {
ssize_t ret;
off_t this_num = MIN(sizeof(vfs_cc_state->buf),
num - vfs_cc_state->copied);

ret = SMB_VFS_PREAD(src_fsp, vfs_cc_state->buf,
this_num, src_off);
if (ret == -1) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
return tevent_req_post(req, ev);
}
if (ret != this_num) {
/* zero tolerance for short reads */
tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
return tevent_req_post(req, ev);
}
src_off += ret;

ret = SMB_VFS_PWRITE(dest_fsp, vfs_cc_state->buf,
this_num, dest_off);
if (ret == -1) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
return tevent_req_post(req, ev);
}
if (ret != this_num) {
/* zero tolerance for short writes */
tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
return tevent_req_post(req, ev);
}
dest_off += ret;

vfs_cc_state->copied += this_num;
}

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);
NTSTATUS status;

if (tevent_req_is_nterror(req, &status)) {
DEBUG(2, ("server side copy chunk failed: %s\n",
nt_errstr(status)));
*copied = 0;
tevent_req_received(req);
return status;
}

*copied = vfs_cc_state->copied;
DEBUG(10, ("server side copy chunk copied %lu\n",
(unsigned long)*copied));
tevent_req_received(req);

return NT_STATUS_OK;
}

/********************************************************************
Given a stat buffer return the allocated size on disk, taking into
account sparse files.
Expand Down Expand Up @@ -2367,6 +2476,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. */

Expand Down
Loading

0 comments on commit ef00eb9

Please sign in to comment.