在 Objective C 或 OSX 上的 C++ 中检测文件夹访问(类似于 fs_usage 命令)

Detect Folder Access in Objective C or C++ on OSX (Like fs_usage command)

我正在 OSX 上开发实时病毒扫描程序。 OSX 的命令行命令 fs_usage 可以通过以下方式确定文件夹访问权限(并且只能 运行 作为 root 用户):

fs_usage -w -f pathname | grep '/Users/.*/Documents\|/Users/.*/Downloads' | grep mds

然后,只需扫描包含短语的行:

    open    

(前面4个空格,后面4个空格)

当文件下载到 Documents 或 Downloads 文件夹时会发出。然后,您可以对其进行文件哈希处理(sha256 最好),并使用 SQLite 数据库检查您之前是否已经扫描过该文件。如果没有,那么您可以扫描该文件。

好吧,这很有趣,但是 C++ 或 Objective C 确定文件夹访问权限的方法是什么?我的意思是,fs_usage 命令肯定为此使用了某种 API,对吧?

我认为的一个线索是 Apple File System Events API。但是,我只是从针对我的特定场景给出的示例中不太了解它。

以下代码必须在 main.m 而不是 main.mm 中,否则将无法编译。 (参见下面的 C++ 附录 (main.mm)。)以下代码 运行 循环,观察 /Users/mike/Documents/Users/mike/Downloads 中的新文件创建。 (抱歉,它不支持这些路径上的通配符——我希望它支持!)按 CTRL+C 退出 运行 循环。

注意在输出中,如果你下载一个文件,你会看到一个一致的标志 ID 125184。如果一个新文件从同一文件夹复制到一个文件夹,标志 ID 是 128256。如果一个新的文件是新鲜创建的(就像从编辑器中创建的一样),标志 ID 是 108544。如果将现有文件拖到文件夹中,标志 ID 是 67584。您需要继续试验 ID 以查看要捕获的事件.例如,如果编写实时病毒扫描程序,您可能希望检测通过命令行、拖放、cut/paste 移动或从 Web 下载到特定文件夹的文件。尝试各种方案和子文件夹,查看您获得的 ID,并编写捕获这些标志 ID 的代码。

#import <Foundation/Foundation.h>

void detectNewFile (
    ConstFSEventStreamRef streamRef,
    void *clientCallBackInfo,
    size_t numEvents,
    void *eventPaths,
    const FSEventStreamEventFlags eventFlags[],
    const FSEventStreamEventId eventIds[])
{
    int i;
    char **paths = eventPaths;

    printf("GOT AN EVENT!!!!\n");
    for (i=0; i<numEvents; i++) {
        printf("Change %llu in %s, flags %u\n", eventIds[i], paths[i], (unsigned int)eventFlags[i]);
    }
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        short nPathCount = 2;
        CFStringRef mypath[nPathCount];
        mypath[0] = CFSTR("/Users/mike/Documents");
        mypath[1] = CFSTR("/Users/mike/Downloads");
        CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, nPathCount, NULL);
        void *callbackInfo = NULL;
        CFAbsoluteTime latency = 1.0; // seconds

        FSEventStreamRef hStream = FSEventStreamCreate(NULL,
            &detectNewFile,
            callbackInfo,
            pathsToWatch,
            kFSEventStreamEventIdSinceNow,
            latency,
            kFSEventStreamCreateFlagFileEvents
        );

        FSEventStreamScheduleWithRunLoop(hStream, CFRunLoopGetCurrent(),         kCFRunLoopDefaultMode);
        FSEventStreamStart(hStream);
        printf("Waiting on new file creations...\n");
        CFRunLoopRun(); // runs in an endless loop, only letting the callback function run

    } // end autorelease pool
    return 0;
}

附录

如果您需要它与 main.mm 一起工作,从而与 C++ 一起工作,您需要将 CoreServices.framework 库添加到构建步骤中。然后,更改此行:

char **paths = eventPaths;

...到这一行:

char **paths = (char **)eventPaths;

然后更改此行:

void *callbackInfo = NULL;

...到这一行:

FSEventStreamContext *callbackInfo = NULL;

然后更改此行:

CFAbsoluteTime latency = 1.0; // seconds

...到这一行:

CFTimeInterval latency = 1.0; // seconds