1
0
mirror of https://github.com/samba-team/samba.git synced 2025-07-16 20:59:12 +03:00

s3: libsmbclient: Add server-side copy support

Introduce a new operation, splice, which copies data from one SMBCFILE
to another. Implement this operation using FSCTL_SRV_COPYCHUNK_WRITE for
SMB2+ protocols and using read+write for older protocols. Since the
operation may be long running, it takes a callback which gets called
periodically to indicate progress to the application and given an
opportunity to stop it.

Signed-off-by: Ross Lagerwall <rosslagerwall@gmail.com>
Reviewed-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Ross Lagerwall
2015-05-27 23:13:15 +01:00
committed by Jeremy Allison
parent 2ffa939bbe
commit f73bcf4934
13 changed files with 624 additions and 6 deletions

View File

@ -316,6 +316,115 @@ SMBC_read_ctx(SMBCCTX *context,
return ret; /* Success, ret bytes of data ... */
}
off_t
SMBC_splice_ctx(SMBCCTX *context,
SMBCFILE *srcfile,
SMBCFILE *dstfile,
off_t count,
int (*splice_cb)(off_t n, void *priv),
void *priv)
{
off_t written;
char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
char *path = NULL;
char *targetpath = NULL;
struct cli_state *srccli = NULL;
struct cli_state *dstcli = NULL;
uint16_t port = 0;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
if (!context || !context->internal->initialized) {
errno = EINVAL;
TALLOC_FREE(frame);
return -1;
}
if (!srcfile ||
!SMBC_dlist_contains(context->internal->files, srcfile))
{
errno = EBADF;
TALLOC_FREE(frame);
return -1;
}
if (!dstfile ||
!SMBC_dlist_contains(context->internal->files, dstfile))
{
errno = EBADF;
TALLOC_FREE(frame);
return -1;
}
if (SMBC_parse_path(frame,
context,
srcfile->fname,
NULL,
&server,
&port,
&share,
&path,
&user,
&password,
NULL)) {
errno = EINVAL;
TALLOC_FREE(frame);
return -1;
}
status = cli_resolve_path(frame, "", context->internal->auth_info,
srcfile->srv->cli, path,
&srccli, &targetpath);
if (!NT_STATUS_IS_OK(status)) {
d_printf("Could not resolve %s\n", path);
errno = ENOENT;
TALLOC_FREE(frame);
return -1;
}
if (SMBC_parse_path(frame,
context,
dstfile->fname,
NULL,
&server,
&port,
&share,
&path,
&user,
&password,
NULL)) {
errno = EINVAL;
TALLOC_FREE(frame);
return -1;
}
status = cli_resolve_path(frame, "", context->internal->auth_info,
dstfile->srv->cli, path,
&dstcli, &targetpath);
if (!NT_STATUS_IS_OK(status)) {
d_printf("Could not resolve %s\n", path);
errno = ENOENT;
TALLOC_FREE(frame);
return -1;
}
status = cli_splice(srccli, dstcli,
srcfile->cli_fd, dstfile->cli_fd,
count, srcfile->offset, dstfile->offset, &written,
splice_cb, priv);
if (!NT_STATUS_IS_OK(status)) {
errno = SMBC_errno(context, srccli);
TALLOC_FREE(frame);
return -1;
}
srcfile->offset += written;
dstfile->offset += written;
TALLOC_FREE(frame);
return written;
}
/*
* Routine to write() a file ...
*/