繁体   English   中英

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

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

一些上下文

尝试为列表中的每个文件的内容保留一个哈希值。

例子

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

为此,程序侦听器检测对这些文件的任何修改,以便在创建/修改/删除的情况下使散列无效(并重新计算)。

文件路径是为 FSEvent 注册的,对文件的任何修改都会使散列无效。

这种策略在大多数情况下都有效,但在使用链接时会出现复杂情况:

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

这会修改/Users/myself/test_file.txt的文件,但没有收到此修改的事件(破坏哈希 <-> 文件等效性)。

以下是一个简短的代码示例:

#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;
}

题:

如何通过链接检测对文件的修改?

为什么未检测到链接创建/修改?

显然,为整个文件系统注册事件不是一种选择。


附加数据

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

为了方便:

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} ) 

到目前为止我的发现(我将停止研究这个主题):

  1. 符号链接运行良好,问题仅与硬链接有关
  2. 文件夹无法使用硬链接,因此 FSEvents 是监视给定文件夹内文件的创建/删除和移动的好方法。
  3. 为了监控文件修改,我切换到内核队列,它允许正确监控硬链接。

可以在此处找到如何使用内核队列监视文件的示例:

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