format-patch: improve head calculation for cover-letter
[gitweb.git] / path.c
diff --git a/path.c b/path.c
index cbbdf7d6ba68160a3a9936976e53d773d181ceac..2fdccc2f18367399b8247ee79ec8bf4934f596cb 100644 (file)
--- a/path.c
+++ b/path.c
  */
 #include "cache.h"
 #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/";
 
@@ -390,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) {
@@ -399,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;
@@ -569,43 +584,38 @@ 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)
 {
-       char buf[PATH_MAX+1];
-       const char *ceil, *colon;
-       int len, max_len = -1;
+       int i, max_len = -1;
 
-       if (prefix_list == NULL || !strcmp(path, "/"))
+       if (!strcmp(path, "/"))
                return -1;
 
-       for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
-               for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
-               len = colon - ceil;
-               if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-                       continue;
-               strlcpy(buf, ceil, len+1);
-               if (normalize_path_copy(buf, buf) < 0)
-                       continue;
-               len = strlen(buf);
-               if (len > 0 && buf[len-1] == '/')
-                       buf[--len] = '\0';
+       for (i = 0; i < prefixes->nr; i++) {
+               const char *ceil = prefixes->items[i].string;
+               int len = strlen(ceil);
+
+               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;
-               }
        }
 
        return max_len;