#691·winfsp

Rename IRP silently dropped after successful open with DELETE access - never forwarded to user-mode Rename callback

Author: YoufffengCreated Sep 2, 2026Updated Sep 2, 2026

Environment

  • WinFsp 2.1.25156.ddca7bd
  • Windows 11 Pro (build 26200)
  • User-mode file system: custom FS in Rust via winfsp-rust 0.13.0 (all FSP_FILE_SYSTEM_INTERFACE callbacks implemented)
  • Drive letter mount
  • VolumeParams: filesystem_name, case_sensitive_search=TRUE, case_preserved_names=TRUE, unicode_on_disk=TRUE, sector_size=512, sectors_per_allocation_unit=8, max_component_length=255, no_reparse_points_dir_check=TRUE, supports_posix_unlink_rename=TRUE

Symptom

All rename operations return STATUS_ACCESS_DENIED to the caller immediately. The rename IRP is never forwarded to the user-mode Rename callback — traced via entry-point logging on every callback.

What works on the same files

  • CreateFileW(file, DELETE_ACCESS) — succeeds, DELETE is in granted access
  • FileDispositionInformation (delete) via SetDeleteCleanup — works, file removed from backing store
  • create, read, write, flush, close — all work
  • Directory rename also fails with the same ACCESS_DENIED

Control experiment (minimal stub FS, same driver, same volume params)

A minimal stub FS with only 4 required callbacks + rename on a fresh drive letter: rename works perfectly in all scenarios (fresh file, subdirectory file, leaked handles, concurrent polling). This rules out: driver version, volume params, caller behavior, handle leaks, oplock, concurrent access.

IRP sequences (traced from user-mode callbacks)

Stub FS (rename succeeds):

gsbn(source) → create(source)
gsbn(source) → open(source,128) ×3
gsbn(source) → open(source, DELETE=1114240)
gsbn(root) → open(root,1048578)     ← driver opens target parent dir
gsbn(target) exists=false            ← driver queries target
→ Rename callback invoked → SUCCESS

App FS (rename fails):

gsbn(source) → create(source)
[write + close + cleanup]
gsbn(source) → open(source,128) ×3
gsbn(source) → open(source, DELETE=1114240)
【nothing — driver never sends open(root) / gsbn(target) / rename】
Caller gets ERROR_ACCESS_DENIED

Key observation

The divergence point is between the successful open(source, DELETE) and the expected open(target_parent_dir) + gsbn(target_name) — meaning FspFsvolSetRenameInformation exits in driver-internal checks (PosixDelete flag at :1788 or RenameCheck at :1870 in fileinfo.c) before forwarding to user-mode.

What we've ruled out

  • DACL/SD: icacls shows Everyone:(OI)(CI)(F) with explicit DELETE; open(source, DELETE) succeeds with DELETE in granted access
  • file_info_timeout: removed, still fails
  • PosixDelete flag: fresh files with no prior delete attempts
  • Oplock: replicated oplock-hold + rename on stub, passes
  • SetDelete/cleanup semantics: replicated on stub, passes
  • Leaked handles: replicated on stub, passes
  • Volume params: stub uses identical set, passes

Question

Is there a known issue in WinFsp 2.1 where FspFsvolSetRenameInformation can return ACCESS_DENIED without forwarding to user-mode when the FileNode was created by the user-mode FS? Could certain FileInfo field values (e.g. index_number, hard_links, ea_size) or the absence of a GetSecurityByName pattern trigger driver-internal rename checks to fail?

Happy to run experiments or provide additional traces.