Fixes #1046
Problem
PinnedDirectoryCreation.DeletePinnedEmptyDirectoryImmediately (Windows path) deletes an empty directory with FileDispositionInfoEx POSIX semantics and allowLegacyFallback: false. SMB mounts don't support POSIX immediate deletion and return ERROR_INVALID_FUNCTION (1), ERROR_NOT_SUPPORTED (50) or ERROR_INVALID_PARAMETER (87), so the call throws and the directory is left behind. On a network library root this bricks deletion, empty-directory cleanup, content-move and relocation flows.
A flag flip alone isn't enough: the legacy FileDispositionInfo path is delete-on-close, and the pinned _directoryHandle stays open, so the directory lingers and the post-delete visibility check then throws 145.
Fix
- New
TryDeleteOpenedDirectoryImmediatelyWindowsthat returnsfalseon the SMB error codes (1/50/87) and throws on any other failure. - When POSIX immediate deletion is unavailable, degrade to delete-on-close: mark the transient deletion handle, take ownership of the pinned directory handle and dispose it, then let the deletion handle close as the block exits. Both handles are opened with
FILE_SHARE_DELETE, so the entry is unlinked once the last handle closes — before the method returns, preserving the child-before-parent ordering contract. - Proof of removal in the degraded path is that the parent-relative name no longer resolves (reopen →
2/3). If it still resolves the delete fails closed (Win32 145) rather than falsely reporting an immediate deletion. - The NTFS/POSIX path is unchanged (still uses
FileDispositionInfoExand the identity-compared visibility proof).
Testing
New DeletePinnedEmptyDirectoryImmediately_NetworkStorage_RemovesDirectory under a new WindowsNetworkStorageFact (Windows + LISTENARR_NETWORK_STORAGE_PATH, skipped otherwise). It deletes a directory on a real SMB mount and asserts — via an internal degrade counter — that the delete-on-close fallback actually e...
Automated Canary build