2011-04-27 8 views
8

Estoy usando la API FSEvents para recibir notificaciones de cambios en un directorio local que estoy rastreando.¿Es posible utilizar FSEvents para recibir notificaciones de que se ha movido una carpeta?

¿Es posible obtener una notificación de que el directorio visto se ha movido a otra ubicación en el disco, utilizando FSEvents o cualquier otra cosa?

Actualización:

Aquí está el código que tengo hasta ahora, ahora estoy tratando de usar la bandera kFSEventStreamCreateFlagWatchRoot con FSEventStreamCreate para obtener la raíz cambió la notificación, hasta ahora sin éxito.

- (void)registerForFileSystemNotifications { 

    NSString *watchedDirectoryPath = [[NSUserDefaults standardUserDefaults] valueForKey:kMyWatchedDirectoryPathKey]; 
    self.watchedDirectoryFileDescriptor = open([watchedDirectoryPath cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); 

    NSArray *paths = [NSArray arrayWithObject:watchedDirectoryPath]; 
    void *appController = (void *)self; 
    FSEventStreamContext context = {0, appController, NULL, NULL, NULL}; 
    FSEventStreamRef streamRef = FSEventStreamCreate(NULL, 
                &fsevents_callback, 
                &context, 
                (CFArrayRef) paths, 
                kFSEventStreamEventIdSinceNow, 
                (CFTimeInterval)2.0, 
                kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagWatchRoot); 

    FSEventStreamScheduleWithRunLoop(streamRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 
    FSEventStreamStart(streamRef); 

} 

void fsevents_callback(ConstFSEventStreamRef streamRef, 
         void *userData, 
         size_t numumberOfEvents, 
         void *eventPaths, 
         const FSEventStreamEventFlags eventFlags[], 
         const FSEventStreamEventId eventIds[]) { 

    MyAppController *appController = (MyAppController *)userData; 
    char *newPath = calloc(4096, sizeof(char)); 
    int pathIntPointer = (int)newPath; 

    int length = fcntl(appController.watchedDirectoryFileDescriptor, F_GETPATH, pathIntPointer); 

    NSString *newPathString = [[NSString alloc] initWithBytes:newPath length:(NSUInteger)length encoding:NSUTF8StringEncoding]; 
    NSLog(@"newPathString: %@", newPathString); // empty 
} 

Respuesta

6

Sí. Pase kFSEventStreamCreateFlagWatchRoot como último argumento al FSEventStreamCreate, y se le notificará si el directorio se movió o renombró. Desde docs:

Solicite notificaciones de cambios a lo largo de la (s) ruta (s) que está viendo. Por ejemplo, con esta bandera, si mira "/ foo/bar" y se renombra a "/foo/bar.old", recibirá un evento RootChanged. Lo mismo es cierto si se cambió el nombre del directorio "/ foo". El evento que recibe es un evento especial: la ruta del evento es la ruta original que especificó, el indicador kFSEventStreamEventFlagRootChanged está establecido y el evento ID es cero. Los eventos RootChanged son útiles para indicar que debe volver a explorar una jerarquía en particular, ya que cambió completamente (a diferencia de las cosas dentro de ella que cambian). Si desea rastrear la ubicación actual de un directorio, es mejor abrir el directorio antes de crear la secuencia para que tenga un descriptor de archivo y pueda emitir una F_GETPATH ​​fcntl() para encontrar la ruta actual.

Editar: añadiendo ejemplo fcntl

Ese ejemplo cocoadev sugiere el autor de un poco inexperto con los punteros. El pathIntPointer no solo es innecesario, sino que también es la causa de su problema. La comprobación de error del código de retorno de fnctl lo habría atrapado. Aquí hay una versión revisada de su devolución de llamada:

void fsevents_callback(ConstFSEventStreamRef streamRef, 
        void *userData, 
        size_t numumberOfEvents, 
        void *eventPaths, 
        const FSEventStreamEventFlags eventFlags[], 
        const FSEventStreamEventId eventIds[]) { 

    MyAppController *appController = (MyAppController *)userData; 
    char newPath[ MAXPATHLEN ]; 
    int rc; 

    rc = fcntl(appController.watchedDirectoryFileDescriptor, F_GETPATH, newPath); 
    if (rc == -1) { 
     perror("fnctl F_GETPATH"); 
     return; 
    } 

    NSString *newPathString = [[NSString alloc] initWithUTF8String: newPath ]; 
    NSLog(@"newPathString: %@", newPathString); 
    [ newPathString release ]; 
} 
+0

Gracias! Estoy intentando esto ahora, pero hasta ahora sin suerte. He agregado mi código actual a la pregunta. El único ejemplo que puedo encontrar de usar F_GETPATH ​​es aquí http://www.cocoadev.com/index.pl?DescriptorToPath. ¡Gracias por tu ayuda! –

+0

Impresionante. Gracias :) –

Cuestiones relacionadas