Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c - OSX FSEventStreamEventFlags not working correctly

I am watching a directory for file system events. Everything seems to work fine with one exception. When I create a file the first time, it spits out that it was created. Then I can remove it and it says it was removed. When I go to create the same file again, I get both a created and removed flag at the same time. I obviously am misunderstanding how the flags are being set when the callback is being called. What is happening here?

//
//  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
", pathsList[i]);
        }
        else if(flag & created) {
            printf("Item Created: %s
", 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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

As far as I can tell, you will have to look for either kFSEventStreamEventFlagItemRemoved or kFSEventStreamEventFlagItemCreated, and then use stat() or similar to check if the file was in fact added or deleted. The FSEvents documentation seems to hint as such.

It looks like the API is or'ing the events bits together... so really it's an OR of all the changes made since the FSEventsListener is created. Since that seems to be the case, another option might be to create a new FSEventListener each time (and use the coalesce timer option).

I did some Googling, but didn't find other examples of this problem or even apple sample code, but I didn't spend too long on it.

I have previously used the kqueue API: https://gist.github.com/nielsbot/5155671 (This gist is an obj-c wrapper around kqueue)

I changed your sample code to show all flags set for each 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
", ++__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
", i ) ;
        printf("path %s
", pathsList[i]) ;
        printf("flags: ") ;
        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("
") ;
    }

    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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...