]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Revert "Merge branch 'pt/fsmonitor-linux' into next"
authorJunio C Hamano <gitster@pobox.com>
Tue, 14 Apr 2026 20:33:08 +0000 (13:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 14 Apr 2026 20:33:08 +0000 (13:33 -0700)
This reverts commit 37fa47889d5763ec3876606fb475bb68af9fd90f,
reversing changes made to 289fcba08108603e2370294eeff384fb2090ed6a,
as the tests in the topic was pointed out to be seriously broken.

cf. <ad6hovxCkwMTG11U@szeder.dev>

20 files changed:
Documentation/config/fsmonitor--daemon.adoc
Documentation/git-fsmonitor--daemon.adoc
Makefile
builtin/fsmonitor--daemon.c
compat/fsmonitor/fsm-health-linux.c [deleted file]
compat/fsmonitor/fsm-ipc-darwin.c [moved from compat/fsmonitor/fsm-ipc-unix.c with 100% similarity]
compat/fsmonitor/fsm-listen-linux.c [deleted file]
compat/fsmonitor/fsm-path-utils-linux.c [deleted file]
compat/fsmonitor/fsm-settings-darwin.c [moved from compat/fsmonitor/fsm-settings-unix.c with 100% similarity]
compat/win32/pthread.c
compat/win32/pthread.h
config.mak.uname
contrib/buildsystems/CMakeLists.txt
fsmonitor-ipc.c
meson.build
run-command.c
run-command.h
t/t7527-builtin-fsmonitor.sh
t/t9210-scalar.sh
t/t9211-scalar-clone.sh

index 6f8386e29150ff852a3fe36a57103f3b3d806729..671f9b94628446b1ee4704d6e6730c22719ebcaf 100644 (file)
@@ -4,8 +4,8 @@ fsmonitor.allowRemote::
     behavior.  Only respected when `core.fsmonitor` is set to `true`.
 
 fsmonitor.socketDir::
-    This Mac OS and Linux-specific option, if set, specifies the directory in
+    This Mac OS-specific option, if set, specifies the directory in
     which to create the Unix domain socket used for communication
     between the fsmonitor daemon and various Git commands. The directory must
-    reside on a native filesystem.  Only respected when `core.fsmonitor`
+    reside on a native Mac OS filesystem.  Only respected when `core.fsmonitor`
     is set to `true`.
index 12fa866a64ecc9e0bd6c016300b8b0b3adee104d..8fe5241b08b0078e3e8c9c6d205ca660439931f6 100644 (file)
@@ -76,9 +76,9 @@ repositories; this may be overridden by setting `fsmonitor.allowRemote` to
 correctly with all network-mounted repositories, so such use is considered
 experimental.
 
-On Mac OS and Linux, the inter-process communication (IPC) between various Git
+On Mac OS, the inter-process communication (IPC) between various Git
 commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
-special type of file -- which is supported by native Mac OS and Linux filesystems,
+special type of file -- which is supported by native Mac OS filesystems,
 but not on network-mounted filesystems, NTFS, or FAT32.  Other filesystems
 may or may not have the needed support; the fsmonitor daemon is not guaranteed
 to work with these filesystems and such use is considered experimental.
@@ -87,33 +87,13 @@ By default, the socket is created in the `.git` directory.  However, if the
 `.git` directory is on a network-mounted filesystem, it will instead be
 created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
 network-mounted filesystem, in which case you must set the configuration
-variable `fsmonitor.socketDir` to the path of a directory on a native
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
 filesystem in which to create the socket file.
 
 If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
-is on a native filesystem the fsmonitor daemon will report an
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
 error that will cause the daemon and the currently running command to exit.
 
-LINUX CAVEATS
-~~~~~~~~~~~~~
-
-On Linux, the fsmonitor daemon uses inotify to monitor filesystem events.
-The inotify system has per-user limits on the number of watches that can
-be created.  The default limit is typically 8192 watches per user.
-
-For large repositories with many directories, you may need to increase
-this limit.  Check the current limit with:
-
-    cat /proc/sys/fs/inotify/max_user_watches
-
-To temporarily increase the limit:
-
-    sudo sysctl fs.inotify.max_user_watches=65536
-
-To make the change permanent, add to `/etc/sysctl.conf`:
-
-    fs.inotify.max_user_watches=65536
-
 CONFIGURATION
 -------------
 
index 6c535f14ccd3349eb3af3345dbb04a97df0f64b9..bd24dd0409f97f90b96cce154eb747e964d3b1a8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -420,7 +420,7 @@ include shared.mak
 # If your platform has OS-specific ways to tell if a repo is incompatible with
 # fsmonitor (whether the hook or IPC daemon version), set FSMONITOR_OS_SETTINGS
 # to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
-# and `compat/fsmonitor/fsm-ipc-<name>.c` files.
+# that implements the `fsm_os_settings__*()` routines.
 #
 # Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
 # programs in oss-fuzz/.
@@ -2379,13 +2379,13 @@ ifdef FSMONITOR_DAEMON_BACKEND
        COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
        COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
        COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+       COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
 endif
 
 ifdef FSMONITOR_OS_SETTINGS
        COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
-       COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_OS_SETTINGS).o
        COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
-       COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_DAEMON_BACKEND).o
+       COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
 endif
 
 ifdef WITH_BREAKING_CHANGES
index f920cf3a8202f69b6eea2c2065babc919a4ce168..242c594646d1f5efc5022a936a636b2fe07ca36e 100644 (file)
@@ -16,7 +16,7 @@
 #include "fsmonitor--daemon.h"
 
 #include "simple-ipc.h"
-#include "strmap.h"
+#include "khash.h"
 #include "run-command.h"
 #include "trace.h"
 #include "trace2.h"
@@ -86,8 +86,6 @@ static int do_as_client__send_stop(void)
 {
        struct strbuf answer = STRBUF_INIT;
        int ret;
-       int max_wait_ms = 30000;
-       int elapsed_ms = 0;
 
        ret = fsmonitor_ipc__send_command("quit", &answer);
 
@@ -98,16 +96,8 @@ static int do_as_client__send_stop(void)
                return ret;
 
        trace2_region_enter("fsm_client", "polling-for-daemon-exit", NULL);
-       while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING) {
-               if (elapsed_ms >= max_wait_ms) {
-                       trace2_region_leave("fsm_client",
-                                           "polling-for-daemon-exit", NULL);
-                       return error(_("daemon did not stop within %d seconds"),
-                                    max_wait_ms / 1000);
-               }
+       while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
                sleep_millisec(50);
-               elapsed_ms += 50;
-       }
        trace2_region_leave("fsm_client", "polling-for-daemon-exit", NULL);
 
        return 0;
@@ -207,31 +197,20 @@ static enum fsmonitor_cookie_item_result with_lock__wait_for_cookie(
        unlink(cookie_pathname.buf);
 
        /*
-        * Wait for the listener thread to observe the cookie file.
-        * Time out after a short interval so that the client
-        * does not hang forever if the filesystem does not deliver
-        * events (e.g., on certain container/overlay filesystems
-        * where inotify watches succeed but events never arrive).
+        * Technically, this is an infinite wait (well, unless another
+        * thread sends us an abort).  I'd like to change this to
+        * use `pthread_cond_timedwait()` and return an error/timeout
+        * and let the caller do the trivial response thing, but we
+        * don't have that routine in our thread-utils.
+        *
+        * After extensive beta testing I'm not really worried about
+        * this.  Also note that the above open() and unlink() calls
+        * will cause at least two FS events on that path, so the odds
+        * of getting stuck are pretty slim.
         */
-       {
-               struct timeval now;
-               struct timespec ts;
-               int err = 0;
-
-               gettimeofday(&now, NULL);
-               ts.tv_sec = now.tv_sec + 1;
-               ts.tv_nsec = now.tv_usec * 1000;
-
-               while (cookie->result == FCIR_INIT && !err)
-                       err = pthread_cond_timedwait(&state->cookies_cond,
-                                                    &state->main_lock,
-                                                    &ts);
-               if (err == ETIMEDOUT && cookie->result == FCIR_INIT) {
-                       trace_printf_key(&trace_fsmonitor,
-                                        "cookie_wait timed out");
-                       cookie->result = FCIR_ERROR;
-               }
-       }
+       while (cookie->result == FCIR_INIT)
+               pthread_cond_wait(&state->cookies_cond,
+                                 &state->main_lock);
 
 done:
        hashmap_remove(&state->cookies, &cookie->entry, NULL);
@@ -674,6 +653,8 @@ static int fsmonitor_parse_client_token(const char *buf_token,
        return 0;
 }
 
+KHASH_INIT(str, const char *, int, 0, kh_str_hash_func, kh_str_hash_equal)
+
 static int do_handle_client(struct fsmonitor_daemon_state *state,
                            const char *command,
                            ipc_server_reply_cb *reply,
@@ -690,7 +671,8 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
        const struct fsmonitor_batch *batch;
        struct fsmonitor_batch *remainder = NULL;
        intmax_t count = 0, duplicates = 0;
-       struct strset shown = STRSET_INIT;
+       kh_str_t *shown;
+       int hash_ret;
        int do_trivial = 0;
        int do_flush = 0;
        int do_cookie = 0;
@@ -879,14 +861,14 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
         * so walk the batch list backwards from the current head back
         * to the batch (sequence number) they named.
         *
-        * We use a strset to de-dup the list of pathnames.
+        * We use khash to de-dup the list of pathnames.
         *
         * NEEDSWORK: each batch contains a list of interned strings,
         * so we only need to do pointer comparisons here to build the
         * hash table.  Currently, we're still comparing the string
         * values.
         */
-       strset_init_with_options(&shown, NULL, 0);
+       shown = kh_init_str();
        for (batch = batch_head;
             batch && batch->batch_seq_nr > requested_oldest_seq_nr;
             batch = batch->next) {
@@ -896,9 +878,11 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
                        const char *s = batch->interned_paths[k];
                        size_t s_len;
 
-                       if (!strset_add(&shown, s))
+                       if (kh_get_str(shown, s) != kh_end(shown))
                                duplicates++;
                        else {
+                               kh_put_str(shown, s, &hash_ret);
+
                                trace_printf_key(&trace_fsmonitor,
                                                 "send[%"PRIuMAX"]: %s",
                                                 count, s);
@@ -925,6 +909,8 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
                total_response_len += payload.len;
        }
 
+       kh_release_str(shown);
+
        pthread_mutex_lock(&state->main_lock);
 
        if (token_data->client_ref_count > 0)
@@ -968,7 +954,6 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
        trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
 
 cleanup:
-       strset_clear(&shown);
        strbuf_release(&response_token);
        strbuf_release(&requested_token_id);
        strbuf_release(&payload);
@@ -1420,15 +1405,6 @@ static int fsmonitor_run_daemon(void)
 done:
        pthread_cond_destroy(&state.cookies_cond);
        pthread_mutex_destroy(&state.main_lock);
-       {
-               struct hashmap_iter iter;
-               struct fsmonitor_cookie_item *cookie;
-
-               hashmap_for_each_entry(&state.cookies, &iter, cookie, entry)
-                       free(cookie->name);
-               hashmap_clear_and_free(&state.cookies,
-                                      struct fsmonitor_cookie_item, entry);
-       }
        fsm_listen__dtor(&state);
        fsm_health__dtor(&state);
 
@@ -1444,7 +1420,7 @@ done:
        return err;
 }
 
-static int try_to_run_foreground_daemon(int detach_console)
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
 {
        /*
         * Technically, we don't need to probe for an existing daemon
@@ -1464,21 +1440,10 @@ static int try_to_run_foreground_daemon(int detach_console)
                fflush(stderr);
        }
 
-       if (detach_console) {
 #ifdef GIT_WINDOWS_NATIVE
+       if (detach_console)
                FreeConsole();
-#else
-               /*
-                * Create a new session so that the daemon is detached
-                * from the parent's process group.  This prevents
-                * shells with job control (e.g. bash with "set -m")
-                * from waiting on the daemon when they wait for a
-                * foreground command that implicitly spawned it.
-                */
-               if (setsid() == -1)
-                       warning_errno(_("setsid failed"));
 #endif
-       }
 
        return !!fsmonitor_run_daemon();
 }
@@ -1541,7 +1506,6 @@ static int try_to_start_background_daemon(void)
        cp.no_stdin = 1;
        cp.no_stdout = 1;
        cp.no_stderr = 1;
-       cp.close_fd_above_stderr = 1;
 
        sbgr = start_bg_command(&cp, bg_wait_cb, NULL,
                                fsmonitor__start_timeout_sec);
diff --git a/compat/fsmonitor/fsm-health-linux.c b/compat/fsmonitor/fsm-health-linux.c
deleted file mode 100644 (file)
index 43d67c4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "git-compat-util.h"
-#include "config.h"
-#include "fsmonitor-ll.h"
-#include "fsm-health.h"
-#include "fsmonitor--daemon.h"
-
-/*
- * The Linux fsmonitor implementation uses inotify which has its own
- * mechanisms for detecting filesystem unmount and other events that
- * would require the daemon to shutdown.  Therefore, we don't need
- * a separate health thread like Windows does.
- *
- * These stub functions satisfy the interface requirements.
- */
-
-int fsm_health__ctor(struct fsmonitor_daemon_state *state UNUSED)
-{
-       return 0;
-}
-
-void fsm_health__dtor(struct fsmonitor_daemon_state *state UNUSED)
-{
-       return;
-}
-
-void fsm_health__loop(struct fsmonitor_daemon_state *state UNUSED)
-{
-       return;
-}
-
-void fsm_health__stop_async(struct fsmonitor_daemon_state *state UNUSED)
-{
-}
diff --git a/compat/fsmonitor/fsm-listen-linux.c b/compat/fsmonitor/fsm-listen-linux.c
deleted file mode 100644 (file)
index e3dca14..0000000
+++ /dev/null
@@ -1,746 +0,0 @@
-#include "git-compat-util.h"
-#include "dir.h"
-#include "fsmonitor-ll.h"
-#include "fsm-listen.h"
-#include "fsmonitor--daemon.h"
-#include "fsmonitor-path-utils.h"
-#include "gettext.h"
-#include "simple-ipc.h"
-#include "string-list.h"
-#include "trace.h"
-
-#include <sys/inotify.h>
-
-/*
- * Safe value to bitwise OR with rest of mask for
- * kernels that do not support IN_MASK_CREATE
- */
-#ifndef IN_MASK_CREATE
-#define IN_MASK_CREATE 0x00000000
-#endif
-
-enum shutdown_reason {
-       SHUTDOWN_CONTINUE = 0,
-       SHUTDOWN_STOP,
-       SHUTDOWN_ERROR,
-       SHUTDOWN_FORCE
-};
-
-struct watch_entry {
-       struct hashmap_entry ent;
-       int wd;
-       uint32_t cookie;
-       const char *dir;
-};
-
-struct rename_entry {
-       struct hashmap_entry ent;
-       time_t whence;
-       uint32_t cookie;
-       const char *dir;
-};
-
-struct fsm_listen_data {
-       int fd_inotify;
-       enum shutdown_reason shutdown;
-       struct hashmap watches;
-       struct hashmap renames;
-       struct hashmap revwatches;
-};
-
-static int watch_entry_cmp(const void *cmp_data UNUSED,
-                          const struct hashmap_entry *eptr,
-                          const struct hashmap_entry *entry_or_key,
-                          const void *keydata UNUSED)
-{
-       const struct watch_entry *e1, *e2;
-
-       e1 = container_of(eptr, const struct watch_entry, ent);
-       e2 = container_of(entry_or_key, const struct watch_entry, ent);
-       return e1->wd != e2->wd;
-}
-
-static int revwatches_entry_cmp(const void *cmp_data UNUSED,
-                               const struct hashmap_entry *eptr,
-                               const struct hashmap_entry *entry_or_key,
-                               const void *keydata UNUSED)
-{
-       const struct watch_entry *e1, *e2;
-
-       e1 = container_of(eptr, const struct watch_entry, ent);
-       e2 = container_of(entry_or_key, const struct watch_entry, ent);
-       return strcmp(e1->dir, e2->dir);
-}
-
-static int rename_entry_cmp(const void *cmp_data UNUSED,
-                           const struct hashmap_entry *eptr,
-                           const struct hashmap_entry *entry_or_key,
-                           const void *keydata UNUSED)
-{
-       const struct rename_entry *e1, *e2;
-
-       e1 = container_of(eptr, const struct rename_entry, ent);
-       e2 = container_of(entry_or_key, const struct rename_entry, ent);
-       return e1->cookie != e2->cookie;
-}
-
-/*
- * Register an inotify watch, add watch descriptor to path mapping
- * and the reverse mapping.
- */
-static int add_watch(const char *path, struct fsm_listen_data *data)
-{
-       const char *interned = strintern(path);
-       struct watch_entry *w1, *w2;
-
-       /* add the inotify watch, don't allow watches to be modified */
-       int wd = inotify_add_watch(data->fd_inotify, interned,
-                                  (IN_ALL_EVENTS | IN_ONLYDIR | IN_MASK_CREATE)
-                                   ^ IN_ACCESS ^ IN_CLOSE ^ IN_OPEN);
-       if (wd < 0) {
-               if (errno == ENOENT || errno == ENOTDIR)
-                       return 0; /* directory was deleted or is not a directory */
-               if (errno == EEXIST)
-                       return 0; /* watch already exists, no action needed */
-               if (errno == ENOSPC)
-                       return error(_("inotify watch limit reached; "
-                                      "increase fs.inotify.max_user_watches"));
-               return error_errno(_("inotify_add_watch('%s') failed"), interned);
-       }
-
-       /* add watch descriptor -> directory mapping */
-       CALLOC_ARRAY(w1, 1);
-       w1->wd = wd;
-       w1->dir = interned;
-       hashmap_entry_init(&w1->ent, memhash(&w1->wd, sizeof(int)));
-       hashmap_add(&data->watches, &w1->ent);
-
-       /* add directory -> watch descriptor mapping */
-       CALLOC_ARRAY(w2, 1);
-       w2->wd = wd;
-       w2->dir = interned;
-       hashmap_entry_init(&w2->ent, strhash(w2->dir));
-       hashmap_add(&data->revwatches, &w2->ent);
-
-       return 0;
-}
-
-/*
- * Remove the inotify watch, the watch descriptor to path mapping
- * and the reverse mapping.
- */
-static void remove_watch(struct watch_entry *w, struct fsm_listen_data *data)
-{
-       struct watch_entry k1, k2, *w1, *w2;
-
-       /* remove watch, ignore error if kernel already did it */
-       if (inotify_rm_watch(data->fd_inotify, w->wd) && errno != EINVAL)
-               error_errno(_("inotify_rm_watch() failed"));
-
-       k1.wd = w->wd;
-       hashmap_entry_init(&k1.ent, memhash(&k1.wd, sizeof(int)));
-       w1 = hashmap_remove_entry(&data->watches, &k1, ent, NULL);
-       if (!w1)
-               BUG("double remove of watch for '%s'", w->dir);
-
-       if (w1->cookie)
-               BUG("removing watch for '%s' which has a pending rename", w1->dir);
-
-       k2.dir = w->dir;
-       hashmap_entry_init(&k2.ent, strhash(k2.dir));
-       w2 = hashmap_remove_entry(&data->revwatches, &k2, ent, NULL);
-       if (!w2)
-               BUG("double remove of reverse watch for '%s'", w->dir);
-
-       /* w1->dir and w2->dir are interned strings, we don't own them */
-       free(w1);
-       free(w2);
-}
-
-/*
- * Check for stale directory renames.
- *
- * https://man7.org/linux/man-pages/man7/inotify.7.html
- *
- * Allow for some small timeout to account for the fact that insertion of the
- * IN_MOVED_FROM+IN_MOVED_TO event pair is not atomic, and the possibility that
- * there may not be any IN_MOVED_TO event.
- *
- * If the IN_MOVED_TO event is not received within the timeout then events have
- * been missed and the monitor is in an inconsistent state with respect to the
- * filesystem.
- */
-static int check_stale_dir_renames(struct hashmap *renames, time_t max_age)
-{
-       struct rename_entry *re;
-       struct hashmap_iter iter;
-
-       hashmap_for_each_entry(renames, &iter, re, ent) {
-               if (re->whence <= max_age)
-                       return -1;
-       }
-       return 0;
-}
-
-/*
- * Track pending renames.
- *
- * Tracking is done via an event cookie to watch descriptor mapping.
- *
- * A rename is not complete until matching an IN_MOVED_TO event is received
- * for a corresponding IN_MOVED_FROM event.
- */
-static void add_dir_rename(uint32_t cookie, const char *path,
-                          struct fsm_listen_data *data)
-{
-       struct watch_entry k, *w;
-       struct rename_entry *re;
-
-       /* lookup the watch descriptor for the given path */
-       k.dir = path;
-       hashmap_entry_init(&k.ent, strhash(path));
-       w = hashmap_get_entry(&data->revwatches, &k, ent, NULL);
-       if (!w) {
-               /*
-                * This can happen in rare cases where the directory was
-                * moved before we had a chance to add a watch on it.
-                * Just ignore this rename.
-                */
-               trace_printf_key(&trace_fsmonitor,
-                                "no watch found for rename from '%s'", path);
-               return;
-       }
-       w->cookie = cookie;
-
-       /* add the pending rename to match against later */
-       CALLOC_ARRAY(re, 1);
-       re->dir = w->dir;
-       re->cookie = w->cookie;
-       re->whence = time(NULL);
-       hashmap_entry_init(&re->ent, memhash(&re->cookie, sizeof(uint32_t)));
-       hashmap_add(&data->renames, &re->ent);
-}
-
-/*
- * Handle directory renames
- *
- * Once an IN_MOVED_TO event is received, lookup the rename tracking information
- * via the event cookie and use this information to update the watch.
- */
-static void rename_dir(uint32_t cookie, const char *path,
-                      struct fsm_listen_data *data)
-{
-       struct rename_entry rek, *re;
-       struct watch_entry k, *w;
-
-       /* lookup a pending rename to match */
-       rek.cookie = cookie;
-       hashmap_entry_init(&rek.ent, memhash(&rek.cookie, sizeof(uint32_t)));
-       re = hashmap_get_entry(&data->renames, &rek, ent, NULL);
-       if (re) {
-               k.dir = re->dir;
-               hashmap_entry_init(&k.ent, strhash(k.dir));
-               w = hashmap_get_entry(&data->revwatches, &k, ent, NULL);
-               if (w) {
-                       w->cookie = 0; /* rename handled */
-                       remove_watch(w, data);
-                       if (add_watch(path, data))
-                               trace_printf_key(&trace_fsmonitor,
-                                                "failed to add watch for renamed dir '%s'",
-                                                path);
-               } else {
-                       /* Directory was moved out of watch tree */
-                       trace_printf_key(&trace_fsmonitor,
-                                        "no matching watch for rename to '%s'", path);
-               }
-               hashmap_remove_entry(&data->renames, &rek, ent, NULL);
-               free(re);
-       } else {
-               /* Directory was moved from outside the watch tree */
-               trace_printf_key(&trace_fsmonitor,
-                                "no matching cookie for rename to '%s'", path);
-       }
-}
-
-/*
- * Recursively add watches to every directory under path
- */
-static int register_inotify(const char *path,
-                           struct fsmonitor_daemon_state *state,
-                           struct fsmonitor_batch *batch)
-{
-       DIR *dir;
-       const char *rel;
-       struct strbuf current = STRBUF_INIT;
-       struct dirent *de;
-       struct stat fs;
-       int ret = -1;
-
-       dir = opendir(path);
-       if (!dir) {
-               if (errno == ENOENT || errno == ENOTDIR)
-                       return 0; /* directory was deleted */
-               return error_errno(_("opendir('%s') failed"), path);
-       }
-
-       while ((de = readdir_skip_dot_and_dotdot(dir)) != NULL) {
-               strbuf_reset(&current);
-               strbuf_addf(&current, "%s/%s", path, de->d_name);
-               if (lstat(current.buf, &fs)) {
-                       if (errno == ENOENT)
-                               continue; /* file was deleted */
-                       error_errno(_("lstat('%s') failed"), current.buf);
-                       goto failed;
-               }
-
-               /* recurse into directory */
-               if (S_ISDIR(fs.st_mode)) {
-                       if (add_watch(current.buf, state->listen_data))
-                               goto failed;
-                       if (register_inotify(current.buf, state, batch))
-                               goto failed;
-               } else if (batch) {
-                       rel = current.buf + state->path_worktree_watch.len + 1;
-                       trace_printf_key(&trace_fsmonitor, "explicitly adding '%s'", rel);
-                       fsmonitor_batch__add_path(batch, rel);
-               }
-       }
-       ret = 0;
-
-failed:
-       strbuf_release(&current);
-       if (closedir(dir) < 0)
-               return error_errno(_("closedir('%s') failed"), path);
-       return ret;
-}
-
-static int em_rename_dir_from(uint32_t mask)
-{
-       return ((mask & IN_ISDIR) && (mask & IN_MOVED_FROM));
-}
-
-static int em_rename_dir_to(uint32_t mask)
-{
-       return ((mask & IN_ISDIR) && (mask & IN_MOVED_TO));
-}
-
-static int em_remove_watch(uint32_t mask)
-{
-       return (mask & IN_DELETE_SELF);
-}
-
-static int em_dir_renamed(uint32_t mask)
-{
-       return ((mask & IN_ISDIR) && (mask & IN_MOVE));
-}
-
-static int em_dir_created(uint32_t mask)
-{
-       return ((mask & IN_ISDIR) && (mask & IN_CREATE));
-}
-
-static int em_dir_deleted(uint32_t mask)
-{
-       return ((mask & IN_ISDIR) && (mask & IN_DELETE));
-}
-
-static int em_force_shutdown(uint32_t mask)
-{
-       return (mask & IN_UNMOUNT) || (mask & IN_Q_OVERFLOW);
-}
-
-static int em_ignore(uint32_t mask)
-{
-       return (mask & IN_IGNORED) || (mask & IN_MOVE_SELF);
-}
-
-static void log_mask_set(const char *path, uint32_t mask)
-{
-       struct strbuf msg = STRBUF_INIT;
-
-       if (mask & IN_ACCESS)
-               strbuf_addstr(&msg, "IN_ACCESS|");
-       if (mask & IN_MODIFY)
-               strbuf_addstr(&msg, "IN_MODIFY|");
-       if (mask & IN_ATTRIB)
-               strbuf_addstr(&msg, "IN_ATTRIB|");
-       if (mask & IN_CLOSE_WRITE)
-               strbuf_addstr(&msg, "IN_CLOSE_WRITE|");
-       if (mask & IN_CLOSE_NOWRITE)
-               strbuf_addstr(&msg, "IN_CLOSE_NOWRITE|");
-       if (mask & IN_OPEN)
-               strbuf_addstr(&msg, "IN_OPEN|");
-       if (mask & IN_MOVED_FROM)
-               strbuf_addstr(&msg, "IN_MOVED_FROM|");
-       if (mask & IN_MOVED_TO)
-               strbuf_addstr(&msg, "IN_MOVED_TO|");
-       if (mask & IN_CREATE)
-               strbuf_addstr(&msg, "IN_CREATE|");
-       if (mask & IN_DELETE)
-               strbuf_addstr(&msg, "IN_DELETE|");
-       if (mask & IN_DELETE_SELF)
-               strbuf_addstr(&msg, "IN_DELETE_SELF|");
-       if (mask & IN_MOVE_SELF)
-               strbuf_addstr(&msg, "IN_MOVE_SELF|");
-       if (mask & IN_UNMOUNT)
-               strbuf_addstr(&msg, "IN_UNMOUNT|");
-       if (mask & IN_Q_OVERFLOW)
-               strbuf_addstr(&msg, "IN_Q_OVERFLOW|");
-       if (mask & IN_IGNORED)
-               strbuf_addstr(&msg, "IN_IGNORED|");
-       if (mask & IN_ISDIR)
-               strbuf_addstr(&msg, "IN_ISDIR|");
-
-       strbuf_strip_suffix(&msg, "|");
-
-       trace_printf_key(&trace_fsmonitor, "inotify_event: '%s', mask=%#8.8x %s",
-                        path, mask, msg.buf);
-
-       strbuf_release(&msg);
-}
-
-int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
-{
-       int fd;
-       int ret = 0;
-       struct fsm_listen_data *data;
-
-       CALLOC_ARRAY(data, 1);
-       state->listen_data = data;
-       state->listen_error_code = -1;
-       data->fd_inotify = -1;
-       data->shutdown = SHUTDOWN_ERROR;
-
-       fd = inotify_init1(O_NONBLOCK);
-       if (fd < 0) {
-               FREE_AND_NULL(state->listen_data);
-               return error_errno(_("inotify_init1() failed"));
-       }
-
-       data->fd_inotify = fd;
-
-       hashmap_init(&data->watches, watch_entry_cmp, NULL, 0);
-       hashmap_init(&data->renames, rename_entry_cmp, NULL, 0);
-       hashmap_init(&data->revwatches, revwatches_entry_cmp, NULL, 0);
-
-       if (add_watch(state->path_worktree_watch.buf, data))
-               ret = -1;
-       else if (register_inotify(state->path_worktree_watch.buf, state, NULL))
-               ret = -1;
-       else if (state->nr_paths_watching > 1) {
-               if (add_watch(state->path_gitdir_watch.buf, data))
-                       ret = -1;
-               else if (register_inotify(state->path_gitdir_watch.buf, state, NULL))
-                       ret = -1;
-       }
-
-       if (!ret) {
-               state->listen_error_code = 0;
-               data->shutdown = SHUTDOWN_CONTINUE;
-       }
-
-       return ret;
-}
-
-void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
-{
-       struct fsm_listen_data *data;
-       struct hashmap_iter iter;
-       struct watch_entry *w;
-       struct watch_entry **to_remove;
-       size_t nr_to_remove = 0, alloc_to_remove = 0;
-       size_t i;
-       int fd;
-
-       if (!state || !state->listen_data)
-               return;
-
-       data = state->listen_data;
-       fd = data->fd_inotify;
-
-       /*
-        * Collect all entries first, then remove them.
-        * We can't modify the hashmap while iterating over it.
-        */
-       to_remove = NULL;
-       hashmap_for_each_entry(&data->watches, &iter, w, ent) {
-               ALLOC_GROW(to_remove, nr_to_remove + 1, alloc_to_remove);
-               to_remove[nr_to_remove++] = w;
-       }
-
-       for (i = 0; i < nr_to_remove; i++) {
-               to_remove[i]->cookie = 0; /* ignore any pending renames */
-               remove_watch(to_remove[i], data);
-       }
-       free(to_remove);
-
-       hashmap_clear(&data->watches);
-
-       hashmap_clear(&data->revwatches); /* remove_watch freed the entries */
-
-       hashmap_clear_and_free(&data->renames, struct rename_entry, ent);
-
-       FREE_AND_NULL(state->listen_data);
-
-       if (fd >= 0 && (close(fd) < 0))
-               error_errno(_("closing inotify file descriptor failed"));
-}
-
-void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
-{
-       if (state && state->listen_data &&
-           state->listen_data->shutdown == SHUTDOWN_CONTINUE)
-               state->listen_data->shutdown = SHUTDOWN_STOP;
-}
-
-/*
- * Process a single inotify event and queue for publication.
- */
-static int process_event(const char *path,
-                        const struct inotify_event *event,
-                        struct fsmonitor_batch **batch,
-                        struct string_list *cookie_list,
-                        struct fsmonitor_daemon_state *state)
-{
-       const char *rel;
-       const char *last_sep;
-
-       switch (fsmonitor_classify_path_absolute(state, path)) {
-       case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX:
-       case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
-               /* Use just the filename of the cookie file. */
-               last_sep = find_last_dir_sep(path);
-               string_list_append(cookie_list,
-                                  last_sep ? last_sep + 1 : path);
-               break;
-       case IS_INSIDE_DOT_GIT:
-       case IS_INSIDE_GITDIR:
-               break;
-       case IS_DOT_GIT:
-       case IS_GITDIR:
-               /*
-                * If .git directory is deleted or renamed away,
-                * we have to quit.
-                */
-               if (em_dir_deleted(event->mask)) {
-                       trace_printf_key(&trace_fsmonitor,
-                                        "event: gitdir removed");
-                       state->listen_data->shutdown = SHUTDOWN_FORCE;
-                       goto done;
-               }
-
-               if (em_dir_renamed(event->mask)) {
-                       trace_printf_key(&trace_fsmonitor,
-                                        "event: gitdir renamed");
-                       state->listen_data->shutdown = SHUTDOWN_FORCE;
-                       goto done;
-               }
-               break;
-       case IS_WORKDIR_PATH:
-               /* normal events in the working directory */
-               if (trace_pass_fl(&trace_fsmonitor))
-                       log_mask_set(path, event->mask);
-
-               if (!*batch)
-                       *batch = fsmonitor_batch__new();
-
-               rel = path + state->path_worktree_watch.len + 1;
-               fsmonitor_batch__add_path(*batch, rel);
-
-               if (em_dir_deleted(event->mask))
-                       break;
-
-               /* received IN_MOVE_FROM, add tracking for expected IN_MOVE_TO */
-               if (em_rename_dir_from(event->mask))
-                       add_dir_rename(event->cookie, path, state->listen_data);
-
-               /* received IN_MOVE_TO, update watch to reflect new path */
-               if (em_rename_dir_to(event->mask)) {
-                       rename_dir(event->cookie, path, state->listen_data);
-                       if (register_inotify(path, state, *batch)) {
-                               state->listen_data->shutdown = SHUTDOWN_ERROR;
-                               goto done;
-                       }
-               }
-
-               if (em_dir_created(event->mask)) {
-                       if (add_watch(path, state->listen_data)) {
-                               state->listen_data->shutdown = SHUTDOWN_ERROR;
-                               goto done;
-                       }
-                       if (register_inotify(path, state, *batch)) {
-                               state->listen_data->shutdown = SHUTDOWN_ERROR;
-                               goto done;
-                       }
-               }
-               break;
-       case IS_OUTSIDE_CONE:
-       default:
-               trace_printf_key(&trace_fsmonitor,
-                                "ignoring '%s'", path);
-               break;
-       }
-       return 0;
-done:
-       return -1;
-}
-
-/*
- * Read the inotify event stream and pre-process events before further
- * processing and eventual publishing.
- */
-static void handle_events(struct fsmonitor_daemon_state *state)
-{
-       /* See https://man7.org/linux/man-pages/man7/inotify.7.html */
-       char buf[4096]
-               __attribute__ ((aligned(__alignof__(struct inotify_event))));
-
-       struct hashmap *watches = &state->listen_data->watches;
-       struct fsmonitor_batch *batch = NULL;
-       struct string_list cookie_list = STRING_LIST_INIT_DUP;
-       struct watch_entry k, *w;
-       struct strbuf path = STRBUF_INIT;
-       const struct inotify_event *event;
-       int fd = state->listen_data->fd_inotify;
-       ssize_t len;
-       char *ptr, *p;
-
-       for (;;) {
-               len = read(fd, buf, sizeof(buf));
-               if (len == -1) {
-                       if (errno == EAGAIN || errno == EINTR)
-                               goto done;
-                       error_errno(_("reading inotify message stream failed"));
-                       state->listen_data->shutdown = SHUTDOWN_ERROR;
-                       goto done;
-               }
-
-               /* nothing to read */
-               if (len == 0)
-                       goto done;
-
-               /* Loop over all events in the buffer. */
-               for (ptr = buf; ptr < buf + len;
-                    ptr += sizeof(struct inotify_event) + event->len) {
-
-                       event = (const struct inotify_event *)ptr;
-
-                       if (em_ignore(event->mask))
-                               continue;
-
-                       /* File system was unmounted or event queue overflowed */
-                       if (em_force_shutdown(event->mask)) {
-                               if (trace_pass_fl(&trace_fsmonitor))
-                                       log_mask_set("forcing shutdown", event->mask);
-                               state->listen_data->shutdown = SHUTDOWN_FORCE;
-                               goto done;
-                       }
-
-                       k.wd = event->wd;
-                       hashmap_entry_init(&k.ent, memhash(&k.wd, sizeof(int)));
-
-                       w = hashmap_get_entry(watches, &k, ent, NULL);
-                       if (!w) {
-                               /* Watch was removed, skip event */
-                               continue;
-                       }
-
-                       /* directory watch was removed */
-                       if (em_remove_watch(event->mask)) {
-                               remove_watch(w, state->listen_data);
-                               continue;
-                       }
-
-                       strbuf_reset(&path);
-                       strbuf_addf(&path, "%s/%s", w->dir, event->name);
-
-                       p = fsmonitor__resolve_alias(path.buf, &state->alias);
-                       if (!p)
-                               p = strbuf_detach(&path, NULL);
-
-                       if (process_event(p, event, &batch, &cookie_list, state)) {
-                               free(p);
-                               goto done;
-                       }
-                       free(p);
-               }
-               strbuf_reset(&path);
-               fsmonitor_publish(state, batch, &cookie_list);
-               string_list_clear(&cookie_list, 0);
-               batch = NULL;
-       }
-done:
-       strbuf_release(&path);
-       fsmonitor_batch__free_list(batch);
-       string_list_clear(&cookie_list, 0);
-}
-
-/*
- * Non-blocking read of the inotify events stream. The inotify fd is polled
- * frequently to help minimize the number of queue overflows.
- */
-void fsm_listen__loop(struct fsmonitor_daemon_state *state)
-{
-       int poll_num;
-       /*
-        * Interval in seconds between checks for stale directory renames.
-        * A directory rename that is not completed within this window
-        * (i.e. no matching IN_MOVED_TO for an IN_MOVED_FROM) indicates
-        * missed events, forcing a shutdown.
-        */
-       const int interval = 1;
-       time_t checked = time(NULL);
-       struct pollfd fds[1];
-
-       fds[0].fd = state->listen_data->fd_inotify;
-       fds[0].events = POLLIN;
-
-       /*
-        * Our fs event listener is now running, so it's safe to start
-        * serving client requests.
-        */
-       ipc_server_start_async(state->ipc_server_data);
-
-       for (;;) {
-               switch (state->listen_data->shutdown) {
-               case SHUTDOWN_CONTINUE:
-                       poll_num = poll(fds, 1, 50);
-                       if (poll_num == -1) {
-                               if (errno == EINTR)
-                                       continue;
-                               error_errno(_("polling inotify message stream failed"));
-                               state->listen_data->shutdown = SHUTDOWN_ERROR;
-                               continue;
-                       }
-
-                       if ((time(NULL) - checked) >= interval) {
-                               checked = time(NULL);
-                               if (check_stale_dir_renames(&state->listen_data->renames,
-                                                           checked - interval)) {
-                                       trace_printf_key(&trace_fsmonitor,
-                                                        "missed IN_MOVED_TO events, forcing shutdown");
-                                       state->listen_data->shutdown = SHUTDOWN_FORCE;
-                                       continue;
-                               }
-                       }
-
-                       if (poll_num > 0 && (fds[0].revents & POLLIN))
-                               handle_events(state);
-
-                       continue;
-               case SHUTDOWN_ERROR:
-                       state->listen_error_code = -1;
-                       ipc_server_stop_async(state->ipc_server_data);
-                       break;
-               case SHUTDOWN_FORCE:
-                       state->listen_error_code = 0;
-                       ipc_server_stop_async(state->ipc_server_data);
-                       break;
-               case SHUTDOWN_STOP:
-               default:
-                       state->listen_error_code = 0;
-                       break;
-               }
-               return;
-       }
-}
diff --git a/compat/fsmonitor/fsm-path-utils-linux.c b/compat/fsmonitor/fsm-path-utils-linux.c
deleted file mode 100644 (file)
index c9866b1..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-#include "git-compat-util.h"
-#include "fsmonitor-ll.h"
-#include "fsmonitor-path-utils.h"
-#include "gettext.h"
-#include "trace.h"
-
-#include <sys/statfs.h>
-
-#ifdef HAVE_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-
-/*
- * Filesystem magic numbers for remote filesystems.
- * Defined here if not available in linux/magic.h.
- */
-#ifndef CIFS_SUPER_MAGIC
-#define CIFS_SUPER_MAGIC 0xff534d42
-#endif
-#ifndef SMB_SUPER_MAGIC
-#define SMB_SUPER_MAGIC 0x517b
-#endif
-#ifndef SMB2_SUPER_MAGIC
-#define SMB2_SUPER_MAGIC 0xfe534d42
-#endif
-#ifndef NFS_SUPER_MAGIC
-#define NFS_SUPER_MAGIC 0x6969
-#endif
-#ifndef AFS_SUPER_MAGIC
-#define AFS_SUPER_MAGIC 0x5346414f
-#endif
-#ifndef CODA_SUPER_MAGIC
-#define CODA_SUPER_MAGIC 0x73757245
-#endif
-#ifndef FUSE_SUPER_MAGIC
-#define FUSE_SUPER_MAGIC 0x65735546
-#endif
-
-/*
- * Check if filesystem type is a remote filesystem.
- */
-static int is_remote_fs(unsigned long f_type)
-{
-       switch (f_type) {
-       case CIFS_SUPER_MAGIC:
-       case SMB_SUPER_MAGIC:
-       case SMB2_SUPER_MAGIC:
-       case NFS_SUPER_MAGIC:
-       case AFS_SUPER_MAGIC:
-       case CODA_SUPER_MAGIC:
-       case FUSE_SUPER_MAGIC:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-/*
- * Map filesystem magic numbers to human-readable names as a fallback
- * when /proc/mounts is unavailable.  This only covers the remote and
- * special filesystems in is_remote_fs() above; local filesystems are
- * never flagged as incompatible, so we do not need their names here.
- */
-static const char *get_fs_typename(unsigned long f_type)
-{
-       switch (f_type) {
-       case CIFS_SUPER_MAGIC:
-               return "cifs";
-       case SMB_SUPER_MAGIC:
-               return "smb";
-       case SMB2_SUPER_MAGIC:
-               return "smb2";
-       case NFS_SUPER_MAGIC:
-               return "nfs";
-       case AFS_SUPER_MAGIC:
-               return "afs";
-       case CODA_SUPER_MAGIC:
-               return "coda";
-       case FUSE_SUPER_MAGIC:
-               return "fuse";
-       default:
-               return "unknown";
-       }
-}
-
-/*
- * Find the mount point for a given path by reading /proc/mounts.
- *
- * statfs(2) gives us f_type (the magic number) but not the human-readable
- * filesystem type string.  We scan /proc/mounts to find the mount entry
- * whose path is the longest prefix of ours and whose f_fsid matches,
- * which gives us the fstype string (e.g. "nfs", "ext4") for logging.
- */
-static char *find_mount(const char *path, const struct statfs *path_fs)
-{
-       FILE *fp;
-       struct strbuf line = STRBUF_INIT;
-       struct strbuf match = STRBUF_INIT;
-       struct strbuf fstype = STRBUF_INIT;
-       char *result = NULL;
-
-       fp = fopen("/proc/mounts", "r");
-       if (!fp)
-               return NULL;
-
-       while (strbuf_getline(&line, fp) != EOF) {
-               char *fields[6];
-               char *p = line.buf;
-               int i;
-
-               /* Parse mount entry: device mountpoint fstype options dump pass */
-               for (i = 0; i < 6 && p; i++) {
-                       fields[i] = p;
-                       p = strchr(p, ' ');
-                       if (p)
-                               *p++ = '\0';
-               }
-
-               if (i >= 3) {
-                       const char *mountpoint = fields[1];
-                       const char *type = fields[2];
-                       struct statfs mount_fs;
-
-                       /* Check if this mount point is a prefix of our path */
-                       if (starts_with(path, mountpoint) &&
-                           (path[strlen(mountpoint)] == '/' ||
-                            path[strlen(mountpoint)] == '\0')) {
-                               /* Check if filesystem ID matches */
-                               if (statfs(mountpoint, &mount_fs) == 0 &&
-                                   !memcmp(&mount_fs.f_fsid, &path_fs->f_fsid,
-                                           sizeof(mount_fs.f_fsid))) {
-                                       /* Keep the longest matching mount point */
-                                       if (strlen(mountpoint) > match.len) {
-                                               strbuf_reset(&match);
-                                               strbuf_addstr(&match, mountpoint);
-                                               strbuf_reset(&fstype);
-                                               strbuf_addstr(&fstype, type);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       fclose(fp);
-       strbuf_release(&line);
-       strbuf_release(&match);
-
-       if (fstype.len)
-               result = strbuf_detach(&fstype, NULL);
-       else
-               strbuf_release(&fstype);
-
-       return result;
-}
-
-int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
-{
-       struct statfs fs;
-
-       if (statfs(path, &fs) == -1) {
-               int saved_errno = errno;
-               trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
-                                path, strerror(saved_errno));
-               errno = saved_errno;
-               return -1;
-       }
-
-       trace_printf_key(&trace_fsmonitor,
-                        "statfs('%s') [type 0x%08lx]",
-                        path, (unsigned long)fs.f_type);
-
-       fs_info->is_remote = is_remote_fs(fs.f_type);
-
-       /*
-        * Try to get filesystem type from /proc/mounts for a more
-        * descriptive name.
-        */
-       fs_info->typename = find_mount(path, &fs);
-       if (!fs_info->typename)
-               fs_info->typename = xstrdup(get_fs_typename(fs.f_type));
-
-       trace_printf_key(&trace_fsmonitor,
-                        "'%s' is_remote: %d, typename: %s",
-                        path, fs_info->is_remote, fs_info->typename);
-
-       return 0;
-}
-
-int fsmonitor__is_fs_remote(const char *path)
-{
-       struct fs_info fs;
-
-       if (fsmonitor__get_fs_info(path, &fs))
-               return -1;
-
-       free(fs.typename);
-
-       return fs.is_remote;
-}
-
-/*
- * No-op for Linux - we don't have firmlinks like macOS.
- */
-int fsmonitor__get_alias(const char *path UNUSED,
-                        struct alias_info *info UNUSED)
-{
-       return 0;
-}
-
-/*
- * No-op for Linux - we don't have firmlinks like macOS.
- */
-char *fsmonitor__resolve_alias(const char *path UNUSED,
-                              const struct alias_info *info UNUSED)
-{
-       return NULL;
-}
index 398caa96029718acece706835633e9a2b3e95703..7e93146963ec56b9c6b126151fd3e01fdabd3f6f 100644 (file)
@@ -66,29 +66,3 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
                return err_win_to_posix(GetLastError());
        return 0;
 }
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
-                          const struct timespec *abstime)
-{
-       struct timeval now;
-       long long now_ms, deadline_ms;
-       DWORD timeout_ms;
-
-       gettimeofday(&now, NULL);
-       now_ms = (long long)now.tv_sec * 1000 + now.tv_usec / 1000;
-       deadline_ms = (long long)abstime->tv_sec * 1000 +
-                     abstime->tv_nsec / 1000000;
-
-       if (deadline_ms <= now_ms)
-               return ETIMEDOUT;
-       else
-               timeout_ms = (DWORD)(deadline_ms - now_ms);
-
-       if (SleepConditionVariableCS(cond, mutex, timeout_ms) == 0) {
-               DWORD err = GetLastError();
-               if (err == ERROR_TIMEOUT)
-                       return ETIMEDOUT;
-               return err_win_to_posix(err);
-       }
-       return 0;
-}
index d80df8d12af2dc3078cd82e38d42fa7df941f66c..ccacc5a53ba9766ca3a2c8fa100b1033199362f2 100644 (file)
@@ -64,8 +64,6 @@ int win32_pthread_join(pthread_t *thread, void **value_ptr);
 pthread_t pthread_self(void);
 
 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
-                          const struct timespec *abstime);
 
 static inline void NORETURN pthread_exit(void *ret)
 {
index 75dc1140296fdc63aee385e67e1e8b28ddce4a12..5feb5825587e65f62a4ccbb507fbccd9f062693f 100644 (file)
@@ -68,16 +68,6 @@ ifeq ($(uname_S),Linux)
                BASIC_CFLAGS += -std=c99
         endif
        LINK_FUZZ_PROGRAMS = YesPlease
-
-       # The builtin FSMonitor on Linux builds upon Simple-IPC.  Both require
-       # Unix domain sockets and PThreads.
-        ifndef NO_PTHREADS
-        ifndef NO_UNIX_SOCKETS
-       FSMONITOR_DAEMON_BACKEND = linux
-       FSMONITOR_OS_SETTINGS = unix
-       BASIC_CFLAGS += -DHAVE_LINUX_MAGIC_H
-        endif
-        endif
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
        HAVE_ALLOCA_H = YesPlease
@@ -177,7 +167,7 @@ ifeq ($(uname_S),Darwin)
         ifndef NO_PTHREADS
         ifndef NO_UNIX_SOCKETS
        FSMONITOR_DAEMON_BACKEND = darwin
-       FSMONITOR_OS_SETTINGS = unix
+       FSMONITOR_OS_SETTINGS = darwin
         endif
         endif
 
index d102e4696f7fa3c5e6254ecb125b56b7f63876ce..81b4306e72046c243f3aea5465490f28abd1e4e2 100644 (file)
@@ -293,26 +293,23 @@ endif()
 
 if(SUPPORTS_SIMPLE_IPC)
        if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
-               set(FSMONITOR_DAEMON_BACKEND "win32")
-               set(FSMONITOR_OS_SETTINGS "win32")
-       elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
-               set(FSMONITOR_DAEMON_BACKEND "darwin")
-               set(FSMONITOR_OS_SETTINGS "unix")
-       elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-               set(FSMONITOR_DAEMON_BACKEND "linux")
-               set(FSMONITOR_OS_SETTINGS "unix")
-               add_compile_definitions(HAVE_LINUX_MAGIC_H)
-       endif()
+               add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
 
-       if(FSMONITOR_DAEMON_BACKEND)
+               add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
+       elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
                add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
-               list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-${FSMONITOR_DAEMON_BACKEND}.c)
-               list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-${FSMONITOR_DAEMON_BACKEND}.c)
-               list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-${FSMONITOR_OS_SETTINGS}.c)
-               list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-${FSMONITOR_DAEMON_BACKEND}.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
 
                add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
-               list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-${FSMONITOR_OS_SETTINGS}.c)
+               list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
        endif()
 endif()
 
@@ -1155,8 +1152,8 @@ endif()
 file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-BUILD-OPTIONS.in git_build_options NEWLINE_CONSUME)
 string(REPLACE "@BROKEN_PATH_FIX@" "" git_build_options "${git_build_options}")
 string(REPLACE "@DIFF@" "'${DIFF}'" git_build_options "${git_build_options}")
-string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "${FSMONITOR_DAEMON_BACKEND}" git_build_options "${git_build_options}")
-string(REPLACE "@FSMONITOR_OS_SETTINGS@" "${FSMONITOR_OS_SETTINGS}" git_build_options "${git_build_options}")
+string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "win32" git_build_options "${git_build_options}")
+string(REPLACE "@FSMONITOR_OS_SETTINGS@" "win32" git_build_options "${git_build_options}")
 string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_PERF_LARGE_REPO@" "" git_build_options "${git_build_options}")
index 6112d130644f04d970c60b0b71203d7603fd2482..f1b163111194fb7c528e733366da7c280ce36456 100644 (file)
@@ -61,9 +61,6 @@ static int spawn_daemon(void)
 
        cmd.git_cmd = 1;
        cmd.no_stdin = 1;
-       cmd.no_stdout = 1;
-       cmd.no_stderr = 1;
-       cmd.close_fd_above_stderr = 1;
        cmd.trace2_child_class = "fsmonitor";
        strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
 
index 3a64b14e73f80a17b6bc10056b86563570ee7b58..b28571e08e2b54410a73605f1efaf41813114aa2 100644 (file)
@@ -1344,17 +1344,10 @@ else
 endif
 
 fsmonitor_backend = ''
-fsmonitor_os = ''
 if host_machine.system() == 'windows'
   fsmonitor_backend = 'win32'
