Based on patch by Michael Müller.
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com
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 );
Nikolay Sivov (@nsivov) commented about dlls/kernelbase/file.c:
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);
- }
From what I can tell this does not work. You'll need delete access on dest handle, which according to the test you can't have. Please make sure you don't need to undo last DeleteFile() test.
This merge request was closed by Alistair Leslie-Hughes.