Merge branch 'am/real-path-fix'

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()
This commit is contained in:
Junio C Hamano 2020-03-25 13:57:42 -07:00
Родитель 38afd2d1ad 49d3c4b481
Коммит 4d0e8996ec
16 изменённых файлов: 107 добавлений и 75 удалений

Просмотреть файл

@ -202,22 +202,6 @@ error_out:
return retval; 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) char *real_pathdup(const char *path, int die_on_error)
{ {
struct strbuf realpath = STRBUF_INIT; struct strbuf realpath = STRBUF_INIT;
@ -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 * 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) const char *absolute_path(const char *path)
{ {

Просмотреть файл

@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
struct dir_iterator *iter; struct dir_iterator *iter;
int iter_status; int iter_status;
unsigned int flags; unsigned int flags;
struct strbuf realpath = STRBUF_INIT;
mkdir_if_missing(dest->buf, 0777); mkdir_if_missing(dest->buf, 0777);
@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT) if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf); die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) { 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; continue;
if (option_local > 0) if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf); die_errno(_("failed to create link '%s'"), dest->buf);
@ -468,6 +470,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len); strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf); die(_("failed to iterate over '%s'"), src->buf);
} }
strbuf_release(&realpath);
} }
static void clone_local(const char *src_repo, const char *dest_repo) static void clone_local(const char *src_repo, const char *dest_repo)

Просмотреть файл

@ -39,14 +39,17 @@ static struct object_directory *find_odb(struct repository *r,
{ {
struct object_directory *odb; struct object_directory *odb;
char *obj_dir_real = real_pathdup(obj_dir, 1); char *obj_dir_real = real_pathdup(obj_dir, 1);
struct strbuf odb_path_real = STRBUF_INIT;
prepare_alt_odb(r); prepare_alt_odb(r);
for (odb = r->objects->odb; odb; odb = odb->next) { 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; break;
} }
free(obj_dir_real); free(obj_dir_real);
strbuf_release(&odb_path_real);
if (!odb) if (!odb)
die(_("could not find object directory matching %s"), obj_dir); die(_("could not find object directory matching %s"), obj_dir);

Просмотреть файл

@ -356,12 +356,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
if (!exist_ok && !stat(real_git_dir, &st)) if (!exist_ok && !stat(real_git_dir, &st))
die(_("%s already exists"), real_git_dir); 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(); git_dir = get_git_dir();
separate_git_dir(git_dir, original_git_dir); separate_git_dir(git_dir, original_git_dir);
} }
else { else {
set_git_dir(real_path(git_dir)); set_git_dir(git_dir, 1);
git_dir = get_git_dir(); git_dir = get_git_dir();
} }
startup_info->have_repository = 1; startup_info->have_repository = 1;

Просмотреть файл

@ -808,9 +808,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue; continue;
} }
if (!strcmp(arg, "--show-superproject-working-tree")) { if (!strcmp(arg, "--show-superproject-working-tree")) {
const char *superproject = get_superproject_working_tree(); struct strbuf superproject = STRBUF_INIT;
if (superproject) if (get_superproject_working_tree(&superproject))
puts(superproject); puts(superproject.buf);
strbuf_release(&superproject);
continue; continue;
} }
if (!strcmp(arg, "--show-prefix")) { if (!strcmp(arg, "--show-prefix")) {
@ -857,7 +858,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!gitdir && !prefix) if (!gitdir && !prefix)
gitdir = ".git"; gitdir = ".git";
if (gitdir) { if (gitdir) {
puts(real_path(gitdir)); struct strbuf realpath = STRBUF_INIT;
strbuf_realpath(&realpath, gitdir, 1);
puts(realpath.buf);
strbuf_release(&realpath);
continue; continue;
} }
} }

Просмотреть файл

@ -258,7 +258,7 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts) const struct add_opts *opts)
{ {
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; 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; const char *name;
struct child_process cp = CHILD_PROCESS_INIT; struct child_process cp = CHILD_PROCESS_INIT;
struct argv_array child_env = ARGV_ARRAY_INIT; struct argv_array child_env = ARGV_ARRAY_INIT;
@ -330,9 +330,11 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb); strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); 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", 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 * This is to keep resolve_ref() happy. We need a valid HEAD
* or is_git_directory() will reject the directory. Any value which * or is_git_directory() will reject the directory. Any value which
@ -418,6 +420,7 @@ done:
strbuf_release(&sb_repo); strbuf_release(&sb_repo);
strbuf_release(&sb_git); strbuf_release(&sb_git);
strbuf_release(&sb_name); strbuf_release(&sb_name);
strbuf_release(&realpath);
return ret; return ret;
} }

