diff options
-rw-r--r-- | cache.h | 2 | ||||
-rw-r--r-- | common-main.c | 4 | ||||
-rw-r--r-- | setup.c | 65 |
3 files changed, 71 insertions, 0 deletions
@@ -1834,8 +1834,10 @@ void overlay_tree_on_index(struct index_state *istate, struct startup_info { int have_repository; const char *prefix; + const char *original_cwd; }; extern struct startup_info *startup_info; +extern const char *tmp_original_cwd; /* merge.c */ struct commit_list; diff --git a/common-main.c b/common-main.c index 71e21dd20a..aa8d5aba5b 100644 --- a/common-main.c +++ b/common-main.c @@ -26,6 +26,7 @@ static void restore_sigpipe_to_default(void) int main(int argc, const char **argv) { int result; + struct strbuf tmp = STRBUF_INIT; trace2_initialize_clock(); @@ -49,6 +50,9 @@ int main(int argc, const char **argv) trace2_cmd_start(argv); trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP); + if (!strbuf_getcwd(&tmp)) + tmp_original_cwd = strbuf_detach(&tmp, NULL); + result = cmd_main(argc, argv); trace2_cmd_exit(result); @@ -12,6 +12,7 @@ static int work_tree_config_is_bogus; static struct startup_info the_startup_info; struct startup_info *startup_info = &the_startup_info; +const char *tmp_original_cwd; /* * The input parameter must contain an absolute path, and it must already be @@ -432,6 +433,69 @@ void setup_work_tree(void) initialized = 1; } +static void setup_original_cwd(void) +{ + struct strbuf tmp = STRBUF_INIT; + const char *worktree = NULL; + int offset = -1; + + if (!tmp_original_cwd) + return; + + /* + * startup_info->original_cwd points to the current working + * directory we inherited from our parent process, which is a + * directory we want to avoid removing. + * + * For convience, we would like to have the path relative to the + * worktree instead of an absolute path. + * + * Yes, startup_info->original_cwd is usually the same as 'prefix', + * but differs in two ways: + * - prefix has a trailing '/' + * - if the user passes '-C' to git, that modifies the prefix but + * not startup_info->original_cwd. + */ + + /* Normalize the directory */ + strbuf_realpath(&tmp, tmp_original_cwd, 1); + free((char*)tmp_original_cwd); + tmp_original_cwd = NULL; + startup_info->original_cwd = strbuf_detach(&tmp, NULL); + + /* + * Get our worktree; we only protect the current working directory + * if it's in the worktree. + */ + worktree = get_git_work_tree(); + if (!worktree) + goto no_prevention_needed; + + offset = dir_inside_of(startup_info->original_cwd, worktree); + if (offset >= 0) { + /* + * If startup_info->original_cwd == worktree, that is already + * protected and we don't need original_cwd as a secondary + * protection measure. + */ + if (!*(startup_info->original_cwd + offset)) + goto no_prevention_needed; + + /* + * original_cwd was inside worktree; precompose it just as + * we do prefix so that built up paths will match + */ + startup_info->original_cwd = \ + precompose_string_if_needed(startup_info->original_cwd + + offset); + return; + } + +no_prevention_needed: + free((char*)startup_info->original_cwd); + startup_info->original_cwd = NULL; +} + static int read_worktree_config(const char *var, const char *value, void *vdata) { struct repository_format *data = vdata; @@ -1330,6 +1394,7 @@ const char *setup_git_directory_gently(int *nongit_ok) setenv(GIT_PREFIX_ENVIRONMENT, "", 1); } + setup_original_cwd(); strbuf_release(&dir); strbuf_release(&gitdir); |