Skip to content

Instantly share code, notes, and snippets.

@jparishy
Created August 22, 2013 02:41
Show Gist options
  • Save jparishy/6302621 to your computer and use it in GitHub Desktop.
Save jparishy/6302621 to your computer and use it in GitHub Desktop.
//
// main.m
// FSEventsTest
//
// Created by Julius Parishy on 8/20/13.
// Copyright (c) 2013 Fitocracy. All rights reserved.
//
#import <Foundation/Foundation.h>
NSString *LEFSEventDescription(FSEventStreamEventFlags flags, NSString *path)
{
BOOL(^flags_has)(FSEventStreamEventFlags, FSEventStreamEventFlags) = ^BOOL(FSEventStreamEventFlags flags, FSEventStreamEventFlags flag){
return ((flags & flag) != 0);
};
NSString *type = @"Unknown Type";
if(flags_has(flags,kFSEventStreamEventFlagItemIsFile))
{
type = @"File";
}
else if(flags_has(flags, kFSEventStreamEventFlagItemIsDir))
{
type = @"Directory";
}
else if(flags_has(flags, kFSEventStreamEventFlagItemIsSymlink))
{
type = @"Symbolic Link";
}
NSMutableString *action = [@"" mutableCopy];
NSDictionary *flagsMap = @{
@(kFSEventStreamEventFlagItemCreated) : @"ItemCreated",
@(kFSEventStreamEventFlagItemRemoved) : @"ItemRemoved",
@(kFSEventStreamEventFlagItemInodeMetaMod) : @"ItemInodeMetaMod",
@(kFSEventStreamEventFlagItemRenamed) : @"ItemRenamed",
@(kFSEventStreamEventFlagItemModified) : @"ItemModified",
@(kFSEventStreamEventFlagItemFinderInfoMod) : @"ItemFinderInfoMod",
@(kFSEventStreamEventFlagItemChangeOwner) : @"ItemChangeOwner",
@(kFSEventStreamEventFlagItemXattrMod) : @"@ItemXattrMod",
@(kFSEventStreamEventFlagItemIsFile) : @"ItemIsFile",
@(kFSEventStreamEventFlagItemIsDir) : @"ItemIsDir",
@(kFSEventStreamEventFlagItemIsSymlink) : @"ItemIsSymlink"
};
[flagsMap enumerateKeysAndObjectsUsingBlock:^(NSNumber *flag, NSString *value, BOOL *stop) {
if(flags_has(flags, flag.unsignedIntValue))
{
[action appendFormat:@"%@,", value];
}
}];
return [NSString stringWithFormat:@"%@ - %@: %@", type, action, path];
}
@interface LEDirectoryWatcher : NSObject
@property (nonatomic, assign, readonly) FSEventStreamRef stream;
@property (nonatomic, strong, readonly) NSArray *directories;
@property (nonatomic, assign) NSTimeInterval updateInterval;
- (id)initWithDirectories:(NSArray *)directories;
- (void)begin;
- (void)end;
- (void)handleCallbackWithEventPaths:(NSArray *)paths flags:(NSArray *)eventFlags;
- (void)handlePath:(NSString *)path flags:(FSEventStreamEventFlags)flags;
@end
void LEFSEventCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[])
{
const char **castedPaths = eventPaths;
NSMutableArray *paths = [NSMutableArray array];
NSMutableArray *flags = [NSMutableArray array];
for(NSInteger i = 0; i < numEvents; ++i)
{
const char *pathCString = (const char *)castedPaths[i];
NSString *path = [NSString stringWithCString:pathCString encoding:NSUTF8StringEncoding];
[paths addObject:path];
[flags addObject:@(eventFlags[i])];
}
LEDirectoryWatcher *watcher = (__bridge LEDirectoryWatcher *)clientCallBackInfo;
[watcher handleCallbackWithEventPaths:[paths copy] flags:[flags copy]];
}
@implementation LEDirectoryWatcher
- (id)initWithDirectories:(NSArray *)directories
{
if((self = [super init]))
{
_directories = [directories copy];
self.updateInterval = 1.0f;
}
return self;
}
- (void)begin
{
FSEventStreamEventId latestEventId = kFSEventStreamEventIdSinceNow;
FSEventStreamContext context = { 0 };
context.info = (__bridge void *)self;
CFArrayRef paths = (__bridge CFArrayRef)self.directories;
_stream = FSEventStreamCreate(kCFAllocatorDefault, &LEFSEventCallback, &context, paths, latestEventId, self.updateInterval, kFSEventStreamCreateFlagFileEvents);
FSEventStreamScheduleWithRunLoop(self.stream, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
FSEventStreamStart(self.stream);
}
- (void)end
{
FSEventStreamStop(self.stream);
FSEventStreamRelease(self.stream);
}
- (void)handleCallbackWithEventPaths:(NSArray *)paths flags:(NSArray *)eventFlags
{
[paths enumerateObjectsUsingBlock:^(NSString *path, NSUInteger idx, BOOL *stop) {
BOOL included = NO;
for(NSString *directory in self.directories)
{
if([path hasPrefix:directory])
{
included = YES;
break;
}
}
if(included)
{
FSEventStreamEventFlags flags = [eventFlags[idx] unsignedIntValue];
[self handlePath:path flags:flags];
}
}];
}
- (void)handlePath:(NSString *)path flags:(FSEventStreamEventFlags)flags
{
NSLog(@"%@", LEFSEventDescription(flags, path));
}
@end
BOOL running = YES;
void sigint_callback(int signal)
{
running = NO;
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
signal(SIGINT, sigint_callback);
LEDirectoryWatcher *watcher = [[LEDirectoryWatcher alloc] initWithDirectories:@[ @"/" ]];
[watcher begin];
while(running)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate.date dateByAddingTimeInterval:1.0f]];
}
[watcher end];
printf("\n\nQuiting.\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment