/* * FSEventsFix * * Works around a long-standing bug in realpath() that prevents FSEvents API from * monitoring certain folders on a wide range of OS X releases (10.6-10.10 at least). * * The underlying issue is that for some folders, realpath() call starts returning * a path with incorrect casing (e.g. "/users/smt" instead of "/Users/smt"). * FSEvents is case-sensitive and calls realpath() on the paths you pass in, so * an incorrect value returned by realpath() prevents FSEvents from seeing any * change events. * * See the discussion at https://github.com/thibaudgg/rb-fsevent/issues/10 about * the history of this bug and how this library came to exist. * * This library uses Facebook's fishhook to replace a custom implementation of * realpath in place of the system realpath; FSEvents will then invoke our custom * implementation (which does not screw up the names) and will thus work correctly. * * Our implementation of realpath is based on the open-source implementation from * OS X 10.10, with a single change applied (enclosed in "BEGIN WORKAROUND FOR * OS X BUG" ... "END WORKAROUND FOR OS X BUG"). * * Include FSEventsFix.{h,c} into your project and call FSEventsFixInstall(). * * It is recommended that you install FSEventsFix on demand, using FSEventsFixIsBroken * to check if the folder you're about to pass to FSEventStreamCreate needs the fix. * Note that the fix must be applied before calling FSEventStreamCreate. * * FSEventsFixIsBroken requires a path that uses the correct case for all folder names, * i.e. a path provided by the system APIs or constructed from folder names provided * by the directory enumeration APIs. * * See .c file for license & copyrights, but basically this is available under a mix * of MIT and BSD licenses. */ #ifndef __FSEventsFix__ #define __FSEventsFix__ #include /// A library version string (e.g. 1.2.3) for displaying and logging purposes extern const char *const FSEventsFixVersionString; /// See FSEventsFixDebugOptionSimulateBroken #define FSEventsFixSimulatedBrokenFolderMarker "__!FSEventsBroken!__" typedef CF_OPTIONS(unsigned, FSEventsFixDebugOptions) { /// Always return an uppercase string from realpath FSEventsFixDebugOptionUppercaseReturn = 0x01, /// Log all calls to realpath using the logger configured via FSEventsFixConfigure FSEventsFixDebugOptionLogCalls = 0x02, /// In addition to the logging block (if any), log everything to stderr FSEventsFixDebugOptionLogToStderr = 0x08, /// Report paths containing FSEventsFixSimulatedBrokenFolderMarker as broken FSEventsFixDebugOptionSimulateBroken = 0x10, /// Repair paths containing FSEventsFixSimulatedBrokenFolderMarker by renaming them FSEventsFixDebugOptionSimulateRepair = 0x20, }; typedef CF_ENUM(int, FSEventsFixMessageType) { /// Call logging requested via FSEventsFixDebugOptionLogCalls FSEventsFixMessageTypeCall, /// Results of actions like repair, and other pretty verbose, but notable, stuff. FSEventsFixMessageTypeResult, /// Enabled/disabled status change FSEventsFixMessageTypeStatusChange, /// Expected failure (treat as a warning) FSEventsFixMessageTypeExpectedFailure, /// Severe failure that most likely means that the library won't work FSEventsFixMessageTypeFatalError }; typedef CF_ENUM(int, FSEventsFixRepairStatus) { FSEventsFixRepairStatusNotBroken, FSEventsFixRepairStatusRepaired, FSEventsFixRepairStatusFailed, }; /// Note that the logging block can be called on any dispatch queue. void FSEventsFixConfigure(FSEventsFixDebugOptions debugOptions, void(^loggingBlock)(FSEventsFixMessageType type, const char *message)); void FSEventsFixEnable(); void FSEventsFixDisable(); bool FSEventsFixIsOperational(); bool FSEventsFixIsBroken(const char *path); /// If the path is broken, returns a string identifying the root broken folder, /// otherwise, returns NULL. You need to free() the returned string. char *FSEventsFixCopyRootBrokenFolderPath(const char *path); FSEventsFixRepairStatus FSEventsFixRepairIfNeeded(const char *path); #endif