如何删除由 ReadDirectoryChangesW 监视的子项的父项

How to delete parent of child being monitored by ReadDirectoryChangesW

本文关键字:监视 ReadDirectoryChangesW 何删除 删除      更新时间:2023-10-16

使用 ReadDirectoryChangesW 监视文件夹会导致其父文件夹被锁定且无法删除。

这里有一篇关于这个的帖子:

查找第一个更改通知锁定父文件夹

但其中提到的唯一解决方案是,我们应该始终在顶层倾听。

有没有人找到更好的方法来做到这一点,而不是在顶级观看?

有时,这可以一直到观看驱动器,并且不会在机器上花费大量处理时间。

谢谢!

文件夹只有在为空的情况下才能删除,否则我们得到错误STATUS_DIRECTORY_NOT_EMPTY-指示尝试删除的目录不为空。

从另一侧 - 如果您有文件的打开句柄 - 在您不关闭它句柄之前无法删除它(此处更改的内容从 Win10 RS1 开始(

因此,如果您使用ReadDirectoryChangesW监视某个子子文件夹,则在未关闭此句柄之前,无法(在WIN10_RS1之前(删除父文件夹。

在一般过程中看起来像 - 当有人尝试删除文件夹时 - 它必须枚举其中的所有文件(子文件夹(并首先删除它。 当对调用ReadDirectoryChangesW文件夹应用删除操作时 - IO 请求将以状态STATUS_DELETE_PENDING完成 -已请求对删除挂起的文件对象执行非关闭操作。 (它转换为Win32错误代码ERROR_ACCESS_DENIED-访问被拒绝。).从ReadDirectoryChangesW收到此错误时,必须关闭此调用中使用的目录句柄。然后是提高 - 谁是第一个 - 你关闭目录句柄或其他代码尝试删除父文件夹...


从 win10 RS1 开始,可能删除父文件,即使有人通过调用NtSetInformationFileFileDispositionInformationExSetFileInformationByHandleFileDispositionInfoEx来打开它的子文件(文件夹(。

新标志FILE_DISPOSITION_POSIX_SEMANTICS中的魔力(指定系统应执行 POSIX 样式的删除(

通常,标记为删除的文件实际上不会被删除,直到所有 文件的打开句柄已关闭,并且 文件为零。使用 标记要删除的文件时FILE_DISPOSITION_POSIX_SEMANTICS,链接将从 一旦 POSIX 删除句柄关闭,可见命名空间, 但该文件的数据流仍可由其他现有数据流访问 句柄,直到最后一个句柄关闭。

因此,当我们使用它时 - 文件本身当然不会被删除,直到ReadDirectoryChangesW调用者不关闭自句柄,但文件将从父文件夹中删除。 结果,父文件夹可以变为空,之后我们可以将其删除。

请注意,这里的DeleteFileWRemoveDirectoryW在这里不起作用,因为他们使用旧的信息类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也很重要。