Commit 04ccd995 authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

kernel32: Open replaced file without GENERIC_WRITE in ReplaceFileW().

As MSDN says, the replaced file is opened with the GENERIC_READ, DELETE, and SYNCHRONIZE access rights. If GENERIC_WRITE is added, then it will fail with previous file opens without FILE_SHARE_WRITE. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=33845Signed-off-by: 's avatarZhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 57e8e2d5
...@@ -1746,6 +1746,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa ...@@ -1746,6 +1746,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
FILE_BASIC_INFORMATION info;
TRACE("%s %s %s 0x%08x %p %p\n", debugstr_w(lpReplacedFileName), TRACE("%s %s %s 0x%08x %p %p\n", debugstr_w(lpReplacedFileName),
debugstr_w(lpReplacementFileName), debugstr_w(lpBackupFileName), debugstr_w(lpReplacementFileName), debugstr_w(lpBackupFileName),
...@@ -1772,7 +1773,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa ...@@ -1772,7 +1773,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
attr.SecurityDescriptor = NULL; attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL; attr.SecurityQualityOfService = NULL;
/* Open the "replaced" file for reading and writing */ /* Open the "replaced" file for reading */
if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL))) if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
{ {
error = ERROR_PATH_NOT_FOUND; error = ERROR_PATH_NOT_FOUND;
...@@ -1780,7 +1781,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa ...@@ -1780,7 +1781,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
} }
replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF; replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
attr.ObjectName = &nt_replaced_name; attr.ObjectName = &nt_replaced_name;
status = NtOpenFile(&hReplaced, GENERIC_READ|GENERIC_WRITE|DELETE|SYNCHRONIZE, status = NtOpenFile(&hReplaced, GENERIC_READ|DELETE|SYNCHRONIZE,
&attr, &io, &attr, &io,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE); FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
...@@ -1796,6 +1797,20 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa ...@@ -1796,6 +1797,20 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
goto fail; goto fail;
} }
/* Replacement should fail if replaced is READ_ONLY */
status = NtQueryInformationFile(hReplaced, &io, &info, sizeof(info), FileBasicInformation);
if (status != STATUS_SUCCESS)
{
error = RtlNtStatusToDosError(status);
goto fail;
}
if (info.FileAttributes & FILE_ATTRIBUTE_READONLY)
{
error = ERROR_ACCESS_DENIED;
goto fail;
}
/* /*
* Open the replacement file for reading, writing, and deleting * Open the replacement file for reading, writing, and deleting
* (writing and deleting are needed when finished) * (writing and deleting are needed when finished)
......
...@@ -3691,7 +3691,7 @@ static void test_ReplaceFileA(void) ...@@ -3691,7 +3691,7 @@ static void test_ReplaceFileA(void)
*/ */
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); 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 */ /* make sure that the replacement file still exists */
hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
ok(hReplacementFile != INVALID_HANDLE_VALUE || ok(hReplacementFile != INVALID_HANDLE_VALUE ||
...@@ -3727,7 +3727,7 @@ static void test_ReplaceFileA(void) ...@@ -3727,7 +3727,7 @@ static void test_ReplaceFileA(void)
"unexpected error, replaced file should be able to be opened %d\n", GetLastError()); "unexpected error, replaced file should be able to be opened %d\n", GetLastError());
/*Calling ReplaceFileA on an exe should succeed*/ /*Calling ReplaceFileA on an exe should succeed*/
ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0); 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); CloseHandle(hReplacedFile);
/* replace file while replacement is opened */ /* replace file while replacement is opened */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment