From 3551eb7cbfb3bf7573c00d349def884cd70c89c7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 25 Feb 2010 11:15:16 -0800 Subject: Implement rename/move in SMB2 from Windows7. Jeremy. --- source3/include/trans2.h | 1 + source3/smbd/smb2_setinfo.c | 3 +- source3/smbd/trans2.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) (limited to 'source3') diff --git a/source3/include/trans2.h b/source3/include/trans2.h index 3759d59681..d42554551a 100644 --- a/source3/include/trans2.h +++ b/source3/include/trans2.h @@ -294,6 +294,7 @@ Byte offset Type name description #define SMB_FILE_ACCESS_INFORMATION 1008 #define SMB_FILE_NAME_INFORMATION 1009 #define SMB_FILE_RENAME_INFORMATION 1010 +#define SMB2_FILE_RENAME_INFORMATION_INTERNAL 0xFF0A /* Internal mapped version. */ #define SMB_FILE_LINK_INFORMATION 1011 #define SMB_FILE_NAMES_INFORMATION 1012 #define SMB_FILE_DISPOSITION_INFORMATION 1013 diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c index f3e3fc964f..a5193eba7a 100644 --- a/source3/smbd/smb2_setinfo.c +++ b/source3/smbd/smb2_setinfo.c @@ -213,7 +213,8 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx, file_info_level = in_file_info_class + 1000; if (file_info_level == SMB_FILE_RENAME_INFORMATION) { - file_info_level = 0xFF00 + in_file_info_class; + /* SMB2_FILE_RENAME_INFORMATION_INTERNAL == 0xFF00 + in_file_info_class */ + file_info_level = SMB2_FILE_RENAME_INFORMATION_INTERNAL; } if (fsp->is_directory || fsp->fh->fd == -1) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 073bee628a..eff5fba676 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5887,6 +5887,107 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new); } +/**************************************************************************** + Deal with SMB2_FILE_RENAME_INFORMATION_INTERNAL +****************************************************************************/ + +static NTSTATUS smb2_file_rename_information(connection_struct *conn, + struct smb_request *req, + const char *pdata, + int total_data, + files_struct *fsp, + struct smb_filename *smb_fname_src) +{ + bool overwrite; + uint32_t len; + char *newname = NULL; + struct smb_filename *smb_fname_dst = NULL; + NTSTATUS status = NT_STATUS_OK; + TALLOC_CTX *ctx = talloc_tos(); + + if (!fsp) { + return NT_STATUS_INVALID_HANDLE; + } + + if (total_data < 20) { + return NT_STATUS_INVALID_PARAMETER; + } + + overwrite = (CVAL(pdata,0) ? True : False); + len = IVAL(pdata,16); + + if (len > (total_data - 20) || (len == 0)) { + return NT_STATUS_INVALID_PARAMETER; + } + + srvstr_get_path(ctx, pdata, req->flags2, &newname, + &pdata[20], len, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10,("smb_file_rename_information: got name |%s|\n", + newname)); + +#if 0 + /* Check the new name has no '/' characters. */ + if (strchr_m(newname, '/')) { + return NT_STATUS_NOT_SUPPORTED; + } +#endif + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + 0, + NULL, + &smb_fname_dst); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (fsp && fsp->base_fsp) { + /* newname must be a stream name. */ + if (newname[0] != ':') { + return NT_STATUS_NOT_SUPPORTED; + } + + /* Create an smb_fname to call rename_internals_fsp() with. */ + status = create_synthetic_smb_fname(talloc_tos(), + fsp->base_fsp->fsp_name->base_name, newname, NULL, + &smb_fname_dst); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + /* + * Set the original last component, since + * rename_internals_fsp() requires it. + */ + smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, + newname); + if (smb_fname_dst->original_lcomp == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + } + + DEBUG(10,("smb_file_rename_information: " + "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp_str_dbg(fsp), + smb_fname_str_dbg(smb_fname_dst))); + status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0, + overwrite); + + out: + TALLOC_FREE(smb_fname_dst); + return status; +} + + /**************************************************************************** Deal with SMB_FILE_RENAME_INFORMATION. ****************************************************************************/ @@ -7475,6 +7576,14 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, break; } + case SMB2_FILE_RENAME_INFORMATION_INTERNAL: + { + /* SMB2 rename information. */ + status = smb2_file_rename_information(conn, req, + pdata, total_data, + fsp, smb_fname); + break; + } #if defined(HAVE_POSIX_ACLS) case SMB_SET_POSIX_ACL: { -- cgit