-  fsmonitor_os = 'win32'
-elif host_machine.system() == 'linux' and threads.found() and compiler.has_header('linux/magic.h')
-  fsmonitor_backend = 'linux'
-  fsmonitor_os = 'unix'
-  libgit_c_args += '-DHAVE_LINUX_MAGIC_H'
 elif host_machine.system() == 'darwin'
   fsmonitor_backend = 'darwin'
-  fsmonitor_os = 'unix'
   libgit_dependencies += dependency('CoreServices')
 endif
 if fsmonitor_backend != ''
@@ -1363,14 +1356,14 @@ if fsmonitor_backend != ''
 
   compat_sources += [
     'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
-    'compat/fsmonitor/fsm-ipc-' + fsmonitor_os + '.c',
+    'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c',
     'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
     'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
-    'compat/fsmonitor/fsm-settings-' + fsmonitor_os + '.c',
+    'compat/fsmonitor/fsm-settings-' + fsmonitor_backend + '.c',
   ]
 endif
 build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend)
-build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_os)
+build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_backend)
 
 if not get_option('b_sanitize').contains('address') and get_option('regex').allowed() and compiler.has_header('regex.h') and compiler.get_define('REG_STARTEND', prefix: '#include <regex.h>') != ''
   build_options_config.set('NO_REGEX', '')
