如何在win32 NTFS下检测文件移动?

时间:2016-02-06 15:21:51

标签: c++ visual-studio winapi visual-c++ ntfs

我有一个数据库,允许将附加信息附加到文件系统(NTFS)中的任何文件。文件ID是其完整路径,因此为了保持一致性,我需要观察数据库中的任何文件是否被删除,重命名或移动。

目前,我正在努力通过使用带有FILE_NOTIFY_CHANGE_FILE_NAME的ReadDirectoryChangesW函数来实现这一目标。 FILE_NOTIFY_CHANGE_DIR_NAME作为过滤条件。

问题是这样,我只收到重命名,创建和删除的通知。因此,我需要猜测何时发生移动,基于“添加”#39;和'删除'事件和相关文件名(在同一卷上,一个移动[ctrl-x,ctrl-v]实际上是一个文件删除,紧接着是文件创建,路径不同,但文件名保持不变)。

有人知道是否有更好的解决方案吗?

以下是基于观察的理解

关于在NTFS下移动文件

在同一卷内

A'删除'通过添加'立即跟踪事件(没有或很少延迟)。相同文件名和不同路径的事件(无论移动文件的大小如何)。

如果正在监视整个卷的特殊情况:当删除文件时,它实际上被添加到recylce bin(路径包含卷回收站,但文件名不同[某种哈希])。

在两个不同的卷之间

首先,添加了一个'目的地卷上的活动。
之后,当复制完成时,会删除'原始卷上的事件。

(注意:同时可能会发生几个事件:文件越大,滞后时间越长。)

2 个答案:

答案 0 :(得分:2)

如果这些文件在您的控制之下(如果您在添加到数据库时具有写入权限,然后您始终至少具有读取权限),我可以通过替代数据流中的GUID标记它们,或者使用对象ID(https://msdn.microsoft.com/en-us/library/aa364557%28v=VS.85%29.aspx),无论什么更合适。

答案 1 :(得分:1)

确实没有办法通知移动'事件,因为这样的事件总是路径/文件名重命名或duo事件删除&创作。
虽然使用USN期刊可以使事情变得更容易,但仍有一些额外的工作要做。

在这种情况下,我需要动态检查文件系统更改(我的应用程序在后台运行),因此没有必要使用日志(日志)。

这是我想出的与DeviceIoControl和ReadDirectoryChangesW函数一起使用的逻辑以及一个包含自定义FileActionInfo项的队列。

  <div ng-model='myInput' barcode-generator="{{myInput}}" style="height:208px;">
                </div>

};

在使用USN时,这对于猜测所有移动事件可能也很有用:

算法

struct FileActionInfo {
    WCHAR fileName[FILE_NAME_MAX];
    CHAR drive;
    DWORD action;
    time_t timeStamp;

例外

  • 如果在不同卷上的同一会话期间创建了具有相同文件名的两个文件,并且在删除其中一个文件之后,将错误地将其作为“移动”来处理。事件
  • 随着时间的推移,FileActionInfo队列可能会变大,我们偶尔可以清理它(设置移动文件的最大延迟)
    • 如果复制持续时间超过允许的延迟时间,我们可能会错过“移动的”#39;事件
    • 队列越大,搜索事件的时间就越长,所以我们需要快速访问:(几个对象存储具有不同访问模式的相同项目:vector,hashtable)

以防它可能会有所帮助,这是我写的FileActionQueue.h 最重要的方法是Last()和Search(LPCWSTR fileName,DWORD action,PCHAR drives)。

- when a 'added' event occurs
    - if previous event was a 'removed' event on same volume
        - if 'added' event contains recycle bin path, ignore it (file deleted)
        - else if 'removed' event contains recycle bin path, handle as a 'restored'/'undelete' event, remove 'removed' event from queue
        - else 
            - if 'added' event has same filename, handle as a 'moved' event, remove 'removed' event from queue
            - else push 'added' event to queue
    - else push 'added' event to queue


- when a 'removed' event occurs, search the queue for an 'added' event for the same filename on a different volume
    - if found, handle it as a 'moved' event and remove 'added' event from queue
    - else push 'removed' event to queue, launch a delayedRemoval thread


delayedRemoval thread(&FileActionInfo) {
    // we cannot wait forever , because 'added' event might never occur (if the file was actually deleted).
    sleep(2000)
    if given 'removed' event is still in the queue
        handle as an actual 'removed' event, and remove it from queue
    return;
}