parse_pathspec: make sure the prefix part is wildcard-free
Prepending prefix to pathspec is a trick to workaround the fact that commands can be executed in a subdirectory, but all git commands run at worktree's root. The prefix part should always be treated as literal string. Make it so. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
b3920bbdc5
commit
645a29c40a
2
cache.h
2
cache.h
@ -414,6 +414,7 @@ extern void setup_work_tree(void);
|
|||||||
extern const char *setup_git_directory_gently(int *);
|
extern const char *setup_git_directory_gently(int *);
|
||||||
extern const char *setup_git_directory(void);
|
extern const char *setup_git_directory(void);
|
||||||
extern char *prefix_path(const char *prefix, int len, const char *path);
|
extern char *prefix_path(const char *prefix, int len, const char *path);
|
||||||
|
extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
|
||||||
extern const char *prefix_filename(const char *prefix, int len, const char *path);
|
extern const char *prefix_filename(const char *prefix, int len, const char *path);
|
||||||
extern int check_filename(const char *prefix, const char *name);
|
extern int check_filename(const char *prefix, const char *name);
|
||||||
extern void verify_filename(const char *prefix,
|
extern void verify_filename(const char *prefix,
|
||||||
@ -741,6 +742,7 @@ const char *real_path(const char *path);
|
|||||||
const char *real_path_if_valid(const char *path);
|
const char *real_path_if_valid(const char *path);
|
||||||
const char *absolute_path(const char *path);
|
const char *absolute_path(const char *path);
|
||||||
const char *relative_path(const char *abs, const char *base);
|
const char *relative_path(const char *abs, const char *base);
|
||||||
|
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
|
||||||
int normalize_path_copy(char *dst, const char *src);
|
int normalize_path_copy(char *dst, const char *src);
|
||||||
int longest_ancestor_length(const char *path, struct string_list *prefixes);
|
int longest_ancestor_length(const char *path, struct string_list *prefixes);
|
||||||
char *strip_path_suffix(const char *path, const char *suffix);
|
char *strip_path_suffix(const char *path, const char *suffix);
|
||||||
|
15
path.c
15
path.c
@ -492,8 +492,14 @@ const char *relative_path(const char *abs, const char *base)
|
|||||||
*
|
*
|
||||||
* 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.
|
||||||
|
*
|
||||||
|
* prefix_len != NULL is for a specific case of prefix_pathspec():
|
||||||
|
* assume that src == dst and src[0..prefix_len-1] is already
|
||||||
|
* normalized, any time "../" eats up to the prefix_len part,
|
||||||
|
* prefix_len is reduced. In the end prefix_len is the remaining
|
||||||
|
* prefix that has not been overridden by user pathspec.
|
||||||
*/
|
*/
|
||||||
int normalize_path_copy(char *dst, const char *src)
|
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
|
||||||
{
|
{
|
||||||
char *dst0;
|
char *dst0;
|
||||||
|
|
||||||
@ -568,11 +574,18 @@ int normalize_path_copy(char *dst, const char *src)
|
|||||||
/* Windows: dst[-1] cannot be backslash anymore */
|
/* Windows: dst[-1] cannot be backslash anymore */
|
||||||
while (dst0 < dst && dst[-1] != '/')
|
while (dst0 < dst && dst[-1] != '/')
|
||||||
dst--;
|
dst--;
|
||||||
|
if (prefix_len && *prefix_len > dst - dst0)
|
||||||
|
*prefix_len = dst - dst0;
|
||||||
}
|
}
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int normalize_path_copy(char *dst, const char *src)
|
||||||
|
{
|
||||||
|
return normalize_path_copy_len(dst, src, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* path = Canonical absolute path
|
* path = Canonical absolute path
|
||||||
* prefixes = string_list containing normalized, absolute paths without
|
* prefixes = string_list containing normalized, absolute paths without
|
||||||
|
21
pathspec.c
21
pathspec.c
@ -150,10 +150,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
magic |= short_magic;
|
magic |= short_magic;
|
||||||
*p_short_magic = short_magic;
|
*p_short_magic = short_magic;
|
||||||
|
|
||||||
if (magic & PATHSPEC_FROMTOP)
|
if (magic & PATHSPEC_FROMTOP) {
|
||||||
match = xstrdup(copyfrom);
|
match = xstrdup(copyfrom);
|
||||||
else
|
prefixlen = 0;
|
||||||
match = prefix_path(prefix, prefixlen, copyfrom);
|
} else {
|
||||||
|
match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
|
||||||
|
if (!match)
|
||||||
|
die(_("%s: '%s' is outside repository"), elt, copyfrom);
|
||||||
|
}
|
||||||
*raw = item->match = match;
|
*raw = item->match = match;
|
||||||
/*
|
/*
|
||||||
* Prefix the pathspec (keep all magic) and assign to
|
* Prefix the pathspec (keep all magic) and assign to
|
||||||
@ -167,6 +171,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
} else
|
} else
|
||||||
item->original = elt;
|
item->original = elt;
|
||||||
item->len = strlen(item->match);
|
item->len = strlen(item->match);
|
||||||
|
item->prefix = prefixlen;
|
||||||
|
|
||||||
if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
|
if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
|
||||||
(item->len >= 1 && item->match[item->len - 1] == '/') &&
|
(item->len >= 1 && item->match[item->len - 1] == '/') &&
|
||||||
@ -198,13 +203,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
|
|
||||||
if (limit_pathspec_to_literal())
|
if (limit_pathspec_to_literal())
|
||||||
item->nowildcard_len = item->len;
|
item->nowildcard_len = item->len;
|
||||||
else
|
else {
|
||||||
item->nowildcard_len = simple_length(item->match);
|
item->nowildcard_len = simple_length(item->match);
|
||||||
|
if (item->nowildcard_len < prefixlen)
|
||||||
|
item->nowildcard_len = prefixlen;
|
||||||
|
}
|
||||||
item->flags = 0;
|
item->flags = 0;
|
||||||
if (item->nowildcard_len < item->len &&
|
if (item->nowildcard_len < item->len &&
|
||||||
item->match[item->nowildcard_len] == '*' &&
|
item->match[item->nowildcard_len] == '*' &&
|
||||||
no_wildcard(item->match + item->nowildcard_len + 1))
|
no_wildcard(item->match + item->nowildcard_len + 1))
|
||||||
item->flags |= PATHSPEC_ONESTAR;
|
item->flags |= PATHSPEC_ONESTAR;
|
||||||
|
|
||||||
|
/* sanity checks, pathspec matchers assume these are sane */
|
||||||
|
assert(item->nowildcard_len <= item->len &&
|
||||||
|
item->prefix <= item->len);
|
||||||
return magic;
|
return magic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +296,7 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
item->match = prefix;
|
item->match = prefix;
|
||||||
item->original = prefix;
|
item->original = prefix;
|
||||||
item->nowildcard_len = item->len = strlen(prefix);
|
item->nowildcard_len = item->len = strlen(prefix);
|
||||||
|
item->prefix = item->len;
|
||||||
raw[0] = prefix;
|
raw[0] = prefix;
|
||||||
raw[1] = NULL;
|
raw[1] = NULL;
|
||||||
pathspec->nr = 1;
|
pathspec->nr = 1;
|
||||||
|
@ -21,7 +21,7 @@ struct pathspec {
|
|||||||
const char *match;
|
const char *match;
|
||||||
const char *original;
|
const char *original;
|
||||||
unsigned magic;
|
unsigned magic;
|
||||||
int len;
|
int len, prefix;
|
||||||
int nowildcard_len;
|
int nowildcard_len;
|
||||||
int flags;
|
int flags;
|
||||||
} *items;
|
} *items;
|
||||||
|
24
setup.c
24
setup.c
@ -5,7 +5,19 @@
|
|||||||
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 char *prefix_path_gently(const char *prefix, int len, const char *path)
|
/*
|
||||||
|
* Normalize "path", prepending the "prefix" for relative paths. If
|
||||||
|
* remaining_prefix is not NULL, return the actual prefix still
|
||||||
|
* remains in the path. For example, prefix = sub1/sub2/ and path is
|
||||||
|
*
|
||||||
|
* foo -> sub1/sub2/foo (full prefix)
|
||||||
|
* ../foo -> sub1/foo (remaining prefix is sub1/)
|
||||||
|
* ../../bar -> bar (no remaining prefix)
|
||||||
|
* ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)
|
||||||
|
* `pwd`/../bar -> sub1/bar (no remaining prefix)
|
||||||
|
*/
|
||||||
|
char *prefix_path_gently(const char *prefix, int len,
|
||||||
|
int *remaining_prefix, const char *path)
|
||||||
{
|
{
|
||||||
const char *orig = path;
|
const char *orig = path;
|
||||||
char *sanitized;
|
char *sanitized;
|
||||||
@ -13,13 +25,17 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
|
|||||||
const char *temp = real_path(path);
|
const char *temp = real_path(path);
|
||||||
sanitized = xmalloc(len + strlen(temp) + 1);
|
sanitized = xmalloc(len + strlen(temp) + 1);
|
||||||
strcpy(sanitized, temp);
|
strcpy(sanitized, temp);
|
||||||
|
if (remaining_prefix)
|
||||||
|
*remaining_prefix = 0;
|
||||||
} else {
|
} else {
|
||||||
sanitized = xmalloc(len + strlen(path) + 1);
|
sanitized = xmalloc(len + strlen(path) + 1);
|
||||||
if (len)
|
if (len)
|
||||||
memcpy(sanitized, prefix, len);
|
memcpy(sanitized, prefix, len);
|
||||||
strcpy(sanitized + len, path);
|
strcpy(sanitized + len, path);
|
||||||
|
if (remaining_prefix)
|
||||||
|
*remaining_prefix = len;
|
||||||
}
|
}
|
||||||
if (normalize_path_copy(sanitized, sanitized))
|
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
|
||||||
goto error_out;
|
goto error_out;
|
||||||
if (is_absolute_path(orig)) {
|
if (is_absolute_path(orig)) {
|
||||||
size_t root_len, len, total;
|
size_t root_len, len, total;
|
||||||
@ -44,7 +60,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)
|
|||||||
|
|
||||||
char *prefix_path(const char *prefix, int len, const char *path)
|
char *prefix_path(const char *prefix, int len, const char *path)
|
||||||
{
|
{
|
||||||
char *r = prefix_path_gently(prefix, len, path);
|
char *r = prefix_path_gently(prefix, len, NULL, path);
|
||||||
if (!r)
|
if (!r)
|
||||||
die("'%s' is outside repository", path);
|
die("'%s' is outside repository", path);
|
||||||
return r;
|
return r;
|
||||||
@ -53,7 +69,7 @@ char *prefix_path(const char *prefix, int len, const char *path)
|
|||||||
int path_inside_repo(const char *prefix, const char *path)
|
int path_inside_repo(const char *prefix, const char *path)
|
||||||
{
|
{
|
||||||
int len = prefix ? strlen(prefix) : 0;
|
int len = prefix ? strlen(prefix) : 0;
|
||||||
char *r = prefix_path_gently(prefix, len, path);
|
char *r = prefix_path_gently(prefix, len, NULL, path);
|
||||||
if (r) {
|
if (r) {
|
||||||
free(r);
|
free(r);
|
||||||
return 1;
|
return 1;
|
||||||
|
Reference in New Issue
Block a user