real_pathdup(): fix callsites that wanted it to die on error

In 4ac9006f832 (real_path: have callers use real_pathdup and strbuf_realpath, 2016-12-12), we changed the xstrdup(real_path()) pattern to use real_pathdup() directly. The problem with this change is that real_path() calls strbuf_realpath() with die_on_error = 1 while real_pathdup() calls it with die_on_error = 0. Meaning that in cases where real_path() causes Git to die() with an error message, real_pathdup() is silent and returns NULL instead. The callers, however, are ill-prepared for that change, as they expect the return value to be non-NULL (and otherwise the function died with an appropriate error message). Fix this by extending real_pathdup()'s signature to accept the die_on_error flag and simply pass it through to strbuf_realpath(), and then adjust all callers after a careful audit whether they would handle NULLs well. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Mar 8, 2017 at 16:43 UTC ce83eadd9a2c63db6263df91933da1b1b865d26a
9 files changed +18 -18
abspath.c
+2 -2
@@ -214,12 +214,12 @@ const char *real_path_if_valid(const char *path)
214 return strbuf_realpath(&realpath, path, 0);
215 }
216
217 -char *real_pathdup(const char *path)
217 +char *real_pathdup(const char *path, int die_on_error)
218 {
219 struct strbuf realpath = STRBUF_INIT;
220 char *retval = NULL;
221
222 - if (strbuf_realpath(&realpath, path, 0))
222 + if (strbuf_realpath(&realpath, path, die_on_error))
223 retval = strbuf_detach(&realpath, NULL);
224
225 strbuf_release(&realpath);
builtin/init-db.c
+3 -3
@@ -338,7 +338,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
338 {
339 int reinit;
340 int exist_ok = flags & INIT_DB_EXIST_OK;
341 - char *original_git_dir = real_pathdup(git_dir);
341 + char *original_git_dir = real_pathdup(git_dir, 1);
342
343 if (real_git_dir) {
344 struct stat st;
@@ -489,7 +489,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
489 argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
490
491 if (real_git_dir && !is_absolute_path(real_git_dir))
492 - real_git_dir = real_pathdup(real_git_dir);
492 + real_git_dir = real_pathdup(real_git_dir, 1);
493
494 if (argc == 1) {
495 int mkdir_tried = 0;
@@ -560,7 +560,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
560 const char *git_dir_parent = strrchr(git_dir, '/');
561 if (git_dir_parent) {
562 char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
563 - git_work_tree_cfg = real_pathdup(rel);
563 + git_work_tree_cfg = real_pathdup(rel, 1);
564 free(rel);
565 }
566 if (!git_work_tree_cfg)
cache.h
+1 -1
@@ -1109,7 +1109,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
1109 int die_on_error);
1110 const char *real_path(const char *path);
1111 const char *real_path_if_valid(const char *path);
1112 -char *real_pathdup(const char *path);
1112 +char *real_pathdup(const char *path, int die_on_error);
1113 const char *absolute_path(const char *path);
1114 char *absolute_pathdup(const char *path);
1115 const char *remove_leading_path(const char *in, const char *prefix);
dir.c
+2 -2
@@ -2730,8 +2730,8 @@ void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
2730 {
2731 struct strbuf file_name = STRBUF_INIT;
2732 struct strbuf rel_path = STRBUF_INIT;
2733 - char *git_dir = real_pathdup(git_dir_);
2734 - char *work_tree = real_pathdup(work_tree_);
2733 + char *git_dir = real_pathdup(git_dir_, 1);
2734 + char *work_tree = real_pathdup(work_tree_, 1);
2735
2736 /* Update gitfile */
2737 strbuf_addf(&file_name, "%s/.git", work_tree);
environment.c
+1 -1
@@ -259,7 +259,7 @@ void set_git_work_tree(const char *new_work_tree)
259 return;
260 }
261 git_work_tree_initialized = 1;
262 - work_tree = real_pathdup(new_work_tree);
262 + work_tree = real_pathdup(new_work_tree, 1);
263 }
264
265 const char *get_git_work_tree(void)
setup.c
+2 -2
@@ -698,7 +698,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
698 /* --work-tree is set without --git-dir; use discovered one */
699 if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
700 if (offset != cwd->len && !is_absolute_path(gitdir))
701 - gitdir = real_pathdup(gitdir);
701 + gitdir = real_pathdup(gitdir, 1);
702 if (chdir(cwd->buf))
703 die_errno("Could not come back to cwd");
704 return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
@@ -806,7 +806,7 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
806 /* Keep entry but do not canonicalize it */
807 return 1;
808 } else {
809 - char *real_path = real_pathdup(ceil);
809 + char *real_path = real_pathdup(ceil, 0);
810 if (!real_path) {
811 return 0;
812 }
submodule.c
+5 -5
@@ -1403,7 +1403,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
1403 /* If it is an actual gitfile, it doesn't need migration. */
1404 return;
1405
1406 - real_old_git_dir = real_pathdup(old_git_dir);
1406 + real_old_git_dir = real_pathdup(old_git_dir, 1);
1407
1408 sub = submodule_from_path(null_sha1, path);
1409 if (!sub)
@@ -1412,7 +1412,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
1412 new_git_dir = git_path("modules/%s", sub->name);
1413 if (safe_create_leading_directories_const(new_git_dir) < 0)
1414 die(_("could not create directory '%s'"), new_git_dir);
1415 - real_new_git_dir = real_pathdup(new_git_dir);
1415 + real_new_git_dir = real_pathdup(new_git_dir, 1);
1416
1417 if (!prefix)
1418 prefix = get_super_prefix();
@@ -1472,14 +1472,14 @@ void absorb_git_dir_into_superproject(const char *prefix,
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);
1475 + real_new_git_dir = real_pathdup(new_git_dir, 1);
1476 connect_work_tree_and_git_dir(path, real_new_git_dir);
1477
1478 free(real_new_git_dir);
1479 } else {
1480 /* Is it already absorbed into the superprojects git dir? */
1481 - char *real_sub_git_dir = real_pathdup(sub_git_dir);
1482 - char *real_common_git_dir = real_pathdup(get_git_common_dir());
1481 + char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
1482 + char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
1483
1484 if (!starts_with(real_sub_git_dir, real_common_git_dir))
1485 relocate_single_git_dir_into_superproject(prefix, path);
t/t1501-work-tree.sh
+1 -1
@@ -423,7 +423,7 @@ test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
423 )
424 '
425
426 -test_expect_failure 'error out gracefully on invalid $GIT_WORK_TREE' '
426 +test_expect_success 'error out gracefully on invalid $GIT_WORK_TREE' '
427 (
428 GIT_WORK_TREE=/.invalid/work/tree &&
429 export GIT_WORK_TREE &&
worktree.c
+1 -1
@@ -255,7 +255,7 @@ struct worktree *find_worktree(struct worktree **list,
255 return wt;
256
257 arg = prefix_filename(prefix, strlen(prefix), arg);
258 - path = real_pathdup(arg);
258 + path = real_pathdup(arg, 1);
259 for (; *list; list++)
260 if (!fspathcmp(path, real_path((*list)->path)))
261 break;