Skip to content

Commit

Permalink
Merge branch 'am/real-path-fix' into next
Browse files Browse the repository at this point in the history
The real_path() convenience function can easily be misused; with a
bit of code refactoring in the callers' side, its use has been
eliminated.

* am/real-path-fix:
  get_superproject_working_tree(): return strbuf
  real_path_if_valid(): remove unsafe API
  real_path: remove unsafe API
  set_git_dir: fix crash when used with real_path()
  • Loading branch information
gitster committed Mar 11, 2020
2 parents 0496b26 + 49d3c4b commit 1f84382
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 75 deletions.
18 changes: 1 addition & 17 deletions abspath.c
Expand Up @@ -202,22 +202,6 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
return retval;
}

/*
* Resolve `path` into an absolute, cleaned-up path. The return value
* comes from a shared buffer.
*/
const char *real_path(const char *path)
{
static struct strbuf realpath = STRBUF_INIT;
return strbuf_realpath(&realpath, path, 1);
}

const char *real_path_if_valid(const char *path)
{
static struct strbuf realpath = STRBUF_INIT;
return strbuf_realpath(&realpath, path, 0);
}

char *real_pathdup(const char *path, int die_on_error)
{
struct strbuf realpath = STRBUF_INIT;
Expand All @@ -233,7 +217,7 @@ char *real_pathdup(const char *path, int die_on_error)

/*
* Use this to get an absolute path from a relative one. If you want
* to resolve links, you should use real_path.
* to resolve links, you should use strbuf_realpath.
*/
const char *absolute_path(const char *path)
{
Expand Down
6 changes: 5 additions & 1 deletion builtin/clone.c
Expand Up @@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
struct dir_iterator *iter;
int iter_status;
unsigned int flags;
struct strbuf realpath = STRBUF_INIT;

mkdir_if_missing(dest->buf, 0777);

Expand Down Expand Up @@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
if (!link(real_path(src->buf), dest->buf))
strbuf_realpath(&realpath, src->buf, 1);
if (!link(realpath.buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
Expand All @@ -468,6 +470,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf);
}

strbuf_release(&realpath);
}

static void clone_local(const char *src_repo, const char *dest_repo)
Expand Down
5 changes: 4 additions & 1 deletion builtin/commit-graph.c
Expand Up @@ -50,14 +50,17 @@ static struct object_directory *find_odb(struct repository *r,
{
struct object_directory *odb;
char *obj_dir_real = real_pathdup(obj_dir, 1);
struct strbuf odb_path_real = STRBUF_INIT;

prepare_alt_odb(r);
for (odb = r->objects->odb; odb; odb = odb->next) {
if (!strcmp(obj_dir_real, real_path(odb->path)))
strbuf_realpath(&odb_path_real, odb->path, 1);
if (!strcmp(obj_dir_real, odb_path_real.buf))
break;
}

free(obj_dir_real);
strbuf_release(&odb_path_real);

if (!odb)
die(_("could not find object directory matching %s"), obj_dir);
Expand Down
4 changes: 2 additions & 2 deletions builtin/init-db.c
Expand Up @@ -356,12 +356,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
if (!exist_ok && !stat(real_git_dir, &st))
die(_("%s already exists"), real_git_dir);

set_git_dir(real_path(real_git_dir));
set_git_dir(real_git_dir, 1);
git_dir = get_git_dir();
separate_git_dir(git_dir, original_git_dir);
}
else {
set_git_dir(real_path(git_dir));
set_git_dir(git_dir, 1);
git_dir = get_git_dir();
}
startup_info->have_repository = 1;
Expand Down
12 changes: 8 additions & 4 deletions builtin/rev-parse.c
Expand Up @@ -808,9 +808,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--show-superproject-working-tree")) {
const char *superproject = get_superproject_working_tree();
if (superproject)
puts(superproject);
struct strbuf superproject = STRBUF_INIT;
if (get_superproject_working_tree(&superproject))
puts(superproject.buf);
strbuf_release(&superproject);
continue;
}
if (!strcmp(arg, "--show-prefix")) {
Expand Down Expand Up @@ -857,7 +858,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!gitdir && !prefix)
gitdir = ".git";
if (gitdir) {
puts(real_path(gitdir));
struct strbuf realpath = STRBUF_INIT;
strbuf_realpath(&realpath, gitdir, 1);
puts(realpath.buf);
strbuf_release(&realpath);
continue;
}
}
Expand Down
9 changes: 6 additions & 3 deletions builtin/worktree.c
Expand Up @@ -258,7 +258,7 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
const char *name;
struct child_process cp = CHILD_PROCESS_INIT;
struct argv_array child_env = ARGV_ARRAY_INIT;
Expand Down Expand Up @@ -330,9 +330,11 @@ static int add_worktree(const char *path, const char *refname,

strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
write_file(sb.buf, "%s", real_path(sb_git.buf));
strbuf_realpath(&realpath, sb_git.buf, 1);
write_file(sb.buf, "%s", realpath.buf);
strbuf_realpath(&realpath, get_git_common_dir(), 1);
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
real_path(get_git_common_dir()), name);
realpath.buf, name);
/*
* This is to keep resolve_ref() happy. We need a valid HEAD
* or is_git_directory() will reject the directory. Any value which
Expand Down Expand Up @@ -418,6 +420,7 @@ static int add_worktree(const char *path, const char *refname,
strbuf_release(&sb_repo);
strbuf_release(&sb_git);
strbuf_release(&sb_name);
strbuf_release(&realpath);
return ret;
}

Expand Down
4 changes: 1 addition & 3 deletions cache.h
Expand Up @@ -543,7 +543,7 @@ const char *get_git_common_dir(void);
char *get_object_directory(void);
char *get_index_file(void);
char *get_graft_file(struct repository *r);
void set_git_dir(const char *path);
void set_git_dir(const char *path, int make_realpath);
int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
int get_common_dir(struct strbuf *sb, const char *gitdir);
const char *get_git_namespace(void);
Expand Down Expand Up @@ -1314,8 +1314,6 @@ static inline int is_absolute_path(const char *path)
int is_directory(const char *);
char *strbuf_realpath(struct strbuf *resolved, const char *path,
int die_on_error);
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
char *real_pathdup(const char *path, int die_on_error);
const char *absolute_path(const char *path);
char *absolute_pathdup(const char *path);
Expand Down
11 changes: 9 additions & 2 deletions editor.c
Expand Up @@ -54,7 +54,8 @@ static int launch_specified_editor(const char *editor, const char *path,
return error("Terminal is dumb, but EDITOR unset");

if (strcmp(editor, ":")) {
const char *args[] = { editor, real_path(path), NULL };
struct strbuf realpath = STRBUF_INIT;
const char *args[] = { editor, NULL, NULL };
struct child_process p = CHILD_PROCESS_INIT;
int ret, sig;
int print_waiting_for_editor = advice_waiting_for_editor && isatty(2);
Expand All @@ -75,16 +76,22 @@ static int launch_specified_editor(const char *editor, const char *path,
fflush(stderr);
}

strbuf_realpath(&realpath, path, 1);
args[1] = realpath.buf;

p.argv = args;
p.env = env;
p.use_shell = 1;
p.trace2_child_class = "editor";
if (start_command(&p) < 0)
if (start_command(&p) < 0) {
strbuf_release(&realpath);
return error("unable to start editor '%s'", editor);
}

sigchain_push(SIGINT, SIG_IGN);
sigchain_push(SIGQUIT, SIG_IGN);
ret = finish_command(&p);
strbuf_release(&realpath);
sig = ret - 128;
sigchain_pop(SIGINT);
sigchain_pop(SIGQUIT);
Expand Down
18 changes: 16 additions & 2 deletions environment.c
Expand Up @@ -254,8 +254,11 @@ static int git_work_tree_initialized;
*/
void set_git_work_tree(const char *new_work_tree)
{
struct strbuf realpath = STRBUF_INIT;

if (git_work_tree_initialized) {
new_work_tree = real_path(new_work_tree);
strbuf_realpath(&realpath, new_work_tree, 1);
new_work_tree = realpath.buf;
if (strcmp(new_work_tree, the_repository->worktree))
die("internal error: work tree has already been set\n"
"Current worktree: %s\nNew worktree: %s",
Expand All @@ -264,6 +267,8 @@ void set_git_work_tree(const char *new_work_tree)
}
git_work_tree_initialized = 1;
repo_set_worktree(the_repository, new_work_tree);

strbuf_release(&realpath);
}

const char *get_git_work_tree(void)
Expand Down Expand Up @@ -345,11 +350,20 @@ static void update_relative_gitdir(const char *name,
free(path);
}

void set_git_dir(const char *path)
void set_git_dir(const char *path, int make_realpath)
{
struct strbuf realpath = STRBUF_INIT;

if (make_realpath) {
strbuf_realpath(&realpath, path, 1);
path = realpath.buf;
}

set_git_dir_1(path);
if (!is_absolute_path(path))
chdir_notify_register(NULL, update_relative_gitdir, NULL);

strbuf_release(&realpath);
}

const char *get_log_output_encoding(void)
Expand Down
4 changes: 2 additions & 2 deletions path.c
Expand Up @@ -723,7 +723,7 @@ static struct passwd *getpw_str(const char *username, size_t len)
* then it is a newly allocated string. Returns NULL on getpw failure or
* if path is NULL.
*
* If real_home is true, real_path($HOME) is used in the expansion.
* If real_home is true, strbuf_realpath($HOME) is used in the expansion.
*/
char *expand_user_path(const char *path, int real_home)
{
Expand Down Expand Up @@ -850,7 +850,7 @@ const char *enter_repo(const char *path, int strict)
}

if (is_git_directory(".")) {
set_git_dir(".");
set_git_dir(".", 0);
check_repository_format();
return path;
}
Expand Down

0 comments on commit 1f84382

Please sign in to comment.