简体   繁体   English

如果通过(硬)符号链接修改文件,如何检测(FSEvent)?

[英]How to detect (FSEvent) if a file is modified through a (hard) symlink?

Some context一些上下文

The attempt is keep a hash for the content of each file in a list.尝试为列表中的每个文件的内容保留一个哈希值。

Example例子

file1.txt "This is a long story about dragons and..." -> Hash A28F30...
file2.txt "Larousse dictionary. Letter A..." -> Hash 98BC012...

For this, the program listener to detect any modification to these files, in order to invalidate (and recalculate) the hash in case of creation/modification/deletion.为此,程序侦听器检测对这些文件的任何修改,以便在创建/修改/删除的情况下使散列无效(并重新计算)。

The file path is registered for an FSEvent and any modification to the file will then invalidate the hash.文件路径是为 FSEvent 注册的,对文件的任何修改都会使散列无效。

This strategy works most of the time, but complications arrives when links are used:这种策略在大多数情况下都有效,但在使用链接时会出现复杂情况:

$ ln /Users/myself/test_file.txt /other_path/file.txt
$ echo "changed" >> /other_path/file.txt

This modify the file in /Users/myself/test_file.txt , but no event for this modification is received (breaking the hash <-> file equivalence).这会修改/Users/myself/test_file.txt的文件,但没有收到此修改的事件(破坏哈希 <-> 文件等效性)。

Following is aa short code example:以下是一个简短的代码示例:

#include <iostream>
#include <unordered_map>
#include <vector>

#include <CoreServices/CoreServices.h>
#include <sys/stat.h>

using namespace std;

using FileKey = string;
using FileData = struct{};
using AppHashTable = std::unordered_map<FileKey, FileData>;

void invalidateCache( AppHashTable& appCache, const string& file)
{
    (void) appCache; //no unused
    
    cout << "Invalidate " << file << endl;      
}

auto callback(
    ConstFSEventStreamRef streamRef, 
    void *info, 
    size_t numEvents, 
    void *eventPaths, 
    const FSEventStreamEventFlags *eventFlags, 
    const FSEventStreamEventId * eventIds)-> void
{
    (void) streamRef; //No unused
    (void) eventIds;  //No unused
    
    static const char* flags[] = {
        "MustScanSubDirs",
        "UserDropped",
        "KernelDropped",
        "EventIdsWrapped",
        "HistoryDone",
        "RootChanged",
        "Mount",
        "Unmount",
        "ItemCreated",
        "ItemRemoved",
        "ItemInodeMetaMod",
        "ItemRenamed",
        "ItemModified",
        "ItemFinderInfoMod",
        "ItemChangeOwner",
        "ItemXattrMod",
        "ItemIsFile",
        "ItemIsDir",
        "ItemIsSymlink",
        "OwnEvent"
    } ;
    
    cout << endl;
    char** pathsList = static_cast<char**>(eventPaths);
    for(size_t i = 0; i<numEvents; i++)
    {
        cout << "Event " << i << " of " << numEvents << endl;
        cout << "    " << pathsList[i] << endl;
        cout << "    Flags: ";
        long bit = 1 ;
        for( int index=0, count = sizeof( flags ) / sizeof( flags[0]); 
            index < count; ++index )
        {
            if ( ( eventFlags[i] & bit ) != 0 )
            {
                cout << flags[index] << " ";
            }
            bit <<= 1 ;
        }
        cout << endl;
        invalidateCache(*static_cast<AppHashTable*>(info), pathsList[i]);
    }
    
}


vector<string> getPaths()
{
    return {
        "/Users/myself/test_folder",
        "/Users/myself/test_file.txt"};
}

int main(int , const char * [])
{
    AppHashTable appHashTable;
    
    const auto vecPaths = getPaths();
    
    // Create CF array of paths TODO to structure RAII
    vector<CFStringRef> cfVecPaths;
    for (const auto& p: vecPaths)
    {
        cfVecPaths.push_back( CFStringCreateWithCString( kCFAllocatorDefault, p.c_str(), 
            kCFStringEncodingUTF8 ));
    }
    
    CFArrayRef paths = CFArrayCreate(nullptr, reinterpret_cast<const void **>(cfVecPaths.data()), 
        static_cast<CFIndex>(cfVecPaths.size()), &kCFTypeArrayCallBacks );

    FSEventStreamContext info{0, reinterpret_cast<void*>(&appHashTable), nullptr, nullptr, nullptr};
    
    
    CFRunLoopRef loop = CFRunLoopGetCurrent() ;
    FSEventStreamRef stream = FSEventStreamCreate(nullptr, callback, &info, paths, 
        kFSEventStreamEventIdSinceNow, 0.1, kFSEventStreamCreateFlagFileEvents );

    FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode);
    FSEventStreamStart(stream);
    
    CFRunLoopRun() ;
    
    FSEventStreamStop(stream);
    FSEventStreamInvalidate(stream);
    FSEventStreamRelease(stream);
    
    
    // Release CF array of paths
    if ( paths ) { CFRelease( paths ) ; }
    for (auto& p: cfVecPaths)
    {
        CFRelease(p);
    }

    return 0;
}

Question:题:

How to detect modifications to the file through a link?如何通过链接检测对文件的修改?

And why is the link creation/modification not detected?为什么未检测到链接创建/修改?

Obviously, registering events for the full file-system is not an option.显然,为整个文件系统注册事件不是一种选择。


Additional data附加数据

(Targeting macOS High-sierra to Big-Sur, using C++) (针对 macOS High-sierra 到 Big-Sur,使用 C++)

For convenience:为了方便:

cmake_minimum_required(VERSION 3.0)

set(PROJECT_NAME "poc_events")
project(${PROJECT_NAME})
set(CMAKE_CXX_STANDARD 17)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices")

set ( TESTCPP main.cpp )

add_executable( ${PROJECT_NAME} ${TESTCPP} ) 

My founds up to now (and I will stop researching this topic):到目前为止我的发现(我将停止研究这个主题):

  1. symbolic links work well, the problem is only related with hardlinks符号链接运行良好,问题仅与硬链接有关
  2. Hardlinks are not possible for folders, so FSEvents is a good way to monitor the creation/deletion and move of files inside the given folder.文件夹无法使用硬链接,因此 FSEvents 是监视给定文件夹内文件的创建/删除和移动的好方法。
  3. In order to monitor file modification, I switched to Kernel Queues, which allows to monitor properly hardlinks.为了监控文件修改,我切换到内核队列,它允许正确监控硬链接。

An example of how to monitor a file with Kernel Queues can be found here:可以在此处找到如何使用内核队列监视文件的示例:

https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/KernelQueues/KernelQueues.html#A_Brief_Example https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/KernelQueues/KernelQueues.html#A_Brief_Example

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM