[PATCH] s3:client: Add "scopy" cmd to perform Server Side copy using smbclient.
Jeremy Allison
jra at samba.org
Mon Jul 13 21:47:33 UTC 2015
On Tue, Jul 14, 2015 at 09:39:03AM +1200, Andrew Bartlett wrote:
>
> Yes, we need both those tests. This isn't urgent, we should be able to
> wait till those are written. (I indeed know what your queue looks like,
> and I really don't want tests forgotten, we must never add untested
> code).
As it's easier and a lot more fun than doing the bloody review (which
is extremely complicated code :-), here is a version with both tests added.
Hope you're happy now :-). Banging out smbclient_s3 tests is always
fun to do :-).
Ralph, please review and push !
Jeremy.
-------------- next part --------------
From ec74fd6ee48a07ff58156e63f010aeb6dd2ba55f Mon Sep 17 00:00:00 2001
From: Anubhav Rakshit <anubhav.rakshit at gmail.com>
Date: Thu, 25 Jun 2015 11:37:18 +0530
Subject: [PATCH 1/3] s3:client: Add "scopy" cmd to perform Server Side copy
using smbclient.
Signed-off-by: Anubhav Rakshit <anubhav.rakshit at gmail.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
source3/client/client.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
diff --git a/source3/client/client.c b/source3/client/client.c
index fde5b49..d0da6bc 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -3806,6 +3806,140 @@ static int cmd_rename(void)
return 0;
}
+struct scopy_timing {
+ struct timespec tp_start;
+};
+
+static int scopy_status(off_t written, void *priv)
+{
+ struct timespec tp_end;
+ unsigned int scopy_total_time_ms;
+ struct scopy_timing *st = priv;
+
+ clock_gettime_mono(&tp_end);
+ scopy_total_time_ms = nsec_time_diff(&tp_end,&st->tp_start)/1000000;
+
+ DEBUG(5,("Copied ""%" PRIu64 " bytes at an ", written));
+ DEBUG(5,("average %3.1f kb/s\n",
+ written / (1.024*scopy_total_time_ms)));
+
+ return true;
+}
+
+/****************************************************************************
+ Server-Side copy some file.
+****************************************************************************/
+
+static int cmd_scopy(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *src, *dest;
+ char *buf, *buf2;
+ struct cli_state *targetcli;
+ char *targetsrc;
+ char *targetdest;
+ uint32_t DesiredAccess, ShareAccess, CreateDisposition, CreateOptions;
+ struct smb_create_returns cr;
+ uint16_t destfnum = (uint16_t)-1;
+ uint16_t srcfnum = (uint16_t)-1;
+ off_t written = 0;
+ struct scopy_timing st;
+ int rc = 0;
+ NTSTATUS status;
+
+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
+ d_printf("scopy <src> <dest>\n");
+ return 1;
+ }
+
+ src = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf);
+ if (!src) {
+ return 1;
+ }
+
+ dest = talloc_asprintf(ctx,
+ "%s%s",
+ client_get_cur_dir(),
+ buf2);
+ if (!dest) {
+ return 1;
+ }
+
+ status = cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
+ &targetsrc);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("scopy %s: %s\n", src, nt_errstr(status));
+ return 1;
+ }
+
+ status = cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli,
+ &targetdest);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("scopy %s: %s\n", dest, nt_errstr(status));
+ return 1;
+ }
+
+
+ DesiredAccess = (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|
+ READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS);
+ ShareAccess = FILE_SHARE_READ|FILE_SHARE_DELETE;
+ CreateDisposition = FILE_OPEN;
+ CreateOptions = (FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE|
+ FILE_OPEN_REPARSE_POINT);
+ status = cli_ntcreate(targetcli, targetsrc, 0, DesiredAccess, 0,
+ ShareAccess, CreateDisposition, CreateOptions, 0x0,
+ &srcfnum, &cr);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Failed to open file %s. %s\n",
+ targetsrc, nt_errstr(status));
+ return 1;
+ }
+
+ DesiredAccess = (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|
+ FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|
+ DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|SYNCHRONIZE_ACCESS);
+ ShareAccess = FILE_SHARE_NONE;
+ CreateDisposition = FILE_CREATE;
+ CreateOptions = FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE;
+ status = cli_ntcreate(targetcli, targetdest, 0, DesiredAccess,
+ FILE_ATTRIBUTE_ARCHIVE, ShareAccess, CreateDisposition,
+ CreateOptions, 0x0, &destfnum, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Failed to create file %s. %s\n",
+ targetdest, nt_errstr(status));
+ cli_close(targetcli, srcfnum);
+ return 1;
+ }
+
+ clock_gettime_mono(&st.tp_start);
+ status = cli_splice(targetcli, targetcli, srcfnum, destfnum,
+ cr.end_of_file, 0, 0, &written, scopy_status, &st);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("%s copying file %s -> %s \n",
+ nt_errstr(status),
+ targetsrc,
+ targetdest);
+ rc = 1;
+ }
+
+ status = cli_close(targetcli, srcfnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Error %s closing remote source file\n", nt_errstr(status));
+ rc = 1;
+ }
+ status = cli_close(targetcli, destfnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Error %s closing remote dest file\n", nt_errstr(status));
+ rc = 1;
+ }
+
+ return rc;
+}
+
/****************************************************************************
Print the volume name.
****************************************************************************/
@@ -4699,6 +4833,7 @@ static struct {
{"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
{COMPL_REMOTE, COMPL_LOCAL}},
{"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+ {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
{"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
{"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
{"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
--
2.4.3.573.g4eafbef
From 10f5414f343995cd2901ae93d19e0fe0163451a0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Fri, 10 Jul 2015 10:29:01 -0700
Subject: [PATCH 2/3] docs: Document new scopy command.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
docs-xml/manpages/smbclient.1.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml
index 8b166d1..e1d805a 100644
--- a/docs-xml/manpages/smbclient.1.xml
+++ b/docs-xml/manpages/smbclient.1.xml
@@ -1011,6 +1011,14 @@
</varlistentry>
<varlistentry>
+ <term>scopy <source filename> <destination filename></term>
+ <listitem><para>Attempt to copy a file on the server using the
+ most efficient server-side copy calls. Falls back to using
+ read then write if server doesn't support server-side copy.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>setmode <filename> <perm=[+|\-]rsha></term>
<listitem><para>A version of the DOS attrib command to set
file permissions. For example: </para>
--
2.4.3.573.g4eafbef
From e5615b289803de7cadf01ed03c3c91e8c3afca5a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 13 Jul 2015 14:15:45 -0700
Subject: [PATCH 3/3] s3: tests: Add blackbox test for scopy.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/script/tests/test_smbclient_s3.sh | 79 +++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh
index faf8d98..69c7452 100755
--- a/source3/script/tests/test_smbclient_s3.sh
+++ b/source3/script/tests/test_smbclient_s3.sh
@@ -896,6 +896,81 @@ EOF
fi
}
+# Test using scopy to copy a file on the server.
+test_scopy()
+{
+ tmpfile=$PREFIX/smbclient_interactive_prompt_commands
+ scopy_file=$PREFIX/scopy_file
+
+ rm -f $scopy_file
+ cat > $tmpfile <<EOF
+put ${SMBCLIENT}
+scopy smbclient scopy_file
+lcd ${PREFIX}
+get scopy_file
+del smbclient
+del scopy_file
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -mSMB3 -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=`eval $cmd`
+ ret=$?
+ out1=`md5sum ${SMBCLIENT} | sed -e 's/ .*//'`
+ out2=`md5sum ${scopy_file} | sed -e 's/ .*//'`
+ rm -f $tmpfile
+ rm -f $scopy_file
+
+ if [ $ret != 0 ] ; then
+ echo "$out"
+ echo "failed scopy test (1) with output $ret"
+ false
+ return
+ fi
+
+ if [ $out1 != $out2 ] ; then
+ echo "$out1 $out2"
+ echo "failed md5sum (1)"
+ false
+ fi
+
+#
+# Now do again using SMB1
+# to force client-side fallback.
+#
+
+ cat > $tmpfile <<EOF
+put ${SMBCLIENT}
+scopy smbclient scopy_file
+lcd ${PREFIX}
+get scopy_file
+del smbclient
+del scopy_file
+quit
+EOF
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -mNT1 -U$USERNAME%$PASSWORD //$SERVER/tmp -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=`eval $cmd`
+ ret=$?
+ out1=`md5sum ${SMBCLIENT} | sed -e 's/ .*//'`
+ out2=`md5sum ${scopy_file} | sed -e 's/ .*//'`
+ rm -f $tmpfile
+ rm -f $scopy_file
+
+ if [ $ret != 0 ] ; then
+ echo "$out"
+ echo "failed scopy test (2) with output $ret"
+ false
+ return
+ fi
+
+ if [ $out1 != $out2 ] ; then
+ echo "$out1 $out2"
+ echo "failed md5sum (2)"
+ false
+ fi
+}
+
LOGDIR_PREFIX=test_smbclient_s3
@@ -980,6 +1055,10 @@ testit "list a share with a mangled name + acl_xattr object" \
test_mangled_names || \
failed=`expr $failed + 1`
+testit "server-side file copy" \
+ test_scopy || \
+ failed=`expr $failed + 1`
+
testit "rm -rf $LOGDIR" \
rm -rf $LOGDIR || \
failed=`expr $failed + 1`
--
2.4.3.573.g4eafbef
More information about the samba-technical
mailing list