connect_work_tree_and_git_dir: safely create leading directories

In a later patch we'll use connect_work_tree_and_git_dir when the directory for the gitlink file doesn't exist yet. This patch makes connect_work_tree_and_git_dir safe to use for both cases of either the git dir or the working dir missing. To do so, we need to call safe_create_leading_directories[_const] on both directories. However this has to happen before we construct the absolute paths as real_pathdup assumes the directories to be there already. So for both the config file in the git dir as well as the .git link file we need to a) construct the name b) call SCLD c) get the absolute path d) once a-c is done for both we can consume the absolute path to compute the relative path to each other and store those relative paths. The implementation provided here puts a) and b) for both cases first, and then performs c and d after. One of the two users of 'connect_work_tree_and_git_dir' already checked for the directory being there, so we can loose that check as connect_work_tree_and_git_dir handles this functionality now. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Mar 14, 2017 at 14:46 UTC 365444a6a55391e192662964d523e2b0887557bd
2 files changed +23 -20
dir.c
+21 -11
@@ -2728,23 +2728,33 @@ void untracked_cache_add_to_index(struct index_state *istate,
2728 /* Update gitfile and core.worktree setting to connect work tree and git dir */
2729 void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
2730 {
2731 - struct strbuf file_name = STRBUF_INIT;
2731 + struct strbuf gitfile_sb = STRBUF_INIT;
2732 + struct strbuf cfg_sb = STRBUF_INIT;
2733 struct strbuf rel_path = STRBUF_INIT;
2733 - char *git_dir = real_pathdup(git_dir_);
2734 - char *work_tree = real_pathdup(work_tree_);
2734 + char *git_dir, *work_tree;
2735
2736 - /* Update gitfile */
2737 - strbuf_addf(&file_name, "%s/.git", work_tree);
2738 - write_file(file_name.buf, "gitdir: %s",
2739 - relative_path(git_dir, work_tree, &rel_path));
2736 + /* Prepare .git file */
2737 + strbuf_addf(&gitfile_sb, "%s/.git", work_tree_);
2738 + if (safe_create_leading_directories_const(gitfile_sb.buf))
2739 + die(_("could not create directories for %s"), gitfile_sb.buf);
2740 +
2741 + /* Prepare config file */
2742 + strbuf_addf(&cfg_sb, "%s/config", git_dir_);
2743 + if (safe_create_leading_directories_const(cfg_sb.buf))
2744 + die(_("could not create directories for %s"), cfg_sb.buf);
2745
2746 + git_dir = real_pathdup(git_dir_);
2747 + work_tree = real_pathdup(work_tree_);
2748 +
2749 + /* Write .git file */
2750 + write_file(gitfile_sb.buf, "gitdir: %s",
2751 + relative_path(git_dir, work_tree, &rel_path));
2752 /* Update core.worktree setting */
2742 - strbuf_reset(&file_name);
2743 - strbuf_addf(&file_name, "%s/config", git_dir);
2744 - git_config_set_in_file(file_name.buf, "core.worktree",
2753 + git_config_set_in_file(cfg_sb.buf, "core.worktree",
2754 relative_path(work_tree, git_dir, &rel_path));
2755
2747 - strbuf_release(&file_name);
2756 + strbuf_release(&gitfile_sb);
2757 + strbuf_release(&cfg_sb);
2758 strbuf_release(&rel_path);
2759 free(work_tree);
2760 free(git_dir);
submodule.c
+2 -9
@@ -1445,8 +1445,6 @@ void absorb_git_dir_into_superproject(const char *prefix,
1445
1446 /* Not populated? */
1447 if (!sub_git_dir) {
1448 - char *real_new_git_dir;
1449 - const char *new_git_dir;
1448 const struct submodule *sub;
1449
1450 if (err_code == READ_GITFILE_ERR_STAT_FAILED) {
@@ -1469,13 +1467,8 @@ void absorb_git_dir_into_superproject(const char *prefix,
1467 sub = submodule_from_path(null_sha1, path);
1468 if (!sub)
1469 die(_("could not lookup name for submodule '%s'"), path);
1472 - new_git_dir = git_path("modules/%s", sub->name);
1473 - if (safe_create_leading_directories_const(new_git_dir) < 0)
1474 - die(_("could not create directory '%s'"), new_git_dir);
1475 - real_new_git_dir = real_pathdup(new_git_dir);
1476 - connect_work_tree_and_git_dir(path, real_new_git_dir);
1477 -
1478 - free(real_new_git_dir);
1470 + connect_work_tree_and_git_dir(path,
1471 + git_path("modules/%s", sub->name));
1472 } else {
1473 /* Is it already absorbed into the superprojects git dir? */
1474 char *real_sub_git_dir = real_pathdup(sub_git_dir);