]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fsmonitor--daemon: cd out of worktree root
authorJeff Hostetler <jeffhost@microsoft.com>
Thu, 26 May 2022 21:47:07 +0000 (21:47 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 26 May 2022 22:59:26 +0000 (15:59 -0700)
Teach the fsmonitor--daemon to CD outside of the worktree
before starting up.

The common Git startup mechanism causes the CWD of the daemon process
to be in the root of the worktree.  On Windows, this causes the daemon
process to hold a locked handle on the CWD and prevents other
processes from moving or deleting the worktree while the daemon is
running.

CD to HOME before entering main event loops.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fsmonitor--daemon.c
compat/fsmonitor/fsm-listen-win32.c
fsmonitor--daemon.h

index 66b78a0353f6af50056d8d2a8a37f7020fd076c5..db297649daff38c7b02f3d80833a6dc0325d94c0 100644 (file)
@@ -1181,11 +1181,11 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
         * before we need it.
         */
        if (ipc_server_run_async(&state->ipc_server_data,
-                                fsmonitor_ipc__get_path(), &ipc_opts,
+                                state->path_ipc.buf, &ipc_opts,
                                 handle_client, state))
                return error_errno(
                        _("could not start IPC thread pool on '%s'"),
-                       fsmonitor_ipc__get_path());
+                       state->path_ipc.buf);
 
        /*
         * Start the fsmonitor listener thread to collect filesystem
@@ -1220,6 +1220,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
 static int fsmonitor_run_daemon(void)
 {
        struct fsmonitor_daemon_state state;
+       const char *home;
        int err;
 
        memset(&state, 0, sizeof(state));
@@ -1289,6 +1290,15 @@ static int fsmonitor_run_daemon(void)
 
        strbuf_addch(&state.path_cookie_prefix, '/');
 
+       /*
+        * We create a named-pipe or unix domain socket inside of the
+        * ".git" directory.  (Well, on Windows, we base our named
+        * pipe in the NPFS on the absolute path of the git
+        * directory.)
+        */
+       strbuf_init(&state.path_ipc, 0);
+       strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+
        /*
         * Confirm that we can create platform-specific resources for the
         * filesystem listener before we bother starting all the threads.
@@ -1298,6 +1308,23 @@ static int fsmonitor_run_daemon(void)
                goto done;
        }
 
+       /*
+        * CD out of the worktree root directory.
+        *
+        * The common Git startup mechanism causes our CWD to be the
+        * root of the worktree.  On Windows, this causes our process
+        * to hold a locked handle on the CWD.  This prevents the
+        * worktree from being moved or deleted while the daemon is
+        * running.
+        *
+        * We assume that our FS and IPC listener threads have either
+        * opened all of the handles that they need or will do
+        * everything using absolute paths.
+        */
+       home = getenv("HOME");
+       if (home && *home && chdir(home))
+               die_errno(_("could not cd home '%s'"), home);
+
        err = fsmonitor_run_daemon_1(&state);
 
 done:
@@ -1310,6 +1337,7 @@ done:
        strbuf_release(&state.path_worktree_watch);
        strbuf_release(&state.path_gitdir_watch);
        strbuf_release(&state.path_cookie_prefix);
+       strbuf_release(&state.path_ipc);
 
        return err;
 }
index 4f46bd1d0a623171638bdd4844eadc2f9bd8bbe8..35f2fb957847558131c57e4411e1e0d90c6b1fb9 100644 (file)
@@ -424,12 +424,22 @@ static int recv_rdcw_watch(struct one_watch *watch)
        }
 
        /*
-        * NEEDSWORK: If an external <gitdir> is deleted, the above
-        * returns an error.  I'm not sure that there's anything that
-        * we can do here other than failing -- the <worktree>/.git
-        * link file would be broken anyway.  We might try to check
-        * for that and return a better error message, but I'm not
-        * sure it is worth it.
+        * GetOverlappedResult() fails if the watched directory is
+        * deleted while we were waiting for an overlapped IO to
+        * complete.  The documentation did not list specific errors,
+        * but I observed ERROR_ACCESS_DENIED (0x05) errors during
+        * testing.
+        *
+        * Note that we only get notificaiton events for events
+        * *within* the directory, not *on* the directory itself.
+        * (These might be properies of the parent directory, for
+        * example).
+        *
+        * NEEDSWORK: We might try to check for the deleted directory
+        * case and return a better error message, but I'm not sure it
+        * is worth it.
+        *
+        * Shutdown if we get any error.
         */
 
        error(_("GetOverlappedResult failed on '%s' [GLE %ld]"),
index bd09fffc1767a36282ca8f01381acf969ab159d6..223c2131b58eb637d5b53788d2ff91ebf0c1d3ff 100644 (file)
@@ -54,6 +54,7 @@ struct fsmonitor_daemon_state {
        struct fsmonitor_daemon_backend_data *backend_data;
 
        struct ipc_server_data *ipc_server_data;
+       struct strbuf path_ipc;
 };
 
 /*