Как прослушать изменения файловой системы MAC - kFSEventStreamCreateFlagWatchRoot - PullRequest
9 голосов
/ 28 января 2010

Я слушаю изменения каталога и диска в проекте Какао, используя FSEvents. Мне нужно получить события, когда корневая папка переименована или удалена. Итак, я передал kFSEventStreamCreateFlagWatchRoot при создании FSEventStream. Но даже если я удаляю или переименовываю корневую папку, я не получаю соответствующий FSEventStreamEventFlags. Любая идея, что может быть проблемой. Я слушаю изменения в USB-устройстве. Я использовал FSEventStreamCreate и FSEventStreamCreateRelativeToDevice. Одна вещь, которую я замечаю, это когда я пытаюсь с FSEventStreamCreate, я получаю следующее сообщение об ошибке при создании FSEventStream:

(CarbonCore.framework) FSEventStreamCreate: watch_all_parents:
ошибка при попытке добавить kqueue для fd 7 (/Volumes/NO NAME; операция не поддерживается)

Но с FSEventStreamCreateRelativeToDevice ошибок нет, но по-прежнему не получается kFSEventStreamEventFlagRootChanged в флагах событий. Кроме того, при создании с использованием FSEventStreamCreateRelativeToDevice Apple говорит, что если я хочу прослушать изменения корневого пути, передайте строку emty "". Но я не могу прослушать изменения корневого пути, передав пустую строку. Но когда я прохожу "/", это работает. Но даже за "/" я не получаю должного FSEventStreamEventFlags. Я вставляю код здесь:

-(void) subscribeFileSystemChanges:(NSString*) path
{
    PRINT_FUNCTION_BEGIN;

    // if already subscribed then unsubscribe
    if (stream)
    {
        FSEventStreamStop(stream);
        FSEventStreamInvalidate(stream); /* will remove from runloop */
        FSEventStreamRelease(stream);
    }

    FSEventStreamContext cntxt = {0};
    cntxt.info = self;

    CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void**)&path, 1, NULL);


    stream = FSEventStreamCreate(NULL, &feCallback, &cntxt, 
                                 pathsToWatch, kFSEventStreamEventIdSinceNow, 1,
                                 kFSEventStreamCreateFlagWatchRoot );


    FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), 
                                     kCFRunLoopDefaultMode);

    FSEventStreamStart(stream);


}

Функция обратного вызова:

static void feCallback(ConstFSEventStreamRef streamRef, void* pClientCallBackInfo, 
                       size_t numEvents, void* pEventPaths, const    FSEventStreamEventFlags eventFlags[], 
                       const FSEventStreamEventId eventIds[]) 

{
char** ppPaths = (char**)pEventPaths; int i;

    for (i = 0; i < numEvents; i++)
    {
        NSLog(@"Event Flags %lu Event Id %llu", eventFlags[i], eventIds[i]); 
        NSLog(@"Path changed: %@", 
              [NSString stringWithUTF8String:ppPaths[i]]); 
    }    
}

Заранее большое спасибо.

Ответы [ 2 ]

3 голосов
/ 13 марта 2010

У меня была такая же проблема, и я думаю, что я понял это. Очевидно, kFSEventStreamCreateFlagWatchRoot просто отключается при использовании FSEventStreamCreateRelativeToDevice. Вы должны использовать FSEventStreamCreate. Поскольку первая форма предпочтительнее, если вы полагаетесь на идентификаторы исторических событий, вам может потребоваться создать 2 потока. Также обратите внимание, что, по-видимому, вы не получаете kEventFlagChangedRoot, отправленное вам, если ваше приложение не запущено, поэтому вам нужно будет проверить каталог при запуске.

3 голосов
/ 28 января 2010

Я думаю, что изменение имени тома не считается изменением файловой системы, о котором сообщает FSEvents. Помните, что имя тома на самом деле не существует как запись файловой системы. Те, что под /Volumes, готовятся ОС.

Вместо этого он распространяется на Дисковый арбитраж .

Ниже приведен краткий пример кода. Сначала определите обратный вызов

#import <DiskArbitration/DiskArbitration.h>
void callBack(DADiskRef disk,CFArrayRef keys,void *context )
{
    CFDictionaryRef dict=DADiskCopyDescription(disk);
    NSString*mountPoint=[(NSDictionary*)dict objectForKey:(NSString*)kDADiskDescriptionVolumePathKey];
    NSLog(@"disk at %@:",mountPoint);
    for(NSString*key in (NSArray*)keys){
    NSLog(@"key %@ changed: %@",key,[(NSDictionary*)dict objectForKey:key]);    
    }
    CFRelease(dict);
}

и затем установите обработчик следующим образом

DASessionRef session=DASessionCreate(NULL);
DARegisterDiskDescriptionChangedCallback(session, NULL, NULL, callBack, NULL);
DASessionScheduleWithRunLoop(session, [[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes);
...