[PATCH v2 6/6] kernel32: Reimplement MoveFileWithProgress() on top of NtSetInformationFile(FileRenameInformation).

Zebediah Figura z.figura12 at gmail.com
Thu Mar 5 20:47:17 CST 2020


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/kernel32/path.c       | 104 +++++++------------------------------
 dlls/kernel32/tests/file.c |   8 +--
 2 files changed, 22 insertions(+), 90 deletions(-)

diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index 617b14a7178..31652d3164b 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -448,14 +448,14 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
                                    LPPROGRESS_ROUTINE fnProgress,
                                    LPVOID param, DWORD flag )
 {
+    FILE_RENAME_INFORMATION *rename_info;
     FILE_BASIC_INFORMATION info;
     UNICODE_STRING nt_name;
     OBJECT_ATTRIBUTES attr;
     IO_STATUS_BLOCK io;
     NTSTATUS status;
-    HANDLE source_handle = 0, dest_handle = 0;
-    ANSI_STRING source_unix, dest_unix;
-    DWORD options;
+    HANDLE source_handle = 0;
+    ULONG size;
 
     TRACE("(%s,%s,%p,%p,%04x)\n",
           debugstr_w(source), debugstr_w(dest), fnProgress, param, flag );
@@ -473,8 +473,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
         SetLastError( ERROR_PATH_NOT_FOUND );
         return FALSE;
     }
-    source_unix.Buffer = NULL;
-    dest_unix.Buffer = NULL;
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;
     attr.Attributes = OBJ_CASE_INSENSITIVE;
@@ -484,8 +482,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
 
     status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io,
                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT );
-    if (status == STATUS_SUCCESS)
-        status = wine_nt_to_unix_file_name( &nt_name, &source_unix, FILE_OPEN, FALSE );
     RtlFreeUnicodeString( &nt_name );
     if (status != STATUS_SUCCESS)
     {
@@ -499,101 +495,37 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
         goto error;
     }
 
-    /* we must have write access to the destination, and it must */
-    /* not exist except if MOVEFILE_REPLACE_EXISTING is set */
-
     if (!RtlDosPathNameToNtPathName_U( dest, &nt_name, NULL, NULL ))
     {
         SetLastError( ERROR_PATH_NOT_FOUND );
         goto error;
     }
-    options = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT;
-    if (flag & MOVEFILE_WRITE_THROUGH)
-        options |= FILE_WRITE_THROUGH;
-    status = NtOpenFile( &dest_handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
-                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, options );
-    if (status == STATUS_SUCCESS)  /* destination exists */
-    {
-        if (!(flag & MOVEFILE_REPLACE_EXISTING))
-        {
-            if (!is_same_file( source_handle, dest_handle ))
-            {
-                SetLastError( ERROR_ALREADY_EXISTS );
-                RtlFreeUnicodeString( &nt_name );
-                goto error;
-            }
-        }
-        else if (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) /* cannot replace directory */
-        {
-            SetLastError( ERROR_ACCESS_DENIED );
-            goto error;
-        }
 
-        NtClose( dest_handle );
-        dest_handle = NULL;
-    }
-    else if (status != STATUS_OBJECT_NAME_NOT_FOUND)
-    {
-        SetLastError( RtlNtStatusToDosError(status) );
-        RtlFreeUnicodeString( &nt_name );
+    size = offsetof( FILE_RENAME_INFORMATION, FileName ) + nt_name.Length;
+    if (!(rename_info = HeapAlloc( GetProcessHeap(), 0, size )))
         goto error;
-    }
 
-    status = wine_nt_to_unix_file_name( &nt_name, &dest_unix, FILE_OPEN_IF, FALSE );
+    rename_info->ReplaceIfExists = !!(flag & MOVEFILE_REPLACE_EXISTING);
+    rename_info->RootDirectory = NULL;
+    rename_info->FileNameLength = nt_name.Length;
+    memcpy( rename_info->FileName, nt_name.Buffer, nt_name.Length );
     RtlFreeUnicodeString( &nt_name );
-    if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
-    {
-        SetLastError( RtlNtStatusToDosError(status) );
-        goto error;
-    }
-
-    /* now perform the rename */
-
-    if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1)
+    status = NtSetInformationFile( source_handle, &io, rename_info, size, FileRenameInformation );
+    if (status == STATUS_NOT_SAME_DEVICE && (flag & MOVEFILE_COPY_ALLOWED))
     {
-        if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED))
-        {
-            NtClose( source_handle );
-            RtlFreeAnsiString( &source_unix );
-            RtlFreeAnsiString( &dest_unix );
-            if (!CopyFileExW( source, dest, fnProgress, param, NULL,
-                              flag & MOVEFILE_REPLACE_EXISTING ?
-                              0 : COPY_FILE_FAIL_IF_EXISTS ))
-                return FALSE;
-            return DeleteFileW( source );
-        }
-        FILE_SetDosError();
-        /* if we created the destination, remove it */
-        if (io.Information == FILE_CREATED) unlink( dest_unix.Buffer );
-        goto error;
-    }
-
-    /* fixup executable permissions */
-
-    if (is_executable( source ) != is_executable( dest ))
-    {
-        struct stat fstat;
-        if (stat( dest_unix.Buffer, &fstat ) != -1)
-        {
-            if (is_executable( dest ))
-                /* set executable bit where read bit is set */
-                fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
-            else
-                fstat.st_mode &= ~0111;
-            chmod( dest_unix.Buffer, fstat.st_mode );
-        }
+        NtClose( source_handle );
+        if (!CopyFileExW( source, dest, fnProgress, param, NULL,
+                          flag & MOVEFILE_REPLACE_EXISTING ?
+                          0 : COPY_FILE_FAIL_IF_EXISTS ))
+            return FALSE;
+        return DeleteFileW( source );
     }
 
     NtClose( source_handle );
-    RtlFreeAnsiString( &source_unix );
-    RtlFreeAnsiString( &dest_unix );
-    return TRUE;
+    return set_ntstatus( status );
 
 error:
     if (source_handle) NtClose( source_handle );
-    if (dest_handle) NtClose( dest_handle );
-    RtlFreeAnsiString( &source_unix );
-    RtlFreeAnsiString( &dest_unix );
     return FALSE;
 }
 
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index ad0c694f410..785bd60c237 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -5631,7 +5631,7 @@ static void test_move_file(void)
     SetLastError(0xdeadbeef);
     ret = MoveFileA( "winetest_dir3", "winetest_dir2" );
     ok(!ret, "expected failure\n");
-    todo_wine ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError());
+    ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError());
 
     file = CreateFileA( "winetest_file3", DELETE, 0, NULL, OPEN_EXISTING, 0, 0 );
     ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError());
@@ -5658,14 +5658,14 @@ static void test_move_file(void)
     ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError());
     SetLastError(0xdeadbeef);
     ret = MoveFileExA( "winetest_file2", "winetest_file1", MOVEFILE_REPLACE_EXISTING );
-    todo_wine ok(!ret, "expected failure\n");
-    todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError());
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError());
     CloseHandle( file );
 
     SetLastError(0xdeadbeef);
     ret = MoveFileExA( "winetest_file2", "winetest_dir2", MOVEFILE_REPLACE_EXISTING );
     ok(!ret, "expected failure\n");
-    todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError());
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     ret = MoveFileExA( "winetest_dir3", "winetest_dir2", MOVEFILE_REPLACE_EXISTING );
-- 
2.25.1




More information about the wine-devel mailing list