Skip to content

Commit 5be8f5c

Browse files
committed
fsmonitor: invalidate entire cone on directory move/rename
Invalidate the CE_FSMONITOR_VALID bit for all of the files in the cone under a directory when it is moved or renamed. Previously, we only invalidated the files immediately contained within the directory, but that ignored the fact that the pathnames of nested items also changed. Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 711baf1 commit 5be8f5c

File tree

2 files changed

+68
-10
lines changed

2 files changed

+68
-10
lines changed

fsmonitor.c

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,29 +198,61 @@ int fsmonitor_is_trivial_response(const struct strbuf *query_result)
198198
static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
199199
{
200200
int i, len = strlen(name);
201+
int pos = index_name_pos(istate, name, len);
202+
201203
if (name[len - 1] == '/') {
202-
const char *rel;
203-
int pos = index_name_pos(istate, name, len);
204+
/*
205+
* The daemon can decorate directory events, such as
206+
* moves or renames, with a trailing slash if the OS
207+
* FS Event contains sufficient information, such as
208+
* MacOS.
209+
*
210+
* Use this to invalidate the entire cone under that
211+
* directory.
212+
*
213+
* We do not expect an exact match because the index
214+
* does not normally contain directory entries, so we
215+
* start at the insertion point and scan.
216+
*/
204217
if (pos < 0)
205218
pos = -pos - 1;
206219

207220
/* Mark all entries for the folder invalid */
208221
for (i = pos; i < istate->cache_nr; i++) {
209222
if (!starts_with(istate->cache[i]->name, name))
210223
break;
211-
/* Only mark the immediate children in the folder */
212-
rel = istate->cache[i]->name + len;
213-
if (!strchr(rel, '/'))
214-
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
224+
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
215225
}
226+
216227
/* Need to remove the / from the path for the untracked cache */
217228
name[len - 1] = '\0';
229+
230+
} else if (pos >= 0) {
231+
/*
232+
* We have an exact match for this path and can just
233+
* invalidate it.
234+
*/
235+
istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
218236
} else {
219-
int pos = index_name_pos(istate, name, len);
237+
/*
238+
* The path is not a tracked file -or- it is a
239+
* directory event on a platform that cannot
240+
* distinguish between file and directory events in
241+
* the event handler, such as Windows.
242+
*
243+
* Scan as if it is a directory and invalidate the
244+
* cone under it.
245+
*/
246+
pos = -pos - 1;
220247

221-
if (pos >= 0) {
222-
struct cache_entry *ce = istate->cache[pos];
223-
ce->ce_flags &= ~CE_FSMONITOR_VALID;
248+
for (i = pos; i < istate->cache_nr; i++) {
249+
if (!starts_with(istate->cache[i]->name, name))
250+
break;
251+
if (istate->cache[i]->name[len] > '/')
252+
break;
253+
if (istate->cache[i]->name[len] < '/')
254+
continue;
255+
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
224256
}
225257
}
226258

t/t7527-builtin-fsmonitor.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,16 @@ test_expect_success 'setup' '
261261
trace*
262262
EOF
263263
264+
mkdir -p T1/T2/T3/T4 &&
265+
echo 1 >T1/F1 &&
266+
echo 1 >T1/T2/F1 &&
267+
echo 1 >T1/T2/T3/F1 &&
268+
echo 1 >T1/T2/T3/T4/F1 &&
269+
echo 2 >T1/F2 &&
270+
echo 2 >T1/T2/F2 &&
271+
echo 2 >T1/T2/T3/F2 &&
272+
echo 2 >T1/T2/T3/T4/F2 &&
273+
264274
git -c core.useBuiltinFSMonitor= add . &&
265275
test_tick &&
266276
git -c core.useBuiltinFSMonitor= commit -m initial &&
@@ -354,6 +364,19 @@ verify_status() {
354364
echo HELLO AFTER
355365
}
356366

367+
move_directory_contents_deeper() {
368+
mkdir T1/_new_
369+
mv T1/[A-Z]* T1/_new_
370+
}
371+
372+
move_directory_up() {
373+
mv T1/T2/T3 T1
374+
}
375+
376+
move_directory() {
377+
mv T1/T2/T3 T1/T2/NewT3
378+
}
379+
357380
# The next few test cases confirm that our fsmonitor daemon sees each type
358381
# of OS filesystem notification that we care about. At this layer we just
359382
# ensure we are getting the OS notifications and do not try to confirm what
@@ -687,6 +710,9 @@ do
687710
matrix_try $uc_val $fsm_val rename_files
688711
matrix_try $uc_val $fsm_val file_to_directory
689712
matrix_try $uc_val $fsm_val directory_to_file
713+
matrix_try $uc_val $fsm_val move_directory_contents_deeper
714+
matrix_try $uc_val $fsm_val move_directory_up
715+
matrix_try $uc_val $fsm_val move_directory
690716

691717
if test $fsm_val = true
692718
then

0 commit comments

Comments
 (0)