在 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
我正在 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