Skip to content

Commit f470e90

Browse files
committedJan 2, 2013
Merge branch 'mh/ceiling'
An element on GIT_CEILING_DIRECTORIES list that does not name the real path to a directory (i.e. a symbolic link) could have caused the GIT_DIR discovery logic to escape the ceiling. * mh/ceiling: string_list_longest_prefix(): remove function setup_git_directory_gently_1(): resolve symlinks in ceiling paths longest_ancestor_length(): require prefix list entries to be normalized longest_ancestor_length(): take a string_list argument for prefixes longest_ancestor_length(): use string_list_split() Introduce new function real_path_if_valid() real_path_internal(): add comment explaining use of cwd Introduce new static function real_path_internal()
2 parents 5d41784 + 059b379 commit f470e90

11 files changed

+202
-165
lines changed
 

‎Documentation/technical/api-string-list.txt

-8
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,6 @@ Functions
8282
call free() on the util members of any items that have to be
8383
deleted. Preserve the order of the items that are retained.
8484

85-
`string_list_longest_prefix`::
86-
87-
Return the longest string within a string_list that is a
88-
prefix (in the sense of prefixcmp()) of the specified string,
89-
or NULL if no such prefix exists. This function does not
90-
require the string_list to be sorted (it does a linear
91-
search).
92-
9385
`print_string_list`::
9486

9587
Dump a string_list to stdout, useful mainly for debugging purposes. It

‎abspath.c

+84-21
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,34 @@ int is_directory(const char *path)
1515
#define MAXDEPTH 5
1616

1717
/*
18-
* Use this to get the real path, i.e. resolve links. If you want an
19-
* absolute path but don't mind links, use absolute_path.
18+
* Return the real path (i.e., absolute path, with symlinks resolved
19+
* and extra slashes removed) equivalent to the specified path. (If
20+
* you want an absolute path but don't mind links, use
21+
* absolute_path().) The return value is a pointer to a static
22+
* buffer.
23+
*
24+
* The input and all intermediate paths must be shorter than MAX_PATH.
25+
* The directory part of path (i.e., everything up to the last
26+
* dir_sep) must denote a valid, existing directory, but the last
27+
* component need not exist. If die_on_error is set, then die with an
28+
* informative error message if there is a problem. Otherwise, return
29+
* NULL on errors (without generating any output).
2030
*
2131
* If path is our buffer, then return path, as it's already what the
2232
* user wants.
2333
*/
24-
const char *real_path(const char *path)
34+
static const char *real_path_internal(const char *path, int die_on_error)
2535
{
2636
static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
37+
char *retval = NULL;
38+
39+
/*
40+
* If we have to temporarily chdir(), store the original CWD
41+
* here so that we can chdir() back to it at the end of the
42+
* function:
43+
*/
2744
char cwd[1024] = "";
45+
2846
int buf_index = 1;
2947

3048
int depth = MAXDEPTH;
@@ -35,11 +53,19 @@ const char *real_path(const char *path)
3553
if (path == buf || path == next_buf)
3654
return path;
3755

38-
if (!*path)
39-
die("The empty string is not a valid path");
56+
if (!*path) {
57+
if (die_on_error)
58+
die("The empty string is not a valid path");
59+
else
60+
goto error_out;
61+
}
4062

41-
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
42-
die ("Too long path: %.*s", 60, path);
63+
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
64+
if (die_on_error)
65+
die("Too long path: %.*s", 60, path);
66+
else
67+
goto error_out;
68+
}
4369

4470
while (depth--) {
4571
if (!is_directory(buf)) {
@@ -54,20 +80,36 @@ const char *real_path(const char *path)
5480
}
5581

5682
if (*buf) {
57-
if (!*cwd && !getcwd(cwd, sizeof(cwd)))
58-
die_errno ("Could not get current working directory");
83+
if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
84+
if (die_on_error)
85+
die_errno("Could not get current working directory");
86+
else
87+
goto error_out;
88+
}
5989

60-
if (chdir(buf))
61-
die_errno ("Could not switch to '%s'", buf);
90+
if (chdir(buf)) {
91+
if (die_on_error)
92+
die_errno("Could not switch to '%s'", buf);
93+
else
94+
goto error_out;
95+
}
96+
}
97+
if (!getcwd(buf, PATH_MAX)) {
98+
if (die_on_error)
99+
die_errno("Could not get current working directory");
100+
else
101+
goto error_out;
62102
}
63-
if (!getcwd(buf, PATH_MAX))
64-
die_errno ("Could not get current working directory");
65103

66104
if (last_elem) {
67105
size_t len = strlen(buf);
68-
if (len + strlen(last_elem) + 2 > PATH_MAX)
69-
die ("Too long path name: '%s/%s'",
70-
buf, last_elem);
106+
if (len + strlen(last_elem) + 2 > PATH_MAX) {
107+
if (die_on_error)
108+
die("Too long path name: '%s/%s'",
109+
buf, last_elem);
110+
else
111+
goto error_out;
112+
}
71113
if (len && !is_dir_sep(buf[len-1]))
72114
buf[len++] = '/';
73115
strcpy(buf + len, last_elem);
@@ -77,10 +119,18 @@ const char *real_path(const char *path)
77119

78120
if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
79121
ssize_t len = readlink(buf, next_buf, PATH_MAX);
80-
if (len < 0)
81-
die_errno ("Invalid symlink '%s'", buf);
82-
if (PATH_MAX <= len)
83-
die("symbolic link too long: %s", buf);
122+
if (len < 0) {
123+
if (die_on_error)
124+
die_errno("Invalid symlink '%s'", buf);
125+
else
126+
goto error_out;
127+
}
128+
if (PATH_MAX <= len) {
129+
if (die_on_error)
130+
die("symbolic link too long: %s", buf);
131+
else
132+
goto error_out;
133+
}
84134
next_buf[len] = '\0';
85135
buf = next_buf;
86136
buf_index = 1 - buf_index;
@@ -89,10 +139,23 @@ const char *real_path(const char *path)
89139
break;
90140
}
91141

142+
retval = buf;
143+
error_out:
144+
free(last_elem);
92145
if (*cwd && chdir(cwd))
93146
die_errno ("Could not change back to '%s'", cwd);
94147

95-
return buf;
148+
return retval;
149+
}
150+
151+
const char *real_path(const char *path)
152+
{
153+
return real_path_internal(path, 1);
154+
}
155+
156+
const char *real_path_if_valid(const char *path)
157+
{
158+
return real_path_internal(path, 0);
96159
}
97160

98161
static const char *get_pwd_cwd(void)

‎cache.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,11 @@ static inline int is_absolute_path(const char *path)
714714
}
715715
int is_directory(const char *);
716716
const char *real_path(const char *path);
717+
const char *real_path_if_valid(const char *path);
717718
const char *absolute_path(const char *path);
718719
const char *relative_path(const char *abs, const char *base);
719720
int normalize_path_copy(char *dst, const char *src);
720-
int longest_ancestor_length(const char *path, const char *prefix_list);
721+
int longest_ancestor_length(const char *path, struct string_list *prefixes);
721722
char *strip_path_suffix(const char *path, const char *suffix);
722723
int daemon_avoid_alias(const char *path);
723724
int offset_1st_component(const char *path);

‎path.c

+21-25
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
#include "cache.h"
1414
#include "strbuf.h"
15+
#include "string-list.h"
1516

1617
static char bad_path[] = "/bad-path/";
1718

@@ -569,43 +570,38 @@ int normalize_path_copy(char *dst, const char *src)
569570

570571
/*
571572
* path = Canonical absolute path
572-
* prefix_list = Colon-separated list of absolute paths
573+
* prefixes = string_list containing normalized, absolute paths without
574+
* trailing slashes (except for the root directory, which is denoted by "/").
573575
*
574-
* Determines, for each path in prefix_list, whether the "prefix" really
576+
* Determines, for each path in prefixes, whether the "prefix"
575577
* is an ancestor directory of path. Returns the length of the longest
576578
* ancestor directory, excluding any trailing slashes, or -1 if no prefix
577-
* is an ancestor. (Note that this means 0 is returned if prefix_list is
578-
* "/".) "/foo" is not considered an ancestor of "/foobar". Directories
579+
* is an ancestor. (Note that this means 0 is returned if prefixes is
580+
* ["/"].) "/foo" is not considered an ancestor of "/foobar". Directories
579581
* are not considered to be their own ancestors. path must be in a
580582
* canonical form: empty components, or "." or ".." components are not
581-
* allowed. prefix_list may be null, which is like "".
583+
* allowed.
582584
*/
583-
int longest_ancestor_length(const char *path, const char *prefix_list)
585+
int longest_ancestor_length(const char *path, struct string_list *prefixes)
584586
{
585-
char buf[PATH_MAX+1];
586-
const char *ceil, *colon;
587-
int len, max_len = -1;
587+
int i, max_len = -1;
588588

589-
if (prefix_list == NULL || !strcmp(path, "/"))
589+
if (!strcmp(path, "/"))
590590
return -1;
591591

592-
for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
593-
for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
594-
len = colon - ceil;
595-
if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
596-
continue;
597-
strlcpy(buf, ceil, len+1);
598-
if (normalize_path_copy(buf, buf) < 0)
599-
continue;
600-
len = strlen(buf);
601-
if (len > 0 && buf[len-1] == '/')
602-
buf[--len] = '\0';
592+
for (i = 0; i < prefixes->nr; i++) {
593+
const char *ceil = prefixes->items[i].string;
594+
int len = strlen(ceil);
603595

604-
if (!strncmp(path, buf, len) &&
605-
path[len] == '/' &&
606-
len > max_len) {
596+
if (len == 1 && ceil[0] == '/')
597+
len = 0; /* root matches anything, with length 0 */
598+
else if (!strncmp(path, ceil, len) && path[len] == '/')
599+
; /* match of length len */
600+
else
601+
continue; /* no match */
602+
603+
if (len > max_len)
607604
max_len = len;
608-
}
609605
}
610606

611607
return max_len;

‎setup.c

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "cache.h"
22
#include "dir.h"
3+
#include "string-list.h"
34

45
static int inside_git_dir = -1;
56
static int inside_work_tree = -1;
@@ -620,17 +621,39 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
620621
return buf.st_dev;
621622
}
622623

624+
/*
625+
* A "string_list_each_func_t" function that canonicalizes an entry
626+
* from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
627+
* discards it if unusable.
628+
*/
629+
static int canonicalize_ceiling_entry(struct string_list_item *item,
630+
void *unused)
631+
{
632+
char *ceil = item->string;
633+
const char *real_path;
634+
635+
if (!*ceil || !is_absolute_path(ceil))
636+
return 0;
637+
real_path = real_path_if_valid(ceil);
638+
if (!real_path)
639+
return 0;
640+
free(item->string);
641+
item->string = xstrdup(real_path);
642+
return 1;
643+
}
644+
623645
/*
624646
* We cannot decide in this function whether we are in the work tree or
625647
* not, since the config can only be read _after_ this function was called.
626648
*/
627649
static const char *setup_git_directory_gently_1(int *nongit_ok)
628650
{
629651
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
652+
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
630653
static char cwd[PATH_MAX+1];
631654
const char *gitdirenv, *ret;
632655
char *gitfile;
633-
int len, offset, offset_parent, ceil_offset;
656+
int len, offset, offset_parent, ceil_offset = -1;
634657
dev_t current_device = 0;
635658
int one_filesystem = 1;
636659

@@ -655,7 +678,14 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
655678
if (gitdirenv)
656679
return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
657680

658-
ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
681+
if (env_ceiling_dirs) {
682+
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
683+
filter_string_list(&ceiling_dirs, 0,
684+
canonicalize_ceiling_entry, NULL);
685+
ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
686+
string_list_clear(&ceiling_dirs, 0);
687+
}
688+
659689
if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
660690
ceil_offset = 1;
661691

‎string-list.c

-20
Original file line numberDiff line numberDiff line change
@@ -145,26 +145,6 @@ void string_list_remove_empty_items(struct string_list *list, int free_util) {
145145
filter_string_list(list, free_util, item_is_not_empty, NULL);
146146
}
147147

148-
char *string_list_longest_prefix(const struct string_list *prefixes,
149-
const char *string)
150-
{
151-
int i, max_len = -1;
152-
char *retval = NULL;
153-
154-
for (i = 0; i < prefixes->nr; i++) {
155-
char *prefix = prefixes->items[i].string;
156-
if (!prefixcmp(string, prefix)) {
157-
int len = strlen(prefix);
158-
if (len > max_len) {
159-
retval = prefix;
160-
max_len = len;
161-
}
162-
}
163-
}
164-
165-
return retval;
166-
}
167-
168148
void string_list_clear(struct string_list *list, int free_util)
169149
{
170150
if (list->items) {

‎string-list.h

-9
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,6 @@ void filter_string_list(struct string_list *list, int free_util,
4545
*/
4646
void string_list_remove_empty_items(struct string_list *list, int free_util);
4747

48-
/*
49-
* Return the longest string in prefixes that is a prefix (in the
50-
* sense of prefixcmp()) of string, or NULL if no such prefix exists.
51-
* This function does not require the string_list to be sorted (it
52-
* does a linear search).
53-
*/
54-
char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
55-
56-
5748
/* Use these functions only on sorted lists: */
5849
int string_list_has_string(const struct string_list *list, const char *string);
5950
int string_list_find_insert_index(const struct string_list *list, const char *string,

0 commit comments

Comments
 (0)