Implement rename/move in SMB2 from Windows7.
authorJeremy Allison <jra@samba.org>
Thu, 25 Feb 2010 19:15:16 +0000 (11:15 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 25 Feb 2010 19:15:16 +0000 (11:15 -0800)
Jeremy.

source3/include/trans2.h
source3/smbd/smb2_setinfo.c
source3/smbd/trans2.c

index 3759d59681161aff4d1db6b3e29882404b60b4cf..d42554551a7e95da04116252163f36f85ffc00ea 100644 (file)
@@ -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 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
 #define SMB_FILE_LINK_INFORMATION                      1011
 #define SMB_FILE_NAMES_INFORMATION                     1012
 #define SMB_FILE_DISPOSITION_INFORMATION               1013
index f3e3fc964f9855750ff7a1d142056efa05fcb049..a5193eba7a0f1d5e4933a98408597047da24fee6 100644 (file)
@@ -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 = 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) {
                }
 
                if (fsp->is_directory || fsp->fh->fd == -1) {
index 073bee628ad7931eacdd08dff08d2ae14e3a5286..eff5fba6760649b73e9fb3ac14876aa9561ed8d7 100644 (file)
@@ -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);
 }
 
        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.
 ****************************************************************************/
 /****************************************************************************
  Deal with SMB_FILE_RENAME_INFORMATION.
 ****************************************************************************/
@@ -7475,6 +7576,14 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
                        break;
                }
 
                        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:
                {
 #if defined(HAVE_POSIX_ACLS)
                case SMB_SET_POSIX_ACL:
                {