[PATCH 1/1] kernelbase: Add support for progress callback in CopyFileEx.

Alistair Leslie-Hughes wine at gitlab.winehq.org
Tue Apr 26 00:25:05 CDT 2022


From: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>

Based on patch by Michael Müller.

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/kernel32/tests/file.c |  7 +----
 dlls/kernelbase/file.c     | 58 ++++++++++++++++++++++++++++++++++----
 2 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 1fb9e98cf41..4f47dd8a51f 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -1176,21 +1176,16 @@ static void test_CopyFileEx(void)
     ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError());
     SetLastError(0xdeadbeef);
     retok = CopyFileExA(source, dest, copy_progress_cb, hfile, NULL, 0);
-    todo_wine
     ok(!retok, "CopyFileExA unexpectedly succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %ld\n", GetLastError());
     ok(GetFileAttributesA(dest) != INVALID_FILE_ATTRIBUTES, "file was deleted\n");
 
     hfile = CreateFileA(dest, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                         NULL, OPEN_EXISTING, 0, 0);
-    todo_wine
     ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError());
     SetLastError(0xdeadbeef);
     retok = CopyFileExA(source, dest, copy_progress_cb, hfile, NULL, 0);
-    todo_wine
     ok(!retok, "CopyFileExA unexpectedly succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %ld\n", GetLastError());
     todo_wine
     ok(GetFileAttributesA(dest) == INVALID_FILE_ATTRIBUTES, "file was not deleted\n");
@@ -1205,7 +1200,7 @@ static void test_CopyFileEx(void)
     ret = DeleteFileA(source);
     ok(ret, "DeleteFileA failed with error %ld\n", GetLastError());
     ret = DeleteFileA(dest);
-    ok(!ret, "DeleteFileA unexpectedly succeeded\n");
+    todo_wine ok(!ret, "DeleteFileA unexpectedly succeeded\n");
 }
 
 /*
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 8ae982294f6..840aacc4b92 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -490,16 +490,43 @@ BOOL WINAPI DECLSPEC_HOTPATCH AreFileApisANSI(void)
     return !oem_file_apis;
 }
 
+static BOOL call_progress_callback(LPPROGRESS_ROUTINE *callback, LARGE_INTEGER size, LARGE_INTEGER transferred,
+                                  DWORD cbtype, HANDLE src, HANDLE dest, void *param)
+{
+    DWORD cbret;
+
+    if (!*callback)
+        return TRUE;
+
+    cbret = (*callback)( size, transferred, size, transferred, 1, cbtype, src, dest, param );
+    if (cbret == PROGRESS_QUIET)
+    {
+        *callback = NULL;
+        return TRUE;
+    }
+    else if (cbret == PROGRESS_CANCEL)
+    {
+        FILE_DISPOSITION_INFORMATION fdi;
+        IO_STATUS_BLOCK io;
+
+        fdi.DoDeleteFile = TRUE;
+        NtSetInformationFile(dest, &io, &fdi, sizeof(fdi), FileDispositionInformation);
+    }
+
+    return cbret == PROGRESS_CONTINUE;
+}
 
 /***********************************************************************
  *	CopyFileExW   (kernelbase.@)
  */
-BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUTINE progress,
+BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUTINE callback,
                          void *param, BOOL *cancel_ptr, DWORD flags )
 {
     static const int buffer_size = 65536;
     HANDLE h1, h2;
-    FILE_BASIC_INFORMATION info;
+    FILE_NETWORK_OPEN_INFORMATION info;
+    FILE_BASIC_INFORMATION basic_info;
+    LARGE_INTEGER transferred;
     IO_STATUS_BLOCK io;
     DWORD count;
     BOOL ret = FALSE;
@@ -533,9 +560,9 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
         return FALSE;
     }
 
-    if (!set_ntstatus( NtQueryInformationFile( h1, &io, &info, sizeof(info), FileBasicInformation )))
+    if (!set_ntstatus( NtQueryInformationFile( h1, &io, &info, sizeof(info), FileNetworkOpenInformation )))
     {
-        WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
+        WARN("NtQueryInformationFile returned error for %s\n", debugstr_w(source));
         HeapFree( GetProcessHeap(), 0, buffer );
         CloseHandle( h1 );
         return FALSE;
@@ -569,6 +596,14 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
         return FALSE;
     }
 
+    transferred.QuadPart = 0;
+
+    if (!(call_progress_callback(&callback, info.EndOfFile, transferred, CALLBACK_STREAM_SWITCH, h1, h2, param)))
+    {
+        SetLastError( ERROR_REQUEST_ABORTED );
+        goto done;
+    }
+
     while (ReadFile( h1, buffer, buffer_size, &count, NULL ) && count)
     {
         char *p = buffer;
@@ -578,13 +613,24 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
             p += res;
             count -= res;
+
+            transferred.QuadPart += res;
+            if (!(call_progress_callback(&callback, info.EndOfFile, transferred, CALLBACK_CHUNK_FINISHED, h1, h2, param)))
+            {
+                SetLastError( ERROR_REQUEST_ABORTED );
+                goto done;
+            }
         }
     }
     ret =  TRUE;
 done:
     /* Maintain the timestamp of source file to destination file */
-    info.FileAttributes = 0;
-    NtSetInformationFile( h2, &io, &info, sizeof(info), FileBasicInformation );
+    basic_info.CreationTime = info.CreationTime;
+    basic_info.LastAccessTime = info.LastAccessTime;
+    basic_info.LastWriteTime = info.LastWriteTime;
+    basic_info.ChangeTime = info.ChangeTime;
+    basic_info.FileAttributes = 0;
+    NtSetInformationFile( h2, &io, &basic_info, sizeof(basic_info), FileBasicInformation );
     HeapFree( GetProcessHeap(), 0, buffer );
     CloseHandle( h1 );
     CloseHandle( h2 );
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/2



More information about the wine-devel mailing list