setup_git_directory_gently_1(): resolve symlinks in ceiling paths

longest_ancestor_length() relies on a textual comparison of directory
parts to find the part of path that overlaps with one of the paths in
prefix_list.  But this doesn't work if any of the prefixes involves a
symbolic link, because the directories will look different even though
they might logically refer to the same directory.  So canonicalize the
paths listed in GIT_CEILING_DIRECTORIES using real_path_if_valid()
before passing them to longest_ancestor_length().  (Also rename
normalize_ceiling_entry() to canonicalize_ceiling_entry() to reflect
the change.)

path is already in canonical form, so doesn't need to be canonicalized
again.

This fixes some problems with using GIT_CEILING_DIRECTORIES that
contains paths involving symlinks, including t4035 if run with --root
set to a path involving symlinks.

Please note that test t0060 is *not* changed analogously, because that
would make the test suite results dependent on the contents of the
local root directory.  However, real_path() is already tested
independently, and the "ancestor" tests cover the non-normalization
aspects of longest_ancestor_length(), so coverage remains sufficient.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Jeff King <peff@peff.net>
This commit is contained in:
Michael Haggerty 2012-10-28 17:16:26 +01:00 committed by Jeff King
parent 9e2326c7e1
commit 1b77d83cab

26
setup.c
View file

@ -622,24 +622,23 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
}
/*
* A "string_list_each_func_t" function that normalizes an entry from
* GIT_CEILING_DIRECTORIES or discards it if unusable.
* A "string_list_each_func_t" function that canonicalizes an entry
* from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
* discards it if unusable.
*/
static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
static int canonicalize_ceiling_entry(struct string_list_item *item,
void *unused)
{
const char *ceil = item->string;
int len = strlen(ceil);
char buf[PATH_MAX+1];
char *ceil = item->string;
const char *real_path;
if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
if (!*ceil || !is_absolute_path(ceil))
return 0;
if (normalize_path_copy(buf, ceil) < 0)
real_path = real_path_if_valid(ceil);
if (!real_path)
return 0;
len = strlen(buf);
if (len > 1 && buf[len-1] == '/')
buf[--len] = '\0';
free(item->string);
item->string = xstrdup(buf);
item->string = xstrdup(real_path);
return 1;
}
@ -681,7 +680,8 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
if (env_ceiling_dirs) {
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
filter_string_list(&ceiling_dirs, 0, normalize_ceiling_entry, NULL);
filter_string_list(&ceiling_dirs, 0,
canonicalize_ceiling_entry, NULL);
ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
string_list_clear(&ceiling_dirs, 0);
}