Merge branch 'rr/triangle'
[gitweb.git] / path.c
diff --git a/path.c b/path.c
index f455e8e63de59fbbe72a29dd07baa33b6e0c56a2..2fdccc2f18367399b8247ee79ec8bf4934f596cb 100644 (file)
--- a/path.c
+++ b/path.c
 #include "strbuf.h"
 #include "string-list.h"
 
+#ifndef get_st_mode_bits
+/*
+ * The replacement lstat(2) we use on Cygwin is incomplete and
+ * may return wrong permission bits. Most of the time we do not care,
+ * but the callsites of this wrapper do care.
+ */
+int get_st_mode_bits(const char *path, int *mode)
+{
+       struct stat st;
+       if (lstat(path, &st) < 0)
+               return -1;
+       *mode = st.st_mode;
+       return 0;
+}
+#endif
+
 static char bad_path[] = "/bad-path/";
 
 static char *get_pathname(void)
@@ -391,7 +407,6 @@ const char *enter_repo(const char *path, int strict)
 
 int set_shared_perm(const char *path, int mode)
 {
-       struct stat st;
        int tweak, shared, orig_mode;
 
        if (!shared_repository) {
@@ -400,9 +415,8 @@ int set_shared_perm(const char *path, int mode)
                return 0;
        }
        if (!mode) {
-               if (lstat(path, &st) < 0)
+               if (get_st_mode_bits(path, &mode) < 0)
                        return -1;
-               mode = st.st_mode;
                orig_mode = mode;
        } else
                orig_mode = 0;
@@ -570,48 +584,40 @@ int normalize_path_copy(char *dst, const char *src)
 
 /*
  * path = Canonical absolute path
- * prefix_list = Colon-separated list of absolute paths
+ * prefixes = string_list containing normalized, absolute paths without
+ * trailing slashes (except for the root directory, which is denoted by "/").
  *
- * Determines, for each path in prefix_list, whether the "prefix" really
+ * Determines, for each path in prefixes, whether the "prefix"
  * is an ancestor directory of path.  Returns the length of the longest
  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
- * is an ancestor.  (Note that this means 0 is returned if prefix_list is
- * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
+ * is an ancestor.  (Note that this means 0 is returned if prefixes is
+ * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
  * are not considered to be their own ancestors.  path must be in a
  * canonical form: empty components, or "." or ".." components are not
- * allowed.  prefix_list may be null, which is like "".
+ * allowed.
  */
-int longest_ancestor_length(const char *path, const char *prefix_list)
+int longest_ancestor_length(const char *path, struct string_list *prefixes)
 {
-       struct string_list prefixes = STRING_LIST_INIT_DUP;
-       char buf[PATH_MAX+1];
        int i, max_len = -1;
 
-       if (prefix_list == NULL || !strcmp(path, "/"))
+       if (!strcmp(path, "/"))
                return -1;
 
-       string_list_split(&prefixes, prefix_list, PATH_SEP, -1);
-
-       for (i = 0; i < prefixes.nr; i++) {
-               const char *ceil = prefixes.items[i].string;
+       for (i = 0; i < prefixes->nr; i++) {
+               const char *ceil = prefixes->items[i].string;
                int len = strlen(ceil);
 
-               if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-                       continue;
-               if (normalize_path_copy(buf, ceil) < 0)
-                       continue;
-               len = strlen(buf);
-               if (len > 0 && buf[len-1] == '/')
-                       buf[--len] = '\0';
+               if (len == 1 && ceil[0] == '/')
+                       len = 0; /* root matches anything, with length 0 */
+               else if (!strncmp(path, ceil, len) && path[len] == '/')
+                       ; /* match of length len */
+               else
+                       continue; /* no match */
 
-               if (!strncmp(path, buf, len) &&
-                   path[len] == '/' &&
-                   len > max_len) {
+               if (len > max_len)
                        max_len = len;
-               }
        }
 
-       string_list_clear(&prefixes, 0);
        return max_len;
 }