index a9beec722caf9f516566fffc4cdb9b64c11c12f1..c146a56532a1397fcafe769fac1968d01f912771 100644 (file)
@@ -545,7 +545,6 @@ static void atfork_parent(struct atfork_state *as)
                "restoring signal mask");
 #endif
 }
-
 #endif /* GIT_WINDOWS_NATIVE */
 
 static inline void set_cloexec(int fd)
@@ -832,17 +831,6 @@ fail_pipe:
                        child_close(cmd->out);
                }
 
-               if (cmd->close_fd_above_stderr) {
-                       long max_fd = sysconf(_SC_OPEN_MAX);
-                       int fd;
-                       if (max_fd < 0 || max_fd > 4096)
-                               max_fd = 4096;
-                       for (fd = 3; fd < max_fd; fd++) {
-                               if (fd != child_notifier)
-                                       close(fd);
-                       }
-               }
-
                if (cmd->dir && chdir(cmd->dir))
                        child_die(CHILD_ERR_CHDIR);
 
index c2fad4f0f8380c87bbe73c6857b3cc086c505d4d..8ca496d7bdebfd434cb625cb0295bbdd50474ca5 100644 (file)
@@ -143,15 +143,6 @@ struct child_process {
        unsigned stdout_to_stderr:1;
        unsigned clean_on_exit:1;
        unsigned wait_after_clean:1;
-
-       /**
-        * Close file descriptors 3 and above in the child after forking
-        * but before exec.  This prevents the child from inheriting
-        * pipe endpoints or other descriptors from the parent
-        * environment (e.g., the test harness).
-        */
-       unsigned close_fd_above_stderr:1;
-
        void (*clean_on_exit_handler)(struct child_process *process);
 };
 
