[PATCH] kernelbase: Add support for progress callback in CopyFileEx.
Nikolay Sivov
nsivov at codeweavers.com
Thu Apr 21 05:19:25 CDT 2022
On 4/21/22 12:53, Alistair Leslie-Hughes wrote:
>
> +static DWORD call_progress_dialog(LPPROGRESS_ROUTINE progress, LARGE_INTEGER size, LARGE_INTEGER transferred,
> + DWORD cbtype, HANDLE h1, HANDLE h2, void *param)
> +{
> + DWORD cbret;
> +
> + cbret = progress( size, transferred, size, transferred, 1, cbtype, h1, h2, param );
> + if (cbret == PROGRESS_STOP)
> + SetLastError( ERROR_REQUEST_ABORTED );
> + else if (cbret == PROGRESS_CANCEL)
> + {
> + BOOLEAN disp = TRUE;
> + SetFileInformationByHandle( h2, FileDispositionInfo, &disp, sizeof(disp) );
Might be better to use Nt* function here, and corresponding structure
instead of a bare BOOLEAN.
> + SetLastError( ERROR_REQUEST_ABORTED );
> + }
> +
> + return cbret;
> +}
It seems returning NTSTATUS here and setting last error once would be
easier to follow.
>
> /***********************************************************************
> * CopyFileExW (kernelbase.@)
> @@ -499,11 +516,14 @@ 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 transferred;
> + DWORD cbret;
>
> if (!source || !dest)
> {
> @@ -533,7 +553,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 )))
Why is this necessary?
> {
> WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
Outdated message text (not caused by this patch of course).
> HeapFree( GetProcessHeap(), 0, buffer );
> @@ -569,6 +589,17 @@ BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUT
> return FALSE;
> }
>
> + if (progress)
> + {
> + transferred.QuadPart = 0;
> +
> + cbret = call_progress_dialog(progress, info.EndOfFile, transferred, CALLBACK_STREAM_SWITCH, h1, h2, param);
> + if (cbret == PROGRESS_QUIET)
> + progress = NULL;
> + else if (cbret != PROGRESS_CONTINUE)
> + goto done;
> + }
> +
> while (ReadFile( h1, buffer, buffer_size, &count, NULL ) && count)
> {
> char *p = buffer;
> @@ -578,13 +609,28 @@ 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 = call_progress_dialog(progress, info.EndOfFile, transferred, CALLBACK_CHUNK_FINISHED, h1, h2, param);
> + if (cbret == PROGRESS_QUIET)
> + progress = NULL;
> + else if (cbret != PROGRESS_CONTINUE)
> + goto done;
> + }
> }
It should be possible to avoid duplication of continue/quite conditions,
and progress != null check.
> }
> 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 );
More information about the wine-devel
mailing list