Skip to content

Commit a0525f9

Browse files
jeffhostetlerdscho
authored andcommitted
fsmonitor--daemon: cd out of worktree root
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 <[email protected]>
1 parent 4725384 commit a0525f9

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

builtin/fsmonitor--daemon.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,11 +1169,11 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11691169
* before we need it.
11701170
*/
11711171
if (ipc_server_run_async(&state->ipc_server_data,
1172-
fsmonitor_ipc__get_path(), &ipc_opts,
1172+
state->path_ipc.buf, &ipc_opts,
11731173
handle_client, state))
11741174
return error_errno(
11751175
_("could not start IPC thread pool on '%s'"),
1176-
fsmonitor_ipc__get_path());
1176+
state->path_ipc.buf);
11771177

11781178
/*
11791179
* Start the fsmonitor listener thread to collect filesystem
@@ -1208,6 +1208,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
12081208
static int fsmonitor_run_daemon(void)
12091209
{
12101210
struct fsmonitor_daemon_state state;
1211+
const char *home;
12111212
int err;
12121213

12131214
memset(&state, 0, sizeof(state));
@@ -1277,6 +1278,15 @@ static int fsmonitor_run_daemon(void)
12771278

12781279
strbuf_addch(&state.path_cookie_prefix, '/');
12791280

1281+
/*
1282+
* We create a named-pipe or unix domain socket inside of the
1283+
* ".git" directory. (Well, on Windows, we base our named
1284+
* pipe in the NPFS on the absolute path of the git
1285+
* directory.)
1286+
*/
1287+
strbuf_init(&state.path_ipc, 0);
1288+
strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
1289+
12801290
/*
12811291
* Confirm that we can create platform-specific resources for the
12821292
* filesystem listener before we bother starting all the threads.
@@ -1286,6 +1296,23 @@ static int fsmonitor_run_daemon(void)
12861296
goto done;
12871297
}
12881298

1299+
/*
1300+
* CD out of the worktree root directory.
1301+
*
1302+
* The common Git startup mechanism causes our CWD to be the
1303+
* root of the worktree. On Windows, this causes our process
1304+
* to hold a locked handle on the CWD. This prevents the
1305+
* worktree from being moved or deleted while the daemon is
1306+
* running.
1307+
*
1308+
* We assume that our FS and IPC listener threads have either
1309+
* opened all of the handles that they need or will do
1310+
* everything using absolute paths.
1311+
*/
1312+
home = getenv("HOME");
1313+
if (home && *home && chdir(home))
1314+
die_errno("could not cd home '%s'", home);
1315+
12891316
err = fsmonitor_run_daemon_1(&state);
12901317

12911318
done:
@@ -1298,6 +1325,7 @@ static int fsmonitor_run_daemon(void)
12981325
strbuf_release(&state.path_worktree_watch);
12991326
strbuf_release(&state.path_gitdir_watch);
13001327
strbuf_release(&state.path_cookie_prefix);
1328+
strbuf_release(&state.path_ipc);
13011329

13021330
/*
13031331
* NEEDSWORK: Consider "rm -rf <gitdir>/<fsmonitor-dir>"

compat/fsmonitor/fsm-listen-win32.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,22 @@ static int recv_rdcw_watch(struct one_watch *watch)
398398
}
399399

400400
/*
401-
* NEEDSWORK: If an external <gitdir> is deleted, the above
402-
* returns an error. I'm not sure that there's anything that
403-
* we can do here other than failing -- the <worktree>/.git
404-
* link file would be broken anyway. We might try to check
405-
* for that and return a better error message, but I'm not
406-
* sure it is worth it.
401+
* GetOverlappedResult() fails if the watched directory is
402+
* deleted while we were waiting for an overlapped IO to
403+
* complete. The documentation did not list specific errors,
404+
* but I observed ERROR_ACCESS_DENIED (0x05) errors during
405+
* testing.
406+
*
407+
* Note that we only get notificaiton events for events
408+
* *within* the directory, not *on* the directory itself.
409+
* (These might be properies of the parent directory, for
410+
* example).
411+
*
412+
* NEEDSWORK: We might try to check for the deleted directory
413+
* case and return a better error message, but I'm not sure it
414+
* is worth it.
415+
*
416+
* Shutdown if we get any error.
407417
*/
408418

409419
error("GetOverlappedResult failed on '%s' [GLE %ld]",

fsmonitor--daemon.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct fsmonitor_daemon_state {
5454
struct fsmonitor_daemon_backend_data *backend_data;
5555

5656
struct ipc_server_data *ipc_server_data;
57+
struct strbuf path_ipc;
5758
};
5859

5960
/*

0 commit comments

Comments
 (0)