Merge branch 'js/maint-1.6.0-path-normalize'
* js/maint-1.6.0-path-normalize: Remove unused normalize_absolute_path() Test and fix normalize_path_copy() Fix GIT_CEILING_DIRECTORIES on Windows Move sanitary_path_copy() to path.c and rename it to normalize_path_copy() Make test-path-utils more robust against incorrect use
This commit is contained in:
commit
6e5d7ddc49
2
cache.h
2
cache.h
@ -627,7 +627,7 @@ int is_directory(const char *);
|
|||||||
const char *make_absolute_path(const char *path);
|
const char *make_absolute_path(const char *path);
|
||||||
const char *make_nonrelative_path(const char *path);
|
const char *make_nonrelative_path(const char *path);
|
||||||
const char *make_relative_path(const char *abs, const char *base);
|
const char *make_relative_path(const char *abs, const char *base);
|
||||||
int normalize_absolute_path(char *buf, const char *path);
|
int normalize_path_copy(char *dst, const char *src);
|
||||||
int longest_ancestor_length(const char *path, const char *prefix_list);
|
int longest_ancestor_length(const char *path, const char *prefix_list);
|
||||||
|
|
||||||
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
|
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
|
||||||
|
124
path.c
124
path.c
@ -363,56 +363,97 @@ const char *make_relative_path(const char *abs, const char *base)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* path = absolute path
|
* It is okay if dst == src, but they should not overlap otherwise.
|
||||||
* 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:
|
* Performs the following normalizations on src, storing the result in dst:
|
||||||
* - Removes trailing slashes.
|
* - Ensures that components are separated by '/' (Windows only)
|
||||||
* - Removes empty components.
|
* - Squashes sequences of '/'.
|
||||||
* - Removes "." components.
|
* - Removes "." components.
|
||||||
* - Removes ".." components, and the components the precede them.
|
* - Removes ".." components, and the components the precede them.
|
||||||
* "" and paths that contain only slashes are normalized to "/".
|
* Returns failure (non-zero) if a ".." component appears as first path
|
||||||
* Returns the length of the output.
|
* component anytime during the normalization. Otherwise, returns success (0).
|
||||||
*
|
*
|
||||||
* Note that this function is purely textual. It does not follow symlinks,
|
* Note that this function is purely textual. It does not follow symlinks,
|
||||||
* verify the existence of the path, or make any system calls.
|
* verify the existence of the path, or make any system calls.
|
||||||
*/
|
*/
|
||||||
int normalize_absolute_path(char *buf, const char *path)
|
int normalize_path_copy(char *dst, const char *src)
|
||||||
{
|
{
|
||||||
const char *comp_start = path, *comp_end = path;
|
char *dst0;
|
||||||
char *dst = buf;
|
|
||||||
int comp_len;
|
|
||||||
assert(buf);
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
while (*comp_start) {
|
if (has_dos_drive_prefix(src)) {
|
||||||
assert(*comp_start == '/');
|
*dst++ = *src++;
|
||||||
while (*++comp_end && *comp_end != '/')
|
*dst++ = *src++;
|
||||||
; /* nothing */
|
}
|
||||||
comp_len = comp_end - comp_start;
|
dst0 = dst;
|
||||||
|
|
||||||
if (!strncmp("/", comp_start, comp_len) ||
|
if (is_dir_sep(*src)) {
|
||||||
!strncmp("/.", comp_start, comp_len))
|
*dst++ = '/';
|
||||||
goto next;
|
while (is_dir_sep(*src))
|
||||||
|
src++;
|
||||||
if (!strncmp("/..", comp_start, comp_len)) {
|
|
||||||
while (dst > buf && *--dst != '/')
|
|
||||||
; /* nothing */
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
|
|
||||||
memmove(dst, comp_start, comp_len);
|
|
||||||
dst += comp_len;
|
|
||||||
next:
|
|
||||||
comp_start = comp_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst == buf)
|
for (;;) {
|
||||||
*dst++ = '/';
|
char c = *src;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A path component that begins with . could be
|
||||||
|
* special:
|
||||||
|
* (1) "." and ends -- ignore and terminate.
|
||||||
|
* (2) "./" -- ignore them, eat slash and continue.
|
||||||
|
* (3) ".." and ends -- strip one and terminate.
|
||||||
|
* (4) "../" -- strip one, eat slash and continue.
|
||||||
|
*/
|
||||||
|
if (c == '.') {
|
||||||
|
if (!src[1]) {
|
||||||
|
/* (1) */
|
||||||
|
src++;
|
||||||
|
} else if (is_dir_sep(src[1])) {
|
||||||
|
/* (2) */
|
||||||
|
src += 2;
|
||||||
|
while (is_dir_sep(*src))
|
||||||
|
src++;
|
||||||
|
continue;
|
||||||
|
} else if (src[1] == '.') {
|
||||||
|
if (!src[2]) {
|
||||||
|
/* (3) */
|
||||||
|
src += 2;
|
||||||
|
goto up_one;
|
||||||
|
} else if (is_dir_sep(src[2])) {
|
||||||
|
/* (4) */
|
||||||
|
src += 3;
|
||||||
|
while (is_dir_sep(*src))
|
||||||
|
src++;
|
||||||
|
goto up_one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy up to the next '/', and eat all '/' */
|
||||||
|
while ((c = *src++) != '\0' && !is_dir_sep(c))
|
||||||
|
*dst++ = c;
|
||||||
|
if (is_dir_sep(c)) {
|
||||||
|
*dst++ = '/';
|
||||||
|
while (is_dir_sep(c))
|
||||||
|
c = *src++;
|
||||||
|
src--;
|
||||||
|
} else if (!c)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
up_one:
|
||||||
|
/*
|
||||||
|
* dst0..dst is prefix portion, and dst[-1] is '/';
|
||||||
|
* go up one level.
|
||||||
|
*/
|
||||||
|
dst--; /* go to trailing '/' */
|
||||||
|
if (dst <= dst0)
|
||||||
|
return -1;
|
||||||
|
/* Windows: dst[-1] cannot be backslash anymore */
|
||||||
|
while (dst0 < dst && dst[-1] != '/')
|
||||||
|
dst--;
|
||||||
|
}
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
return dst - buf;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -438,15 +479,16 @@ int longest_ancestor_length(const char *path, const char *prefix_list)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
|
for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
|
||||||
for (colon = ceil; *colon && *colon != ':'; colon++);
|
for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
|
||||||
len = colon - ceil;
|
len = colon - ceil;
|
||||||
if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
|
if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
|
||||||
continue;
|
continue;
|
||||||
strlcpy(buf, ceil, len+1);
|
strlcpy(buf, ceil, len+1);
|
||||||
len = normalize_absolute_path(buf, buf);
|
if (normalize_path_copy(buf, buf) < 0)
|
||||||
/* Strip "trailing slashes" from "/". */
|
continue;
|
||||||
if (len == 1)
|
len = strlen(buf);
|
||||||
len = 0;
|
if (len > 0 && buf[len-1] == '/')
|
||||||
|
buf[--len] = '\0';
|
||||||
|
|
||||||
if (!strncmp(path, buf, len) &&
|
if (!strncmp(path, buf, len) &&
|
||||||
path[len] == '/' &&
|
path[len] == '/' &&
|
||||||
|
88
setup.c
88
setup.c
@ -4,92 +4,6 @@
|
|||||||
static int inside_git_dir = -1;
|
static int inside_git_dir = -1;
|
||||||
static int inside_work_tree = -1;
|
static int inside_work_tree = -1;
|
||||||
|
|
||||||
static int sanitary_path_copy(char *dst, const char *src)
|
|
||||||
{
|
|
||||||
char *dst0;
|
|
||||||
|
|
||||||
if (has_dos_drive_prefix(src)) {
|
|
||||||
*dst++ = *src++;
|
|
||||||
*dst++ = *src++;
|
|
||||||
}
|
|
||||||
dst0 = dst;
|
|
||||||
|
|
||||||
if (is_dir_sep(*src)) {
|
|
||||||
*dst++ = '/';
|
|
||||||
while (is_dir_sep(*src))
|
|
||||||
src++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
char c = *src;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A path component that begins with . could be
|
|
||||||
* special:
|
|
||||||
* (1) "." and ends -- ignore and terminate.
|
|
||||||
* (2) "./" -- ignore them, eat slash and continue.
|
|
||||||
* (3) ".." and ends -- strip one and terminate.
|
|
||||||
* (4) "../" -- strip one, eat slash and continue.
|
|
||||||
*/
|
|
||||||
if (c == '.') {
|
|
||||||
if (!src[1]) {
|
|
||||||
/* (1) */
|
|
||||||
src++;
|
|
||||||
} else if (is_dir_sep(src[1])) {
|
|
||||||
/* (2) */
|
|
||||||
src += 2;
|
|
||||||
while (is_dir_sep(*src))
|
|
||||||
src++;
|
|
||||||
continue;
|
|
||||||
} else if (src[1] == '.') {
|
|
||||||
if (!src[2]) {
|
|
||||||
/* (3) */
|
|
||||||
src += 2;
|
|
||||||
goto up_one;
|
|
||||||
} else if (is_dir_sep(src[2])) {
|
|
||||||
/* (4) */
|
|
||||||
src += 3;
|
|
||||||
while (is_dir_sep(*src))
|
|
||||||
src++;
|
|
||||||
goto up_one;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy up to the next '/', and eat all '/' */
|
|
||||||
while ((c = *src++) != '\0' && !is_dir_sep(c))
|
|
||||||
*dst++ = c;
|
|
||||||
if (is_dir_sep(c)) {
|
|
||||||
*dst++ = '/';
|
|
||||||
while (is_dir_sep(c))
|
|
||||||
c = *src++;
|
|
||||||
src--;
|
|
||||||
} else if (!c)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
up_one:
|
|
||||||
/*
|
|
||||||
* dst0..dst is prefix portion, and dst[-1] is '/';
|
|
||||||
* go up one level.
|
|
||||||
*/
|
|
||||||
dst -= 2; /* go past trailing '/' if any */
|
|
||||||
if (dst < dst0)
|
|
||||||
return -1;
|
|
||||||
while (1) {
|
|
||||||
if (dst <= dst0)
|
|
||||||
break;
|
|
||||||
c = *dst--;
|
|
||||||
if (c == '/') { /* MinGW: cannot be '\\' anymore */
|
|
||||||
dst += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dst = '\0';
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *prefix_path(const char *prefix, int len, const char *path)
|
const char *prefix_path(const char *prefix, int len, const char *path)
|
||||||
{
|
{
|
||||||
const char *orig = path;
|
const char *orig = path;
|
||||||
@ -101,7 +15,7 @@ const char *prefix_path(const char *prefix, int len, const char *path)
|
|||||||
memcpy(sanitized, prefix, len);
|
memcpy(sanitized, prefix, len);
|
||||||
strcpy(sanitized + len, path);
|
strcpy(sanitized + len, path);
|
||||||
}
|
}
|
||||||
if (sanitary_path_copy(sanitized, sanitized))
|
if (normalize_path_copy(sanitized, sanitized))
|
||||||
goto error_out;
|
goto error_out;
|
||||||
if (is_absolute_path(orig)) {
|
if (is_absolute_path(orig)) {
|
||||||
const char *work_tree = get_git_work_tree();
|
const char *work_tree = get_git_work_tree();
|
||||||
|
@ -8,36 +8,37 @@ test_description='Test various path utilities'
|
|||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
norm_abs() {
|
norm_abs() {
|
||||||
test_expect_success "normalize absolute" \
|
test_expect_success "normalize absolute: $1 => $2" \
|
||||||
"test \$(test-path-utils normalize_absolute_path '$1') = '$2'"
|
"test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'"
|
||||||
}
|
}
|
||||||
|
|
||||||
ancestor() {
|
ancestor() {
|
||||||
test_expect_success "longest ancestor" \
|
test_expect_success "longest ancestor: $1 $2 => $3" \
|
||||||
"test \$(test-path-utils longest_ancestor_length '$1' '$2') = '$3'"
|
"test \"\$(test-path-utils longest_ancestor_length '$1' '$2')\" = '$3'"
|
||||||
}
|
}
|
||||||
|
|
||||||
norm_abs "" /
|
norm_abs "" ""
|
||||||
norm_abs / /
|
norm_abs / /
|
||||||
norm_abs // /
|
norm_abs // /
|
||||||
norm_abs /// /
|
norm_abs /// /
|
||||||
norm_abs /. /
|
norm_abs /. /
|
||||||
norm_abs /./ /
|
norm_abs /./ /
|
||||||
norm_abs /./.. /
|
norm_abs /./.. ++failed++
|
||||||
norm_abs /../. /
|
norm_abs /../. ++failed++
|
||||||
norm_abs /./../.// /
|
norm_abs /./../.// ++failed++
|
||||||
norm_abs /dir/.. /
|
norm_abs /dir/.. /
|
||||||
norm_abs /dir/sub/../.. /
|
norm_abs /dir/sub/../.. /
|
||||||
|
norm_abs /dir/sub/../../.. ++failed++
|
||||||
norm_abs /dir /dir
|
norm_abs /dir /dir
|
||||||
norm_abs /dir// /dir
|
norm_abs /dir// /dir/
|
||||||
norm_abs /./dir /dir
|
norm_abs /./dir /dir
|
||||||
norm_abs /dir/. /dir
|
norm_abs /dir/. /dir/
|
||||||
norm_abs /dir///./ /dir
|
norm_abs /dir///./ /dir/
|
||||||
norm_abs /dir//sub/.. /dir
|
norm_abs /dir//sub/.. /dir/
|
||||||
norm_abs /dir/sub/../ /dir
|
norm_abs /dir/sub/../ /dir/
|
||||||
norm_abs //dir/sub/../. /dir
|
norm_abs //dir/sub/../. /dir/
|
||||||
norm_abs /dir/s1/../s2/ /dir/s2
|
norm_abs /dir/s1/../s2/ /dir/s2/
|
||||||
norm_abs /d1/s1///s2/..//../s3/ /d1/s3
|
norm_abs /d1/s1///s2/..//../s3/ /d1/s3/
|
||||||
norm_abs /d1/s1//../s2/../../d2 /d2
|
norm_abs /d1/s1//../s2/../../d2 /d2
|
||||||
norm_abs /d1/.../d2 /d1/.../d2
|
norm_abs /d1/.../d2 /d1/.../d2
|
||||||
norm_abs /d1/..././../d2 /d1/d2
|
norm_abs /d1/..././../d2 /d1/d2
|
||||||
|
@ -93,13 +93,13 @@ GIT_CEILING_DIRECTORIES="$TRASH_ROOT/subdi"
|
|||||||
test_prefix subdir_ceil_at_subdi_slash "sub/dir/"
|
test_prefix subdir_ceil_at_subdi_slash "sub/dir/"
|
||||||
|
|
||||||
|
|
||||||
GIT_CEILING_DIRECTORIES="foo:$TRASH_ROOT/sub"
|
GIT_CEILING_DIRECTORIES="/foo:$TRASH_ROOT/sub"
|
||||||
test_fail second_of_two
|
test_fail second_of_two
|
||||||
|
|
||||||
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub:bar"
|
GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub:/bar"
|
||||||
test_fail first_of_two
|
test_fail first_of_two
|
||||||
|
|
||||||
GIT_CEILING_DIRECTORIES="foo:$TRASH_ROOT/sub:bar"
|
GIT_CEILING_DIRECTORIES="/foo:$TRASH_ROOT/sub:/bar"
|
||||||
test_fail second_of_three
|
test_fail second_of_three
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc == 3 && !strcmp(argv[1], "normalize_absolute_path")) {
|
if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
|
||||||
char *buf = xmalloc(PATH_MAX + 1);
|
char *buf = xmalloc(PATH_MAX + 1);
|
||||||
int rv = normalize_absolute_path(buf, argv[2]);
|
int rv = normalize_path_copy(buf, argv[2]);
|
||||||
assert(strlen(buf) == rv);
|
if (rv)
|
||||||
|
buf = "++failed++";
|
||||||
puts(buf);
|
puts(buf);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc >= 2 && !strcmp(argv[1], "make_absolute_path")) {
|
if (argc >= 2 && !strcmp(argv[1], "make_absolute_path")) {
|
||||||
@ -15,12 +17,16 @@ int main(int argc, char **argv)
|
|||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
|
if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
|
||||||
int len = longest_ancestor_length(argv[2], argv[3]);
|
int len = longest_ancestor_length(argv[2], argv[3]);
|
||||||
printf("%d\n", len);
|
printf("%d\n", len);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
|
||||||
|
argv[1] ? argv[1] : "(there was none)");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user