Fix git-am safety checks
[gitweb.git] / http-fetch.c
index 7619b338feb92a431268fc5a3963415af1b53e99..a113bb8c4b0c8d59b5b6df3c7689ba9f50818753 100644 (file)
@@ -559,9 +559,36 @@ static void process_alternates_response(void *callback_data)
                        char *target = NULL;
                        char *path;
                        if (data[i] == '/') {
-                               serverlen = strchr(base + 8, '/') - base;
-                               okay = 1;
+                               /* This counts
+                                * http://git.host/pub/scm/linux.git/
+                                * -----------here^
+                                * so memcpy(dst, base, serverlen) will
+                                * copy up to "...git.host".
+                                */
+                               const char *colon_ss = strstr(base,"://");
+                               if (colon_ss) {
+                                       serverlen = (strchr(colon_ss + 3, '/')
+                                                    - base);
+                                       okay = 1;
+                               }
                        } else if (!memcmp(data + i, "../", 3)) {
+                               /* Relative URL; chop the corresponding
+                                * number of subpath from base (and ../
+                                * from data), and concatenate the result.
+                                *
+                                * The code first drops ../ from data, and
+                                * then drops one ../ from data and one path
+                                * from base.  IOW, one extra ../ is dropped
+                                * from data than path is dropped from base.
+                                *
+                                * This is not wrong.  The alternate in
+                                *     http://git.host/pub/scm/linux.git/
+                                * to borrow from
+                                *     http://git.host/pub/scm/linus.git/
+                                * is ../../linus.git/objects/.  You need
+                                * two ../../ to borrow from your direct
+                                * neighbour.
+                                */
                                i += 3;
                                serverlen = strlen(base);
                                while (i + 2 < posn &&
@@ -583,11 +610,13 @@ static void process_alternates_response(void *callback_data)
                                        okay = 1;
                                }
                        }
-                       /* skip 'objects' at end */
+                       /* skip "objects\n" at end */
                        if (okay) {
                                target = xmalloc(serverlen + posn - i - 6);
-                               strlcpy(target, base, serverlen);
-                               strlcpy(target + serverlen, data + i, posn - i - 6);
+                               memcpy(target, base, serverlen);
+                               memcpy(target + serverlen, data + i,
+                                      posn - i - 7);
+                               target[serverlen + posn - i - 7] = 0;
                                if (get_verbosely)
                                        fprintf(stderr,
                                                "Also look at %s\n", target);
@@ -696,10 +725,8 @@ xml_start_tag(void *userData, const char *name, const char **atts)
        strcat(ctx->name, ".");
        strcat(ctx->name, c);
 
-       if (ctx->cdata) {
-               free(ctx->cdata);
-               ctx->cdata = NULL;
-       }
+       free(ctx->cdata);
+       ctx->cdata = NULL;
 
        ctx->userFunc(ctx, 0);
 }
@@ -726,8 +753,7 @@ static void
 xml_cdata(void *userData, const XML_Char *s, int len)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
-       if (ctx->cdata)
-               free(ctx->cdata);
+       free(ctx->cdata);
        ctx->cdata = xmalloc(len + 1);
        strlcpy(ctx->cdata, s, len + 1);
 }
@@ -765,9 +791,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
                        ls->dentry_flags |= IS_DIR;
                }
        } else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
-               if (ls->dentry_name) {
-                       free(ls->dentry_name);
-               }
+               free(ls->dentry_name);
                ls->dentry_name = NULL;
                ls->dentry_flags = 0;
        }
@@ -792,7 +816,7 @@ static int remote_ls(struct alt_base *repo, const char *path, int flags,
 
        ls.flags = flags;
        ls.repo = repo;
-       ls.path = strdup(path);
+       ls.path = xstrdup(path);
        ls.dentry_name = NULL;
        ls.dentry_flags = 0;
        ls.userData = userData;