【问题标题】:How to delete parent of child being monitored by ReadDirectoryChangesW如何删除被 ReadDirectoryChangesW 监控的孩子的父母
【发布时间】:2018-08-17 20:38:07
【问题描述】:

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

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

FindFirstChangeNotification locks parent folder

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

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

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

谢谢!

【问题讨论】:

    标签: c++ winapi visual-c++ readdirectorychangesw change-notification


    【解决方案1】:

    文件夹只有在空的情况下才能删除,否则会报错STATUS_DIRECTORY_NOT_EMPTY - 表示要删除的目录不为空。

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

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

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


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

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

    通常,标记为删除的文件直到全部删除后才会真正删除 文件的打开句柄已关闭,并且该文件的链接计数 文件为零。使用标记删除文件时 FILE_DISPOSITION_POSIX_SEMANTICS,链接从 POSIX 删除句柄关闭后可见的命名空间, 但是文件的数据流仍然可以被其他现有的 句柄,直到最后一个句柄被关闭。

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

    注意这里的DeleteFileWRemoveDirectoryW在这里是行不通的,因为他们使用了旧的信息类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;
    }
    

    当然child必须在其他调用中用FILE_SHARE_DELETE打开,否则我们以后根本无法用DELETE打开它

    【讨论】:

    • 请注意,FILE_DISPOSITION_POSIX_SEMANTICS 可能会失败(例如,如果文件系统不是 NTFS),因此在这种情况下您应该尝试定期删除。
    【解决方案2】:

    获取目录句柄时,为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 也很重要。

    【讨论】:

      猜你喜欢
      • 2019-02-02
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      相关资源
      最近更新 更多