Add a README.md
[fseventw.git] / fseventw.c
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include <CoreServices/CoreServices.h>
16 #include <dispatch/dispatch.h>
17 #include <stdio.h>
18
19 typedef char FlagDescription[8];
20
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");
26 });
27 } else if (flags & kFSEventStreamEventFlagKernelDropped) {
28 dispatch_async(log_queue, ^{
29 printf("Kernel-side buffer dropped event\n");
30 });
31 } else if (flags & kFSEventStreamEventFlagEventIdsWrapped) {
32 dispatch_async(log_queue, ^{
33 printf("Event IDs have wrapped\n");
34 });
35 }
36 }
37
38 void DescribeFlags(FSEventStreamEventFlags flags, FlagDescription description) {
39 memset(description, '-', sizeof(FlagDescription));
40 description[sizeof(FlagDescription) - 1] = '\0';
41
42 if (flags & kFSEventStreamEventFlagItemCreated)
43 description[0] = 'C';
44 else if (flags & kFSEventStreamEventFlagItemModified)
45 description[1] = 'M';
46 else if (flags & kFSEventStreamEventFlagItemRemoved)
47 description[2] = 'R';
48 else if (flags & kFSEventStreamEventFlagItemRenamed)
49 description[3] = 'N';
50 else if (flags & (kFSEventStreamEventFlagItemInodeMetaMod |
51 kFSEventStreamEventFlagItemFinderInfoMod))
52 description[4] = 'M';
53 else if (flags & kFSEventStreamEventFlagItemChangeOwner)
54 description[5] = 'O';
55 else if (flags & kFSEventStreamEventFlagItemXattrMod)
56 description[6] = 'X';
57 }
58
59 void EventStreamCallback(ConstFSEventStreamRef event_stream,
60 void* callback_info,
61 size_t num_events,
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;
67
68 for (size_t i = 0; i < num_events; ++i) {
69 const FSEventStreamEventFlags flags = event_flags[i];
70 const FSEventStreamEventId ids = event_ids[i];
71
72 LogControlFlagInfo(log_queue, flags);
73
74 char* path = strdup(event_paths[i]);
75
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);
80 free(path);
81 });
82 }
83 }
84
85 int main() {
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
88 // event queue.
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);
91
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);
95
96 FSEventStreamContext context = {
97 .version = 0,
98 .info = log_queue,
99 .retain = (const void* (*)(const void*))&dispatch_retain,
100 .release = (void (*)(const void*))&dispatch_release,
101 .copyDescription = NULL
102 };
103 FSEventStreamRef event_stream =
104 FSEventStreamCreate(NULL,
105 &EventStreamCallback,
106 &context,
107 paths_to_watch,
108 kFSEventStreamEventIdSinceNow,
109 1,
110 kFSEventStreamCreateFlagFileEvents);
111
112 CFRelease(paths_to_watch);
113
114 FSEventStreamSetDispatchQueue(event_stream, event_queue);
115
116 if (!FSEventStreamStart(event_stream)) {
117 fprintf(stderr, "Failed to start FSEventStream\n");
118 return EXIT_FAILURE;
119 }
120
121 dispatch_main();
122
123 FSEventStreamStop(event_stream);
124 FSEventStreamSetDispatchQueue(event_stream, NULL);
125 FSEventStreamRelease(event_stream);
126
127 dispatch_release(event_queue);
128 dispatch_barrier_sync(log_queue, ^{
129 dispatch_release(log_queue);
130 });
131 }