Merge branch 'js/icase-wt-detection'
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Oct 2015 22:43:39 +0000 (15:43 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Oct 2015 22:43:39 +0000 (15:43 -0700)
On a case insensitive filesystems, setting GIT_WORK_TREE variable
using a random cases that does not agree with what the filesystem
thinks confused Git that it wasn't inside the working tree.

* js/icase-wt-detection:
setup: fix "inside work tree" detection on case-insensitive filesystems

1  2 
dir.c
diff --combined dir.c
index b90484acf8831150bce34670315e00d2f6f6480b,22402c730efdf7b4f5e4f4c2527d94c22a96b3d9..fba938b70166a9397d072bf1e05a393375a0dbc5
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -882,25 -882,6 +882,25 @@@ int match_pathname(const char *pathname
                 */
                if (!patternlen && !namelen)
                        return 1;
 +              /*
 +               * This can happen when we ignore some exclude rules
 +               * on directories in other to see if negative rules
 +               * may match. E.g.
 +               *
 +               * /abc
 +               * !/abc/def/ghi
 +               *
 +               * The pattern of interest is "/abc". On the first
 +               * try, we should match path "abc" with this pattern
 +               * in the "if" statement right above, but the caller
 +               * ignores it.
 +               *
 +               * On the second try with paths within "abc",
 +               * e.g. "abc/xyz", we come here and try to match it
 +               * with "/abc".
 +               */
 +              if (!patternlen && namelen && *name == '/')
 +                      return 1;
        }
  
        return fnmatch_icase_mem(pattern, patternlen,
                                 WM_PATHNAME) == 0;
  }
  
 +/*
 + * Return non-zero if pathname is a directory and an ancestor of the
 + * literal path in a (negative) pattern. This is used to keep
 + * descending in "foo" and "foo/bar" when the pattern is
 + * "!foo/bar/.gitignore". "foo/notbar" will not be descended however.
 + */
 +static int match_neg_path(const char *pathname, int pathlen, int *dtype,
 +                        const char *base, int baselen,
 +                        const char *pattern, int prefix, int patternlen,
 +                        int flags)
 +{
 +      assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR));
 +
 +      if (*dtype == DT_UNKNOWN)
 +              *dtype = get_dtype(NULL, pathname, pathlen);
 +      if (*dtype != DT_DIR)
 +              return 0;
 +
 +      if (*pattern == '/') {
 +              pattern++;
 +              patternlen--;
 +              prefix--;
 +      }
 +
 +      if (baselen) {
 +              if (((pathlen < baselen && base[pathlen] == '/') ||
 +                   pathlen == baselen) &&
 +                  !strncmp_icase(pathname, base, pathlen))
 +                      return 1;
 +              pathname += baselen + 1;
 +              pathlen  -= baselen + 1;
 +      }
 +
 +
 +      if (prefix &&
 +          ((pathlen < prefix && pattern[pathlen] == '/') &&
 +           !strncmp_icase(pathname, pattern, pathlen)))
 +              return 1;
 +
 +      return 0;
 +}
 +
  /*
   * Scan the given exclude list in reverse to see whether pathname
   * should be ignored.  The first match (i.e. the last on the list), if
@@@ -962,8 -901,7 +962,8 @@@ static struct exclude *last_exclude_mat
                                                       int *dtype,
                                                       struct exclude_list *el)
  {
 -      int i;
 +      struct exclude *exc = NULL; /* undecided */
 +      int i, matched_negative_path = 0;
  
        if (!el->nr)
                return NULL;    /* undefined */
                        if (match_basename(basename,
                                           pathlen - (basename - pathname),
                                           exclude, prefix, x->patternlen,
 -                                         x->flags))
 -                              return x;
 +                                         x->flags)) {
 +                              exc = x;
 +                              break;
 +                      }
                        continue;
                }
  
                assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
                if (match_pathname(pathname, pathlen,
                                   x->base, x->baselen ? x->baselen - 1 : 0,
 +                                 exclude, prefix, x->patternlen, x->flags)) {
 +                      exc = x;
 +                      break;
 +              }
 +
 +              if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path &&
 +                  match_neg_path(pathname, pathlen, dtype, x->base,
 +                                 x->baselen ? x->baselen - 1 : 0,
                                   exclude, prefix, x->patternlen, x->flags))
 -                      return x;
 +                      matched_negative_path = 1;
        }
 -      return NULL; /* undecided */
 +      if (exc &&
 +          !(exc->flags & EXC_FLAG_NEGATIVE) &&
 +          !(exc->flags & EXC_FLAG_NODIR) &&
 +          matched_negative_path)
 +              exc = NULL;
 +      return exc;
  }
  
  /*
@@@ -2107,6 -2030,15 +2107,15 @@@ int file_exists(const char *f
        return lstat(f, &sb) == 0;
  }
  
+ static int cmp_icase(char a, char b)
+ {
+       if (a == b)
+               return 0;
+       if (ignore_case)
+               return toupper(a) - toupper(b);
+       return a - b;
+ }
  /*
   * Given two normalized paths (a trailing slash is ok), if subdir is
   * outside dir, return -1.  Otherwise return the offset in subdir that
@@@ -2118,7 -2050,7 +2127,7 @@@ int dir_inside_of(const char *subdir, c
  
        assert(dir && subdir && *dir && *subdir);
  
-       while (*dir && *subdir && *dir == *subdir) {
+       while (*dir && *subdir && !cmp_icase(*dir, *subdir)) {
                dir++;
                subdir++;
                offset++;
@@@ -2253,8 -2185,6 +2262,8 @@@ int remove_dir_recursively(struct strbu
        return remove_dir_recurse(path, flag, NULL);
  }
  
 +static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
 +
  void setup_standard_excludes(struct dir_struct *dir)
  {
        const char *path;
                                         dir->untracked ? &dir->ss_excludes_file : NULL);
  
        /* per repository user preference */
 -      path = git_path("info/exclude");
 +      path = git_path_info_exclude();
        if (!access_or_warn(path, R_OK, 0))
                add_excludes_from_file_1(dir, path,
                                         dir->untracked ? &dir->ss_info_exclude : NULL);