Question

I just set up an FSEvent in order to monitor the state of a target folder. It works just fine, because I am notified every time a change takes place and I am also given the path to the subdirectory where the change has taken place. But what if I want to undertand what was the operation performed? Was a file added, modified, renamed or deleted?

In the Mac Developer Library I am reading that by using persistent events

"you can find out what files have been modified even when your application is not running. This can greatly simplify tasks such as backing up modified files, checking for changed dependencies in multi-file projects, and so on."

but if I understood well, this is just a way of comparing the current state of a directory with a previous one defined by the event ID. So again I would only get the path to the subdirectory where the change happened.

My question is: do I really have to "manually" take snapshots of the state of my directory at different times by creating Directory Hierarchy Snapshots and later compare them in order to find out what are the operations performed in the time between the snapshots? Isn't there a faster way?

Was it helpful?

Solution

I did what follows in order to be able to discriminate the different operations on the files inside the folder that is being watched with the FSEvent (file added, file renamed, file deleted and file modified).

I created a object File with the following properties (you can get as many as you want by calling attributesOfItemAtPath:error:):

@property (strong) NSString *name;
@property (strong) NSString *type;
@property (strong) NSDate *creationDate;
@property (strong) NSDate *modificationDate;
@property (strong) NSString *hash;
@property (strong) NSString *path;

It is possible to populate an NSMutableArray of File objects in the following way:

NSMutableArray *files = [[NSMutableArray alloc] init];
NSString *dirPath = //directory you are watching
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *theFiles =  [fileManager contentsOfDirectoryAtURL:[NSURL fileURLWithPath:dirPath]
                                includingPropertiesForKeys:[NSArray arrayWithObject:NSURLNameKey]
                                                   options:NSDirectoryEnumerationSkipsHiddenFiles
                                                     error:nil];
NSArray* fileNames = [theFiles valueForKeyPath:@"lastPathComponent"];
if ( [fileNames count] > 0 ) {
    for (NSInteger i=0; i<[fileNames count]; i=i+1) {
        NSString *currentPath = [dirPath stringByAppendingString:[fileNames objectAtIndex:i]];
        NSError *error;
        NSDictionary *fileInfo = [fileManager attributesOfItemAtPath:currentPath error:&error];
        File *currentFile = [[File alloc] initWithName:[fileNames objectAtIndex:i]
                                                  withType:fileInfo.fileType
                                                  withPath:currentPath
                                                  withHash: //get file hash
                                          withCreationDate:fileInfo.fileCreationDate
                                   andWithModificationDate:fileInfo.fileModificationDate];
        [files addObject:currentFile];
}

If the directory contains subfolders, it is sufficient to iterate this process for every subfolder, returning and array of File objects.

To understand what operation was performed it is now sufficient to confront the information gathered before (saved in NSMutableArray *oldSnap) and after the callback (saved in NSMutableArray *newSnap)of the FSEvent. First it is necessary to confront the files in oldSnap with the one in newSnap and then viceversa.

If in oldSnap there is a file with a given name that is missing in newSnap, it means this file has been either deleted or renamed. If there is a file which has the same hash in newSnap, then the file has been renamed; else it has been deleted from the folder.

Finishing with the comparison, if there is a file in newSnap with a different fileModificationDate from the one with the same name in oldSnap, this file has been modified. If there is a file in newSnap that is missing in oldSnap, this file is a newly added one.

I have not yet come up with a solution regardant both the renaming and modification of a file. Hope this answer can help others to!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top