[PATCH 1/2] kernel32: Support MOVEFILE_WRITE_THROUGH / CopyFileExW progress

Tom Watson coder at tommywatson.com
Sat Mar 3 12:02:07 CST 2018


Signed-off-by: Tom Watson <coder at tommywatson.com>
---
 dlls/kernel32/path.c | 106
++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 101 insertions(+), 5 deletions(-)

diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index a389743171..98891cde6d 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -43,6 +43,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(file);

 #define MAX_PATHNAME_LEN        1024

+/* struct to hold progress function callback for MoveFileWithProgressW */
+typedef struct {
+    LPPROGRESS_ROUTINE progress;
+    VOID *data;
+    BOOL status;                    /* flush successful */
+} MFWFData;
+
 static int path_safe_mode = -1;  /* path mode set by SetSearchPathMode */

 /* check if a file name is for an executable file (.exe or .com) */
@@ -1159,10 +1166,14 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR
dest,
     static const int buffer_size = 65536;
     HANDLE h1, h2;
     BY_HANDLE_FILE_INFORMATION info;
+    LARGE_INTEGER file_position,file_size;
     DWORD count;
     BOOL ret = FALSE;
     char *buffer;
+    DWORD progressExit = 0;

+    /* init file size/position */
+    file_position.QuadPart=file_size.QuadPart=0;
     if (!source || !dest)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
@@ -1193,6 +1204,10 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,
         return FALSE;
     }

+    /* update total size */
+    file_size.LowPart = info.nFileSizeLow;
+    file_size.HighPart = info.nFileSizeHigh;
+
     if (!(flags & COPY_FILE_FAIL_IF_EXISTS))
     {
         BOOL same_file = FALSE;
@@ -1231,6 +1246,32 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,
             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
             p += res;
             count -= res;
+            file_position.QuadPart += res;
+        }
+        /* Call progress function ? */
+        if (progress != NULL) {
+            progressExit = progress(file_size, file_position, file_size,
+                     file_position, 1, CALLBACK_CHUNK_FINISHED, h1, h2,
param);
+            switch (progressExit) {
+                case PROGRESS_CONTINUE:
+                    // keep at it
+                    break;
+                case PROGRESS_QUIET:
+                    // requested not to be called again
+                    progress = NULL;
+                    break;
+                case PROGRESS_CANCEL:
+                    // cancel and clean up
+                    CloseHandle( h2 );
+                    h2 = INVALID_HANDLE_VALUE;
+                    DeleteFileW( dest );
+                    SetLastError( ERROR_REQUEST_ABORTED );
+                    goto done;
+                case PROGRESS_STOP:
+                    // do nothing, allow for a restart (??)
+                    SetLastError( ERROR_REQUEST_ABORTED );
+                    goto done;
+            }
         }
     }
     ret =  TRUE;
@@ -1239,7 +1280,10 @@ done:
     SetFileTime(h2, NULL, NULL, &info.ftLastWriteTime);
     HeapFree( GetProcessHeap(), 0, buffer );
     CloseHandle( h1 );
-    CloseHandle( h2 );
+    if (h2 != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle( h2 );
+    }
     return ret;
 }

@@ -1269,6 +1313,39 @@ BOOL WINAPI CopyFileExA(LPCSTR sourceFilename,
LPCSTR destFilename,
 }


+/**************************************************************************
+ *           moveFileWFlush
+ */
+DWORD CALLBACK moveFileWFlush(LARGE_INTEGER TotalFileSize,
+                              LARGE_INTEGER TotalBytesTransferred,
+                              LARGE_INTEGER StreamSize,
+                              LARGE_INTEGER StreamBytesTransferred,
+                              DWORD dwStreamNumber, DWORD dwCallbackReason,
+                              HANDLE hSourceFile,HANDLE hDestinationFile,
+                              LPVOID lpData )
+{
+    MFWFData *data = (MFWFData *)lpData;
+    DWORD rval = 0;
+
+    if ( data->progress != NULL)
+    {
+        rval = data->progress( TotalFileSize, TotalBytesTransferred,
+                               StreamSize, StreamBytesTransferred,
+                               dwStreamNumber, dwCallbackReason,
+                               hSourceFile, hDestinationFile, data->data);
+    }
+    /* continue the copy? */
+    if (rval == 0 ) {
+        /* completed the copy? */
+        if (TotalFileSize.QuadPart == TotalBytesTransferred.QuadPart)
+        {
+            /* flush the data */
+            data->status = FlushFileBuffers(hDestinationFile)?1:0;
+        }
+    }
+    return rval;
+}
+
 /**************************************************************************
  *           MoveFileWithProgressW   (KERNEL32.@)
  */
@@ -1293,9 +1370,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source,
LPCWSTR dest,
     if (!dest)
         return DeleteFileW( source );

-    if (flag & MOVEFILE_WRITE_THROUGH)
-        FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");
-
     /* check if we are allowed to rename the source */

     if (!RtlDosPathNameToNtPathName_U( source, &nt_name, NULL, NULL ))
@@ -1369,8 +1443,30 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source,
LPCWSTR dest,
     }

     /* now perform the rename */
+    if ((flag & MOVEFILE_WRITE_THROUGH) && !(flag &
MOVEFILE_DELAY_UNTIL_REBOOT))
+    {
+        /* save the original progress function && param, set status to 0 */
+        MFWFData data;
+        data.progress = fnProgress;
+        data.data = param;
+        data.status = 0;
+        /* try to copy the file, if it fails or the flush failed, set
error */
+        if (CopyFileExW( source, dest, moveFileWFlush, &data, NULL, 0) == 0
+         || !data.status) {
+            /* failed, set error */
+            FILE_SetDosError();
+            goto error;
+        }

-    if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1)
+        /* delete the source file */
+        if (!DeleteFileW( source ))
+        {
+            /* failed, set error */
+            FILE_SetDosError();
+            goto error;
+        }
+    }
+    else if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1)
     {
         if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED))
         {
-- 
2.14.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20180303/95b51d5b/attachment.html>


More information about the wine-devel mailing list