git log -p -m: document -m and honor --first-parent
[gitweb.git] / path.c
diff --git a/path.c b/path.c
index 00d06332959af03b036b3d0b5ad115dd3b46b920..79aa104712364a8c18964feecd4c8079449a78cf 100644 (file)
--- a/path.c
+++ b/path.c
@@ -394,17 +394,38 @@ int set_shared_perm(const char *path, int mode)
 const char *make_relative_path(const char *abs, const char *base)
 {
        static char buf[PATH_MAX + 1];
-       int baselen;
-       if (!base)
-               return abs;
-       baselen = strlen(base);
-       if (prefixcmp(abs, base))
+       int i = 0, j = 0;
+
+       if (!base || !base[0])
                return abs;
-       if (abs[baselen] == '/')
-               baselen++;
-       else if (base[baselen - 1] != '/')
+       while (base[i]) {
+               if (is_dir_sep(base[i])) {
+                       if (!is_dir_sep(abs[j]))
+                               return abs;
+                       while (is_dir_sep(base[i]))
+                               i++;
+                       while (is_dir_sep(abs[j]))
+                               j++;
+                       continue;
+               } else if (abs[j] != base[i]) {
+                       return abs;
+               }
+               i++;
+               j++;
+       }
+       if (
+           /* "/foo" is a prefix of "/foo" */
+           abs[j] &&
+           /* "/foo" is not a prefix of "/foobar" */
+           !is_dir_sep(base[i-1]) && !is_dir_sep(abs[j])
+          )
                return abs;
-       strcpy(buf, abs + baselen);
+       while (is_dir_sep(abs[j]))
+               j++;
+       if (!abs[j])
+               strcpy(buf, ".");
+       else
+               strcpy(buf, abs + j);
        return buf;
 }
 
@@ -581,3 +602,50 @@ char *strip_path_suffix(const char *path, const char *suffix)
                return NULL;
        return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
 }
+
+int daemon_avoid_alias(const char *p)
+{
+       int sl, ndot;
+
+       /*
+        * This resurrects the belts and suspenders paranoia check by HPA
+        * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
+        * does not do getcwd() based path canonicalizations.
+        *
+        * sl becomes true immediately after seeing '/' and continues to
+        * be true as long as dots continue after that without intervening
+        * non-dot character.
+        */
+       if (!p || (*p != '/' && *p != '~'))
+               return -1;
+       sl = 1; ndot = 0;
+       p++;
+
+       while (1) {
+               char ch = *p++;
+               if (sl) {
+                       if (ch == '.')
+                               ndot++;
+                       else if (ch == '/') {
+                               if (ndot < 3)
+                                       /* reject //, /./ and /../ */
+                                       return -1;
+                               ndot = 0;
+                       }
+                       else if (ch == 0) {
+                               if (0 < ndot && ndot < 3)
+                                       /* reject /.$ and /..$ */
+                                       return -1;
+                               return 0;
+                       }
+                       else
+                               sl = ndot = 0;
+               }
+               else if (ch == 0)
+                       return 0;
+               else if (ch == '/') {
+                       sl = 1;
+                       ndot = 0;
+               }
+       }
+}