int main(int argc, char *argv[]) { /* Define variables and create a CFArray object containing CFString objects containing paths to watch. */ CFStringRef mypath = CFSTR("/"); CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); void *callbackInfo = NULL; // could put stream-specific data here. FSEventStreamRef stream; CFAbsoluteTime latency = 3.0; /* Latency in seconds */ struct stat Status; stat("/", &Status); dev_t device = Status.st_dev; CFUUIDRef uuidO; CFStringRef uuid; uuidO = FSEventsCopyUUIDForDevice(device); uuid = CFUUIDCreateString(NULL, uuidO); show(CFSTR("%@:256"), uuid); /* Create the stream, passing in a callback, */ stream = FSEventStreamCreateRelativeToDevice(NULL, &myCallbackFunction, callbackInfo, device, pathsToWatch, atoi(argv[2]), /* Or a previous event ID */ latency, kFSEventStreamCreateFlagNone /* Flags explained in reference */ ); /* Create the stream before calling this. */ FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart(stream); //CFRunLoopRun(); CFRunLoopRunInMode(kCFRunLoopDefaultMode,atoi(argv[1]),false); //sleep(10); }
static fse_stream* fse_stream_make( const std::shared_ptr<w_root_t>& root, FSEventStreamEventId since, w_string& failure_reason) { FSEventStreamContext ctx; CFMutableArrayRef parray = nullptr; CFStringRef cpath = nullptr; double latency; struct stat st; auto watcher = watcherFromRoot(root); struct fse_stream* fse_stream = new struct fse_stream(root, since); // Each device has an optional journal maintained by fseventsd that keeps // track of the change events. The journal may not be available if the // filesystem was mounted read-only. The journal has an associated UUID // to track the version of the data. In some cases the journal can become // invalidated and it will have a new UUID generated. This can happen // if the EventId rolls over. // We need to lookup up the UUID for the associated path and use that to // help decide whether we can use a value of `since` other than SinceNow. if (stat(root->root_path.c_str(), &st)) { failure_reason = w_string::printf( "failed to stat(%s): %s\n", root->root_path.c_str(), strerror(errno)); goto fail; } // Obtain the UUID for the device associated with the root fse_stream->uuid = FSEventsCopyUUIDForDevice(st.st_dev); if (since != kFSEventStreamEventIdSinceNow) { CFUUIDBytes a, b; if (!fse_stream->uuid) { // If there is no UUID available and we want to use an event offset, // we fail: a nullptr UUID means that the journal is not available. failure_reason = w_string::printf( "fsevents journal is not available for dev_t=%d\n", st.st_dev); goto fail; } // Compare the UUID with that of the current stream if (!watcher->stream->uuid) { failure_reason = w_string( "fsevents journal was not available for prior stream", W_STRING_UNICODE); goto fail; } a = CFUUIDGetUUIDBytes(fse_stream->uuid); b = CFUUIDGetUUIDBytes(watcher->stream->uuid); if (memcmp(&a, &b, sizeof(a)) != 0) { failure_reason = w_string("fsevents journal UUID is different", W_STRING_UNICODE); goto fail; } } memset(&ctx, 0, sizeof(ctx)); ctx.info = fse_stream; parray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); if (!parray) { failure_reason = w_string("CFArrayCreateMutable failed", W_STRING_UNICODE); goto fail; } cpath = CFStringCreateWithBytes( nullptr, (const UInt8*)root->root_path.data(), root->root_path.size(), kCFStringEncodingUTF8, false); if (!cpath) { failure_reason = w_string("CFStringCreateWithBytes failed", W_STRING_UNICODE); goto fail; } CFArrayAppendValue(parray, cpath); latency = root->config.getDouble("fsevents_latency", 0.01), w_log( W_LOG_DBG, "FSEventStreamCreate for path %s with latency %f seconds\n", root->root_path.c_str(), latency); fse_stream->stream = FSEventStreamCreate( nullptr, fse_callback, &ctx, parray, since, latency, kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagWatchRoot | kFSEventStreamCreateFlagFileEvents); if (!fse_stream->stream) { failure_reason = w_string("FSEventStreamCreate failed", W_STRING_UNICODE); goto fail; } FSEventStreamScheduleWithRunLoop(fse_stream->stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); #ifdef HAVE_FSEVENTSTREAMSETEXCLUSIONPATHS if (!root->ignore.dirs_vec.empty() && root->config.getBool("_use_fsevents_exclusions", true)) { CFMutableArrayRef ignarray; size_t i, nitems = std::min(root->ignore.dirs_vec.size(), MAX_EXCLUSIONS); ignarray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); if (!ignarray) { failure_reason = w_string("CFArrayCreateMutable failed", W_STRING_UNICODE); goto fail; } for (i = 0; i < nitems; ++i) { const auto& path = root->ignore.dirs_vec[i]; CFStringRef ignpath; ignpath = CFStringCreateWithBytes( nullptr, (const UInt8*)path.data(), path.size(), kCFStringEncodingUTF8, false); if (!ignpath) { failure_reason = w_string("CFStringCreateWithBytes failed", W_STRING_UNICODE); CFRelease(ignarray); goto fail; } CFArrayAppendValue(ignarray, ignpath); CFRelease(ignpath); } if (!FSEventStreamSetExclusionPaths(fse_stream->stream, ignarray)) { failure_reason = w_string("FSEventStreamSetExclusionPaths failed", W_STRING_UNICODE); CFRelease(ignarray); goto fail; } CFRelease(ignarray); } #endif out: if (parray) { CFRelease(parray); } if (cpath) { CFRelease(cpath); } return fse_stream; fail: delete fse_stream; fse_stream = nullptr; goto out; }