index b99a940c8dad3c53e7c790fe23c4f603aa424263..e7b40654694c9e1cf58f4db0cfbd04b4ad4f9c89 100755 (executable)
@@ -10,58 +10,9 @@ then
        test_done
 fi
 
-# Verify that the filesystem delivers events to the daemon.
-# On some configurations (e.g., overlayfs with older kernels),
-# inotify watches succeed but events are never delivered.  The
-# cookie wait will time out and the daemon logs a trace message.
-#
-# Use "timeout" (if available) to guard each step against hangs.
-maybe_timeout () {
-       if type timeout >/dev/null 2>&1
-       then
-               timeout "$@"
-       else
-               shift
-               "$@"
-       fi
-}
-verify_fsmonitor_works () {
-       git init test_fsmonitor_smoke || return 1
-
-       GIT_TRACE_FSMONITOR="$PWD/smoke.trace" &&
-       export GIT_TRACE_FSMONITOR &&
-       maybe_timeout 30 \
-               git -C test_fsmonitor_smoke fsmonitor--daemon start \
-                       --start-timeout=10
-       ret=$?
-       unset GIT_TRACE_FSMONITOR
-       if test $ret -ne 0
-       then
-               rm -rf test_fsmonitor_smoke smoke.trace
-               return 1
-       fi
-
-       maybe_timeout 10 \
-               test-tool -C test_fsmonitor_smoke fsmonitor-client query \
-                       --token 0 >/dev/null 2>&1
-       maybe_timeout 5 \
-               git -C test_fsmonitor_smoke fsmonitor--daemon stop 2>/dev/null
-       ! grep -q "cookie_wait timed out" "$PWD/smoke.trace" 2>/dev/null
-       ret=$?
-       rm -rf test_fsmonitor_smoke smoke.trace
-       return $ret
-}
-
-if ! verify_fsmonitor_works
-then
-       skip_all="filesystem does not deliver fsmonitor events (container/overlayfs?)"
-       test_done
-fi
-
 stop_daemon_delete_repo () {
        r=$1 &&
-       test_might_fail maybe_timeout 30 \
-               git -C $r fsmonitor--daemon stop 2>/dev/null
+       test_might_fail git -C $r fsmonitor--daemon stop &&
        rm -rf $1
 }
 
