2013-08-24 35 views
13

Oglądam katalog zdarzeń systemu plików. Wszystko wydaje się działać dobrze z jednym wyjątkiem. Kiedy utworzę plik za pierwszym razem, wypluwa on, że został utworzony. Wtedy mogę go usunąć i mówi, że został usunięty. Kiedy idę do utworzenia tego samego pliku ponownie, otrzymuję jednocześnie flagę utworzoną i usuniętą. Oczywiście nie rozumiem, w jaki sposób flagi są ustawiane podczas wywoływania wywołania zwrotnego. Co tu się dzieje?OSX FSEventStreamEventFlags nie działa poprawnie

// 
// 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

podobne issue: https://github.com/haskell-fswatch/hfsnotify/issues/36 –

+1

Z Twojego kodu wywołania nie widzę żadnego sposobu, aby oba zostały usunięte i utworzone w tym samym czasie. Muszą być drukowane w oddzielnych callbackach. (Masz, jeśli() else if().) –

+0

Czy sprawdziłeś, czy usunięcie flagi 'kFSEventStreamCreateFlagNoDefer' zmienia coś? – JSuar

Odpowiedz

6

O ile mogę powiedzieć, trzeba będzie szukać albo kFSEventStreamEventFlagItemRemoved lub kFSEventStreamEventFlagItemCreated, a następnie użyj stat() lub podobna, by sprawdzić, czy plik został faktycznie dodawane lub usuwane. Dokumentacja FSEvents wydaje się wskazywać jako taka.

Wygląda na to, że interfejs API jest połączeniem bitów zdarzeń ... tak naprawdę jest to OR wszystkich zmian wprowadzonych od czasu utworzenia listy FSEventsListener. Ponieważ wydaje się, że tak jest, inną opcją może być każdorazowe utworzenie nowej listy FSEventListener (i użycie opcji czasu koalescencji).

Zrobiłem trochę Googling, ale nie znalazłem innych przykładów tego problemu lub nawet przykładowy kod jabłek, ale nie spędziłem na nim zbyt długo.

już wcześniej wykorzystał KQUEUE API: https://gist.github.com/nielsbot/5155671 (Ta istota jest obj-c otoki wokół KQUEUE)

zmieniłem swój przykładowy kod, aby pokazać wszystkie flagi ustawione dla każdego FSEvent:

#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

Dzięki! Podoba mi się pomysł użycia kqueue - nie wiedziałem, że działa na Mac OS X. –