[PATCHES] smbclient - add support for superseding the destination file on rename

Jeremy Allison jra at samba.org
Mon Mar 27 19:59:04 UTC 2017


On Sun, Mar 26, 2017 at 09:43:23PM +0300, Uri Simchoni via samba-technical wrote:

> Here's a modified patch set - the original 4 patches, plus 4 patches on
> top that add rename with delete to SMB1, using FileRenameInformation.
> 
> As far as I can see, Windows still uses CIFS-style rename, making
> rename-with-delete a non-atomic operation, so I left the default as-is.
> This can easily be changed though.
> 
> BTW, the motive for adding this is gone - I wanted to use it to
> rename-and-supersede a directory, and as it turns out, Windows doesn't
> allow that (also documented in [MS-FSA] - search for ACCESS_DENIED under
> that 10-page-long description of how it processes a rename). Samba seems
> to allow that in SMB2, probably a bug, I'll follow up with a patch when
> time allows.

Really nice work Uri - that's something I've been planning to
add for a long time but never got the time to do it.

RB+ and pushed !

> From 4444c471e1ae2c51ab92ed9819e84e709d656d16 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 v2 1/8] 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 ceb8aa9d23d695472d0092f7859c6cc088ca4499 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 v2 2/8] 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 dedf46a6d03f7c9637cdf8ea3f9a7669edcda7d3 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 v2 3/8] 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 bbc4176a3bce85f45b2ada6ee55884d25bd097f0 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 v2 4/8] 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
> 
> 
> From 1dd24602fc5f0c9d7d5920ef40b3dfd8030f7078 Mon Sep 17 00:00:00 2001
> From: Uri Simchoni <uri at samba.org>
> Date: Sun, 26 Mar 2017 08:10:34 +0300
> Subject: [PATCH v2 5/8] libcli: introduce smbXcli_conn_support_passthrough()
> 
> This routine queries the client connenction whether
> it supports query/set InfoLevels beyond 1000 (which,
> in Windows OS, is a pass-through mechanism to the
> file system).
> 
> Signed-off-by: Uri Simchoni <uri at samba.org>
> ---
>  libcli/smb/smbXcli_base.c | 17 +++++++++++++++++
>  libcli/smb/smbXcli_base.h |  1 +
>  2 files changed, 18 insertions(+)
> 
> diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
> index 9521fc6..1fcf11e 100644
> --- a/libcli/smb/smbXcli_base.c
> +++ b/libcli/smb/smbXcli_base.c
> @@ -468,6 +468,23 @@ bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn)
>  	return false;
>  }
>  
> +/*
> + * [MS-SMB] 2.2.2.3.5 - SMB1 support for passing through
> + * query/set commands to the file system
> + */
> +bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn)
> +{
> +	if (conn->protocol >= PROTOCOL_SMB2_02) {
> +		return true;
> +	}
> +
> +	if (conn->smb1.capabilities & CAP_W2K_SMBS) {
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
>  void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options)
>  {
>  	set_socket_options(conn->sock_fd, options);
> diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
> index 84f4a6b..1abeb2b 100644
> --- a/libcli/smb/smbXcli_base.h
> +++ b/libcli/smb/smbXcli_base.h
> @@ -47,6 +47,7 @@ bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn);
>  
>  enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn);
>  bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn);
> +bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn);
>  
>  void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options);
>  const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn);
> -- 
> 2.9.3
> 
> 
> From 0af96ce668c993b7fcd92601d1a3e54092c7a86a Mon Sep 17 00:00:00 2001
> From: Uri Simchoni <uri at samba.org>
> Date: Sun, 26 Mar 2017 08:54:42 +0300
> Subject: [PATCH v2 6/8] s3-libsmb: cli_cifs_rename_send()
> 
> Pure refactoring - current rename is [MS-CIFS] - style
> rename. In later patch we'll introduce [MS-SMB] rename.
> 
> Signed-off-by: Uri Simchoni <uri at samba.org>
> ---
>  source3/libsmb/clifile.c | 37 ++++++++++++++++++++++++++-----------
>  1 file changed, 26 insertions(+), 11 deletions(-)
> 
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index 8f96e04..b5f29b6 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -992,25 +992,40 @@ NTSTATUS cli_posix_chown(struct cli_state *cli,
>   Rename a file.
>  ****************************************************************************/
>  
> -static void cli_rename_done(struct tevent_req *subreq);
> +static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
> +					       struct tevent_context *ev,
> +					       struct cli_state *cli,
> +					       const char *fname_src,
> +					       const char *fname_dst);
>  
> -struct cli_rename_state {
> +struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
> +				   struct tevent_context *ev,
> +				   struct cli_state *cli,
> +				   const char *fname_src,
> +				   const char *fname_dst)
> +{
> +	return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src, fname_dst);
> +}
> +
> +static void cli_cifs_rename_done(struct tevent_req *subreq);
> +
> +struct cli_cifs_rename_state {
>  	uint16_t vwv[1];
>  };
>  
> -struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
> -				struct tevent_context *ev,
> -				struct cli_state *cli,
> -				const char *fname_src,
> -				const char *fname_dst)
> +static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
> +					       struct tevent_context *ev,
> +					       struct cli_state *cli,
> +					       const char *fname_src,
> +					       const char *fname_dst)
>  {
>  	struct tevent_req *req = NULL, *subreq = NULL;
> -	struct cli_rename_state *state = NULL;
> +	struct cli_cifs_rename_state *state = NULL;
>  	uint8_t additional_flags = 0;
>  	uint16_t additional_flags2 = 0;
>  	uint8_t *bytes = NULL;
>  
> -	req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
> +	req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
>  	if (req == NULL) {
>  		return NULL;
>  	}
> @@ -1051,11 +1066,11 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
>  	}
> -	tevent_req_set_callback(subreq, cli_rename_done, req);
> +	tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
>  	return req;
>  }
>  
> -static void cli_rename_done(struct tevent_req *subreq)
> +static void cli_cifs_rename_done(struct tevent_req *subreq)
>  {
>  	struct tevent_req *req = tevent_req_callback_data(
>  				subreq, struct tevent_req);
> -- 
> 2.9.3
> 
> 
> From 460c04c2f801a1425857bb014cc1337a12626251 Mon Sep 17 00:00:00 2001
> From: Uri Simchoni <uri at samba.org>
> Date: Sun, 26 Mar 2017 09:14:43 +0300
> Subject: [PATCH v2 7/8] s3-libsmb: fail rename and replace inside cifs variant
> 
> Another refactoring step - fail request to rename and
> replace existing file from within the CIFS version,
> allowing the soon-to-be-added SMB version to succeed.
> 
> Signed-off-by: Uri Simchoni <uri at samba.org>
> ---
>  source3/libsmb/clifile.c | 30 +++++++++++++++++-------------
>  source3/libsmb/proto.h   |  9 +++++----
>  2 files changed, 22 insertions(+), 17 deletions(-)
> 
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index b5f29b6..44fde38 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -996,15 +996,18 @@ static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
>  					       struct tevent_context *ev,
>  					       struct cli_state *cli,
>  					       const char *fname_src,
> -					       const char *fname_dst);
> +					       const char *fname_dst,
> +					       bool replace);
>  
>  struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
>  				   struct tevent_context *ev,
>  				   struct cli_state *cli,
>  				   const char *fname_src,
> -				   const char *fname_dst)
> +				   const char *fname_dst,
> +				   bool replace)
>  {
> -	return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src, fname_dst);
> +	return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src, fname_dst,
> +				    replace);
>  }
>  
>  static void cli_cifs_rename_done(struct tevent_req *subreq);
> @@ -1017,7 +1020,8 @@ static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
>  					       struct tevent_context *ev,
>  					       struct cli_state *cli,
>  					       const char *fname_src,
> -					       const char *fname_dst)
> +					       const char *fname_dst,
> +					       bool replace)
>  {
>  	struct tevent_req *req = NULL, *subreq = NULL;
>  	struct cli_cifs_rename_state *state = NULL;
> @@ -1030,6 +1034,14 @@ static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
>  		return NULL;
>  	}
>  
> +	if (replace) {
> +		/*
> +		 * CIFS doesn't support replace
> +		 */
> +		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
> +		return tevent_req_post(req, ev);
> +	}
> +
>  	SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
>  
>  	bytes = talloc_array(state, uint8_t, 1);
> @@ -1113,21 +1125,13 @@ NTSTATUS cli_rename(struct cli_state *cli,
>  		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;
>  		goto fail;
>  	}
>  
> -	req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
> +	req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
>  	if (req == NULL) {
>  		status = NT_STATUS_NO_MEMORY;
>  		goto fail;
> diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
> index 57a45e3..b453733 100644
> --- a/source3/libsmb/proto.h
> +++ b/source3/libsmb/proto.h
> @@ -325,10 +325,11 @@ NTSTATUS cli_posix_chown(struct cli_state *cli,
>  			uid_t uid,
>  			gid_t gid);
>  struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
> -                                struct tevent_context *ev,
> -                                struct cli_state *cli,
> -                                const char *fname_src,
> -                                const char *fname_dst);
> +				   struct tevent_context *ev,
> +				   struct cli_state *cli,
> +				   const char *fname_src,
> +				   const char *fname_dst,
> +				   bool replace);
>  NTSTATUS cli_rename_recv(struct tevent_req *req);
>  NTSTATUS cli_rename(struct cli_state *cli,
>  		    const char *fname_src,
> -- 
> 2.9.3
> 
> 
> From c0b958c1a128d63519001bfe6d180340e7bc9c80 Mon Sep 17 00:00:00 2001
> From: Uri Simchoni <uri at samba.org>
> Date: Sun, 26 Mar 2017 12:02:09 +0300
> Subject: [PATCH v2 8/8] s3-libsmb: support rename and replace for SMB1
> 
> Add cli_smb1_rename_send() which renames a file via
> setting FileRenameInformation.
> 
> Curretly this path is invoked only if replacing
> an existing file is requested. This is because as far
> as I can see, Windows uses CIFS rename for anything below
> SMB2.
> 
> Signed-off-by: Uri Simchoni <uri at samba.org>
> ---
>  source3/libsmb/clifile.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 92 insertions(+), 2 deletions(-)
> 
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index 44fde38..cc1d1e4 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -999,6 +999,13 @@ static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
>  					       const char *fname_dst,
>  					       bool replace);
>  
> +static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
> +					       struct tevent_context *ev,
> +					       struct cli_state *cli,
> +					       const char *fname_src,
> +					       const char *fname_dst,
> +					       bool replace);
> +
>  struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
>  				   struct tevent_context *ev,
>  				   struct cli_state *cli,
> @@ -1006,8 +1013,91 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
>  				   const char *fname_dst,
>  				   bool replace)
>  {
> -	return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src, fname_dst,
> -				    replace);
> +	if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
> +		return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
> +					    fname_dst, replace);
> +	} else {
> +		return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
> +					    fname_dst, replace);
> +	}
> +}
> +
> +struct cli_smb1_rename_state {
> +	uint8_t *data;
> +};
> +
> +static void cli_smb1_rename_done(struct tevent_req *subreq);
> +
> +static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
> +					       struct tevent_context *ev,
> +					       struct cli_state *cli,
> +					       const char *fname_src,
> +					       const char *fname_dst,
> +					       bool replace)
> +{
> +	NTSTATUS status;
> +	struct tevent_req *req = NULL, *subreq = NULL;
> +	struct cli_smb1_rename_state *state = NULL;
> +	smb_ucs2_t *converted_str = NULL;
> +	size_t converted_size_bytes = 0;
> +
> +	req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
> +	if (req == NULL) {
> +		return NULL;
> +	}
> +
> +	if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
> +			      &converted_size_bytes)) {
> +		status = NT_STATUS_INVALID_PARAMETER;
> +		goto fail;
> +	}
> +
> +	/* W2K8 insists the dest name is not null
> +	   terminated. Remove the last 2 zero bytes
> +	   and reduce the name length. */
> +
> +	if (converted_size_bytes < 2) {
> +		status = NT_STATUS_INVALID_PARAMETER;
> +		goto fail;
> +	}
> +	converted_size_bytes -= 2;
> +
> +	state->data =
> +	    talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
> +	if (state->data == NULL) {
> +		status = NT_STATUS_NO_MEMORY;
> +		goto fail;
> +	}
> +
> +	if (replace) {
> +		SCVAL(state->data, 0, 1);
> +	}
> +
> +	SIVAL(state->data, 8, converted_size_bytes);
> +	memcpy(state->data + 12, converted_str, converted_size_bytes);
> +
> +	TALLOC_FREE(converted_str);
> +
> +	subreq = cli_setpathinfo_send(
> +	    state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
> +	    talloc_get_size(state->data));
> +	if (tevent_req_nomem(subreq, req)) {
> +		status = NT_STATUS_NO_MEMORY;
> +		goto fail;
> +	}
> +	tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
> +	return req;
> +
> +fail:
> +	TALLOC_FREE(converted_str);
> +	tevent_req_nterror(req, status);
> +	return tevent_req_post(req, ev);
> +}
> +
> +static void cli_smb1_rename_done(struct tevent_req *subreq)
> +{
> +	NTSTATUS status = cli_setpathinfo_recv(subreq);
> +	tevent_req_simple_finish_ntstatus(subreq, status);
>  }
>  
>  static void cli_cifs_rename_done(struct tevent_req *subreq);
> -- 
> 2.9.3
> 




More information about the samba-technical mailing list