184
static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
185
{
186
int i, len = strlen(name);
187
- if (name[len - 1] == '/') {
187
+ int pos = index_name_pos(istate, name, len);
188
+
189
+ trace_printf_key(&trace_fsmonitor,
190
+ "fsmonitor_refresh_callback '%s' (pos %d)",
191
+ name, pos);
192
193
+ if (name[len - 1] == '/') {
194
/*
190
- * TODO We should binary search to find the first path with
191
- * TODO this directory prefix. Then linearly update entries
192
- * TODO while the prefix matches. Taking care to search without
193
- * TODO the trailing slash -- because '/' sorts after a few
194
- * TODO interesting special chars, like '.' and ' '.
195
+ * The daemon can decorate directory events, such as
196
+ * moves or renames, with a trailing slash if the OS
197
+ * FS Event contains sufficient information, such as
198
+ * MacOS.
199
+ *
200
+ * Use this to invalidate the entire cone under that
201
+ * directory.
202
+ *
203
+ * We do not expect an exact match because the index
204
+ * does not normally contain directory entries, so we
205
+ * start at the insertion point and scan.
206
*/
207
+ if (pos < 0)
208
+ pos = -pos - 1;
209
210
/* Mark all entries for the folder invalid */
198
- for (i = 0; i < istate->cache_nr; i++) {
199
- if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID &&
200
- starts_with(istate->cache[i]->name, name))
201
- istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
211
+ for (i = pos; i < istate->cache_nr; i++) {
212
+ if (!starts_with(istate->cache[i]->name, name))
213
+ break;
214
+ istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
215
}
203
- /* Need to remove the / from the path for the untracked cache */
216
+
217
+ /*
218
+ * We need to remove the traling "/" from the path
219
+ * for the untracked cache.
220
+ */
221
name[len - 1] = '\0';
222
+ } else if (pos >= 0) {
223
+ /*
224
+ * We have an exact match for this path and can just
225
+ * invalidate it.
226
+ */
227
+ istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
228
} else {
206
- int pos = index_name_pos(istate, name, strlen(name));
207
-
208
- if (pos >= 0) {
209
- struct cache_entry *ce = istate->cache[pos];
210
- ce->ce_flags &= ~CE_FSMONITOR_VALID;
229
+ /*
230
+ * The path is not a tracked file -or- it is a
231
+ * directory event on a platform that cannot
232
+ * distinguish between file and directory events in
233
+ * the event handler, such as Windows.
234
+ *
235
+ * Scan as if it is a directory and invalidate the
236
+ * cone under it. (But remember to ignore items
237
+ * between "name" and "name/", such as "name-" and
238
+ * "name.".
239
+ */
240
+ pos = -pos - 1;
241
+
242
+ for (i = pos; i < istate->cache_nr; i++) {
243
+ if (!starts_with(istate->cache[i]->name, name))
244
+ break;
245
+ if ((unsigned char)istate->cache[i]->name[len] > '/')
246
+ break;
247
+ if (istate->cache[i]->name[len] == '/')
248
+ istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
249
}
250
}
251
253
* Mark the untracked cache dirty even if it wasn't found in the index
254
* as it could be a new untracked file.
255
*/
218
- trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
256
untracked_cache_invalidate_path(istate, name, 0);
257
}
258