Added kernel32-ReplaceFileW patchset

This commit is contained in:
Alistair Leslie-Hughes 2019-04-03 17:06:51 +11:00
parent e20fec1c52
commit 8b930aea2f
3 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,100 @@
From 679a02527fb9051d20940072ab49cc1fa3fc7319 Mon Sep 17 00:00:00 2001
From: Brock York <twunknown@gmail.com>
Date: Wed, 3 Apr 2019 17:00:22 +1100
Subject: [PATCH] kernel32: Correct ReplaceFileW behaviour
ReplaceFileW should fail with ERROR_ACCESS_DENIED when either the replaced
or replacement file is set to read only using SetFileAttributes.
Testing for the return values of ReplaceFileW was performed on a
Windows XP SP3 and Windows 10 vm.
Open replaced file without GENERIC_WRITE flag if a sharing violation is
returned on the first call checking for the READ_ONLY attribute.
ReplaceFileW should not fail when called to replace the current executable which
is the case as tested on Windows 7, 10 and XP this is because the
"replaced" file is opened with the GENERIC_WRITE flag.
The MSDN also mentions that the replaced file is only opened with
GENERIC_READ, DELETE and SYNCHRONIZE.
This patch will fix the following bug once it is
merged into Wine-Staging as the WarFrame launcher
requires patches from Wine-Staging to work.
Wine-Bug:https://bugs.winehq.org/show_bug.cgi?id=33845
---
dlls/kernel32/file.c | 15 +++++++++++++--
dlls/kernel32/tests/file.c | 4 ++--
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index a5c34fae12a..cc22a175fb5 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -1772,7 +1772,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
- /* Open the "replaced" file for reading and writing */
+ /* Open the "replaced" file for reading and writing to check for READ_ONLY attribute */
if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
{
error = ERROR_PATH_NOT_FOUND;
@@ -1784,6 +1784,12 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
&attr, &io,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
+ /*If we didn't get ACCESS_DENIED, then open the file for reading and delete ready for the replacement*/
+ if (status == STATUS_SHARING_VIOLATION)
+ status = NtOpenFile(&hReplaced, GENERIC_READ|DELETE|SYNCHRONIZE,
+ &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
if (status == STATUS_SUCCESS)
status = wine_nt_to_unix_file_name(&nt_replaced_name, &unix_replaced_name, replaced_flags, FALSE);
RtlFreeUnicodeString(&nt_replaced_name);
@@ -1791,6 +1797,8 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
{
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
error = ERROR_FILE_NOT_FOUND;
+ else if (status == STATUS_ACCESS_DENIED)
+ error = ERROR_ACCESS_DENIED;
else
error = ERROR_UNABLE_TO_REMOVE_REPLACED;
goto fail;
@@ -1815,7 +1823,10 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
RtlFreeUnicodeString(&nt_replacement_name);
if (status != STATUS_SUCCESS)
{
- error = RtlNtStatusToDosError(status);
+ if (status == STATUS_ACCESS_DENIED)
+ error = ERROR_ACCESS_DENIED;
+ else
+ error = RtlNtStatusToDosError(status);
goto fail;
}
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 3354bacf967..fb2440e0379 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -3781,7 +3781,7 @@ static void test_ReplaceFileA(void)
*/
SetLastError(0xdeadbeef);
ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0);
- todo_wine ok(ret == 0 && GetLastError() == ERROR_ACCESS_DENIED, "ReplaceFileA: unexpected error %d\n", GetLastError());
+ ok(ret == 0 && GetLastError() == ERROR_ACCESS_DENIED, "ReplaceFileA: unexpected error %d\n", GetLastError());
/* make sure that the replacement file still exists */
hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
ok(hReplacementFile != INVALID_HANDLE_VALUE ||
@@ -3813,7 +3813,7 @@ static void test_ReplaceFileA(void)
"unexpected error, replaced file should be able to be opened %d\n", GetLastError());
/*Calling ReplaceFileA on an exe should succeed*/
ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0);
- todo_wine ok(ret, "ReplaceFileA: unexpected error %d\n", GetLastError());
+ ok(ret, "ReplaceFileA: unexpected error %d\n", GetLastError());
CloseHandle(hReplacedFile);
/* replacement file still exists, make pass w/o "replaced" */
--
2.20.1

View File

@ -0,0 +1,3 @@
# Reference
# https://www.winehq.org/pipermail/wine-devel/2018-October/133068.html
Fixes: [33845] kernel32: Correct ReplaceFileW behaviour for warframe

View File

@ -168,6 +168,7 @@ patch_enable_all ()
enable_kernel32_NeedCurrentDirectoryForExePath="$1"
enable_kernel32_PE_Loader_Fixes="$1"
enable_kernel32_Processor_Group="$1"
enable_kernel32_ReplaceFileW="$1"
enable_kernel32_SCSI_Sysfs="$1"
enable_krnl386_exe16_GDT_LDT_Emulation="$1"
enable_krnl386_exe16_Invalid_Console_Handles="$1"
@ -645,6 +646,9 @@ patch_enable ()
kernel32-Processor_Group)
enable_kernel32_Processor_Group="$2"
;;
kernel32-ReplaceFileW)
enable_kernel32_ReplaceFileW="$2"
;;
kernel32-SCSI_Sysfs)
enable_kernel32_SCSI_Sysfs="$2"
;;
@ -3873,6 +3877,21 @@ if test "$enable_kernel32_Processor_Group" -eq 1; then
) >> "$patchlist"
fi
# Patchset kernel32-ReplaceFileW
# |
# | This patchset fixes the following Wine bugs:
# | * [#33845] kernel32: Correct ReplaceFileW behaviour for warframe
# |
# | Modified files:
# | * dlls/kernel32/file.c, dlls/kernel32/tests/file.c
# |
if test "$enable_kernel32_ReplaceFileW" -eq 1; then
patch_apply kernel32-ReplaceFileW/0001-kernel32-Correct-ReplaceFileW-behaviour.patch
(
printf '%s\n' '+ { "Brock York", "kernel32: Correct ReplaceFileW behaviour.", 1 },';
) >> "$patchlist"
fi
# Patchset kernel32-SCSI_Sysfs
# |
# | This patchset fixes the following Wine bugs: