Merge branch 'dr/ceiling'
* dr/ceiling: Eliminate an unnecessary chdir("..") Add support for GIT_CEILING_DIRECTORIES Fold test-absolute-path into test-path-utils Implement normalize_absolute_path Conflicts: cache.h setup.c
This commit is contained in:
96
path.c
96
path.c
@ -343,3 +343,99 @@ const char *make_relative_path(const char *abs, const char *base)
|
||||
strcpy(buf, abs + baselen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* path = absolute path
|
||||
* buf = buffer of at least max(2, strlen(path)+1) bytes
|
||||
* It is okay if buf == path, but they should not overlap otherwise.
|
||||
*
|
||||
* Performs the following normalizations on path, storing the result in buf:
|
||||
* - Removes trailing slashes.
|
||||
* - Removes empty components.
|
||||
* - Removes "." components.
|
||||
* - Removes ".." components, and the components the precede them.
|
||||
* "" and paths that contain only slashes are normalized to "/".
|
||||
* Returns the length of the output.
|
||||
*
|
||||
* Note that this function is purely textual. It does not follow symlinks,
|
||||
* verify the existence of the path, or make any system calls.
|
||||
*/
|
||||
int normalize_absolute_path(char *buf, const char *path)
|
||||
{
|
||||
const char *comp_start = path, *comp_end = path;
|
||||
char *dst = buf;
|
||||
int comp_len;
|
||||
assert(buf);
|
||||
assert(path);
|
||||
|
||||
while (*comp_start) {
|
||||
assert(*comp_start == '/');
|
||||
while (*++comp_end && *comp_end != '/')
|
||||
; /* nothing */
|
||||
comp_len = comp_end - comp_start;
|
||||
|
||||
if (!strncmp("/", comp_start, comp_len) ||
|
||||
!strncmp("/.", comp_start, comp_len))
|
||||
goto next;
|
||||
|
||||
if (!strncmp("/..", comp_start, comp_len)) {
|
||||
while (dst > buf && *--dst != '/')
|
||||
; /* nothing */
|
||||
goto next;
|
||||
}
|
||||
|
||||
memcpy(dst, comp_start, comp_len);
|
||||
dst += comp_len;
|
||||
next:
|
||||
comp_start = comp_end;
|
||||
}
|
||||
|
||||
if (dst == buf)
|
||||
*dst++ = '/';
|
||||
|
||||
*dst = '\0';
|
||||
return dst - buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* path = Canonical absolute path
|
||||
* prefix_list = Colon-separated list of absolute paths
|
||||
*
|
||||
* Determines, for each path in parent_list, whether the "prefix" really
|
||||
* is an ancestor directory of path. Returns the length of the longest
|
||||
* ancestor directory, excluding any trailing slashes, or -1 if no prefix
|
||||
* is an ancestor. (Note that this means 0 is returned if prefix_list is
|
||||
* "/".) "/foo" is not considered an ancestor of "/foobar". Directories
|
||||
* are not considered to be their own ancestors. path must be in a
|
||||
* canonical form: empty components, or "." or ".." components are not
|
||||
* allowed. prefix_list may be null, which is like "".
|
||||
*/
|
||||
int longest_ancestor_length(const char *path, const char *prefix_list)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
const char *ceil, *colon;
|
||||
int len, max_len = -1;
|
||||
|
||||
if (prefix_list == NULL || !strcmp(path, "/"))
|
||||
return -1;
|
||||
|
||||
for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
|
||||
for (colon = ceil; *colon && *colon != ':'; colon++);
|
||||
len = colon - ceil;
|
||||
if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
|
||||
continue;
|
||||
strlcpy(buf, ceil, len+1);
|
||||
len = normalize_absolute_path(buf, buf);
|
||||
/* Strip "trailing slashes" from "/". */
|
||||
if (len == 1)
|
||||
len = 0;
|
||||
|
||||
if (!strncmp(path, buf, len) &&
|
||||
path[len] == '/' &&
|
||||
len > max_len) {
|
||||
max_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
return max_len;
|
||||
}
|
||||
|
Reference in New Issue
Block a user