Просмотреть файл

@ -543,7 +543,7 @@ const char *get_git_common_dir(void);
char *get_object_directory(void); char *get_object_directory(void);
char *get_index_file(void); char *get_index_file(void);
char *get_graft_file(struct repository *r); 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_noenv(struct strbuf *sb, const char *gitdir);
int get_common_dir(struct strbuf *sb, const char *gitdir); int get_common_dir(struct strbuf *sb, const char *gitdir);
const char *get_git_namespace(void); const char *get_git_namespace(void);
@ -1314,8 +1314,6 @@ static inline int is_absolute_path(const char *path)
int is_directory(const char *); int is_directory(const char *);
char *strbuf_realpath(struct strbuf *resolved, const char *path, char *strbuf_realpath(struct strbuf *resolved, const char *path,
int die_on_error); 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); char *real_pathdup(const char *path, int die_on_error);
const char *absolute_path(const char *path); const char *absolute_path(const char *path);
char *absolute_pathdup(const char *path); char *absolute_pathdup(const char *path);

Просмотреть файл

@ -54,7 +54,8 @@ static int launch_specified_editor(const char *editor, const char *path,
return error("Terminal is dumb, but EDITOR unset"); return error("Terminal is dumb, but EDITOR unset");
if (strcmp(editor, ":")) { 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; struct child_process p = CHILD_PROCESS_INIT;
int ret, sig; int ret, sig;
int print_waiting_for_editor = advice_waiting_for_editor && isatty(2); int print_waiting_for_editor = advice_waiting_for_editor && isatty(2);
@ -75,16 +76,22 @@ static int launch_specified_editor(const char *editor, const char *path,
fflush(stderr); fflush(stderr);
} }
strbuf_realpath(&realpath, path, 1);
args[1] = realpath.buf;
p.argv = args; p.argv = args;
p.env = env; p.env = env;
p.use_shell = 1; p.use_shell = 1;
p.trace2_child_class = "editor"; 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); return error("unable to start editor '%s'", editor);
}
sigchain_push(SIGINT, SIG_IGN); sigchain_push(SIGINT, SIG_IGN);
sigchain_push(SIGQUIT, SIG_IGN); sigchain_push(SIGQUIT, SIG_IGN);
ret = finish_command(&p); ret = finish_command(&p);
strbuf_release(&realpath);
sig = ret - 128; sig = ret - 128;
sigchain_pop(SIGINT); sigchain_pop(SIGINT);
sigchain_pop(SIGQUIT); sigchain_pop(SIGQUIT);

Просмотреть файл

@ -254,8 +254,11 @@ static int git_work_tree_initialized;
*/ */
void set_git_work_tree(const char *new_work_tree) void set_git_work_tree(const char *new_work_tree)
{ {
struct strbuf realpath = STRBUF_INIT;
if (git_work_tree_initialized) { 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)) if (strcmp(new_work_tree, the_repository->worktree))
die("internal error: work tree has already been set\n" die("internal error: work tree has already been set\n"
"Current worktree: %s\nNew worktree: %s", "Current worktree: %s\nNew worktree: %s",
@ -264,6 +267,8 @@ void set_git_work_tree(const char *new_work_tree)
} }
git_work_tree_initialized = 1; git_work_tree_initialized = 1;
repo_set_worktree(the_repository, new_work_tree); repo_set_worktree(the_repository, new_work_tree);
strbuf_release(&realpath);
} }
const char *get_git_work_tree(void) const char *get_git_work_tree(void)
@ -345,11 +350,20 @@ static void update_relative_gitdir(const char *name,
free(path); 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); set_git_dir_1(path);
if (!is_absolute_path(path)) if (!is_absolute_path(path))
chdir_notify_register(NULL, update_relative_gitdir, NULL); chdir_notify_register(NULL, update_relative_gitdir, NULL);
strbuf_release(&realpath);
} }
const char *get_log_output_encoding(void) const char *get_log_output_encoding(void)

