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>

Nguyễn Thái Ngọc Duy committed Jul 14, 2014 at 11:50 UTC aceb9429b37a4a36e91f9eeb60e7ba488f73604b
2 files changed +29 -20
dir.c
+28 -19
@@ -799,12 +799,12 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
799 */
800 while ((stk = dir->exclude_stack) != NULL) {
801 if (stk->baselen <= baselen &&
802 - !strncmp(dir->basebuf, base, stk->baselen))
802 + !strncmp(dir->basebuf.buf, base, stk->baselen))
803 break;
804 el = &group->el[dir->exclude_stack->exclude_ix];
805 dir->exclude_stack = stk->prev;
806 dir->exclude = NULL;
807 - free((char *)el->src); /* see strdup() below */
807 + free((char *)el->src); /* see strbuf_detach() below */
808 clear_exclude_list(el);
809 free(stk);
810 group->nr--;
@@ -814,8 +814,17 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
814 if (dir->exclude)
815 return;
816
817 + /*
818 + * Lazy initialization. All call sites currently just
819 + * memset(dir, 0, sizeof(*dir)) before use. Changing all of
820 + * them seems lots of work for little benefit.
821 + */
822 + if (!dir->basebuf.buf)
823 + strbuf_init(&dir->basebuf, PATH_MAX);
824 +
825 /* Read from the parent directories and push them down. */
826 current = stk ? stk->baselen : -1;
827 + strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current);
828 while (current < baselen) {
829 struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
830 const char *cp;
@@ -833,48 +842,47 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
842 stk->baselen = cp - base;
843 stk->exclude_ix = group->nr;
844 el = add_exclude_list(dir, EXC_DIRS, NULL);
836 - memcpy(dir->basebuf + current, base + current,
837 - stk->baselen - current);
845 + strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
846 + assert(stk->baselen == dir->basebuf.len);
847
848 /* Abort if the directory is excluded */
849 if (stk->baselen) {
850 int dt = DT_DIR;
842 - dir->basebuf[stk->baselen - 1] = 0;
851 + dir->basebuf.buf[stk->baselen - 1] = 0;
852 dir->exclude = last_exclude_matching_from_lists(dir,
844 - dir->basebuf, stk->baselen - 1,
845 - dir->basebuf + current, &dt);
846 - dir->basebuf[stk->baselen - 1] = '/';
853 + dir->basebuf.buf, stk->baselen - 1,
854 + dir->basebuf.buf + current, &dt);
855 + dir->basebuf.buf[stk->baselen - 1] = '/';
856 if (dir->exclude &&
857 dir->exclude->flags & EXC_FLAG_NEGATIVE)
858 dir->exclude = NULL;
859 if (dir->exclude) {
851 - dir->basebuf[stk->baselen] = 0;
860 dir->exclude_stack = stk;
861 return;
862 }
863 }
864
857 - /* Try to read per-directory file unless path is too long */
858 - if (dir->exclude_per_dir &&
859 - stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) {
860 - strcpy(dir->basebuf + stk->baselen,
861 - dir->exclude_per_dir);
865 + /* Try to read per-directory file */
866 + if (dir->exclude_per_dir) {
867 /*
868 * dir->basebuf gets reused by the traversal, but we
869 * need fname to remain unchanged to ensure the src
870 * member of each struct exclude correctly
871 * back-references its source file. Other invocations
872 * of add_exclude_list provide stable strings, so we
868 - * strdup() and free() here in the caller.
873 + * strbuf_detach() and free() here in the caller.
874 */
870 - el->src = strdup(dir->basebuf);
871 - add_excludes_from_file_to_list(dir->basebuf,
872 - dir->basebuf, stk->baselen, el, 1);
875 + struct strbuf sb = STRBUF_INIT;
876 + strbuf_addbuf(&sb, &dir->basebuf);
877 + strbuf_addstr(&sb, dir->exclude_per_dir);
878 + el->src = strbuf_detach(&sb, NULL);
879 + add_excludes_from_file_to_list(el->src, el->src,
880 + stk->baselen, el, 1);
881 }
882 dir->exclude_stack = stk;
883 current = stk->baselen;
884 }
877 - dir->basebuf[baselen] = '\0';
885 + strbuf_setlen(&dir->basebuf, baselen);
886 }
887
888 /*
@@ -1671,4 +1679,5 @@ void clear_directory(struct dir_struct *dir)
1679 free(stk);
1680 stk = prev;
1681 }
1682 + strbuf_release(&dir->basebuf);
1683 }
dir.h
+1 -1
@@ -119,7 +119,7 @@ struct dir_struct {
119 */
120 struct exclude_stack *exclude_stack;
121 struct exclude *exclude;
122 - char basebuf[PATH_MAX];
122 + struct strbuf basebuf;
123 };
124
125 /*