Signed-off-by: Tom Watson coder@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)) {