@@ -99,7 +99,7 @@ void FSEventStreamRelease(FSEventStreamRef stream);
99
99
#include "fsm-listen.h"
100
100
#include "fsmonitor--daemon.h"
101
101
102
- struct fsmonitor_daemon_backend_data
102
+ struct fsm_listen_data
103
103
{
104
104
CFStringRef cfsr_worktree_path ;
105
105
CFStringRef cfsr_gitdir_path ;
@@ -172,12 +172,17 @@ static void log_flags_set(const char *path, const FSEventStreamEventFlags flag)
172
172
if (flag & kFSEventStreamEventFlagItemCloned )
173
173
strbuf_addstr (& msg , "ItemCloned|" );
174
174
175
- trace_printf_key (& trace_fsmonitor , "fsevent: '%s', flags=%u %s" ,
175
+ trace_printf_key (& trace_fsmonitor , "fsevent: '%s', flags=0x%x %s" ,
176
176
path , flag , msg .buf );
177
177
178
178
strbuf_release (& msg );
179
179
}
180
180
181
+ static int ef_is_root_changed (const FSEventStreamEventFlags ef )
182
+ {
183
+ return (ef & kFSEventStreamEventFlagRootChanged );
184
+ }
185
+
181
186
static int ef_is_root_delete (const FSEventStreamEventFlags ef )
182
187
{
183
188
return (ef & kFSEventStreamEventFlagItemIsDir &&
@@ -197,6 +202,31 @@ static int ef_is_dropped(const FSEventStreamEventFlags ef)
197
202
ef & kFSEventStreamEventFlagUserDropped );
198
203
}
199
204
205
+ /*
206
+ * If an `xattr` change is the only reason we received this event,
207
+ * then silently ignore it. Git doesn't care about xattr's. We
208
+ * have to be careful here because the kernel can combine multiple
209
+ * events for a single path. And because events always have certain
210
+ * bits set, such as `ItemIsFile` or `ItemIsDir`.
211
+ *
212
+ * Return 1 if we should ignore it.
213
+ */
214
+ static int ef_ignore_xattr (const FSEventStreamEventFlags ef )
215
+ {
216
+ static const FSEventStreamEventFlags mask =
217
+ kFSEventStreamEventFlagItemChangeOwner |
218
+ kFSEventStreamEventFlagItemCreated |
219
+ kFSEventStreamEventFlagItemFinderInfoMod |
220
+ kFSEventStreamEventFlagItemInodeMetaMod |
221
+ kFSEventStreamEventFlagItemModified |
222
+ kFSEventStreamEventFlagItemRemoved |
223
+ kFSEventStreamEventFlagItemRenamed |
224
+ kFSEventStreamEventFlagItemXattrMod |
225
+ kFSEventStreamEventFlagItemCloned ;
226
+
227
+ return ((ef & mask ) == kFSEventStreamEventFlagItemXattrMod );
228
+ }
229
+
200
230
static void fsevent_callback (ConstFSEventStreamRef streamRef ,
201
231
void * ctx ,
202
232
size_t num_of_events ,
@@ -205,7 +235,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
205
235
const FSEventStreamEventId event_ids [])
206
236
{
207
237
struct fsmonitor_daemon_state * state = ctx ;
208
- struct fsmonitor_daemon_backend_data * data = state -> backend_data ;
238
+ struct fsm_listen_data * data = state -> listen_data ;
209
239
char * * paths = (char * * )event_paths ;
210
240
struct fsmonitor_batch * batch = NULL ;
211
241
struct string_list cookie_list = STRING_LIST_INIT_DUP ;
@@ -262,6 +292,33 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
262
292
continue ;
263
293
}
264
294
295
+ if (ef_is_root_changed (event_flags [k ])) {
296
+ /*
297
+ * The spelling of the pathname of the root directory
298
+ * has changed. This includes the name of the root
299
+ * directory itself of of any parent directory in the
300
+ * path.
301
+ *
302
+ * (There may be other conditions that throw this,
303
+ * but I couldn't find any information on it.)
304
+ *
305
+ * Force a shutdown now and avoid things getting
306
+ * out of sync. The Unix domain socket is inside
307
+ * the .git directory and a spelling change will make
308
+ * it hard for clients to rendezvous with us.
309
+ */
310
+ trace_printf_key (& trace_fsmonitor ,
311
+ "event: root changed" );
312
+ goto force_shutdown ;
313
+ }
314
+
315
+ if (ef_ignore_xattr (event_flags [k ])) {
316
+ trace_printf_key (& trace_fsmonitor ,
317
+ "ignore-xattr: '%s', flags=0x%x" ,
318
+ path_k , event_flags [k ]);
319
+ continue ;
320
+ }
321
+
265
322
switch (fsmonitor_classify_path_absolute (state , path_k )) {
266
323
267
324
case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX :
@@ -390,11 +447,11 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
390
447
NULL ,
391
448
NULL
392
449
};
393
- struct fsmonitor_daemon_backend_data * data ;
450
+ struct fsm_listen_data * data ;
394
451
const void * dir_array [2 ];
395
452
396
453
CALLOC_ARRAY (data , 1 );
397
- state -> backend_data = data ;
454
+ state -> listen_data = data ;
398
455
399
456
data -> cfsr_worktree_path = CFStringCreateWithCString (
400
457
NULL , state -> path_worktree_watch .buf , kCFStringEncodingUTF8 );
@@ -426,18 +483,18 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
426
483
failed :
427
484
error ("Unable to create FSEventStream." );
428
485
429
- FREE_AND_NULL (state -> backend_data );
486
+ FREE_AND_NULL (state -> listen_data );
430
487
return -1 ;
431
488
}
432
489
433
490
void fsm_listen__dtor (struct fsmonitor_daemon_state * state )
434
491
{
435
- struct fsmonitor_daemon_backend_data * data ;
492
+ struct fsm_listen_data * data ;
436
493
437
- if (!state || !state -> backend_data )
494
+ if (!state || !state -> listen_data )
438
495
return ;
439
496
440
- data = state -> backend_data ;
497
+ data = state -> listen_data ;
441
498
442
499
if (data -> stream ) {
443
500
if (data -> stream_started )
@@ -447,24 +504,24 @@ void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
447
504
FSEventStreamRelease (data -> stream );
448
505
}
449
506
450
- FREE_AND_NULL (state -> backend_data );
507
+ FREE_AND_NULL (state -> listen_data );
451
508
}
452
509
453
510
void fsm_listen__stop_async (struct fsmonitor_daemon_state * state )
454
511
{
455
- struct fsmonitor_daemon_backend_data * data ;
512
+ struct fsm_listen_data * data ;
456
513
457
- data = state -> backend_data ;
514
+ data = state -> listen_data ;
458
515
data -> shutdown_style = SHUTDOWN_EVENT ;
459
516
460
517
CFRunLoopStop (data -> rl );
461
518
}
462
519
463
520
void fsm_listen__loop (struct fsmonitor_daemon_state * state )
464
521
{
465
- struct fsmonitor_daemon_backend_data * data ;
522
+ struct fsm_listen_data * data ;
466
523
467
- data = state -> backend_data ;
524
+ data = state -> listen_data ;
468
525
469
526
data -> rl = CFRunLoopGetCurrent ();
470
527
@@ -481,7 +538,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
481
538
482
539
switch (data -> shutdown_style ) {
483
540
case FORCE_ERROR_STOP :
484
- state -> error_code = -1 ;
541
+ state -> listen_error_code = -1 ;
485
542
/* fall thru */
486
543
case FORCE_SHUTDOWN :
487
544
ipc_server_stop_async (state -> ipc_server_data );
@@ -493,7 +550,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
493
550
return ;
494
551
495
552
force_error_stop_without_loop :
496
- state -> error_code = -1 ;
553
+ state -> listen_error_code = -1 ;
497
554
ipc_server_stop_async (state -> ipc_server_data );
498
555
return ;
499
556
}
0 commit comments