4
path.c
Просмотреть файл

@ -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 * then it is a newly allocated string. Returns NULL on getpw failure or
* if path is NULL. * 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) char *expand_user_path(const char *path, int real_home)
{ {
@ -850,7 +850,7 @@ const char *enter_repo(const char *path, int strict)
} }
if (is_git_directory(".")) { if (is_git_directory(".")) {
set_git_dir("."); set_git_dir(".", 0);
check_repository_format(); check_repository_format();
return path; return path;
} }

35
setup.c
Просмотреть файл

@ -32,6 +32,7 @@ static int abspath_part_inside_repo(char *path)
char *path0; char *path0;
int off; int off;
const char *work_tree = get_git_work_tree(); const char *work_tree = get_git_work_tree();
struct strbuf realpath = STRBUF_INIT;
if (!work_tree) if (!work_tree)
return -1; return -1;
@ -60,8 +61,10 @@ static int abspath_part_inside_repo(char *path)
path++; path++;
if (*path == '/') { if (*path == '/') {
*path = '\0'; *path = '\0';
if (fspathcmp(real_path(path0), work_tree) == 0) { strbuf_realpath(&realpath, path0, 1);
if (fspathcmp(realpath.buf, work_tree) == 0) {
memmove(path0, path + 1, len - (path - path0)); memmove(path0, path + 1, len - (path - path0));
strbuf_release(&realpath);
return 0; return 0;
} }
*path = '/'; *path = '/';
@ -69,11 +72,14 @@ static int abspath_part_inside_repo(char *path)
} }
/* check whole path */ /* check whole path */
if (fspathcmp(real_path(path0), work_tree) == 0) { strbuf_realpath(&realpath, path0, 1);
if (fspathcmp(realpath.buf, work_tree) == 0) {
*path0 = '\0'; *path0 = '\0';
strbuf_release(&realpath);
return 0; return 0;
} }
strbuf_release(&realpath);
return -1; return -1;
} }
@ -623,6 +629,7 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
struct stat st; struct stat st;
int fd; int fd;
ssize_t len; ssize_t len;
static struct strbuf realpath = STRBUF_INIT;
if (stat(path, &st)) { if (stat(path, &st)) {
/* NEEDSWORK: discern between ENOENT vs other errors */ /* NEEDSWORK: discern between ENOENT vs other errors */
@ -673,7 +680,9 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
error_code = READ_GITFILE_ERR_NOT_A_REPO; error_code = READ_GITFILE_ERR_NOT_A_REPO;
goto cleanup_return; goto cleanup_return;
} }
path = real_path(dir);
strbuf_realpath(&realpath, dir, 1);
path = realpath.buf;
cleanup_return: cleanup_return:
if (return_error_code) if (return_error_code)
@ -729,7 +738,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
} }
/* #18, #26 */ /* #18, #26 */
set_git_dir(gitdirenv); set_git_dir(gitdirenv, 0);
free(gitfile); free(gitfile);
return NULL; return NULL;
} }
@ -751,7 +760,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
} }
else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) { else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
/* #16d */ /* #16d */
set_git_dir(gitdirenv); set_git_dir(gitdirenv, 0);
free(gitfile); free(gitfile);
return NULL; return NULL;
} }
@ -763,14 +772,14 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
/* both get_git_work_tree() and cwd are already normalized */ /* both get_git_work_tree() and cwd are already normalized */
if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */ if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
set_git_dir(gitdirenv); set_git_dir(gitdirenv, 0);
free(gitfile); free(gitfile);
return NULL; return NULL;
} }
offset = dir_inside_of(cwd->buf, worktree); offset = dir_inside_of(cwd->buf, worktree);
if (offset >= 0) { /* cwd inside worktree? */ if (offset >= 0) { /* cwd inside worktree? */
set_git_dir(real_path(gitdirenv)); set_git_dir(gitdirenv, 1);
if (chdir(worktree)) if (chdir(worktree))
die_errno(_("cannot chdir to '%s'"), worktree); die_errno(_("cannot chdir to '%s'"), worktree);
strbuf_addch(cwd, '/'); strbuf_addch(cwd, '/');
@ -779,7 +788,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
} }
/* cwd outside worktree */ /* cwd outside worktree */
set_git_dir(gitdirenv); set_git_dir(gitdirenv, 0);
free(gitfile); free(gitfile);
return NULL; return NULL;
} }
@ -808,7 +817,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
if (is_bare_repository_cfg > 0) { if (is_bare_repository_cfg > 0) {
set_git_dir(offset == cwd->len ? gitdir : real_path(gitdir)); set_git_dir(gitdir, (offset != cwd->len));
if (chdir(cwd->buf)) if (chdir(cwd->buf))
die_errno(_("cannot come back to cwd")); die_errno(_("cannot come back to cwd"));
return NULL; return NULL;
@ -817,7 +826,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
/* #0, #1, #5, #8, #9, #12, #13 */ /* #0, #1, #5, #8, #9, #12, #13 */
set_git_work_tree("."); set_git_work_tree(".");
if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT)) if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
set_git_dir(gitdir); set_git_dir(gitdir, 0);
inside_git_dir = 0; inside_git_dir = 0;
inside_work_tree = 1; inside_work_tree = 1;
if (offset >= cwd->len) if (offset >= cwd->len)
@ -860,10 +869,10 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
die_errno(_("cannot come back to cwd")); die_errno(_("cannot come back to cwd"));
root_len = offset_1st_component(cwd->buf); root_len = offset_1st_component(cwd->buf);
strbuf_setlen(cwd, offset > root_len ? offset : root_len); strbuf_setlen(cwd, offset > root_len ? offset : root_len);
set_git_dir(cwd->buf); set_git_dir(cwd->buf, 0);
} }
else else
set_git_dir("."); set_git_dir(".", 0);
return NULL; return NULL;
} }
@ -881,7 +890,7 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
/* /*
* A "string_list_each_func_t" function that canonicalizes an entry * A "string_list_each_func_t" function that canonicalizes an entry
* from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or * from GIT_CEILING_DIRECTORIES using real_pathdup(), or
* discards it if unusable. The presence of an empty entry in * discards it if unusable. The presence of an empty entry in
* GIT_CEILING_DIRECTORIES turns off canonicalization for all * GIT_CEILING_DIRECTORIES turns off canonicalization for all
* subsequent entries. * subsequent entries.

Просмотреть файл

@ -676,20 +676,15 @@ void add_to_alternates_memory(const char *reference)
char *compute_alternate_path(const char *path, struct strbuf *err) char *compute_alternate_path(const char *path, struct strbuf *err)
{ {
char *ref_git = NULL; char *ref_git = NULL;
const char *repo, *ref_git_s; const char *repo;
int seen_error = 0; int seen_error = 0;
ref_git_s = real_path_if_valid(path); ref_git = real_pathdup(path, 0);
if (!ref_git_s) { if (!ref_git) {
seen_error = 1; seen_error = 1;
strbuf_addf(err, _("path '%s' does not exist"), path); strbuf_addf(err, _("path '%s' does not exist"), path);
goto out; goto out;
} else }
/*
* Beware: read_gitfile(), real_path() and mkpath()
* return static buffer
*/
ref_git = xstrdup(ref_git_s);
repo = read_gitfile(ref_git); repo = read_gitfile(ref_git);
if (!repo) if (!repo)

