internal void Start() { // Make sure _fullPath doesn't contain a link or alias // since the OS will give back the actual, non link'd or alias'd paths _fullDirectory = Interop.Sys.RealPath(_fullDirectory); if (_fullDirectory == null) { throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } Debug.Assert(string.IsNullOrEmpty(_fullDirectory) == false, "Watch directory is null or empty"); // Normalize the _fullDirectory path to have a trailing slash if (_fullDirectory [_fullDirectory.Length - 1] != '/') { _fullDirectory += "/"; } // Get the path to watch and verify we created the CFStringRef SafeCreateHandle path = Interop.CoreFoundation.CFStringCreateWithCString(_fullDirectory); if (path.IsInvalid) { throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } // Take the CFStringRef and put it into an array to pass to the EventStream SafeCreateHandle arrPaths = Interop.CoreFoundation.CFArrayCreate(new CFStringRef [1] { path.DangerousGetHandle() }, (UIntPtr)1); if (arrPaths.IsInvalid) { path.Dispose(); throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } // Create the callback for the EventStream if it wasn't previously created for this instance. if (_callback == null) { _callback = new Interop.EventStream.FSEventStreamCallback(FileSystemEventCallback); } // Make sure the OS file buffer(s) are fully flushed so we don't get events from cached I/O Interop.Sys.Sync(); // Create the event stream for the path and tell the stream to watch for file system events. _eventStream = Interop.EventStream.FSEventStreamCreate( _callback, arrPaths, Interop.EventStream.kFSEventStreamEventIdSinceNow, 0.0f, EventStreamFlags); if (_eventStream.IsInvalid) { arrPaths.Dispose(); path.Dispose(); throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true); } // Create and start our watcher thread then wait for the thread to initialize and start // the RunLoop. We wait for that to prevent this function from returning before the RunLoop // has a chance to start so that any callers won't race with the background thread's initialization // and calling Stop, which would attempt to stop a RunLoop that hasn't started yet. var runLoopStarted = new ManualResetEventSlim(); new Thread(WatchForFileSystemEventsThreadStart) { IsBackground = true }.Start(runLoopStarted); runLoopStarted.Wait(); }
internal static extern void FSEventStreamStop(SafeEventStreamHandle streamRef);
internal static extern void FSEventStreamUnscheduleFromRunLoop( SafeEventStreamHandle streamRef, CFRunLoopRef runLoop, SafeCreateHandle runLoopMode);
internal static extern bool FSEventStreamStart(SafeEventStreamHandle streamRef);