win: work around wine bug in uv_fs_{unlink,rmdir} (#4833)

Wine has a bug (https://bugs.winehq.org/show_bug.cgi?id=50771) where
FILE_WRITE_ATTRIBUTES will cause CreateFile to fail if the file is
read-only. The recommended work around is to instead use
FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, which we do as of #4318.
However, we were still using FILE_WRITE_ATTRIBUTES to create the
initial handle, despite this no longer being required, except for
the fallback path. As a result, libuv is still broken under wine,
even on master. Fix this by removing the `FILE_WRITE_ATTRIBUTES`
from the initial CreateFile call and re-opening the handle in the
fallback path if necessary. Note that we still have the same issue
in fs_chmod and I've requested some guidance from wine on what
to do about this, but this should at least fix unlink.

Refs: https://github.com/JuliaLang/julia/issues/58980
This commit is contained in:
Keno Fischer 2025-07-24 15:15:39 -04:00 committed by GitHub
parent 7484ab251f
commit 6cf854c11b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1112,7 +1112,7 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) {
DWORD error;
handle = CreateFileW(pathw,
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
FILE_READ_ATTRIBUTES | DELETE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
@ -1187,14 +1187,33 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) {
/* Remove read-only attribute */
FILE_BASIC_INFORMATION basic = { 0 };
/* We opened the handle above without FILE_WRITE_ATTRIBUTES access, which
* is not required in the happy path. On windows, it would probably
* be ok to ask for them anyway, but Wine has a bug that causes such calls
* to fail (https://bugs.winehq.org/show_bug.cgi?id=50771). To work around
* this bug, we re-open the handle here */
HANDLE write_attributes_handle;
basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
FILE_ATTRIBUTE_ARCHIVE;
status = pNtSetInformationFile(handle,
write_attributes_handle = ReOpenFile(handle, FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
FILE_FLAG_OPEN_REPARSE_POINT |
FILE_FLAG_BACKUP_SEMANTICS);
if (write_attributes_handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
CloseHandle(handle);
return;
}
status = pNtSetInformationFile(write_attributes_handle,
&iosb,
&basic,
sizeof basic,
FileBasicInformation);
CloseHandle(write_attributes_handle);
if (!NT_SUCCESS(status)) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
CloseHandle(handle);