Created
August 22, 2013 02:41
-
-
Save jparishy/6302621 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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