summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cache.h2
-rw-r--r--common-main.c4
-rw-r--r--setup.c65
3 files changed, 71 insertions, 0 deletions
diff --git a/cache.h b/cache.h
index eba12487b9..92e181ea75 100644
--- a/cache.h
+++ b/cache.h
@@ -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);
diff --git a/setup.c b/setup.c
index 347d7181ae..af3b8c09ab 100644
--- a/setup.c
+++ b/setup.c
@@ -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);