Просмотреть файл

@ -2168,13 +2168,13 @@ void absorb_git_dir_into_superproject(const char *path,
} }
} }
const char *get_superproject_working_tree(void) int get_superproject_working_tree(struct strbuf *buf)
{ {
struct child_process cp = CHILD_PROCESS_INIT; struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
const char *one_up = real_path_if_valid("../"); struct strbuf one_up = STRBUF_INIT;
const char *cwd = xgetcwd(); const char *cwd = xgetcwd();
const char *ret = NULL; int ret = 0;
const char *subpath; const char *subpath;
int code; int code;
ssize_t len; ssize_t len;
@ -2185,12 +2185,13 @@ const char *get_superproject_working_tree(void)
* We might have a superproject, but it is harder * We might have a superproject, but it is harder
* to determine. * to determine.
*/ */
return NULL; return 0;
if (!one_up) if (!strbuf_realpath(&one_up, "../", 0))
return NULL; return 0;
subpath = relative_path(cwd, one_up, &sb); subpath = relative_path(cwd, one_up.buf, &sb);
strbuf_release(&one_up);
prepare_submodule_repo_env(&cp.env_array); prepare_submodule_repo_env(&cp.env_array);
argv_array_pop(&cp.env_array); argv_array_pop(&cp.env_array);
@ -2231,7 +2232,8 @@ const char *get_superproject_working_tree(void)
super_wt = xstrdup(cwd); super_wt = xstrdup(cwd);
super_wt[cwd_len - super_sub_len] = '\0'; super_wt[cwd_len - super_sub_len] = '\0';
ret = real_path(super_wt); strbuf_realpath(buf, super_wt, 1);
ret = 1;
free(super_wt); free(super_wt);
} }
strbuf_release(&sb); strbuf_release(&sb);
@ -2240,10 +2242,10 @@ const char *get_superproject_working_tree(void)
if (code == 128) if (code == 128)
/* '../' is not a git repository */ /* '../' is not a git repository */
return NULL; return 0;
if (code == 0 && len == 0) if (code == 0 && len == 0)
/* There is an unrelated git repository at '../' */ /* There is an unrelated git repository at '../' */
return NULL; return 0;
if (code) if (code)
die(_("ls-tree returned unexpected return code %d"), code); die(_("ls-tree returned unexpected return code %d"), code);

