[PATCHES] smbclient - add support for superseding the destination file on rename
Uri Simchoni
uri at samba.org
Tue Mar 21 22:09:06 UTC 2017
Hi,
This smbclient patch set supports asking the server to replace an
existing destination file when renaming. This is a feature of SMB2
protocol only - haven't found a parallel in SMB1.
Review appreciated,
Uri.
-------------- next part --------------
From c54e4b20cab2bfe9374611e3b1aecf409a50c063 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 21 Mar 2017 23:02:48 +0200
Subject: [PATCH 1/4] s3: libsmb: add replace support to SMB2 rename
SMB2 rename operation supports replacing the
destination file if it exists.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 9 +++++++--
source3/libsmb/cli_smb2_fnum.h | 5 +++--
source3/libsmb/clifile.c | 4 +---
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 848e077..351fccf 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2010,8 +2010,9 @@ NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
***************************************************************/
NTSTATUS cli_smb2_rename(struct cli_state *cli,
- const char *fname_src,
- const char *fname_dst)
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
{
NTSTATUS status;
DATA_BLOB inbuf = data_blob_null;
@@ -2091,6 +2092,10 @@ NTSTATUS cli_smb2_rename(struct cli_state *cli,
goto fail;
}
+ if (replace) {
+ SCVAL(inbuf.data, 0, 1);
+ }
+
SIVAL(inbuf.data, 16, converted_size_bytes);
memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 12c42a2..43e0471 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -132,8 +132,9 @@ NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
uint32_t sec_info,
const struct security_descriptor *sd);
NTSTATUS cli_smb2_rename(struct cli_state *cli,
- const char *fname_src,
- const char *fname_dst);
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace);
NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
uint16_t fnum,
const char *ea_name,
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 6b32bf1..e6bc40c 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -1082,9 +1082,7 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
NTSTATUS status = NT_STATUS_OK;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return cli_smb2_rename(cli,
- fname_src,
- fname_dst);
+ return cli_smb2_rename(cli, fname_src, fname_dst, false);
}
frame = talloc_stackframe();
--
2.9.3
From 4f9d770258671c6e051bd489a2e0b7032479812c Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 21 Mar 2017 23:13:07 +0200
Subject: [PATCH 2/4] s3: libsmb: add replace support to cli_rename()
Adds support for replacing the destination file at
the higher-level cli_rename(). This is actually supported
only by SMB2, and fails with invalid parameter with SMB1.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/client/client.c | 2 +-
source3/libsmb/clifile.c | 15 +++++++++++++--
source3/libsmb/libsmb_dir.c | 10 +++++++---
source3/libsmb/proto.h | 5 ++++-
source3/torture/nbio.c | 2 +-
source3/torture/torture.c | 14 +++++++-------
6 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/source3/client/client.c b/source3/client/client.c
index 226eb27..78945f9 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -3870,7 +3870,7 @@ static int cmd_rename(void)
return 1;
}
- status = cli_rename(targetcli, targetsrc, targetdest);
+ status = cli_rename(targetcli, targetsrc, targetdest, false);
if (!NT_STATUS_IS_OK(status)) {
d_printf("%s renaming files %s -> %s \n",
nt_errstr(status),
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index e6bc40c..8f96e04 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -1074,7 +1074,10 @@ NTSTATUS cli_rename_recv(struct tevent_req *req)
return tevent_req_simple_recv_ntstatus(req);
}
-NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+NTSTATUS cli_rename(struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace)
{
TALLOC_CTX *frame = NULL;
struct tevent_context *ev;
@@ -1082,7 +1085,7 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
NTSTATUS status = NT_STATUS_OK;
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return cli_smb2_rename(cli, fname_src, fname_dst, false);
+ return cli_smb2_rename(cli, fname_src, fname_dst, replace);
}
frame = talloc_stackframe();
@@ -1095,6 +1098,14 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
goto fail;
}
+ if (replace) {
+ /*
+ * SMB1 doesn't support replace
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
status = NT_STATUS_NO_MEMORY;
diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c
index 8bf3c6b..4a4e084 100644
--- a/source3/libsmb/libsmb_dir.c
+++ b/source3/libsmb/libsmb_dir.c
@@ -2032,12 +2032,16 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
return -1;
}
- if (!NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
+ if (!NT_STATUS_IS_OK(
+ cli_rename(targetcli1, targetpath1, targetpath2, false))) {
int eno = SMBC_errno(ocontext, targetcli1);
if (eno != EEXIST ||
- !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) ||
- !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
+ !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN)) ||
+ !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
+ targetpath2, false))) {
errno = eno;
TALLOC_FREE(frame);
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 764f3fc..57a45e3 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -330,7 +330,10 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
const char *fname_src,
const char *fname_dst);
NTSTATUS cli_rename_recv(struct tevent_req *req);
-NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst);
+NTSTATUS cli_rename(struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst,
+ bool replace);
struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/torture/nbio.c b/source3/torture/nbio.c
index 6c87f9a..861f874 100644
--- a/source3/torture/nbio.c
+++ b/source3/torture/nbio.c
@@ -261,7 +261,7 @@ void nb_rename(const char *oldname, const char *newname)
{
NTSTATUS status;
- status = cli_rename(c, oldname, newname);
+ status = cli_rename(c, oldname, newname, false);
if (!NT_STATUS_IS_OK(status)) {
printf("ERROR: rename %s %s failed (%s)\n",
oldname, newname, nt_errstr(status));
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index dbbd072..0d9a653 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -4703,7 +4703,7 @@ static bool run_rename(int dummy)
return False;
}
- status = cli_rename(cli1, fname, fname1);
+ status = cli_rename(cli1, fname, fname1, false);
if (!NT_STATUS_IS_OK(status)) {
printf("First rename failed (SHARE_READ) (this is correct) - %s\n", nt_errstr(status));
} else {
@@ -4731,7 +4731,7 @@ static bool run_rename(int dummy)
return False;
}
- status = cli_rename(cli1, fname, fname1);
+ status = cli_rename(cli1, fname, fname1, false);
if (!NT_STATUS_IS_OK(status)) {
printf("Second rename failed (SHARE_DELETE | SHARE_READ) - this should have succeeded - %s\n", nt_errstr(status));
correct = False;
@@ -4778,7 +4778,7 @@ static bool run_rename(int dummy)
}
#endif
- status = cli_rename(cli1, fname, fname1);
+ status = cli_rename(cli1, fname, fname1, false);
if (!NT_STATUS_IS_OK(status)) {
printf("Third rename failed (SHARE_NONE) - this should have succeeded - %s\n", nt_errstr(status));
correct = False;
@@ -4806,7 +4806,7 @@ static bool run_rename(int dummy)
return False;
}
- status = cli_rename(cli1, fname, fname1);
+ status = cli_rename(cli1, fname, fname1, false);
if (!NT_STATUS_IS_OK(status)) {
printf("Fourth rename failed (SHARE_READ | SHARE_WRITE) (this is correct) - %s\n", nt_errstr(status));
} else {
@@ -4834,7 +4834,7 @@ static bool run_rename(int dummy)
return False;
}
- status = cli_rename(cli1, fname, fname1);
+ status = cli_rename(cli1, fname, fname1, false);
if (!NT_STATUS_IS_OK(status)) {
printf("Fifth rename failed (SHARE_READ | SHARE_WRITE | SHARE_DELETE) - this should have succeeded - %s ! \n", nt_errstr(status));
correct = False;
@@ -5043,13 +5043,13 @@ static bool run_rename_access(int dummy)
* dst directory should fail.
*/
- status = cli_rename(cli, src, dst);
+ status = cli_rename(cli, src, dst, false);
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
printf("rename of %s -> %s should be ACCESS denied, was %s\n",
src, dst, nt_errstr(status));
goto fail;
}
- status = cli_rename(cli, dsrc, ddst);
+ status = cli_rename(cli, dsrc, ddst, false);
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
printf("rename of %s -> %s should be ACCESS denied, was %s\n",
src, dst, nt_errstr(status));
--
2.9.3
From 0e9715a586dd3747db49623a9ec49bc50a18f3f4 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 21 Mar 2017 23:26:05 +0200
Subject: [PATCH 3/4] smbclient: add -f option to rename command
This option causes the rename to request that the
destination file / directory be replaced if it exists.
Supported only in SMB2 and higher protocol.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/client/client.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/source3/client/client.c b/source3/client/client.c
index 78945f9..d2ebea0 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -3833,10 +3833,11 @@ static int cmd_rename(void)
char *targetsrc;
char *targetdest;
NTSTATUS status;
+ bool replace = false;
if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
!next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
- d_printf("rename <src> <dest>\n");
+ d_printf("rename <src> <dest> [-f]\n");
return 1;
}
@@ -3856,6 +3857,11 @@ static int cmd_rename(void)
return 1;
}
+ if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
+ strcsequal(buf, "-f")) {
+ replace = true;
+ }
+
status = cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
&targetsrc);
if (!NT_STATUS_IS_OK(status)) {
@@ -3870,7 +3876,7 @@ static int cmd_rename(void)
return 1;
}
- status = cli_rename(targetcli, targetsrc, targetdest, false);
+ status = cli_rename(targetcli, targetsrc, targetdest, replace);
if (!NT_STATUS_IS_OK(status)) {
d_printf("%s renaming files %s -> %s \n",
nt_errstr(status),
--
2.9.3
From ddca64ea4472451a7b50ea9f3a0e54ebf9eba642 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 21 Mar 2017 23:56:35 +0200
Subject: [PATCH 4/4] manpages: update smbclient manpage with rename -f option
Document the -f option of the rename command.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
docs-xml/manpages/smbclient.1.xml | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml
index c8f4e40..059e14c 100644
--- a/docs-xml/manpages/smbclient.1.xml
+++ b/docs-xml/manpages/smbclient.1.xml
@@ -1000,10 +1000,13 @@
</varlistentry>
<varlistentry>
- <term>rename <old filename> <new filename></term>
+ <term>rename <old filename> <new filename> [-f]</term>
<listitem><para>Rename files in the current working directory on the
server from <replaceable>old filename</replaceable> to
- <replaceable>new filename</replaceable>. </para></listitem>
+ <replaceable>new filename</replaceable>. The optional
+ -f switch is supported only by SMB2 protocol and beyond,
+ and allows for superseding the destination file,
+ if it exists.</para></listitem>
</varlistentry>
<varlistentry>
--
2.9.3
More information about the samba-technical
mailing list