rb-fsevent 0.9.2 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/Gemfile +3 -0
- data/Guardfile +8 -0
- data/{LICENSE → LICENSE.txt} +3 -1
- data/README.md +260 -0
- data/Rakefile +33 -0
- data/bin/fsevent_watch +0 -0
- data/ext/{fsevent_watch/LICENSE → LICENSE} +1 -1
- data/ext/fsevent_watch/FSEventsFix.c +626 -0
- data/ext/fsevent_watch/FSEventsFix.h +105 -0
- data/ext/fsevent_watch/{fsevent_watch/TSICTString.c → TSICTString.c} +34 -55
- data/ext/fsevent_watch/{fsevent_watch/TSICTString.h → TSICTString.h} +0 -0
- data/ext/fsevent_watch/{fsevent_watch/cli.c → cli.c} +48 -7
- data/ext/fsevent_watch/{fsevent_watch/cli.h → cli.h} +3 -3
- data/ext/fsevent_watch/{fsevent_watch/common.h → common.h} +1 -13
- data/ext/fsevent_watch/compat.c +41 -0
- data/ext/fsevent_watch/compat.h +100 -0
- data/ext/fsevent_watch/defines.h +42 -0
- data/ext/fsevent_watch/{fsevent_watch/main.c → main.c} +101 -62
- data/ext/fsevent_watch/signal_handlers.c +66 -0
- data/ext/fsevent_watch/signal_handlers.h +16 -0
- data/ext/rakefile.rb +225 -41
- data/lib/otnetstring.rb +85 -0
- data/lib/rb-fsevent/fsevent.rb +53 -7
- data/lib/rb-fsevent/version.rb +3 -1
- data/lib/rb-fsevent.rb +2 -1
- data/rb-fsevent.gemspec +26 -0
- metadata +53 -56
- data/README.rdoc +0 -255
- data/ext/fsevent_watch/Info.plist +0 -38
- data/ext/fsevent_watch/fsevent_watch/compat.c +0 -20
- data/ext/fsevent_watch/fsevent_watch/compat.h +0 -40
- data/ext/fsevent_watch/fsevent_watch.xcodeproj/project.pbxproj +0 -254
- data/ext/fsevent_watch/xcconfig/Common.xcconfig +0 -82
- data/ext/fsevent_watch/xcconfig/Debug.xcconfig +0 -19
- data/ext/fsevent_watch/xcconfig/Release.xcconfig +0 -23
- data/ext/fsevent_watch/xcconfig/fsevent_watch.xcconfig +0 -17
- data/ext/rb-fsevent.xcconfig +0 -33
@@ -0,0 +1,105 @@
|
|
1
|
+
/*
|
2
|
+
* FSEventsFix
|
3
|
+
*
|
4
|
+
* Works around a long-standing bug in realpath() that prevents FSEvents API from
|
5
|
+
* monitoring certain folders on a wide range of OS X releases (10.6-10.10 at least).
|
6
|
+
*
|
7
|
+
* The underlying issue is that for some folders, realpath() call starts returning
|
8
|
+
* a path with incorrect casing (e.g. "/users/smt" instead of "/Users/smt").
|
9
|
+
* FSEvents is case-sensitive and calls realpath() on the paths you pass in, so
|
10
|
+
* an incorrect value returned by realpath() prevents FSEvents from seeing any
|
11
|
+
* change events.
|
12
|
+
*
|
13
|
+
* See the discussion at https://github.com/thibaudgg/rb-fsevent/issues/10 about
|
14
|
+
* the history of this bug and how this library came to exist.
|
15
|
+
*
|
16
|
+
* This library uses Facebook's fishhook to replace a custom implementation of
|
17
|
+
* realpath in place of the system realpath; FSEvents will then invoke our custom
|
18
|
+
* implementation (which does not screw up the names) and will thus work correctly.
|
19
|
+
*
|
20
|
+
* Our implementation of realpath is based on the open-source implementation from
|
21
|
+
* OS X 10.10, with a single change applied (enclosed in "BEGIN WORKAROUND FOR
|
22
|
+
* OS X BUG" ... "END WORKAROUND FOR OS X BUG").
|
23
|
+
*
|
24
|
+
* Include FSEventsFix.{h,c} into your project and call FSEventsFixInstall().
|
25
|
+
*
|
26
|
+
* It is recommended that you install FSEventsFix on demand, using FSEventsFixIsBroken
|
27
|
+
* to check if the folder you're about to pass to FSEventStreamCreate needs the fix.
|
28
|
+
* Note that the fix must be applied before calling FSEventStreamCreate.
|
29
|
+
*
|
30
|
+
* FSEventsFixIsBroken requires a path that uses the correct case for all folder names,
|
31
|
+
* i.e. a path provided by the system APIs or constructed from folder names provided
|
32
|
+
* by the directory enumeration APIs.
|
33
|
+
*
|
34
|
+
* See .c file for license & copyrights, but basically this is available under a mix
|
35
|
+
* of MIT and BSD licenses.
|
36
|
+
*/
|
37
|
+
|
38
|
+
#ifndef __FSEventsFix__
|
39
|
+
#define __FSEventsFix__
|
40
|
+
|
41
|
+
#include <CoreFoundation/CoreFoundation.h>
|
42
|
+
|
43
|
+
/// A library version string (e.g. 1.2.3) for displaying and logging purposes
|
44
|
+
extern const char *const FSEventsFixVersionString;
|
45
|
+
|
46
|
+
/// See FSEventsFixDebugOptionSimulateBroken
|
47
|
+
#define FSEventsFixSimulatedBrokenFolderMarker "__!FSEventsBroken!__"
|
48
|
+
|
49
|
+
typedef CF_OPTIONS(unsigned, FSEventsFixDebugOptions) {
|
50
|
+
/// Always return an uppercase string from realpath
|
51
|
+
FSEventsFixDebugOptionUppercaseReturn = 0x01,
|
52
|
+
|
53
|
+
/// Log all calls to realpath using the logger configured via FSEventsFixConfigure
|
54
|
+
FSEventsFixDebugOptionLogCalls = 0x02,
|
55
|
+
|
56
|
+
/// In addition to the logging block (if any), log everything to stderr
|
57
|
+
FSEventsFixDebugOptionLogToStderr = 0x08,
|
58
|
+
|
59
|
+
/// Report paths containing FSEventsFixSimulatedBrokenFolderMarker as broken
|
60
|
+
FSEventsFixDebugOptionSimulateBroken = 0x10,
|
61
|
+
|
62
|
+
/// Repair paths containing FSEventsFixSimulatedBrokenFolderMarker by renaming them
|
63
|
+
FSEventsFixDebugOptionSimulateRepair = 0x20,
|
64
|
+
};
|
65
|
+
|
66
|
+
typedef CF_ENUM(int, FSEventsFixMessageType) {
|
67
|
+
/// Call logging requested via FSEventsFixDebugOptionLogCalls
|
68
|
+
FSEventsFixMessageTypeCall,
|
69
|
+
|
70
|
+
/// Results of actions like repair, and other pretty verbose, but notable, stuff.
|
71
|
+
FSEventsFixMessageTypeResult,
|
72
|
+
|
73
|
+
/// Enabled/disabled status change
|
74
|
+
FSEventsFixMessageTypeStatusChange,
|
75
|
+
|
76
|
+
/// Expected failure (treat as a warning)
|
77
|
+
FSEventsFixMessageTypeExpectedFailure,
|
78
|
+
|
79
|
+
/// Severe failure that most likely means that the library won't work
|
80
|
+
FSEventsFixMessageTypeFatalError
|
81
|
+
};
|
82
|
+
|
83
|
+
typedef CF_ENUM(int, FSEventsFixRepairStatus) {
|
84
|
+
FSEventsFixRepairStatusNotBroken,
|
85
|
+
FSEventsFixRepairStatusRepaired,
|
86
|
+
FSEventsFixRepairStatusFailed,
|
87
|
+
};
|
88
|
+
|
89
|
+
/// Note that the logging block can be called on any dispatch queue.
|
90
|
+
void FSEventsFixConfigure(FSEventsFixDebugOptions debugOptions, void(^loggingBlock)(FSEventsFixMessageType type, const char *message));
|
91
|
+
|
92
|
+
void FSEventsFixEnable();
|
93
|
+
void FSEventsFixDisable();
|
94
|
+
|
95
|
+
bool FSEventsFixIsOperational();
|
96
|
+
|
97
|
+
bool FSEventsFixIsBroken(const char *path);
|
98
|
+
|
99
|
+
/// If the path is broken, returns a string identifying the root broken folder,
|
100
|
+
/// otherwise, returns NULL. You need to free() the returned string.
|
101
|
+
char *FSEventsFixCopyRootBrokenFolderPath(const char *path);
|
102
|
+
|
103
|
+
FSEventsFixRepairStatus FSEventsFixRepairIfNeeded(const char *path);
|
104
|
+
|
105
|
+
#endif
|
@@ -65,13 +65,13 @@ static inline TStringIRep* TSICTStringCreateWithDataOfTypeAndFormat(CFDataRef da
|
|
65
65
|
if (format == kTSITStringFormatDefault) {
|
66
66
|
format = TSICTStringGetDefaultFormat();
|
67
67
|
}
|
68
|
-
|
68
|
+
|
69
69
|
TStringIRep* rep = calloc(1, sizeof(TStringIRep));
|
70
70
|
rep->data = CFDataCreateCopy(kCFAllocatorDefault, data);
|
71
71
|
rep->type = type;
|
72
72
|
rep->format = format;
|
73
73
|
rep->length = calloc(10, sizeof(char));
|
74
|
-
|
74
|
+
|
75
75
|
CFIndex len = CFDataGetLength(rep->data);
|
76
76
|
if (snprintf(rep->length, 10, "%lu", len)) {
|
77
77
|
return rep;
|
@@ -86,10 +86,10 @@ static inline CFDataRef TSICTStringCreateDataFromIntermediateRepresentation(TStr
|
|
86
86
|
CFIndex len = CFDataGetLength(rep->data);
|
87
87
|
CFMutableDataRef buffer = CFDataCreateMutableCopy(kCFAllocatorDefault, (len + 12), rep->data);
|
88
88
|
UInt8* bufferBytes = CFDataGetMutableBytePtr(buffer);
|
89
|
-
|
89
|
+
|
90
90
|
size_t prefixLength = strlen(rep->length) + 1;
|
91
91
|
CFDataReplaceBytes(buffer, BeginningRange, (const UInt8*)rep->length, (CFIndex)prefixLength);
|
92
|
-
|
92
|
+
|
93
93
|
if (rep->format == kTSITStringFormatTNetstring) {
|
94
94
|
const UInt8 ftag = (UInt8)TNetstringTypes[rep->type];
|
95
95
|
CFDataAppendBytes(buffer, &ftag, 1);
|
@@ -98,10 +98,10 @@ static inline CFDataRef TSICTStringCreateDataFromIntermediateRepresentation(TStr
|
|
98
98
|
const UInt8 ftag = (UInt8)OTNetstringTypes[rep->type];
|
99
99
|
bufferBytes[(prefixLength - 1)] = ftag;
|
100
100
|
}
|
101
|
-
|
101
|
+
|
102
102
|
CFDataRef dataRep = CFDataCreateCopy(kCFAllocatorDefault, buffer);
|
103
103
|
CFRelease(buffer);
|
104
|
-
|
104
|
+
|
105
105
|
return dataRep;
|
106
106
|
}
|
107
107
|
|
@@ -113,41 +113,20 @@ static inline CFStringRef TSICTStringCreateStringFromIntermediateRepresentation(
|
|
113
113
|
return string;
|
114
114
|
}
|
115
115
|
|
116
|
-
static inline CFDataRef TSICTStringCreateDataWithDataOfTypeAndFormat(CFDataRef data, TSITStringTag type, TSITStringFormat format)
|
117
|
-
{
|
118
|
-
CFRetain(data);
|
119
|
-
|
120
|
-
if (format == kTSITStringFormatDefault) {
|
121
|
-
format = TSICTStringGetDefaultFormat();
|
122
|
-
}
|
123
|
-
|
124
|
-
TStringIRep* rep = TSICTStringCreateWithDataOfTypeAndFormat(data, type, format);
|
125
|
-
if (rep == NULL) {
|
126
|
-
return NULL;
|
127
|
-
}
|
128
|
-
|
129
|
-
CFDataRef result = TSICTStringCreateDataFromIntermediateRepresentation(rep);
|
130
|
-
|
131
|
-
TSICTStringDestroy(rep);
|
132
|
-
CFRelease(data);
|
133
|
-
|
134
|
-
return result;
|
135
|
-
}
|
136
|
-
|
137
116
|
static inline void TSICTStringAppendObjectToMutableDataWithFormat(CFTypeRef object, CFMutableDataRef buffer, TSITStringFormat format)
|
138
117
|
{
|
139
118
|
if (object == NULL) {
|
140
119
|
object = kCFNull;
|
141
120
|
}
|
142
|
-
|
121
|
+
|
143
122
|
CFRetain(object);
|
144
|
-
|
123
|
+
|
145
124
|
TStringIRep* objRep = TSICTStringCreateWithObjectAndFormat(object, format);
|
146
125
|
CFDataRef objData = TSICTStringCreateDataFromIntermediateRepresentation(objRep);
|
147
126
|
CFDataAppendBytes(buffer, (CFDataGetBytePtr(objData)), CFDataGetLength(objData));
|
148
127
|
CFRelease(objData);
|
149
128
|
TSICTStringDestroy(objRep);
|
150
|
-
|
129
|
+
|
151
130
|
CFRelease(object);
|
152
131
|
}
|
153
132
|
|
@@ -156,7 +135,7 @@ static void ArrayBufferAppendCallback(const void* item, void* context)
|
|
156
135
|
TStringCollectionCallbackContext* cx = (TStringCollectionCallbackContext*)context;
|
157
136
|
CFMutableDataRef buffer = cx->buffer;
|
158
137
|
TSITStringFormat format = cx->format;
|
159
|
-
|
138
|
+
|
160
139
|
TSICTStringAppendObjectToMutableDataWithFormat(item, buffer, format);
|
161
140
|
}
|
162
141
|
|
@@ -165,7 +144,7 @@ static void DictionaryBufferAppendCallback(const void* key, const void* value, v
|
|
165
144
|
TStringCollectionCallbackContext* cx = (TStringCollectionCallbackContext*)context;
|
166
145
|
CFMutableDataRef buffer = cx->buffer;
|
167
146
|
TSITStringFormat format = cx->format;
|
168
|
-
|
147
|
+
|
169
148
|
TSICTStringAppendObjectToMutableDataWithFormat(key, buffer, format);
|
170
149
|
TSICTStringAppendObjectToMutableDataWithFormat(value, buffer, format);
|
171
150
|
}
|
@@ -181,15 +160,15 @@ CFDataRef TSICTStringCreateRenderedDataFromObjectWithFormat(CFTypeRef object, TS
|
|
181
160
|
if (object == NULL) {
|
182
161
|
object = kCFNull;
|
183
162
|
}
|
184
|
-
|
163
|
+
|
185
164
|
CFRetain(object);
|
186
|
-
|
165
|
+
|
187
166
|
TStringIRep* rep = TSICTStringCreateWithObjectAndFormat(object, format);
|
188
167
|
CFDataRef data = TSICTStringCreateDataFromIntermediateRepresentation(rep);
|
189
|
-
|
168
|
+
|
190
169
|
TSICTStringDestroy(rep);
|
191
170
|
CFRelease(object);
|
192
|
-
|
171
|
+
|
193
172
|
return data;
|
194
173
|
}
|
195
174
|
|
@@ -203,15 +182,15 @@ CFStringRef TSICTStringCreateRenderedStringFromObjectWithFormat(CFTypeRef object
|
|
203
182
|
if (object == NULL) {
|
204
183
|
object = kCFNull;
|
205
184
|
}
|
206
|
-
|
185
|
+
|
207
186
|
CFRetain(object);
|
208
|
-
|
187
|
+
|
209
188
|
TStringIRep* rep = TSICTStringCreateWithObjectAndFormat(object, format);
|
210
189
|
CFStringRef string = TSICTStringCreateStringFromIntermediateRepresentation(rep);
|
211
|
-
|
190
|
+
|
212
191
|
TSICTStringDestroy(rep);
|
213
192
|
CFRelease(object);
|
214
|
-
|
193
|
+
|
215
194
|
return string;
|
216
195
|
}
|
217
196
|
|
@@ -222,10 +201,10 @@ TStringIRep* TSICTStringCreateWithObjectAndFormat(CFTypeRef object, TSITStringFo
|
|
222
201
|
return TSICTStringCreateNullWithFormat(format);
|
223
202
|
}
|
224
203
|
CFRetain(object);
|
225
|
-
|
204
|
+
|
226
205
|
CFTypeID cfType = CFGetTypeID(object);
|
227
206
|
TStringIRep* rep = NULL;
|
228
|
-
|
207
|
+
|
229
208
|
if (cfType == kCFDataTypeID) {
|
230
209
|
rep = TSICTStringCreateWithDataOfTypeAndFormat(object, kTSITStringTagString, format);
|
231
210
|
} else if (cfType == kCFStringTypeID) {
|
@@ -247,7 +226,7 @@ TStringIRep* TSICTStringCreateWithObjectAndFormat(CFTypeRef object, TSITStringFo
|
|
247
226
|
} else {
|
248
227
|
rep = TSICTStringCreateInvalidWithFormat(format);
|
249
228
|
}
|
250
|
-
|
229
|
+
|
251
230
|
CFRelease(object);
|
252
231
|
return rep;
|
253
232
|
}
|
@@ -268,7 +247,7 @@ TStringIRep* TSICTStringCreateWithNumberAndFormat(CFNumberRef number, TSITString
|
|
268
247
|
TSITStringTag tag = kTSITStringTagNumber;
|
269
248
|
CFDataRef data;
|
270
249
|
CFNumberType numType = CFNumberGetType(number);
|
271
|
-
|
250
|
+
|
272
251
|
switch(numType) {
|
273
252
|
case kCFNumberCharType:
|
274
253
|
{
|
@@ -291,7 +270,7 @@ TStringIRep* TSICTStringCreateWithNumberAndFormat(CFNumberRef number, TSITString
|
|
291
270
|
break;
|
292
271
|
}
|
293
272
|
}
|
294
|
-
|
273
|
+
|
295
274
|
if (tag == kTSITStringTagBool) {
|
296
275
|
bool value;
|
297
276
|
CFNumberGetValue(number, kCFNumberIntType, &value);
|
@@ -304,17 +283,17 @@ TStringIRep* TSICTStringCreateWithNumberAndFormat(CFNumberRef number, TSITString
|
|
304
283
|
char buf[32];
|
305
284
|
char *p, *e;
|
306
285
|
double value;
|
307
|
-
|
286
|
+
|
308
287
|
CFNumberGetValue(number, numType, &value);
|
309
288
|
sprintf(buf, "%#.15g", value);
|
310
|
-
|
289
|
+
|
311
290
|
e = buf + strlen(buf);
|
312
291
|
p = e;
|
313
292
|
while (p[-1]=='0' && ('0' <= p[-2] && p[-2] <= '9')) {
|
314
293
|
p--;
|
315
294
|
}
|
316
295
|
memmove(p, e, strlen(e)+1);
|
317
|
-
|
296
|
+
|
318
297
|
data = CFDataCreate(kCFAllocatorDefault, (UInt8*)buf, (CFIndex)strlen(buf));
|
319
298
|
} else {
|
320
299
|
char buf[32];
|
@@ -323,7 +302,7 @@ TStringIRep* TSICTStringCreateWithNumberAndFormat(CFNumberRef number, TSITString
|
|
323
302
|
sprintf(buf, "%lli", value);
|
324
303
|
data = CFDataCreate(kCFAllocatorDefault, (UInt8*)buf, (CFIndex)strlen(buf));
|
325
304
|
}
|
326
|
-
|
305
|
+
|
327
306
|
TStringIRep* rep = TSICTStringCreateWithDataOfTypeAndFormat(data, tag, format);
|
328
307
|
CFRelease(data);
|
329
308
|
CFRelease(number);
|
@@ -365,13 +344,13 @@ TStringIRep* TSICTStringCreateInvalidWithFormat(TSITStringFormat format)
|
|
365
344
|
TStringIRep* TSICTStringCreateWithArrayAndFormat(CFArrayRef array, TSITStringFormat format)
|
366
345
|
{
|
367
346
|
CFRetain(array);
|
368
|
-
|
347
|
+
|
369
348
|
CFMutableDataRef buffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
370
|
-
|
349
|
+
|
371
350
|
CFRange all = CFRangeMake(0, CFArrayGetCount(array));
|
372
351
|
TStringCollectionCallbackContext cx = {buffer, format};
|
373
352
|
CFArrayApplyFunction(array, all, ArrayBufferAppendCallback, &cx);
|
374
|
-
|
353
|
+
|
375
354
|
TStringIRep* rep = TSICTStringCreateWithDataOfTypeAndFormat(buffer, kTSITStringTagList, format);
|
376
355
|
CFRelease(buffer);
|
377
356
|
CFRelease(array);
|
@@ -381,12 +360,12 @@ TStringIRep* TSICTStringCreateWithArrayAndFormat(CFArrayRef array, TSITStringFor
|
|
381
360
|
TStringIRep* TSICTStringCreateWithDictionaryAndFormat(CFDictionaryRef dictionary, TSITStringFormat format)
|
382
361
|
{
|
383
362
|
CFRetain(dictionary);
|
384
|
-
|
363
|
+
|
385
364
|
CFMutableDataRef buffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
386
|
-
|
365
|
+
|
387
366
|
TStringCollectionCallbackContext cx = {buffer, format};
|
388
367
|
CFDictionaryApplyFunction(dictionary, DictionaryBufferAppendCallback, &cx);
|
389
|
-
|
368
|
+
|
390
369
|
TStringIRep* rep = TSICTStringCreateWithDataOfTypeAndFormat(buffer, kTSITStringTagDict, format);
|
391
370
|
CFRelease(buffer);
|
392
371
|
CFRelease(dictionary);
|
File without changes
|
@@ -6,6 +6,7 @@ const char* cli_info_usage = "Usage: fsevent_watch [OPTIONS]... [PATHS]...";
|
|
6
6
|
const char* cli_info_help[] = {
|
7
7
|
" -h, --help you're looking at it",
|
8
8
|
" -V, --version print version number and exit",
|
9
|
+
" -p, --show-plist display the embedded Info.plist values",
|
9
10
|
" -s, --since-when=EventID fire historical events since ID",
|
10
11
|
" -l, --latency=seconds latency period (default='0.5')",
|
11
12
|
" -n, --no-defer enable no-defer latency modifier",
|
@@ -25,7 +26,8 @@ static void default_args (struct cli_info* args_info)
|
|
25
26
|
args_info->watch_root_flag = false;
|
26
27
|
args_info->ignore_self_flag = false;
|
27
28
|
args_info->file_events_flag = false;
|
28
|
-
args_info->
|
29
|
+
args_info->mark_self_flag = false;
|
30
|
+
args_info->format_arg = kFSEventWatchOutputFormatOTNetstring;
|
29
31
|
}
|
30
32
|
|
31
33
|
static void cli_parser_release (struct cli_info* args_info)
|
@@ -56,12 +58,46 @@ void cli_parser_free (struct cli_info* args_info)
|
|
56
58
|
cli_parser_release(args_info);
|
57
59
|
}
|
58
60
|
|
61
|
+
static void cli_print_info_dict (const void *key,
|
62
|
+
const void *value,
|
63
|
+
void *context)
|
64
|
+
{
|
65
|
+
CFStringRef entry = CFStringCreateWithFormat(NULL, NULL,
|
66
|
+
CFSTR("%@:\n %@"), key, value);
|
67
|
+
if (entry) {
|
68
|
+
CFShow(entry);
|
69
|
+
CFRelease(entry);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
void cli_show_plist (void)
|
74
|
+
{
|
75
|
+
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
76
|
+
CFRetain(mainBundle);
|
77
|
+
CFDictionaryRef mainBundleDict = CFBundleGetInfoDictionary(mainBundle);
|
78
|
+
if (mainBundleDict) {
|
79
|
+
CFRetain(mainBundleDict);
|
80
|
+
printf("Embedded Info.plist metadata:\n\n");
|
81
|
+
CFDictionaryApplyFunction(mainBundleDict, cli_print_info_dict, NULL);
|
82
|
+
CFRelease(mainBundleDict);
|
83
|
+
}
|
84
|
+
CFRelease(mainBundle);
|
85
|
+
printf("\n");
|
86
|
+
}
|
87
|
+
|
59
88
|
void cli_print_version (void)
|
60
89
|
{
|
61
|
-
printf("%s %s\n", CLI_NAME, CLI_VERSION);
|
90
|
+
printf("%s %s\n\n", CLI_NAME, CLI_VERSION);
|
62
91
|
#ifdef COMPILED_AT
|
63
|
-
printf("Compiled %s\n", COMPILED_AT);
|
92
|
+
printf("Compiled at: %s\n", COMPILED_AT);
|
64
93
|
#endif
|
94
|
+
#ifdef COMPILER
|
95
|
+
printf("Compiled with: %s\n", COMPILER);
|
96
|
+
#endif
|
97
|
+
#ifdef TARGET_CPU
|
98
|
+
printf("Compiled for: %s\n", TARGET_CPU);
|
99
|
+
#endif
|
100
|
+
printf("\n");
|
65
101
|
}
|
66
102
|
|
67
103
|
void cli_print_help (void)
|
@@ -83,17 +119,19 @@ int cli_parser (int argc, const char** argv, struct cli_info* args_info)
|
|
83
119
|
static struct option longopts[] = {
|
84
120
|
{ "help", no_argument, NULL, 'h' },
|
85
121
|
{ "version", no_argument, NULL, 'V' },
|
122
|
+
{ "show-plist", no_argument, NULL, 'p' },
|
86
123
|
{ "since-when", required_argument, NULL, 's' },
|
87
124
|
{ "latency", required_argument, NULL, 'l' },
|
88
125
|
{ "no-defer", no_argument, NULL, 'n' },
|
89
126
|
{ "watch-root", no_argument, NULL, 'r' },
|
90
127
|
{ "ignore-self", no_argument, NULL, 'i' },
|
91
128
|
{ "file-events", no_argument, NULL, 'F' },
|
129
|
+
{ "mark-self", no_argument, NULL, 'm' },
|
92
130
|
{ "format", required_argument, NULL, 'f' },
|
93
131
|
{ 0, 0, 0, 0 }
|
94
132
|
};
|
95
133
|
|
96
|
-
const char* shortopts = "
|
134
|
+
const char* shortopts = "hVps:l:nriFf:";
|
97
135
|
|
98
136
|
int c = -1;
|
99
137
|
|
@@ -117,6 +155,9 @@ int cli_parser (int argc, const char** argv, struct cli_info* args_info)
|
|
117
155
|
case 'F': // file-events
|
118
156
|
args_info->file_events_flag = true;
|
119
157
|
break;
|
158
|
+
case 'm': // mark-self
|
159
|
+
args_info->mark_self_flag = true;
|
160
|
+
break;
|
120
161
|
case 'f': // format
|
121
162
|
if (strcmp(optarg, "classic") == 0) {
|
122
163
|
args_info->format_arg = kFSEventWatchOutputFormatClassic;
|
@@ -134,13 +175,14 @@ int cli_parser (int argc, const char** argv, struct cli_info* args_info)
|
|
134
175
|
case 'V': // version
|
135
176
|
cli_print_version();
|
136
177
|
exit(EXIT_SUCCESS);
|
137
|
-
|
178
|
+
case 'p': // show-plist
|
179
|
+
cli_show_plist();
|
180
|
+
exit(EXIT_SUCCESS);
|
138
181
|
case 'h': // help
|
139
182
|
case '?': // invalid option
|
140
183
|
case ':': // missing argument
|
141
184
|
cli_print_help();
|
142
185
|
exit((c == 'h') ? EXIT_SUCCESS : EXIT_FAILURE);
|
143
|
-
break;
|
144
186
|
}
|
145
187
|
}
|
146
188
|
|
@@ -157,4 +199,3 @@ int cli_parser (int argc, const char** argv, struct cli_info* args_info)
|
|
157
199
|
|
158
200
|
return EXIT_SUCCESS;
|
159
201
|
}
|
160
|
-
|
@@ -1,6 +1,8 @@
|
|
1
1
|
#ifndef CLI_H
|
2
2
|
#define CLI_H
|
3
3
|
|
4
|
+
#include "common.h"
|
5
|
+
|
4
6
|
#ifndef CLI_NAME
|
5
7
|
#define CLI_NAME "fsevent_watch"
|
6
8
|
#endif /* CLI_NAME */
|
@@ -10,12 +12,9 @@
|
|
10
12
|
#endif /* PROJECT_VERSION */
|
11
13
|
|
12
14
|
#ifndef CLI_VERSION
|
13
|
-
#define _str(s) #s
|
14
|
-
#define _xstr(s) _str(s)
|
15
15
|
#define CLI_VERSION _xstr(PROJECT_VERSION)
|
16
16
|
#endif /* CLI_VERSION */
|
17
17
|
|
18
|
-
#include "common.h"
|
19
18
|
|
20
19
|
struct cli_info {
|
21
20
|
UInt64 since_when_arg;
|
@@ -24,6 +23,7 @@ struct cli_info {
|
|
24
23
|
bool watch_root_flag;
|
25
24
|
bool ignore_self_flag;
|
26
25
|
bool file_events_flag;
|
26
|
+
bool mark_self_flag;
|
27
27
|
enum FSEventWatchOutputFormat format_arg;
|
28
28
|
|
29
29
|
char** inputs;
|
@@ -9,21 +9,9 @@
|
|
9
9
|
#include <CoreServices/CoreServices.h>
|
10
10
|
#include <unistd.h>
|
11
11
|
#include "compat.h"
|
12
|
+
#include "defines.h"
|
12
13
|
#include "TSICTString.h"
|
13
14
|
|
14
|
-
#define COMPILED_AT __DATE__ " " __TIME__
|
15
|
-
|
16
|
-
#define FLAG_CHECK(flags, flag) ((flags) & (flag))
|
17
|
-
|
18
|
-
#define FPRINTF_FLAG_CHECK(flags, flag, msg, fd) \
|
19
|
-
do { \
|
20
|
-
if (FLAG_CHECK(flags, flag)) { \
|
21
|
-
fprintf(fd, "%s", msg "\n"); } } \
|
22
|
-
while (0)
|
23
|
-
|
24
|
-
#define FLAG_CHECK_STDERR(flags, flag, msg) \
|
25
|
-
FPRINTF_FLAG_CHECK(flags, flag, msg, stderr)
|
26
|
-
|
27
15
|
enum FSEventWatchOutputFormat {
|
28
16
|
kFSEventWatchOutputFormatClassic,
|
29
17
|
kFSEventWatchOutputFormatNIW,
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#include "compat.h"
|
2
|
+
|
3
|
+
|
4
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || \
|
5
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_6_0)
|
6
|
+
FSEventStreamCreateFlags kFSEventStreamCreateFlagIgnoreSelf = 0x00000008;
|
7
|
+
#endif
|
8
|
+
|
9
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_7) || \
|
10
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_6_0)
|
11
|
+
FSEventStreamCreateFlags kFSEventStreamCreateFlagFileEvents = 0x00000010;
|
12
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemCreated = 0x00000100;
|
13
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemRemoved = 0x00000200;
|
14
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
|
15
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemRenamed = 0x00000800;
|
16
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemModified = 0x00001000;
|
17
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
|
18
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
|
19
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemXattrMod = 0x00008000;
|
20
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemIsFile = 0x00010000;
|
21
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemIsDir = 0x00020000;
|
22
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
|
23
|
+
#endif
|
24
|
+
|
25
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_9) || \
|
26
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0)
|
27
|
+
FSEventStreamCreateFlags kFSEventStreamCreateFlagMarkSelf = 0x00000020;
|
28
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagOwnEvent = 0x00080000;
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_10) || \
|
32
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0)
|
33
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemIsHardlink = 0x00100000;
|
34
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemIsLastHardlink = 0x00200000;
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_13) || \
|
38
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_11_0)
|
39
|
+
FSEventStreamCreateFlags kFSEventStreamCreateFlagUseExtendedData = 0x00000040;
|
40
|
+
FSEventStreamEventFlags kFSEventStreamEventFlagItemCloned = 0x00400000;
|
41
|
+
#endif
|
@@ -0,0 +1,100 @@
|
|
1
|
+
/**
|
2
|
+
* @headerfile compat.h
|
3
|
+
* FSEventStream flag compatibility shim
|
4
|
+
*
|
5
|
+
* In order to compile a binary against an older SDK yet still support the
|
6
|
+
* features present in later OS releases, we need to define any missing enum
|
7
|
+
* constants not present in the older SDK. This allows us to safely defer
|
8
|
+
* feature detection to runtime (and avoid recompilation).
|
9
|
+
*/
|
10
|
+
|
11
|
+
|
12
|
+
#ifndef listen_fsevents_compat_h
|
13
|
+
#define listen_fsevents_compat_h
|
14
|
+
|
15
|
+
#ifndef __CORESERVICES__
|
16
|
+
#include <CoreServices/CoreServices.h>
|
17
|
+
#endif // __CORESERVICES__
|
18
|
+
|
19
|
+
#ifndef __AVAILABILITY__
|
20
|
+
#include <Availability.h>
|
21
|
+
#endif // __AVAILABILITY__
|
22
|
+
|
23
|
+
#ifndef __MAC_10_6
|
24
|
+
#define __MAC_10_6 1060
|
25
|
+
#endif
|
26
|
+
#ifndef __MAC_10_7
|
27
|
+
#define __MAC_10_7 1070
|
28
|
+
#endif
|
29
|
+
#ifndef __MAC_10_9
|
30
|
+
#define __MAC_10_9 1090
|
31
|
+
#endif
|
32
|
+
#ifndef __MAC_10_10
|
33
|
+
#define __MAC_10_10 101000
|
34
|
+
#endif
|
35
|
+
#ifndef __MAC_10_13
|
36
|
+
#define __MAC_10_13 101300
|
37
|
+
#endif
|
38
|
+
#ifndef __IPHONE_6_0
|
39
|
+
#define __IPHONE_6_0 60000
|
40
|
+
#endif
|
41
|
+
#ifndef __IPHONE_7_0
|
42
|
+
#define __IPHONE_7_0 70000
|
43
|
+
#endif
|
44
|
+
#ifndef __IPHONE_9_0
|
45
|
+
#define __IPHONE_9_0 90000
|
46
|
+
#endif
|
47
|
+
#ifndef __IPHONE_11_0
|
48
|
+
#define __IPHONE_11_0 110000
|
49
|
+
#endif
|
50
|
+
|
51
|
+
#ifdef __cplusplus
|
52
|
+
extern "C" {
|
53
|
+
#endif
|
54
|
+
|
55
|
+
|
56
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || \
|
57
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_6_0)
|
58
|
+
extern FSEventStreamCreateFlags kFSEventStreamCreateFlagIgnoreSelf;
|
59
|
+
#endif
|
60
|
+
|
61
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_7) || \
|
62
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_6_0)
|
63
|
+
extern FSEventStreamCreateFlags kFSEventStreamCreateFlagFileEvents;
|
64
|
+
extern FSEventStreamEventFlags kFSEventStreamEventFlagItemCreated,
|
65
|
+
kFSEventStreamEventFlagItemRemoved,
|
66
|
+
kFSEventStreamEventFlagItemInodeMetaMod,
|
67
|
+
kFSEventStreamEventFlagItemRenamed,
|
68
|
+
kFSEventStreamEventFlagItemModified,
|
69
|
+
kFSEventStreamEventFlagItemFinderInfoMod,
|
70
|
+
kFSEventStreamEventFlagItemChangeOwner,
|
71
|
+
kFSEventStreamEventFlagItemXattrMod,
|
72
|
+
kFSEventStreamEventFlagItemIsFile,
|
73
|
+
kFSEventStreamEventFlagItemIsDir,
|
74
|
+
kFSEventStreamEventFlagItemIsSymlink;
|
75
|
+
#endif
|
76
|
+
|
77
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_9) || \
|
78
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0)
|
79
|
+
extern FSEventStreamCreateFlags kFSEventStreamCreateFlagMarkSelf;
|
80
|
+
extern FSEventStreamEventFlags kFSEventStreamEventFlagOwnEvent;
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_10) || \
|
84
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0)
|
85
|
+
extern FSEventStreamEventFlags kFSEventStreamEventFlagItemIsHardlink,
|
86
|
+
kFSEventStreamEventFlagItemIsLastHardlink;
|
87
|
+
#endif
|
88
|
+
|
89
|
+
#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_13) || \
|
90
|
+
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_11_0)
|
91
|
+
extern FSEventStreamCreateFlags kFSEventStreamCreateFlagUseExtendedData;
|
92
|
+
extern FSEventStreamEventFlags kFSEventStreamEventFlagItemCloned;
|
93
|
+
#endif
|
94
|
+
|
95
|
+
|
96
|
+
#ifdef __cplusplus
|
97
|
+
}
|
98
|
+
#endif
|
99
|
+
|
100
|
+
#endif // listen_fsevents_compat_h
|