Resend: Patch to implement utimes in smbclient along with a test

Jeremy Allison jra at samba.org
Mon Oct 16 21:03:23 UTC 2017


On Fri, Sep 22, 2017 at 11:54:49AM -0700, Jeremy Allison via samba-technical wrote:
> On Thu, Sep 21, 2017 at 07:22:19PM -0700, Richard Sharpe via samba-technical wrote:
> > > editor shows red for that new line.
> > 
> > OK, fixed that one as well.
> 
> A few fixes needed:
> 
> 1). d_printf("setmode <filename> <create-time> <access-time> "
> should be: d_printf("utimes...").
> 
> 2). Split the test into a separate patch to go in after
> the client.c fix (I find that easier to back-port if
> needed).
> 
> 3). Needs a docs-xml update for smbclient describing
> the new "utimes" command.
> 
> I can do these for you next week if you're busy, but
> I think these need doing before this can go in.

Here's the version I'd like to ship. Richard, are
you happy with this ?

Thanks,

	Jeremy.
-------------- next part --------------
From d4d36aa78b5afa883d64ffcb24ab586654ec9c0e Mon Sep 17 00:00:00 2001
From: Richard Sharpe <realrichardsharpe at gmail.com>
Date: Mon, 16 Oct 2017 13:51:51 -0700
Subject: [PATCH 1/2] s3:Add a utimes command to smbclient so we can set the
 Windows times.

Add an update to the smbclient man page.

Signed-off-by: Richard Sharpe <realrichardsharpe at gmail.com>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 docs-xml/manpages/smbclient.1.xml |   8 +++
 source3/client/client.c           | 122 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)

diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml
index 432f60da78a..03259828cbc 100644
--- a/docs-xml/manpages/smbclient.1.xml
+++ b/docs-xml/manpages/smbclient.1.xml
@@ -1175,6 +1175,14 @@
 		</para></listitem>
 		</varlistentry>
 
+		<varlistentry>
+		<term>utimes <filename> <create time> <access time> <write time> <
+		change time></term>
+		<listitem><para>Changes the timestamps on a file by name.
+		Times should be specified in the format YY:MM:DD-HH:MM:SS or -1 for no change.
+		</para></listitem>
+		</varlistentry>
+
 	</variablelist>
 </refsect1>
 
diff --git a/source3/client/client.c b/source3/client/client.c
index 5ef9ad52151..df16496ff86 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -4940,6 +4940,126 @@ static int cmd_show_connect( void )
 	return 0;
 }
 
