Summary
test_kevent_vnode_rename_overwrite_ordering is gated off Win32 in test/vnode.c because both MoveFileExA(MOVEFILE_REPLACE_EXISTING) and the kernel-level SetFileInformationByHandle(FileRenameInfo, ReplaceIfExists=TRUE) return STATUS_ACCESS_DENIED (Win32 error 5) on the test's setup, despite every relevant open being made with FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE and the source HANDLE having DELETE access for the SetFileInfo path.
Setup
testfile_create(src_path); // creates files (no leftover handles)
testfile_create(tgt_path);
src_fd = open(src_path, O_RDWR); // shimmed: FILE_SHARE_DELETE
tgt_fd = open(tgt_path, O_RDWR); // shimmed: FILE_SHARE_DELETE
kevent_add(src_fd, EVFILT_VNODE, NOTE_RENAME); // FindFirstChangeNotificationW on parent dir
kevent_add(tgt_fd, EVFILT_VNODE, NOTE_DELETE); // FindFirstChangeNotificationW on parent dir
rename(src_path, tgt_path); // FAILS gle=5
Both the user-mode wrapper (MoveFileExA) and the NT direct path (NtSetInformationFile/SetFileInformationByHandle via a fresh CreateFileA(src, DELETE|SYNCHRONIZE, FILE_SHARE_*, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS) handle) return ERROR_ACCESS_DENIED. Verified empirically across Release / Debug / Debug+ASAN.
What works
test_kevent_vnode_note_rename (rename to a non-existing target) passes - same temp dir, same kqueue, same vnode filter machinery, just no REPLACE_EXISTING.
- Earlier vnode tests pass with the same FindFirstChangeNotificationW handles open on the temp dir.
So the fail mode is specifically the overwrite path: MoveFileEx (and the kernel rename) wants to delete the existing target before atomically swapping the source's name in. Some interlock is rejecting the delete despite the target's open handles all having FILE_SHARE_DELETE.
Hypotheses (unverified)
FindFirstChangeNotificationW opens the parent directory with a share mode that, in combination with the test's per-file watchers (two of them on the same dir), denies the delete-and-rename through the kernel rename API.
- Defender / EDR is incidentally holding a transient handle on the freshly-created target.
- Some Win32-specific access check on
REPLACE_EXISTING requires the current process to own the destination via more than just FILE_SHARE_DELETE (e.g., the deletion path may want DELETE access on every existing handle, which our shimmed open doesn't request).
Pinpointing requires a minimal repro outside the test harness: open a file with FILE_SHARE_DELETE, set up FindFirstChangeNotificationW on its parent, then call MoveFileExA(REPLACE_EXISTING) from another path. None of this is in scope for the Windows port itself; tracking here so it doesn't get lost.
Files
- Test gated:
test/vnode.c:1226-1232 (#if defined(NOTE_RENAME) && !defined(_WIN32))
- Rename shim with NT-direct fallback:
test/win32_compat.h (kq_rename_via_setinfo)
Summary
test_kevent_vnode_rename_overwrite_orderingis gated off Win32 intest/vnode.cbecause bothMoveFileExA(MOVEFILE_REPLACE_EXISTING)and the kernel-levelSetFileInformationByHandle(FileRenameInfo, ReplaceIfExists=TRUE)returnSTATUS_ACCESS_DENIED(Win32 error 5) on the test's setup, despite every relevant open being made withFILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETEand the source HANDLE havingDELETEaccess for the SetFileInfo path.Setup
Both the user-mode wrapper (
MoveFileExA) and the NT direct path (NtSetInformationFile/SetFileInformationByHandlevia a freshCreateFileA(src, DELETE|SYNCHRONIZE, FILE_SHARE_*, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)handle) returnERROR_ACCESS_DENIED. Verified empirically across Release / Debug / Debug+ASAN.What works
test_kevent_vnode_note_rename(rename to a non-existing target) passes - same temp dir, same kqueue, same vnode filter machinery, just noREPLACE_EXISTING.So the fail mode is specifically the overwrite path:
MoveFileEx(and the kernel rename) wants to delete the existing target before atomically swapping the source's name in. Some interlock is rejecting the delete despite the target's open handles all havingFILE_SHARE_DELETE.Hypotheses (unverified)
FindFirstChangeNotificationWopens the parent directory with a share mode that, in combination with the test's per-file watchers (two of them on the same dir), denies the delete-and-rename through the kernel rename API.REPLACE_EXISTINGrequires the current process to own the destination via more than justFILE_SHARE_DELETE(e.g., the deletion path may wantDELETEaccess on every existing handle, which our shimmed open doesn't request).Pinpointing requires a minimal repro outside the test harness: open a file with
FILE_SHARE_DELETE, set upFindFirstChangeNotificationWon its parent, then callMoveFileExA(REPLACE_EXISTING)from another path. None of this is in scope for the Windows port itself; tracking here so it doesn't get lost.Files
test/vnode.c:1226-1232(#if defined(NOTE_RENAME) && !defined(_WIN32))test/win32_compat.h(kq_rename_via_setinfo)