From: Tom Watson Subject: [PATCH 1/2 v4] kernel32: Support MOVEFILE_WRITE_THROUGH / CopyFileExW progress Message-Id: Date: Sun, 4 Mar 2018 23:04:43 -0600 Signed-off-by: Tom Watson --- v4 Added "optional" DWORD return value for WriteFile() to stop segfaults General tidy up and temporarily removed failing tests that require updated kernel32.dll
Signed-off-by: Tom Watson <coder@tommywatson.com>
---
v4
Added "optional" DWORD return value for WriteFile() to stop segfaults
General tidy up and temporarily removed failing tests that require updated kernel32.dll


From 09744e3e6d7a78d2903555b1bf48e45229b549cb Mon Sep 17 00:00:00 2001 From: tommy Date: Sun, 4 Mar 2018 22:54:39 -0600 Subject: [PATCH] MOVEFILE_WRITE_THROUGH --- 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..fd34f31154 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.@) */ @@ -1283,6 +1360,7 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest, NTSTATUS status; HANDLE source_handle = 0, dest_handle; ANSI_STRING source_unix, dest_unix; + MFWFData data; TRACE("(%s,%s,%p,%p,%04x)\n", debugstr_w(source), debugstr_w(dest), fnProgress, param, flag ); @@ -1293,9 +1371,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 +1444,29 @@ 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 */ + 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