[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