[PATCH 1/1] kernelbase: Add support for progress callback in CopyFileEx.
Alistair Leslie-Hughes
wine at gitlab.winehq.org
Fri Apr 29 01:32:15 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 | 6 ---
dlls/kernelbase/file.c | 76 ++++++++++++++++++++++++++++++++------
2 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 378078c20d5..2dec65e3a0e 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -1178,23 +1178,17 @@ 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");
retok = CopyFileExA(source, NULL, copy_progress_cb, hfile, NULL, 0);
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 8ae982294f6..f314382e4fa 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;
@@ -559,14 +586,30 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
}
}
- if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ if ((h2 = CreateFileW( dest, GENERIC_WRITE | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
(flags & COPY_FILE_FAIL_IF_EXISTS) ? CREATE_NEW : CREATE_ALWAYS,
info.FileAttributes, h1 )) == INVALID_HANDLE_VALUE)
{
- WARN("Unable to open dest %s\n", debugstr_w(dest));
- HeapFree( GetProcessHeap(), 0, buffer );
- CloseHandle( h1 );
- return FALSE;
+ /* User has the file opened without FILE_SHARE_DELETE */
+ if (GetLastError() == ERROR_SHARING_VIOLATION)
+ h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ (flags & COPY_FILE_FAIL_IF_EXISTS) ? CREATE_NEW : CREATE_ALWAYS,
+ info.FileAttributes, h1 );
+ if (h2 == INVALID_HANDLE_VALUE)
+ {
+ WARN("Unable to open dest %s\n", debugstr_w(dest));
+ HeapFree( GetProcessHeap(), 0, buffer );
+ CloseHandle( h1 );
+ 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)
@@ -578,13 +621,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/13
More information about the wine-devel
mailing list