1 // Copyright 2015 Google Inc. All rights reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include <CoreServices/CoreServices.h>
16 #include <dispatch/dispatch.h>
19 typedef char FlagDescription
[8];
21 void LogControlFlagInfo(dispatch_queue_t log_queue
,
22 FSEventStreamEventFlags flags
) {
23 if (flags
& kFSEventStreamEventFlagUserDropped
) {
24 dispatch_async(log_queue
, ^{
25 printf("User-side buffer dropped event\n");
27 } else if (flags
& kFSEventStreamEventFlagKernelDropped
) {
28 dispatch_async(log_queue
, ^{
29 printf("Kernel-side buffer dropped event\n");
31 } else if (flags
& kFSEventStreamEventFlagEventIdsWrapped
) {
32 dispatch_async(log_queue
, ^{
33 printf("Event IDs have wrapped\n");
38 void DescribeFlags(FSEventStreamEventFlags flags
, FlagDescription description
) {
39 memset(description
, '-', sizeof(FlagDescription
));
40 description
[sizeof(FlagDescription
) - 1] = '\0';
42 if (flags
& kFSEventStreamEventFlagItemCreated
)
44 else if (flags
& kFSEventStreamEventFlagItemModified
)
46 else if (flags
& kFSEventStreamEventFlagItemRemoved
)
48 else if (flags
& kFSEventStreamEventFlagItemRenamed
)
50 else if (flags
& (kFSEventStreamEventFlagItemInodeMetaMod
|
51 kFSEventStreamEventFlagItemFinderInfoMod
))
53 else if (flags
& kFSEventStreamEventFlagItemChangeOwner
)
55 else if (flags
& kFSEventStreamEventFlagItemXattrMod
)
59 void EventStreamCallback(ConstFSEventStreamRef event_stream
,
62 void* event_paths_void
,
63 const FSEventStreamEventFlags event_flags
[],
64 const FSEventStreamEventId event_ids
[]) {
65 dispatch_queue_t log_queue
= callback_info
;
66 const char** event_paths
= event_paths_void
;
68 for (size_t i
= 0; i
< num_events
; ++i
) {
69 const FSEventStreamEventFlags flags
= event_flags
[i
];
70 const FSEventStreamEventId ids
= event_ids
[i
];
72 LogControlFlagInfo(log_queue
, flags
);
74 char* path
= strdup(event_paths
[i
]);
76 dispatch_async(log_queue
, ^{
77 FlagDescription flag_description
;
78 DescribeFlags(flags
, flag_description
);
79 printf("event %llx %s at %s\n", ids
, flag_description
, path
);
86 // All logging should happen on a serial queue, so that stdout is not
87 // interleaved, as it could be when handling FSEvents on the concurrent
89 dispatch_queue_t log_queue
= dispatch_queue_create("com.google.fseventw.logq", DISPATCH_QUEUE_SERIAL
);
90 dispatch_queue_t event_queue
= dispatch_queue_create("com.google.fseventw.eventq", DISPATCH_QUEUE_CONCURRENT
);
92 const CFStringRef kPath
= CFSTR("/");
93 const void* paths_to_watch_c
[] = { kPath
};
94 CFArrayRef paths_to_watch
= CFArrayCreate(NULL
, paths_to_watch_c
, 1, &kCFTypeArrayCallBacks
);
96 FSEventStreamContext context
= {
99 .retain
= (const void* (*)(const void*))&dispatch_retain
,
100 .release
= (void (*)(const void*))&dispatch_release
,
101 .copyDescription
= NULL
103 FSEventStreamRef event_stream
=
104 FSEventStreamCreate(NULL
,
105 &EventStreamCallback
,
108 kFSEventStreamEventIdSinceNow
,
110 kFSEventStreamCreateFlagFileEvents
);
112 CFRelease(paths_to_watch
);
114 FSEventStreamSetDispatchQueue(event_stream
, event_queue
);
116 if (!FSEventStreamStart(event_stream
)) {
117 fprintf(stderr
, "Failed to start FSEventStream\n");
123 FSEventStreamStop(event_stream
);
124 FSEventStreamSetDispatchQueue(event_stream
, NULL
);
125 FSEventStreamRelease(event_stream
);
127 dispatch_release(event_queue
);
128 dispatch_barrier_sync(log_queue
, ^{
129 dispatch_release(log_queue
);