]> git.ipfire.org Git - thirdparty/git.git/blobdiff - fsmonitor.c
t2407: fix broken &&-chains in compound statement
[thirdparty/git.git] / fsmonitor.c
index 292a6742b4fa23332000a61ad3db6ca28cf88018..57d6a483beede8e3b254634cdb944b19445875d1 100644 (file)
@@ -184,30 +184,68 @@ static int query_fsmonitor_hook(struct repository *r,
 static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
 {
        int i, len = strlen(name);
-       if (name[len - 1] == '/') {
+       int pos = index_name_pos(istate, name, len);
+
+       trace_printf_key(&trace_fsmonitor,
+                        "fsmonitor_refresh_callback '%s' (pos %d)",
+                        name, pos);
 
+       if (name[len - 1] == '/') {
                /*
-                * TODO We should binary search to find the first path with
-                * TODO this directory prefix.  Then linearly update entries
-                * TODO while the prefix matches.  Taking care to search without
-                * TODO the trailing slash -- because '/' sorts after a few
-                * TODO interesting special chars, like '.' and ' '.
+                * The daemon can decorate directory events, such as
+                * moves or renames, with a trailing slash if the OS
+                * FS Event contains sufficient information, such as
+                * MacOS.
+                *
+                * Use this to invalidate the entire cone under that
+                * directory.
+                *
+                * We do not expect an exact match because the index
+                * does not normally contain directory entries, so we
+                * start at the insertion point and scan.
                 */
+               if (pos < 0)
+                       pos = -pos - 1;
 
                /* Mark all entries for the folder invalid */
-               for (i = 0; i < istate->cache_nr; i++) {
-                       if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID &&
-                           starts_with(istate->cache[i]->name, name))
-                               istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
+               for (i = pos; i < istate->cache_nr; i++) {
+                       if (!starts_with(istate->cache[i]->name, name))
+                               break;
+                       istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
                }
-               /* Need to remove the / from the path for the untracked cache */
+
+               /*
+                * We need to remove the traling "/" from the path
+                * for the untracked cache.
+                */
                name[len - 1] = '\0';
+       } else if (pos >= 0) {
+               /*
+                * We have an exact match for this path and can just
+                * invalidate it.
+                */
+               istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
        } else {
-               int pos = index_name_pos(istate, name, strlen(name));
-
-               if (pos >= 0) {
-                       struct cache_entry *ce = istate->cache[pos];
-                       ce->ce_flags &= ~CE_FSMONITOR_VALID;
+               /*
+                * The path is not a tracked file -or- it is a
+                * directory event on a platform that cannot
+                * distinguish between file and directory events in
+                * the event handler, such as Windows.
+                *
+                * Scan as if it is a directory and invalidate the
+                * cone under it.  (But remember to ignore items
+                * between "name" and "name/", such as "name-" and
+                * "name.".
+                */
+               pos = -pos - 1;
+
+               for (i = pos; i < istate->cache_nr; i++) {
+                       if (!starts_with(istate->cache[i]->name, name))
+                               break;
+                       if ((unsigned char)istate->cache[i]->name[len] > '/')
+                               break;
+                       if (istate->cache[i]->name[len] == '/')
+                               istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
                }
        }
 
@@ -215,7 +253,6 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
         * Mark the untracked cache dirty even if it wasn't found in the index
         * as it could be a new untracked file.
         */
-       trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
        untracked_cache_invalidate_path(istate, name, 0);
 }
 
@@ -543,6 +580,8 @@ void tweak_fsmonitor(struct index_state *istate)
                if (fsmonitor_enabled) {
                        /* Mark all entries valid */
                        for (i = 0; i < istate->cache_nr; i++) {
+                               if (S_ISGITLINK(istate->cache[i]->ce_mode))
+                                       continue;
                                istate->cache[i]->ce_flags |= CE_FSMONITOR_VALID;
                        }