Commit 8bd36bbf authored by Michael Müller's avatar Michael Müller Committed by Vitaly Lipatov

kernelbase: Add support for progress callback in CopyFileEx.

parent 24fa4b58
......@@ -1161,23 +1161,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);
......
......@@ -500,11 +500,16 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
{
static const int buffer_size = 65536;
HANDLE h1, h2;
FILE_BASIC_INFORMATION info;
FILE_NETWORK_OPEN_INFORMATION info;
FILE_BASIC_INFORMATION basic_info;
IO_STATUS_BLOCK io;
DWORD count;
BOOL ret = FALSE;
char *buffer;
LARGE_INTEGER size;
LARGE_INTEGER transferred;
DWORD cbret;
DWORD source_access = GENERIC_READ;
if (!source || !dest)
{
......@@ -526,7 +531,10 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
if (flags & COPY_FILE_OPEN_SOURCE_FOR_WRITE)
FIXME("COPY_FILE_OPEN_SOURCE_FOR_WRITE is not supported\n");
if ((h1 = CreateFileW( source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
if (flags & COPY_FILE_OPEN_SOURCE_FOR_WRITE)
source_access |= GENERIC_WRITE;
if ((h1 = CreateFileW( source, source_access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
{
WARN("Unable to open source %s\n", debugstr_w(source));
......@@ -534,7 +542,7 @@ 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));
HeapFree( GetProcessHeap(), 0, buffer );
......@@ -560,7 +568,11 @@ 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 &&
/* retry without DELETE if we got a 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 )) == INVALID_HANDLE_VALUE)
{
......@@ -570,6 +582,29 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
return FALSE;
}
size = info.EndOfFile;
transferred.QuadPart = 0;
if (progress)
{
cbret = progress( size, transferred, size, transferred, 1,
CALLBACK_STREAM_SWITCH, h1, h2, param );
if (cbret == PROGRESS_QUIET)
progress = NULL;
else if (cbret == PROGRESS_STOP)
{
SetLastError( ERROR_REQUEST_ABORTED );
goto done;
}
else if (cbret == PROGRESS_CANCEL)
{
BOOLEAN disp = TRUE;
SetFileInformationByHandle( h2, FileDispositionInfo, &disp, sizeof(disp) );
SetLastError( ERROR_REQUEST_ABORTED );
goto done;
}
}
while (ReadFile( h1, buffer, buffer_size, &count, NULL ) && count)
{
char *p = buffer;
......@@ -579,13 +614,38 @@ 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;
if (progress)
{
transferred.QuadPart += res;
cbret = progress( size, transferred, size, transferred, 1,
CALLBACK_CHUNK_FINISHED, h1, h2, param );
if (cbret == PROGRESS_QUIET)
progress = NULL;
else if (cbret == PROGRESS_STOP)
{
SetLastError( ERROR_REQUEST_ABORTED );
goto done;
}
else if (cbret == PROGRESS_CANCEL)
{
BOOLEAN disp = TRUE;
SetFileInformationByHandle( h2, FileDispositionInfo, &disp, sizeof(disp) );
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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment