From: Alistair Leslie-Hughes leslie_alistair@hotmail.com
Based on patch by Michael Müller.
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@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 );