Merge branch 'master' of git@git.labs.intellij.net:idea/community
[fedora-idea.git] / native / fsNotifier / mac / fsnotifier.c
blobcefe730156ade0d01f3c095c0237c3832697f4d6
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <CoreServices/CoreServices.h>
18 #include <sys/mount.h>
20 static int ReportMountedFileSystems()
21 // If fsBuf is too small to account for all volumes, getfsstat will
22 // silently truncate the returned information. Worse yet, it returns
23 // the number of volumes it passed back, not the number of volumes present,
24 // so you can't tell if the list was truncated.
26 // So, in order to get an accurate snapshot of the volume list, I call
27 // getfsstat with a NULL fsBuf to get a count (fsCountOrig), then allocate a
28 // buffer that holds (fsCountOrig + 1) items, then call getfsstat again with
29 // that buffer. If the list was silently truncated, the second count (fsCount)
30 // will be (fsCountOrig + 1), and we loop to try again.
32 int err;
33 int fsCountOrig;
34 int fsCount;
35 struct statfs * fsBuf;
36 bool done;
39 fsBuf = NULL;
40 fsCount = 0;
42 done = false;
43 do {
44 // Get the initial count.
45 err = 0;
46 fsCountOrig = getfsstat(NULL, 0, MNT_WAIT);
47 if (fsCountOrig < 0) {
48 err = errno;
51 // Allocate a buffer for fsCountOrig + 1 items.
52 if (err == 0) {
53 if (fsBuf != NULL) {
54 free(fsBuf);
56 fsBuf = malloc((fsCountOrig + 1) * sizeof(*fsBuf));
57 if (fsBuf == NULL) {
58 err = ENOMEM;
62 // Get the list.
63 if (err == 0) {
64 fsCount = getfsstat(fsBuf, (int) ((fsCountOrig + 1) * sizeof(*fsBuf)), MNT_WAIT);
65 if (fsCount < 0) {
66 err = errno;
70 // We got the full list if the number of items returned by the kernel
71 // is strictly less than the buffer that we allocated (fsCountOrig + 1).
72 if (err == 0) {
73 if (fsCount <= fsCountOrig) {
74 done = true;
77 } while ( (err == 0) && ! done );
79 int i;
80 int mountCounts = 0;
81 for (i = 0; i < fsCount; i++) {
82 if ((fsBuf[i].f_flags & MNT_LOCAL) == 0 || (fsBuf[i].f_flags & MNT_JOURNALED) == 0) {
83 if (mountCounts == 0) {
84 printf("UNWATCHEABLE\n");
86 printf("%s\n", fsBuf[i].f_mntonname);
87 mountCounts++;
91 if (mountCounts > 0) {
92 printf("#\n");
93 fflush(stdout);
96 free(fsBuf);
97 fsBuf = NULL;
99 return err;
102 void callback(ConstFSEventStreamRef streamRef,
103 void *clientCallBackInfo,
104 size_t numEvents,
105 void *eventPaths,
106 const FSEventStreamEventFlags eventFlags[],
107 const FSEventStreamEventId eventIds[]) {
108 char **paths = eventPaths;
110 int i;
111 for (i=0; i<numEvents; i++) {
112 FSEventStreamEventFlags flags = eventFlags[i];
113 if (flags == kFSEventStreamEventFlagMount || flags == kFSEventStreamEventFlagUnmount) {
114 ReportMountedFileSystems();
116 else if ((flags & kFSEventStreamEventFlagMustScanSubDirs) != 0) {
117 printf("RECDIRTY\n");
118 printf("%s\n", paths[i]);
120 else if (eventFlags[i] != kFSEventStreamEventFlagNone) {
121 printf("RESET\n");
123 else {
124 printf("DIRTY\n");
125 printf("%s\n", paths[i]);
129 fflush(stdout);
132 // Static buffer for fscanf. All of the are being performed from a single thread, so it's thread safe.
133 static char command[2048];
135 static void parseRoots() {
136 while (TRUE) {
137 fscanf(stdin, "%s", command);
138 if (strcmp(command, "#") == 0 || feof(stdin)) break;
142 void *event_processing_thread(void *data) {
143 CFStringRef mypath = CFSTR("/");
144 CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
145 void *callbackInfo = NULL;
147 FSEventStreamRef stream;
148 CFAbsoluteTime latency = 0.3; /* Latency in seconds */
150 // Create the stream, passing in a callback,
151 stream = FSEventStreamCreate(NULL,
152 &callback,
153 callbackInfo,
154 pathsToWatch,
155 kFSEventStreamEventIdSinceNow,
156 latency,
157 kFSEventStreamCreateFlagNoDefer
160 FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
161 FSEventStreamStart(stream);
163 CFRunLoopRun();
164 return NULL;
167 int main (int argc, const char * argv[]) {
168 // Checking if necessary API is available (need MacOS X 10.5 or later).
169 if (FSEventStreamCreate == NULL) {
170 printf("GIVEUP\n");
171 return 1;
174 ReportMountedFileSystems();
176 pthread_t thread_id;
177 int rc = pthread_create(&thread_id, NULL, event_processing_thread, NULL);
179 if (rc != 0) {
180 // Give up if cannot create a thread.
181 printf("GIVEUP\n");
182 exit(1);
185 while (TRUE) {
186 fscanf(stdin, "%s", command);
187 if (strcmp(command, "EXIT") == 0 || feof(stdin)) exit(0);
188 if (strcmp(command, "ROOTS") == 0) parseRoots();
191 return 0;