gitweb: Secure against commit-ish/tree-ish with the same name as path
[gitweb.git] / xdiff-interface.c
index 0a66ded9533009a8efb840db5377f0abf5fccb1b..08602f522183dc43787616f37cba9b8af4e3dade 100644 (file)
@@ -1,6 +1,52 @@
 #include "cache.h"
 #include "xdiff-interface.h"
 
+static int parse_num(char **cp_p, int *num_p)
+{
+       char *cp = *cp_p;
+       int num = 0;
+       int read_some;
+
+       while ('0' <= *cp && *cp <= '9')
+               num = num * 10 + *cp++ - '0';
+       if (!(read_some = cp - *cp_p))
+               return -1;
+       *cp_p = cp;
+       *num_p = num;
+       return 0;
+}
+
+int parse_hunk_header(char *line, int len,
+                     int *ob, int *on,
+                     int *nb, int *nn)
+{
+       char *cp;
+       cp = line + 4;
+       if (parse_num(&cp, ob)) {
+       bad_line:
+               return error("malformed diff output: %s", line);
+       }
+       if (*cp == ',') {
+               cp++;
+               if (parse_num(&cp, on))
+                       goto bad_line;
+       }
+       else
+               *on = 1;
+       if (*cp++ != ' ' || *cp++ != '+')
+               goto bad_line;
+       if (parse_num(&cp, nb))
+               goto bad_line;
+       if (*cp == ',') {
+               cp++;
+               if (parse_num(&cp, nn))
+                       goto bad_line;
+       }
+       else
+               *nn = 1;
+       return -!!memcmp(cp, " @@", 3);
+}
+
 static void consume_one(void *priv_, char *s, unsigned long size)
 {
        struct xdiff_emit_state *priv = priv_;
@@ -23,9 +69,9 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
        for (i = 0; i < nbuf; i++) {
                if (mb[i].ptr[mb[i].size-1] != '\n') {
                        /* Incomplete line */
-                       priv->remainder = realloc(priv->remainder,
-                                                 priv->remainder_size +
-                                                 mb[i].size);
+                       priv->remainder = xrealloc(priv->remainder,
+                                                  priv->remainder_size +
+                                                  mb[i].size);
                        memcpy(priv->remainder + priv->remainder_size,
                               mb[i].ptr, mb[i].size);
                        priv->remainder_size += mb[i].size;
@@ -37,9 +83,9 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
                        consume_one(priv, mb[i].ptr, mb[i].size);
                        continue;
                }
-               priv->remainder = realloc(priv->remainder,
-                                         priv->remainder_size +
-                                         mb[i].size);
+               priv->remainder = xrealloc(priv->remainder,
+                                          priv->remainder_size +
+                                          mb[i].size);
                memcpy(priv->remainder + priv->remainder_size,
                       mb[i].ptr, mb[i].size);
                consume_one(priv, priv->remainder,