2013-08-24 16 views
13

Ich beobachte ein Verzeichnis für Dateisystemereignisse. Alles scheint mit einer Ausnahme gut zu funktionieren. Wenn ich eine Datei zum ersten Mal erstelle, spuckt sie aus, dass sie erstellt wurde. Dann kann ich es entfernen und es sagt, dass es entfernt wurde. Wenn ich dieselbe Datei erneut erstelle, erhalte ich gleichzeitig eine erstellte und entfernte Flagge. Ich verstehe offensichtlich nicht, wie die Flags gesetzt werden, wenn der Callback aufgerufen wird. Was passiert hier?OSX FSEventStreamEventFlags funktioniert nicht richtig

// 
// main.c 
// GoFSEvents 
// 
// Created by Kyle Cook on 8/22/13. 
// Copyright (c) 2013 Kyle Cook. All rights reserved. 
// 

#include <CoreServices/CoreServices.h> 
#include <stdio.h> 
#include <string.h> 

void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) { 
    char **pathsList = paths; 

    for(int i = 0; i<numEvents; i++) { 
     uint32 flag = eventFlags[i]; 

     uint32 created = kFSEventStreamEventFlagItemCreated; 
     uint32 removed = kFSEventStreamEventFlagItemRemoved; 

     if(flag & removed) { 
      printf("Item Removed: %s\n", pathsList[i]); 
     } 
     else if(flag & created) { 
      printf("Item Created: %s\n", pathsList[i]); 
     } 
    } 
} 

int main(int argc, const char * argv[]) 
{ 
    CFStringRef mypath = CFSTR("/path/to/dir"); 
    CFArrayRef paths = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); 

    CFRunLoopRef loop = CFRunLoopGetMain(); 
    FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 1.0, kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer); 
    FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode); 
    FSEventStreamStart(stream); 

    CFRunLoopRun(); 

    FSEventStreamStop(stream); 
    FSEventStreamInvalidate(stream); 
    FSEventStreamRelease(stream); 

    return 0; 
} 
+0

Ähnliche Problem: https://github.com/haskell-fswatch/hfsnotify/issues/36 –

+1

Aus Ihrem Rückruf-Code sehe ich keine Möglichkeit, die Sie beide gleichzeitig entfernen und erstellen können. Sie müssen in separaten Rückrufen gedruckt werden. (Sie haben if() sonst if().) –

+0

Haben Sie getestet, ob das Entfernen des Flags 'kFSEventStreamCreateFlagNoDefer' etwas ändert? – JSuar

Antwort

6

Soweit ich das beurteilen kann, werden Sie entweder kFSEventStreamEventFlagItemRemoved oder kFSEventStreamEventFlagItemCreated suchen müssen, und dann stat() oder ähnliches verwenden, um zu überprüfen, ob die Datei tatsächlich wurde hinzugefügt oder gelöscht werden. Die FSEvents-Dokumentation scheint als solche zu deuten.

Es sieht so aus, als würde die API die Ereignisbits zusammenstellen ... also ist es wirklich ein OR aller Änderungen, die seit der Erstellung des FSEventsListener vorgenommen wurden. Da dies der Fall zu sein scheint, könnte eine andere Möglichkeit darin bestehen, jedes Mal einen neuen FSEventListener zu erstellen (und die Coalesce-Timer-Option zu verwenden).

Ich habe etwas Googeln, fand aber keine anderen Beispiele für dieses Problem oder sogar Apple-Beispielcode, aber ich verbrachte nicht zu lange damit.

Ich habe bisher verwendeten die kqueue API: https://gist.github.com/nielsbot/5155671 (Dieser Kern ist ein obj-c-Wrapper um kqueue)

ich Ihr Beispielcode geändert, um alle Flags für jedes FSEvent gesetzt, um anzuzeigen:

#include <CoreServices/CoreServices.h> 
#include <stdio.h> 
#include <string.h> 

static int __count = 0 ; 
void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) { 
    char **pathsList = paths; 

    printf("callback #%u\n", ++__count) ; 
    const char * flags[] = { 
     "MustScanSubDirs", 
     "UserDropped", 
     "KernelDropped", 
     "EventIdsWrapped", 
     "HistoryDone", 
     "RootChanged", 
     "Mount", 
     "Unmount", 
     "ItemCreated", 
     "ItemRemoved", 
     "ItemInodeMetaMod", 
     "ItemRenamed", 
     "ItemModified", 
     "ItemFinderInfoMod", 
     "ItemChangeOwner", 
     "ItemXattrMod", 
     "ItemIsFile", 
     "ItemIsDir", 
     "ItemIsSymlink", 
     "OwnEvent" 
    } ; 

    for(int i = 0; i<numEvents; i++) 
    { 
     printf("%u\n", i) ; 
     printf("\tpath %s\n", pathsList[i]) ; 
     printf("\tflags: ") ; 
     long bit = 1 ; 
     for(int index=0, count = sizeof(flags)/sizeof(flags[0]); index < count; ++index) 
     { 
      if ((eventFlags[i] & bit) != 0) 
      { 
       printf("%s ", flags[ index ]) ; 
      } 
      bit <<= 1 ; 
     } 
     printf("\n") ; 
    } 

    FSEventStreamFlushSync(stream) ; 

} 

int main(int argc, const char * argv[]) 
{ 
    CFStringRef path = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8) ; 
    CFArrayRef paths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks); 
    if (path) { CFRelease(path) ; } 

    CFRunLoopRef loop = CFRunLoopGetCurrent() ; 
    FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 0, kFSEventStreamCreateFlagFileEvents); 
    if (paths) { CFRelease(paths) ; } 

    FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode); 
    FSEventStreamStart(stream); 

    CFRunLoopRun() ; 

    FSEventStreamStop(stream); 
    FSEventStreamInvalidate(stream); 
    FSEventStreamRelease(stream); 

    return 0; 
} 
+0

Danke! Ich mag die Idee, kqueue zu verwenden - wusste nicht, dass es unter Mac OS X funktioniert. –