Detect Folder Access in Objective C or C++ on OSX

2020-05-09 18:03发布

I'm working on a realtime virus scanner on OSX. The OSX's command line command fs_usage can be used to determine folder access in the following way (and can only be run as root user):

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

Then, just scan for a line containing the phrase:

    open    

(4 spaces in front, 4 spaces after)

This will emit when a file is downloaded into the Documents or Downloads folder. You can then do a file hash (sha256 is best) on that and use a SQLite database to check whether you've already previously scanned that file or not. If not, then you can scan that file.

Okay, that's interesting, but what's the C++ or Objective C way to determine folder access like that? I mean, surely the fs_usage command is using some kind of API for that, right?

One clue I have I think is the Apple File System Events API. However, I just don't quite grasp it from the examples given for my particular scenario.

1条回答
Juvenile、少年°
2楼-- · 2020-05-09 18:28

The following code must be in a main.m and not a main.mm or it won't compile. (SEE ADDENDUM BELOW for C++ (main.mm).) The following code runs in a loop, watching new file creations in /Users/mike/Documents and /Users/mike/Downloads. (Sorry, it doesn't support wildcards on those paths -- I wish it did!) Press CTRL+C to exit the run loop.

Note in the output, if you download a file, you'll see a consistent flag ID of 125184. If a new file is copied into a folder from the same folder, the flag ID is 128256. If a new file is created fresh (like from an editor), the flag ID is 108544. If an existing file is dragged into a folder, the flag ID is 67584. You'll need to keep experimenting with IDs to see what events you want to trap. For instance, if coding a real-time virus scanner, you'd probably want to detect files moved either by command line, drag and drop, cut/paste, or downloaded from the web to a particular folder. Try various scenarios and subfolders, see the IDs you get, and write code that traps those flag IDs.

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

Addendum

If you need this to work with main.mm and thus C++, you need to add CoreServices.framework library to the build steps. Then, change this line:

char **paths = eventPaths;

...to this line:

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

Then change this line:

void *callbackInfo = NULL;

...to this line:

FSEventStreamContext *callbackInfo = NULL;

Then change this line:

CFAbsoluteTime latency = 1.0; // seconds

...to this line:

CFTimeInterval latency = 1.0; // seconds
查看更多
登录 后发表回答