0

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

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

FindFirstChangeNotification 锁定父文件夹

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

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

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

谢谢!

4

2 回答 2

1

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

从另一边- 如果你有文件的打开句柄 - 在你不关闭它之前不能删除它句柄(这里的一些变化从 win10 rs1 开始

ReadDirectoryChangesW因此,如果您使用已打开的句柄监视某些子子文件夹,并且在不关闭此句柄之前不能删除父文件夹(在 WIN10_RS1 之前)。

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


从 win10 rs1 开始可能删除父级,即使有人通过调用NtSetInformationFilewithFileDispositionInformationExSetFileInformationByHandlewith来保持子文件(文件夹)的打开句柄FileDispositionInfoEx

新标志中的神奇之处FILE_DISPOSITION_POSIX_SEMANTICS指定系统应该执行 POSIX 样式的删除

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

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

请注意,DeleteFileW这里RemoveDirectoryW将不起作用,因为他们使用旧的信息类FileDispositionInformationFILE_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

于 2018-08-18T11:32:33.850 回答
0

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共享模式也很重要。

于 2018-08-17T22:31:27.190 回答