Просмотреть файл

@ -152,8 +152,8 @@ void absorb_git_dir_into_superproject(const char *path,
/* /*
* Return the absolute path of the working tree of the superproject, which this * Return the absolute path of the working tree of the superproject, which this
* project is a submodule of. If this repository is not a submodule of * project is a submodule of. If this repository is not a submodule of
* another repository, return NULL. * another repository, return 0.
*/ */
const char *get_superproject_working_tree(void); int get_superproject_working_tree(struct strbuf *buf);
#endif #endif

Просмотреть файл

@ -290,11 +290,14 @@ int cmd__path_utils(int argc, const char **argv)
} }
if (argc >= 2 && !strcmp(argv[1], "real_path")) { if (argc >= 2 && !strcmp(argv[1], "real_path")) {
struct strbuf realpath = STRBUF_INIT;
while (argc > 2) { while (argc > 2) {
puts(real_path(argv[2])); strbuf_realpath(&realpath, argv[2], 1);
puts(realpath.buf);
argc--; argc--;
argv++; argv++;
} }
strbuf_release(&realpath);
return 0; return 0;
} }

Просмотреть файл

@ -226,17 +226,20 @@ struct worktree *find_worktree(struct worktree **list,
struct worktree *find_worktree_by_path(struct worktree **list, const char *p) struct worktree *find_worktree_by_path(struct worktree **list, const char *p)
{ {
struct strbuf wt_path = STRBUF_INIT;
char *path = real_pathdup(p, 0); char *path = real_pathdup(p, 0);
if (!path) if (!path)
return NULL; return NULL;
for (; *list; list++) { for (; *list; list++) {
const char *wt_path = real_path_if_valid((*list)->path); if (!strbuf_realpath(&wt_path, (*list)->path, 0))
continue;
if (wt_path && !fspathcmp(path, wt_path)) if (!fspathcmp(path, wt_path.buf))
break; break;
} }
free(path); free(path);
strbuf_release(&wt_path);
return *list; return *list;
} }
@ -285,6 +288,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
unsigned flags) unsigned flags)
{ {
struct strbuf wt_path = STRBUF_INIT; struct strbuf wt_path = STRBUF_INIT;
struct strbuf realpath = STRBUF_INIT;
char *path = NULL; char *path = NULL;
int err, ret = -1; int err, ret = -1;
@ -336,7 +340,8 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
goto done; goto done;
} }
ret = fspathcmp(path, real_path(git_common_path("worktrees/%s", wt->id))); strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
ret = fspathcmp(path, realpath.buf);
if (ret) if (ret)
strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"), strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
@ -344,6 +349,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
done: done:
free(path); free(path);
strbuf_release(&wt_path); strbuf_release(&wt_path);
strbuf_release(&realpath);
return ret; return ret;
} }