+/**
+ * set_remote_times - set times of a remote file
+ * @filename: path to the file name
+ * @create_time: New create time
+ * @access_time: New access time
+ * @write_time: New write time
+ * @change_time: New metadata change time
+ *
+ * Update the file times with the ones provided.
+ */
+static int set_remote_times(const char *filename, time_t create_time,
+			time_t access_time, time_t write_time,
+			time_t change_time)
+{
+	extern struct cli_state *cli;
+	NTSTATUS status;
+
+	status = cli_setpathinfo_basic(cli, filename, create_time,
+					access_time, write_time,
+					change_time, -1);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("cli_setpathinfo_basic failed: %s\n",
+			 nt_errstr(status));
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * cmd_utimes - interactive command to set the four times
+ *
+ * Read a filename and four times from the client command line and update
+ * the file times. A value of -1 for a time means don't change.
+ */
+static int cmd_utimes(void)
+{
+	const extern char *cmd_ptr;
+	char *buf;
+	char *fname = NULL;
+	time_t times[4] = {0, 0, 0, 0};
+	int time_count = 0;
+	int err = 0;
+	bool ok;
+	TALLOC_CTX *ctx = talloc_new(NULL);
+	if (ctx == NULL) {
+		return 1;
+	}
+
+	ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
+	if (!ok) {
+		d_printf("utimes <filename> <create-time> <access-time> "
+			 "<write-time> <change-time>\n");
+		d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
+			"or -1 for no change\n");
+		err = 1;
+		goto out;
+	}
+
+	fname = talloc_asprintf(ctx,
+				"%s%s",
+				client_get_cur_dir(),
+				buf);
+	if (fname == NULL) {
+		err = 1;
+		goto out;
+	}
+
+	while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
+		time_count < 4) {
+		const char *s = buf;
+		struct tm tm = {0,};
+		char *ret;
+
+		if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
+			times[time_count] = 0;
+			time_count++;
+			continue;
+		} else {
+			ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
+		}
+
+		/* We could not match all the chars, so print error */
+		if (ret == NULL || *ret != 0) {
+			d_printf("Invalid date format: %s\n", s);
+			d_printf("utimes <filename> <create-time> "
+				"<access-time> <write-time> <change-time>\n");
+			d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
+				"or -1 for no change\n");
+			err = 1;
+			goto out;
+		}
+
+		/* Convert tm to a time_t */
+		times[time_count] = mktime(&tm);
+		time_count++;
+	}
+
+	if (time_count < 4) {
+		d_printf("Insufficient dates: %d\n", time_count);
+		d_printf("utimes <filename> <create-time> <access-time> "
+			"<write-time> <change-time>\n");
+		d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
+			"or -1 for no change\n");
+		err = 1;
+		goto out;
+	}
+
+	DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
+		talloc_strdup(ctx, ctime(&times[0])),
+		talloc_strdup(ctx, ctime(&times[1])),
+		talloc_strdup(ctx, ctime(&times[2])),
+		talloc_strdup(ctx, ctime(&times[3]))));
+
+	set_remote_times(fname, times[0], times[1], times[2], times[3]);
+out:
+	talloc_free(ctx);
+	return err;
+}
+
 /**
  * set_remote_attr - set DOS attributes of a remote file
  * @filename: path to the file name
@@ -5254,6 +5374,8 @@ static struct {
   {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
   {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
   {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
+  {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
+	"<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
   {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
   {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
 
-- 
2.15.0.rc0.271.g36b669edcc-goog


From 2e3f93738bd0ea67e1686efa4e276dcc9aa337f2 Mon Sep 17 00:00:00 2001
From: Richard Sharpe <realrichardsharpe at gmail.com>
Date: Mon, 16 Oct 2017 14:00:07 -0700
Subject: [PATCH 2/2] s4: tests: Add a test for smbclient utimes command.

Signed-off-by: Richard Sharpe <realrichardsharpe at gmail.com>
Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source4/selftest/tests.py                   |  1 +
 testprogs/blackbox/test_smbclient_utimes.sh | 87 +++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+)
 create mode 100644 testprogs/blackbox/test_smbclient_utimes.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index cdc62cd362b..168852e91fe 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -431,6 +431,7 @@ plantestsuite("samba4.blackbox.client_etypes_all(ad_dc:client)", "ad_dc:client",
 plantestsuite("samba4.blackbox.client_etypes_legacy(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'legacy', '23'])
 plantestsuite("samba4.blackbox.client_etypes_strong(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'strong', '17_18'])
 plantestsuite("samba4.blackbox.net_ads_dns(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_net_ads_dns.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$USERNAME', '$PASSWORD'])
+plantestsuite("samba4.blackbox.smbclient_utimes(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_smbclient_utimes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$USERNAME', '$PASSWORD'])
 plantestsuite_loadlist("samba4.rpc.echo against NetBIOS alias", "ad_dc_ntvfs", [valgrindify(smbtorture4), "$LISTOPT", "$LOADLIST", 'ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD', 'rpc.echo'])
 
 # Tests using the "Simple" NTVFS backend
diff --git a/testprogs/blackbox/test_smbclient_utimes.sh b/testprogs/blackbox/test_smbclient_utimes.sh
new file mode 100644
index 00000000000..dba87c6fced
--- /dev/null
+++ b/testprogs/blackbox/test_smbclient_utimes.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Blackbox tests for net ads dns register etc.
+# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer at samba.org>
+# Copyright (C) 2006-2008 Andrew Bartlett <abartlet at samba.org>
+
+if [ $# -lt 6 ]; then
+cat <<EOF
+Usage: test_smbclient_utimes.sh SERVER DC_USERNAME DC_PASSWORD REALM USER PASS
+EOF
+exit 1;
+fi
+
+SERVER=$1
+DC_USERNAME=$2
+DC_PASSWORD=$3
+REALM=$4
+USERNAME=$5
+PASSWORD=$6
+shift 6
+failed=0
+
+UNPRIVUSER="unprivuser"
+UNPRIVPPASS="UnPr1vP at ss1"
+
+samba_bindir="$BINDIR"
+smbclient="$samba_bindir/smbclient"
+net_tool="$samba_bindir/net"
+
+SMB_UNC="//$SERVER/tmp"
+
+. `dirname $0`/subunit.sh
+. `dirname $0`/common_test_fns.inc
+
+# These tests check that the smbclient utimes command works.
+# We only test modification of atime and mtime because the server
+# might not support Create_Time and ctime usually cannot be modified.
+
+echo "Starting ..."
+
+err=0
+
+testit "Adding an unprivileged user" $VALGRIND $net_tool user add $UNPRIVUSER $UNPRIVPASS -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+res1=`$smbclient "$SMB_UNC" -U"$UNPRIVUSER%$UNPRIVPASS" -c "allinfo test1"`
+if [ x$status != x0 ] 
+then
+  err=1
+fi
+
+echo $res1 >> /tmp/$$
+
+testit "Test that we can even connect with $USERNAME $PASSWORD" [ $err == 0 ] || failed=`expr $failed + 1`
+if [ $err != 0 ]
+then
+  exit $failed
+fi
+
+# Now, try to change the access time because Create time is not necessarily 
+# handled.
+
+test_smbclient "Set Utimes" "utimes test1 -1 17:01:01-05:10:20 -1 -1" "$SMB_UNC" -U"UNPRIVUSER%$UNPRIVPASS" || failed=`expr $failed + 1`
+
+# Now, get the times again and check they are different from the first result
+res2=`$smbclient "$SMB_UNC" -U"$UNPRIVUSER%$UNPRIVPASS" -c "allinfo test1"`
+if [ x$status != x0 ] 
+then
+  err=1
+fi
+
+testit "Test that we can get the info again" [ $err == 0 ] || failed=`expr $failed + 1`
+if [ $err != 0 ]
+then
+  exit $failed
+fi
+
+echo $res2 >> /tmp/$$
+
+# These must be different!
+diff <(echo "$res1") <(echo "$res2")
+if [ x$status == x0 ] 
+then
+  err=1
+fi
+
+testit "Test that the two times are different" [ $err == 0 ] || failed=`expr $failed + 1`
+
+exit $failed
-- 
2.15.0.rc0.271.g36b669edcc-goog



More information about the samba-technical mailing list