{"thread":{"id":"1849","subject":"[PATCH] Support alternates and http-alternates in http-fetch","startedAt":"2005-09-18T18:14:19Z","lastAt":"2005-09-18T18:14:19Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"8796","messageId":"Pine.LNX.4.63.0509181411110.23242@iabervon.org","threadId":"1849","inReplyTo":null,"subject":"[PATCH] Support alternates and http-alternates in http-fetch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-09-18T18:14:19Z","receivedAt":"2005-09-18T18:14:19Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This allows the remote repository to refer to additional repositories\nin a file objects/info/http-alternates or\nobjects/info/alternates. Each line may be:\n\n a relative path, starting with ../, to get from the objects directory\n  of the starting repository to the objects directory of the added\n  repository.\n\n an absolute path of the objects directory of the added repository (on\n  the same server).\n\n (only in http-alternates) a full URL of the objects directory of the\n  added repository.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n\n---\n\n http-fetch.c |  202 ++++++++++++++++++++++++++++++++++++++++++++++++----------\n 1 files changed, 166 insertions(+), 36 deletions(-)\n\n7640b93541f9422e8d101959c2f6c4fc3277e4f8\ndiff --git a/http-fetch.c b/http-fetch.c\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -16,7 +16,17 @@\n static CURL *curl;\n static struct curl_slist *no_pragma_header;\n \n-static char *base;\n+static char *initial_base;\n+\n+struct alt_base\n+{\n+\tchar *base;\n+\tint got_indices;\n+\tstruct packed_git *packs;\n+\tstruct alt_base *next;\n+};\n+\n+struct alt_base *alt = NULL;\n \n static SHA_CTX c;\n static z_stream stream;\n@@ -72,11 +82,9 @@ void prefetch(unsigned char *sha1)\n {\n }\n \n-static int got_indices = 0;\n-\n-static struct packed_git *packs = NULL;\n+static int got_alternates = 0;\n \n-static int fetch_index(unsigned char *sha1)\n+static int fetch_index(struct alt_base *repo, unsigned char *sha1)\n {\n \tchar *filename;\n \tchar *url;\n@@ -90,9 +98,9 @@ static int fetch_index(unsigned char *sh\n \t\tfprintf(stderr, \"Getting index for pack %s\\n\",\n \t\t\tsha1_to_hex(sha1));\n \t\n-\turl = xmalloc(strlen(base) + 64);\n+\turl = xmalloc(strlen(repo->base) + 64);\n \tsprintf(url, \"%s/objects/pack/pack-%s.idx\",\n-\t\tbase, sha1_to_hex(sha1));\n+\t\trepo->base, sha1_to_hex(sha1));\n \t\n \tfilename = sha1_pack_index_name(sha1);\n \tindexfile = fopen(filename, \"w\");\n@@ -114,22 +122,123 @@ static int fetch_index(unsigned char *sh\n \treturn 0;\n }\n \n-static int setup_index(unsigned char *sha1)\n+static int setup_index(struct alt_base *repo, unsigned char *sha1)\n {\n \tstruct packed_git *new_pack;\n \tif (has_pack_file(sha1))\n \t\treturn 0; // don't list this as something we can get\n \n-\tif (fetch_index(sha1))\n+\tif (fetch_index(repo, sha1))\n \t\treturn -1;\n \n \tnew_pack = parse_pack_index(sha1);\n-\tnew_pack->next = packs;\n-\tpacks = new_pack;\n+\tnew_pack->next = repo->packs;\n+\trepo->packs = new_pack;\n \treturn 0;\n }\n \n-static int fetch_indices(void)\n+static int fetch_alternates(char *base)\n+{\n+\tint ret = 0;\n+\tstruct buffer buffer;\n+\tchar *url;\n+\tchar *data;\n+\tint i = 0;\n+\tint http_specific = 1;\n+\tif (got_alternates)\n+\t\treturn 0;\n+\tdata = xmalloc(4096);\n+\tbuffer.size = 4095;\n+\tbuffer.posn = 0;\n+\tbuffer.buffer = data;\n+\n+\tif (get_verbosely)\n+\t\tfprintf(stderr, \"Getting alternates list\\n\");\n+\t\n+\turl = xmalloc(strlen(base) + 31);\n+\tsprintf(url, \"%s/objects/info/http-alternates\", base);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_FILE, &buffer);\n+\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n+\tcurl_easy_setopt(curl, CURLOPT_URL, url);\n+\n+\tif (curl_easy_perform(curl) || !buffer.posn) {\n+\t\thttp_specific = 0;\n+\n+\t\tsprintf(url, \"%s/objects/info/alternates\", base);\n+\t\t\n+\t\tcurl_easy_setopt(curl, CURLOPT_FILE, &buffer);\n+\t\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n+\t\tcurl_easy_setopt(curl, CURLOPT_URL, url);\n+\t\t\n+\t\tif (curl_easy_perform(curl)) {\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tdata[buffer.posn] = '\\0';\n+\n+\twhile (i < buffer.posn) {\n+\t\tint posn = i;\n+\t\twhile (posn < buffer.posn && data[posn] != '\\n')\n+\t\t\tposn++;\n+\t\tif (data[posn] == '\\n') {\n+\t\t\tint okay = 0;\n+\t\t\tint serverlen = 0;\n+\t\t\tstruct alt_base *newalt;\n+\t\t\tchar *target = NULL;\n+\t\t\tif (data[i] == '/') {\n+\t\t\t\tserverlen = strchr(base + 8, '/') - base;\n+\t\t\t\tokay = 1;\n+\t\t\t} else if (!memcmp(data + i, \"../\", 3)) {\n+\t\t\t\ti += 3;\n+\t\t\t\tserverlen = strlen(base);\n+\t\t\t\twhile (i + 2 < posn && \n+\t\t\t\t       !memcmp(data + i, \"../\", 3)) {\n+\t\t\t\t\tdo {\n+\t\t\t\t\t\tserverlen--;\n+\t\t\t\t\t} while (serverlen &&\n+\t\t\t\t\t\t base[serverlen - 1] != '/');\n+\t\t\t\t\ti += 3;\n+\t\t\t\t}\n+\t\t\t\t// If the server got removed, give up.\n+\t\t\t\tokay = strchr(base, ':') - base + 3 < \n+\t\t\t\t\tserverlen;\n+\t\t\t} else if (http_specific) {\n+\t\t\t\tchar *colon = strchr(data + i, ':');\n+\t\t\t\tchar *slash = strchr(data + i, '/');\n+\t\t\t\tif (colon && slash && colon < data + posn &&\n+\t\t\t\t    slash < data + posn && colon < slash) {\n+\t\t\t\t\tokay = 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\t// skip 'objects' at end\n+\t\t\tif (okay) {\n+\t\t\t\ttarget = xmalloc(serverlen + posn - i - 6);\n+\t\t\t\tstrncpy(target, base, serverlen);\n+\t\t\t\tstrncpy(target + serverlen, data + i,\n+\t\t\t\t\tposn - i - 7);\n+\t\t\t\ttarget[serverlen + posn - i - 7] = '\\0';\n+\t\t\t\tif (get_verbosely)\n+\t\t\t\t\tfprintf(stderr, \n+\t\t\t\t\t\t\"Also look at %s\\n\", target);\n+\t\t\t\tnewalt = xmalloc(sizeof(*newalt));\n+\t\t\t\tnewalt->next = alt;\n+\t\t\t\tnewalt->base = target;\n+\t\t\t\tnewalt->got_indices = 0;\n+\t\t\t\tnewalt->packs = NULL;\n+\t\t\t\talt = newalt;\n+\t\t\t\tret++;\n+\t\t\t}\n+\t\t}\n+\t\ti = posn + 1;\n+\t}\n+\tgot_alternates = 1;\n+\t\n+\treturn ret;\n+}\n+\n+static int fetch_indices(struct alt_base *repo)\n {\n \tunsigned char sha1[20];\n \tchar *url;\n@@ -137,7 +246,7 @@ static int fetch_indices(void)\n \tchar *data;\n \tint i = 0;\n \n-\tif (got_indices)\n+\tif (repo->got_indices)\n \t\treturn 0;\n \n \tdata = xmalloc(4096);\n@@ -148,8 +257,8 @@ static int fetch_indices(void)\n \tif (get_verbosely)\n \t\tfprintf(stderr, \"Getting pack list\\n\");\n \t\n-\turl = xmalloc(strlen(base) + 21);\n-\tsprintf(url, \"%s/objects/info/packs\", base);\n+\turl = xmalloc(strlen(repo->base) + 21);\n+\tsprintf(url, \"%s/objects/info/packs\", repo->base);\n \n \tcurl_easy_setopt(curl, CURLOPT_FILE, &buffer);\n \tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n@@ -157,10 +266,10 @@ static int fetch_indices(void)\n \tcurl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);\n \t\n \tif (curl_easy_perform(curl)) {\n-\t\treturn error(\"Unable to get pack index %s\", url);\n+\t\treturn -1;\n \t}\n \n-\tdo {\n+\twhile (i < buffer.posn) {\n \t\tswitch (data[i]) {\n \t\tcase 'P':\n \t\t\ti++;\n@@ -168,7 +277,7 @@ static int fetch_indices(void)\n \t\t\t    !strncmp(data + i, \" pack-\", 6) &&\n \t\t\t    !strncmp(data + i + 46, \".pack\\n\", 6)) {\n \t\t\t\tget_sha1_hex(data + i + 6, sha1);\n-\t\t\t\tsetup_index(sha1);\n+\t\t\t\tsetup_index(repo, sha1);\n \t\t\t\ti += 51;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -177,13 +286,13 @@ static int fetch_indices(void)\n \t\t\t\ti++;\n \t\t}\n \t\ti++;\n-\t} while (i < buffer.posn);\n+\t}\n \n-\tgot_indices = 1;\n+\trepo->got_indices = 1;\n \treturn 0;\n }\n \n-static int fetch_pack(unsigned char *sha1)\n+static int fetch_pack(struct alt_base *repo, unsigned char *sha1)\n {\n \tchar *url;\n \tstruct packed_git *target;\n@@ -191,12 +300,11 @@ static int fetch_pack(unsigned char *sha\n \tFILE *packfile;\n \tchar *filename;\n \n-\tif (fetch_indices())\n+\tif (fetch_indices(repo))\n \t\treturn -1;\n-\ttarget = find_sha1_pack(sha1, packs);\n+\ttarget = find_sha1_pack(sha1, repo->packs);\n \tif (!target)\n-\t\treturn error(\"Couldn't get %s: not separate or in any pack\",\n-\t\t\t     sha1_to_hex(sha1));\n+\t\treturn -1;\n \n \tif (get_verbosely) {\n \t\tfprintf(stderr, \"Getting pack %s\\n\",\n@@ -205,9 +313,9 @@ static int fetch_pack(unsigned char *sha\n \t\t\tsha1_to_hex(sha1));\n \t}\n \n-\turl = xmalloc(strlen(base) + 65);\n+\turl = xmalloc(strlen(repo->base) + 65);\n \tsprintf(url, \"%s/objects/pack/pack-%s.pack\",\n-\t\tbase, sha1_to_hex(target->sha1));\n+\t\trepo->base, sha1_to_hex(target->sha1));\n \n \tfilename = sha1_pack_name(target->sha1);\n \tpackfile = fopen(filename, \"w\");\n@@ -227,7 +335,7 @@ static int fetch_pack(unsigned char *sha\n \n \tfclose(packfile);\n \n-\tlst = &packs;\n+\tlst = &repo->packs;\n \twhile (*lst != target)\n \t\tlst = &((*lst)->next);\n \t*lst = (*lst)->next;\n@@ -237,7 +345,7 @@ static int fetch_pack(unsigned char *sha\n \treturn 0;\n }\n \n-int fetch(unsigned char *sha1)\n+int fetch_object(struct alt_base *repo, unsigned char *sha1)\n {\n \tchar *hex = sha1_to_hex(sha1);\n \tchar *filename = sha1_file_name(sha1);\n@@ -261,9 +369,9 @@ int fetch(unsigned char *sha1)\n \tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);\n \tcurl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);\n \n-\turl = xmalloc(strlen(base) + 50);\n-\tstrcpy(url, base);\n-\tposn = url + strlen(base);\n+\turl = xmalloc(strlen(repo->base) + 50);\n+\tstrcpy(url, repo->base);\n+\tposn = url + strlen(repo->base);\n \tstrcpy(posn, \"objects/\");\n \tposn += 8;\n \tmemcpy(posn, hex, 2);\n@@ -275,9 +383,7 @@ int fetch(unsigned char *sha1)\n \n \tif (curl_easy_perform(curl)) {\n \t\tunlink(filename);\n-\t\tif (fetch_pack(sha1))\n-\t\t\treturn error(\"Tried %s\", url);\n-\t\treturn 0;\n+\t\treturn -1;\n \t}\n \n \tclose(local);\n@@ -296,11 +402,30 @@ int fetch(unsigned char *sha1)\n \treturn 0;\n }\n \n+int fetch(unsigned char *sha1)\n+{\n+\tstruct alt_base *altbase = alt;\n+\twhile (altbase) {\n+\t\tif (!fetch_object(altbase, sha1))\n+\t\t\treturn 0;\n+\t\tif (!fetch_pack(altbase, sha1))\n+\t\t\treturn 0;\n+\t\tif (fetch_alternates(altbase->base) > 0) {\n+\t\t\taltbase = alt;\n+\t\t\tcontinue;\n+\t\t}\n+\t\taltbase = altbase->next;\n+\t}\n+\treturn error(\"Unable to find %s under %s\\n\", sha1_to_hex(sha1), \n+\t\t     initial_base);\n+}\n+\n int fetch_ref(char *ref, unsigned char *sha1)\n {\n         char *url, *posn;\n         char hex[42];\n         struct buffer buffer;\n+\tchar *base = initial_base;\n         buffer.size = 41;\n         buffer.posn = 0;\n         buffer.buffer = hex;\n@@ -368,7 +493,12 @@ int main(int argc, char **argv)\n \tcurl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);\n #endif\n \n-\tbase = url;\n+\talt = xmalloc(sizeof(*alt));\n+\talt->base = url;\n+\talt->got_indices = 0;\n+\talt->packs = NULL;\n+\talt->next = NULL;\n+\tinitial_base = url;\n \n \tif (pull(commit_id))\n \t\treturn 1;\n"}]}