@@ -116,7 +67,7 @@ start_daemon () {
                        export GIT_TEST_FSMONITOR_TOKEN
                fi &&
 
-               git $r fsmonitor--daemon start --start-timeout=10 &&
+               git $r fsmonitor--daemon start &&
                git $r fsmonitor--daemon status
        )
 }
@@ -572,28 +523,6 @@ test_expect_success 'directory changes to a file' '
        retry_grep "^event: dir1$" .git/trace
 '
 
-test_expect_success 'rapid nested directory creation' '
-       test_when_finished "git fsmonitor--daemon stop; rm -rf rapid" &&
-
-       start_daemon --tf "$PWD/.git/trace" &&
-
-       # Rapidly create nested directories to exercise race conditions
-       # where directory watches may be added concurrently during
-       # event processing and recursive scanning.
-       for i in $(test_seq 1 20)
-       do
-               mkdir -p "rapid/nested/dir$i/subdir/deep" || return 1
-       done &&
-
-       # Give the daemon time to process all events
-       sleep 1 &&
-
-       test-tool fsmonitor-client query --token 0 &&
-
-       # Verify daemon is still running (did not crash)
-       git fsmonitor--daemon status
-'
-
 # The next few test cases exercise the token-resync code.  When filesystem
 # drops events (because of filesystem velocity or because the daemon isn't
 # polling fast enough), we need to discard the cached data (relative to the
