prep_exclude: remove the artificial PATH_MAX limit
This fixes a segfault in git-status with long paths on Windows, where PATH_MAX is only 260. This also fixes the problem of silently ignoring .gitignore if the full path exceeds PATH_MAX. Now add_excludes_from_file() will report if it gets ENAMETOOLONG. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
709359c85c
commit
aceb9429b3
47
dir.c
47
dir.c
@ -799,12 +799,12 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
|
|||||||
*/
|
*/
|
||||||
while ((stk = dir->exclude_stack) != NULL) {
|
while ((stk = dir->exclude_stack) != NULL) {
|
||||||
if (stk->baselen <= baselen &&
|
if (stk->baselen <= baselen &&
|
||||||
!strncmp(dir->basebuf, base, stk->baselen))
|
!strncmp(dir->basebuf.buf, base, stk->baselen))
|
||||||
break;
|
break;
|
||||||
el = &group->el[dir->exclude_stack->exclude_ix];
|
el = &group->el[dir->exclude_stack->exclude_ix];
|
||||||
dir->exclude_stack = stk->prev;
|
dir->exclude_stack = stk->prev;
|
||||||
dir->exclude = NULL;
|
dir->exclude = NULL;
|
||||||
free((char *)el->src); /* see strdup() below */
|
free((char *)el->src); /* see strbuf_detach() below */
|
||||||
clear_exclude_list(el);
|
clear_exclude_list(el);
|
||||||
free(stk);
|
free(stk);
|
||||||
group->nr--;
|
group->nr--;
|
||||||
@ -814,8 +814,17 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
|
|||||||
if (dir->exclude)
|
if (dir->exclude)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lazy initialization. All call sites currently just
|
||||||
|
* memset(dir, 0, sizeof(*dir)) before use. Changing all of
|
||||||
|
* them seems lots of work for little benefit.
|
||||||
|
*/
|
||||||
|
if (!dir->basebuf.buf)
|
||||||
|
strbuf_init(&dir->basebuf, PATH_MAX);
|
||||||
|
|
||||||
/* Read from the parent directories and push them down. */
|
/* Read from the parent directories and push them down. */
|
||||||
current = stk ? stk->baselen : -1;
|
current = stk ? stk->baselen : -1;
|
||||||
|
strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current);
|
||||||
while (current < baselen) {
|
while (current < baselen) {
|
||||||
struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
|
struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
|
||||||
const char *cp;
|
const char *cp;
|
||||||
@ -833,48 +842,47 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
|
|||||||
stk->baselen = cp - base;
|
stk->baselen = cp - base;
|
||||||
stk->exclude_ix = group->nr;
|
stk->exclude_ix = group->nr;
|
||||||
el = add_exclude_list(dir, EXC_DIRS, NULL);
|
el = add_exclude_list(dir, EXC_DIRS, NULL);
|
||||||
memcpy(dir->basebuf + current, base + current,
|
strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
|
||||||
stk->baselen - current);
|
assert(stk->baselen == dir->basebuf.len);
|
||||||
|
|
||||||
/* Abort if the directory is excluded */
|
/* Abort if the directory is excluded */
|
||||||
if (stk->baselen) {
|
if (stk->baselen) {
|
||||||
int dt = DT_DIR;
|
int dt = DT_DIR;
|
||||||
dir->basebuf[stk->baselen - 1] = 0;
|
dir->basebuf.buf[stk->baselen - 1] = 0;
|
||||||
dir->exclude = last_exclude_matching_from_lists(dir,
|
dir->exclude = last_exclude_matching_from_lists(dir,
|
||||||
dir->basebuf, stk->baselen - 1,
|
dir->basebuf.buf, stk->baselen - 1,
|
||||||
dir->basebuf + current, &dt);
|
dir->basebuf.buf + current, &dt);
|
||||||
dir->basebuf[stk->baselen - 1] = '/';
|
dir->basebuf.buf[stk->baselen - 1] = '/';
|
||||||
if (dir->exclude &&
|
if (dir->exclude &&
|
||||||
dir->exclude->flags & EXC_FLAG_NEGATIVE)
|
dir->exclude->flags & EXC_FLAG_NEGATIVE)
|
||||||
dir->exclude = NULL;
|
dir->exclude = NULL;
|
||||||
if (dir->exclude) {
|
if (dir->exclude) {
|
||||||
dir->basebuf[stk->baselen] = 0;
|
|
||||||
dir->exclude_stack = stk;
|
dir->exclude_stack = stk;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to read per-directory file unless path is too long */
|
/* Try to read per-directory file */
|
||||||
if (dir->exclude_per_dir &&
|
if (dir->exclude_per_dir) {
|
||||||
stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) {
|
|
||||||
strcpy(dir->basebuf + stk->baselen,
|
|
||||||
dir->exclude_per_dir);
|
|
||||||
/*
|
/*
|
||||||
* dir->basebuf gets reused by the traversal, but we
|
* dir->basebuf gets reused by the traversal, but we
|
||||||
* need fname to remain unchanged to ensure the src
|
* need fname to remain unchanged to ensure the src
|
||||||
* member of each struct exclude correctly
|
* member of each struct exclude correctly
|
||||||
* back-references its source file. Other invocations
|
* back-references its source file. Other invocations
|
||||||
* of add_exclude_list provide stable strings, so we
|
* of add_exclude_list provide stable strings, so we
|
||||||
* strdup() and free() here in the caller.
|
* strbuf_detach() and free() here in the caller.
|
||||||
*/
|
*/
|
||||||
el->src = strdup(dir->basebuf);
|
struct strbuf sb = STRBUF_INIT;
|
||||||
add_excludes_from_file_to_list(dir->basebuf,
|
strbuf_addbuf(&sb, &dir->basebuf);
|
||||||
dir->basebuf, stk->baselen, el, 1);
|
strbuf_addstr(&sb, dir->exclude_per_dir);
|
||||||
|
el->src = strbuf_detach(&sb, NULL);
|
||||||
|
add_excludes_from_file_to_list(el->src, el->src,
|
||||||
|
stk->baselen, el, 1);
|
||||||
}
|
}
|
||||||
dir->exclude_stack = stk;
|
dir->exclude_stack = stk;
|
||||||
current = stk->baselen;
|
current = stk->baselen;
|
||||||
}
|
}
|
||||||
dir->basebuf[baselen] = '\0';
|
strbuf_setlen(&dir->basebuf, baselen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1671,4 +1679,5 @@ void clear_directory(struct dir_struct *dir)
|
|||||||
free(stk);
|
free(stk);
|
||||||
stk = prev;
|
stk = prev;
|
||||||
}
|
}
|
||||||
|
strbuf_release(&dir->basebuf);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user