使用 ReadDirectoryChangesW 监视文件夹会导致其父级被锁定且无法删除。
这里有一篇关于这个的帖子:
FindFirstChangeNotification 锁定父文件夹
但其中提到的唯一解决方案是我们应该始终在顶层倾听。
有没有人找到更好的方法来做到这一点,而不是在顶层观看?
有时这可以一直到观看驱动器,并且不会在机器上花费很多处理时间。
谢谢!
使用 ReadDirectoryChangesW 监视文件夹会导致其父级被锁定且无法删除。
这里有一篇关于这个的帖子:
FindFirstChangeNotification 锁定父文件夹
但其中提到的唯一解决方案是我们应该始终在顶层倾听。
有没有人找到更好的方法来做到这一点,而不是在顶层观看?
有时这可以一直到观看驱动器,并且不会在机器上花费很多处理时间。
谢谢!
文件夹只有在它为空的情况下才能删除,否则我们得到错误STATUS_DIRECTORY_NOT_EMPTY
-表示试图删除的目录不是空的。
从另一边- 如果你有文件的打开句柄 - 在你不关闭它之前不能删除它句柄(这里的一些变化从 win10 rs1 开始)
ReadDirectoryChangesW
因此,如果您使用已打开的句柄监视某些子子文件夹,并且在不关闭此句柄之前不能删除父文件夹(在 WIN10_RS1 之前)。
一般过程看起来像 - 当有人尝试删除文件夹时 - 它必须枚举其中的所有文件(子文件夹)并首先删除它。当删除操作将应用于ReadDirectoryChangesW
调用的文件夹时 - io 请求将以状态完成STATUS_DELETE_PENDING
-已请求对具有删除挂起的文件对象的非关闭操作。(它转换为 win32 错误代码ERROR_ACCESS_DENIED
-访问被拒绝。)。当您收到此错误时,ReadDirectoryChangesW
您必须关闭此调用中使用的目录句柄。然后是提高-谁是第一个-您关闭目录句柄或其他代码尝试删除父文件夹...
从 win10 rs1 开始可能删除父级,即使有人通过调用NtSetInformationFile
withFileDispositionInformationEx
或SetFileInformationByHandle
with来保持子文件(文件夹)的打开句柄FileDispositionInfoEx
。
新标志中的神奇之处FILE_DISPOSITION_POSIX_SEMANTICS
(指定系统应该执行 POSIX 样式的删除)
通常,在文件的所有打开句柄都已关闭并且文件的链接计数为零之前,实际上不会删除标记为删除的文件。使用 标记要删除的文件时
FILE_DISPOSITION_POSIX_SEMANTICS
,一旦关闭 POSIX 删除句柄,链接就会从可见命名空间中删除,但其他现有句柄仍然可以访问文件的数据流,直到最后一个句柄关闭。
所以当我们使用这个 - 文件本身当然不会被删除,直到调用者ReadDirectoryChangesW
不关闭自己的句柄,但文件将从父文件夹中删除。结果父文件夹可以变为空,之后我们可以将其删除。
请注意,DeleteFileW
这里RemoveDirectoryW
将不起作用,因为他们使用旧的信息类FileDispositionInformation与FILE_DISPOSITION_INFORMATION
ULONG DeletePosix(PCWSTR lpFileName)
{
HANDLE hFile = CreateFileW(lpFileName, DELETE, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
static FILE_DISPOSITION_INFO_EX fdi = { FILE_DISPOSITION_DELETE| FILE_DISPOSITION_POSIX_SEMANTICS };
ULONG dwError = SetFileInformationByHandle(hFile, FileDispositionInfoEx, &fdi, sizeof(fdi))
? NOERROR : GetLastError();
// win10 rs1: file removed from parent folder here
CloseHandle(hFile);
return dwError;
}
当然孩子必须在其他调用中打开,否则我们以后FILE_SHARE_DELETE
根本无法打开它DELETE
CreateFile()
在获取目录句柄时指定正确的属性很重要。尝试这个:
HANDLE hDir = ::CreateFile(
strDirectoryName,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, // security descriptor
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
指定FILE_SHARE_DELETE
共享模式也很重要。