@@ -984,10 +913,7 @@ test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
 start_git_in_background () {
        git "$@" &
        git_pid=$!
-       git_pgid=$(ps -o pgid= -p $git_pid 2>/dev/null ||
-               awk '{print $5}' /proc/$git_pid/stat 2>/dev/null) &&
-       git_pgid="${git_pgid## }" &&
-       git_pgid="${git_pgid%% }"
+       git_pgid=$(ps -o pgid= -p $git_pid)
        nr_tries_left=10
        while true
        do
@@ -998,16 +924,15 @@ start_git_in_background () {
                fi
                sleep 1
                nr_tries_left=$(($nr_tries_left - 1))
-       done >/dev/null 2>&1 3>&- 4>&- 5>&- 6>&- 7>&- &
+       done >/dev/null 2>&1 &
        watchdog_pid=$!
        wait $git_pid
 }
 
 stop_git () {
-       test -n "$git_pgid" || return 0
-       while kill -0 -- -$git_pgid 2>/dev/null
+       while kill -0 -- -$git_pgid
        do
-               kill -- -$git_pgid 2>/dev/null
+               kill -- -$git_pgid
                sleep 1
        done
 }
@@ -1022,7 +947,7 @@ stop_watchdog () {
 
 test_expect_success !MINGW "submodule implicitly starts daemon by pull" '
        test_atexit "stop_watchdog" &&
-       test_when_finished "set +m; stop_git; rm -rf cloned super sub" &&
+       test_when_finished "stop_git; rm -rf cloned super sub" &&
 
        create_super super &&
        create_sub sub &&
index f2a6df77ceeb011b66df7e2208b73e367d3b2893..009437a5f3168fa9e36c5eb30291fcddfc431fdc 100755 (executable)
@@ -152,10 +152,6 @@ test_expect_success 'set up repository to clone' '
 '
 
 test_expect_success 'scalar clone' '
-       # index.skipHash (Scalar default) and GIT_TEST_SPLIT_INDEX are
-       # incompatible: the shared index gets a null OID and fails to
-       # load on re-read.
-       sane_unset GIT_TEST_SPLIT_INDEX &&
        second=$(git rev-parse --verify second:second.t) &&
        scalar clone "file://$(pwd)" cloned --single-branch &&
        (
@@ -186,7 +182,6 @@ test_expect_success 'scalar clone' '
 '
 
 test_expect_success 'scalar clone --no-... opts' '
-       sane_unset GIT_TEST_SPLIT_INDEX &&
        # Note: redirect stderr always to avoid having a verbose test
        # run result in a difference in the --[no-]progress option.
        GIT_TRACE2_EVENT="$(pwd)/no-opt-trace" scalar clone \
@@ -312,7 +307,6 @@ test_expect_success '`scalar [...] <dir>` errors out when dir is missing' '
 
 SQ="'"
 test_expect_success UNZIP 'scalar diagnose' '
-       sane_unset GIT_TEST_SPLIT_INDEX &&
        scalar clone "file://$(pwd)" cloned --single-branch &&
        git repack &&
        echo "$(pwd)/.git/objects/" >>cloned/src/.git/objects/info/alternates &&
index 2043f48a1acdf7a827be9a0e2c1362e764440110..bfbf22a4621843cfde09e813ea7a3e401843185c 100755 (executable)
@@ -8,11 +8,6 @@ test_description='test the `scalar clone` subcommand'
 GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true"
 export GIT_TEST_MAINT_SCHEDULER
 
-# index.skipHash (Scalar default) and GIT_TEST_SPLIT_INDEX are
-# incompatible: the shared index gets a null OID and fails to
-# load on re-read.  Every test here uses scalar clone.
-sane_unset GIT_TEST_SPLIT_INDEX
-
 test_expect_success 'set up repository to clone' '
        rm -rf .git &&
        git init to-clone &&