4

I am writing an application that saves data into a set of text files inside a specific folder. And I have an FSEventStream to be notified when other apps (like Dropbox or TextEdit) alter files, so I can update my application with the new text content provided.

The problem is that with my FSEventStream - despite I set a kFSEventStreamCreateFlagIgnoreSelf flag - I receive notifications even when modifying files within my own application.

This brings a lot of complications, because after I save the file and get the file-change notification, I have to re-check the file. We can talk about optimisation here, but with my structure of data it is a lot of unnecessary operations and disk usage.

The question is: How can I separate the a) File-events from other applications from b) File-events generated with my own application?

I thought there might be a way to get the processID by the FSEventID (the latter is provided in a callback function). But didn't find anything about it. And it looks like the EventID is provided only to define the order in chain of FileEvents.

What I want is to ignore self-generated FileSystem events.

Here is the code I use to setup the FSEventStream:

NSArray * pathArray = [NSArray arrayWithObject:_pathToObserve];

FSEventStreamContext context;
context.info = self;
context.version = 0;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;

_fsEventStream = FSEventStreamCreate(NULL,
                                     filesystemObserverCallback,
                                     &context,
                                     (CFArrayRef)pathArray,
                                     kFSEventStreamEventIdSinceNow,
                                     1.0,
                                     kFSEventStreamCreateFlagIgnoreSelf|kFSEventStreamCreateFlagFileEvents|kFSEventStreamCreateFlagUseCFTypes);

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

And the callback function:

void filesystemObserverCallback(ConstFSEventStreamRef streamRef,
                                void * clientCallBackInfo,
                                size_t numEvents,
                                void * eventPaths,
                                const FSEventStreamEventFlags eventFlags[],
                                const FSEventStreamEventId eventIds[])
{

    NSArray * pathArray = (NSArray *)eventPaths;

    for (int i=0; i < numEvents; i++)
    {
        NSString * path = [pathArray objectAtIndex:i];
        FSEventStreamEventFlags flags = flagsArray[i];

        if (flags & kFSEventStreamEventFlagItemCreated ||
            flags & kFSEventStreamEventFlagItemRemoved ||
            flags & kFSEventStreamEventFlagItemRenamed ||
            flags & kFSEventStreamEventFlagItemFinderInfoMod ||
            flags & kFSEventStreamEventFlagItemChangeOwner ||
            flags & kFSEventStreamEventFlagItemXattrMod)
        {

            NSLog(@">> item has changed at path: %@", path);
        }
    }
}
UJey
  • 1,442
  • 11
  • 15
  • 1
    Looks like there is no such way in case you listen for changes in files. Maybe "ignoring self" works for folder-level only... – UJey Apr 12 '14 at 16:43

2 Answers2

0

Try setting kFSEventStreamCreateFlagMarkSelf as flag to FSEventStreamCreate in addition to kFSEventStreamCreateFlagIgnoreSelf. This worked for me.

I guess, this triggers the "own" flag being generated at all, so it can be ignored then. Please let us know, if that also works for you.

osxdirk
  • 560
  • 6
  • 11
0

osxdirk's answer should definitely work. From FSEvents.h:

  /*
   * Indicates the event was triggered by the current process.
   * (This flag is only ever set if you specified the MarkSelf flag when creating the stream.)
   */
  kFSEventStreamEventFlagOwnEvent __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) = 0x00080000,
Chris Jones
  • 456
  • 2
  • 8