<div dir="ltr"><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><br></span></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">Signed-off-by: Tom Watson <<a href="mailto:coder@tommywatson.com" target="_blank">coder@tommywatson.com</a>></span></span></div><div>---</div><div> dlls/kernel32/path.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++---</div><div> 1 file changed, 101 insertions(+), 5 deletions(-)</div><div><br></div><div>diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c</div><div>index a389743171..98891cde6d 100644</div><div>--- a/dlls/kernel32/path.c</div><div>+++ b/dlls/kernel32/path.c</div><div>@@ -43,6 +43,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(file);</div><div> </div><div> #define MAX_PATHNAME_LEN        1024</div><div> </div><div>+/* struct to hold progress function callback for MoveFileWithProgressW */</div><div>+typedef struct {</div><div>+    LPPROGRESS_ROUTINE progress;</div><div>+    VOID *data;</div><div>+    BOOL status;                    /* flush successful */</div><div>+} MFWFData;</div><div>+</div><div> static int path_safe_mode = -1;  /* path mode set by SetSearchPathMode */</div><div> </div><div> /* check if a file name is for an executable file (.exe or .com) */</div><div>@@ -1159,10 +1166,14 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,</div><div>     static const int buffer_size = 65536;</div><div>     HANDLE h1, h2;</div><div>     BY_HANDLE_FILE_INFORMATION info;</div><div>+    LARGE_INTEGER file_position,file_size;</div><div>     DWORD count;</div><div>     BOOL ret = FALSE;</div><div>     char *buffer;</div><div>+    DWORD progressExit = 0;</div><div> </div><div>+    /* init file size/position */</div><div>+    file_position.QuadPart=file_size.QuadPart=0;</div><div>     if (!source || !dest)</div><div>     {</div><div>         SetLastError(ERROR_INVALID_PARAMETER);</div><div>@@ -1193,6 +1204,10 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,</div><div>         return FALSE;</div><div>     }</div><div> </div><div>+    /* update total size */</div><div>+    file_size.LowPart = info.nFileSizeLow;</div><div>+    file_size.HighPart = info.nFileSizeHigh;</div><div>+</div><div>     if (!(flags & COPY_FILE_FAIL_IF_EXISTS))</div><div>     {</div><div>         BOOL same_file = FALSE;</div><div>@@ -1231,6 +1246,32 @@ BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,</div><div>             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;</div><div>             p += res;</div><div>             count -= res;</div><div>+            file_position.QuadPart += res;</div><div>+        }</div><div>+        /* Call progress function ? */</div><div>+        if (progress != NULL) {</div><div>+            progressExit = progress(file_size, file_position, file_size,</div><div>+                     file_position, 1, CALLBACK_CHUNK_FINISHED, h1, h2, param);</div><div>+            switch (progressExit) {</div><div>+                case PROGRESS_CONTINUE:</div><div>+                    // keep at it</div><div>+                    break;</div><div>+                case PROGRESS_QUIET:</div><div>+                    // requested not to be called again</div><div>+                    progress = NULL;</div><div>+                    break;</div><div>+                case PROGRESS_CANCEL:</div><div>+                    // cancel and clean up</div><div>+                    CloseHandle( h2 );</div><div>+                    h2 = INVALID_HANDLE_VALUE;</div><div>+                    DeleteFileW( dest );</div><div>+                    SetLastError( ERROR_REQUEST_ABORTED );</div><div>+                    goto done;</div><div>+                case PROGRESS_STOP:</div><div>+                    // do nothing, allow for a restart (??)</div><div>+                    SetLastError( ERROR_REQUEST_ABORTED );</div><div>+                    goto done;</div><div>+            }</div><div>         }</div><div>     }</div><div>     ret =  TRUE;</div><div>@@ -1239,7 +1280,10 @@ done:</div><div>     SetFileTime(h2, NULL, NULL, &info.ftLastWriteTime);</div><div>     HeapFree( GetProcessHeap(), 0, buffer );</div><div>     CloseHandle( h1 );</div><div>-    CloseHandle( h2 );</div><div>+    if (h2 != INVALID_HANDLE_VALUE)</div><div>+    {</div><div>+        CloseHandle( h2 );</div><div>+    }</div><div>     return ret;</div><div> }</div><div> </div><div>@@ -1269,6 +1313,39 @@ BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,</div><div> }</div><div> </div><div> </div><div>+/**************************************************************************</div><div>+ *           moveFileWFlush</div><div>+ */</div><div>+DWORD CALLBACK moveFileWFlush(LARGE_INTEGER TotalFileSize,</div><div>+                              LARGE_INTEGER TotalBytesTransferred,</div><div>+                              LARGE_INTEGER StreamSize,</div><div>+                              LARGE_INTEGER StreamBytesTransferred,</div><div>+                              DWORD dwStreamNumber, DWORD dwCallbackReason,</div><div>+                              HANDLE hSourceFile,HANDLE hDestinationFile,</div><div>+                              LPVOID lpData )</div><div>+{</div><div>+    MFWFData *data = (MFWFData *)lpData;</div><div>+    DWORD rval = 0;</div><div>+</div><div>+    if ( data->progress != NULL)</div><div>+    {</div><div>+        rval = data->progress( TotalFileSize, TotalBytesTransferred,</div><div>+                               StreamSize, StreamBytesTransferred,</div><div>+                               dwStreamNumber, dwCallbackReason,</div><div>+                               hSourceFile, hDestinationFile, data->data);</div><div>+    }</div><div>+    /* continue the copy? */</div><div>+    if (rval == 0 ) {</div><div>+        /* completed the copy? */</div><div>+        if (TotalFileSize.QuadPart == TotalBytesTransferred.QuadPart)</div><div>+        {</div><div>+            /* flush the data */</div><div>+            data->status = FlushFileBuffers(hDestinationFile)?1:0;</div><div>+        }</div><div>+    }</div><div>+    return rval;</div><div>+}</div><div>+</div><div> /**************************************************************************</div><div>  *           MoveFileWithProgressW   (KERNEL32.@)</div><div>  */</div><div>@@ -1293,9 +1370,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,</div><div>     if (!dest)</div><div>         return DeleteFileW( source );</div><div> </div><div>-    if (flag & MOVEFILE_WRITE_THROUGH)</div><div>-        FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");</div><div>-</div><div>     /* check if we are allowed to rename the source */</div><div> </div><div>     if (!RtlDosPathNameToNtPathName_U( source, &nt_name, NULL, NULL ))</div><div>@@ -1369,8 +1443,30 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,</div><div>     }</div><div> </div><div>     /* now perform the rename */</div><div>+    if ((flag & MOVEFILE_WRITE_THROUGH) && !(flag & MOVEFILE_DELAY_UNTIL_REBOOT))</div><div>+    {</div><div>+        /* save the original progress function && param, set status to 0 */</div><div>+        MFWFData data;</div><div>+        data.progress = fnProgress;</div><div>+        data.data = param;</div><div>+        data.status = 0;</div><div>+        /* try to copy the file, if it fails or the flush failed, set error */</div><div>+        if (CopyFileExW( source, dest, moveFileWFlush, &data, NULL, 0) == 0</div><div>+         || !data.status) {</div><div>+            /* failed, set error */</div><div>+            FILE_SetDosError();</div><div>+            goto error;</div><div>+        }</div><div> </div><div>-    if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1)</div><div>+        /* delete the source file */</div><div>+        if (!DeleteFileW( source ))</div><div>+        {</div><div>+            /* failed, set error */</div><div>+            FILE_SetDosError();</div><div>+            goto error;</div><div>+        }</div><div>+    }</div><div>+    else if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1)</div><div>     {</div><div>         if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED))</div><div>         {</div><div>-- </div><div>2.14.1</div><div><br></div><div><span style="text-align:start;text-indent:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><span style="text-align:start;text-indent:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><div><br></div></span></span></div></div>