{"thread":{"id":"4094","subject":"[PATCH] Transitively read alternatives","startedAt":"2006-05-07T18:19:21Z","lastAt":"2006-05-07T18:28:25Z","messageCount":2,"participants":["Martin Waitz","Jakub Narebski"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"19657","messageId":"20060507181920.GC23738@admingilde.org","threadId":"4094","inReplyTo":null,"subject":"[PATCH] Transitively read alternatives","fromName":"Martin Waitz","fromEmail":"tali@admingilde.org","sentAt":"2006-05-07T18:19:21Z","receivedAt":"2006-05-07T18:19:21Z","isPatch":true,"sender":{"key":"tali@admingilde.org","avatar":"https://gravatar.com/avatar/3f89b03eee362187effabe257898735b475673a12265c398ea9161259ae91553?d=mp&s=160"},"body":"When adding an alternate object store then add entries from its\ninfo/alternates files, too.\nRelative entries are only allowed in the current repository.\nLoops and duplicate alternates through multiple repositories are ignored.\nJust to be sure that nothing breaks it is not allow to build deep\nnesting levels using info/alternates.\n\nSigned-off-by: Martin Waitz <tali@admingilde.org>\n\n---\n\n sha1_file.c |  178 +++++++++++++++++++++++++++++++++++------------------------\n 1 files changed, 106 insertions(+), 72 deletions(-)\n\n34981f5467a86bb09120cc3c9637b98048fada04\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 5464828..b62d0e3 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -217,6 +217,8 @@ char *sha1_pack_index_name(const unsigne\n struct alternate_object_database *alt_odb_list;\n static struct alternate_object_database **alt_odb_tail;\n \n+static void read_info_alternates(const char * alternates, int depth);\n+\n /*\n  * Prepare alternate object database registry.\n  *\n@@ -232,14 +234,85 @@ static struct alternate_object_database \n  * SHA1, an extra slash for the first level indirection, and the\n  * terminating NUL.\n  */\n-static void link_alt_odb_entries(const char *alt, const char *ep, int sep,\n-\t\t\t\t const char *relative_base)\n+static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)\n {\n-\tconst char *cp, *last;\n-\tstruct alternate_object_database *ent;\n+\tstruct stat st;\n \tconst char *objdir = get_object_directory();\n+\tstruct alternate_object_database *ent;\n+\tstruct alternate_object_database *alt;\n+\t/* 43 = 40-byte + 2 '/' + terminating NUL */\n+\tint pfxlen = len;\n+\tint entlen = pfxlen + 43;\n \tint base_len = -1;\n \n+\tif (*entry != '/' && relative_base) {\n+\t\t/* Relative alt-odb */\n+\t\tif (base_len < 0)\n+\t\t\tbase_len = strlen(relative_base) + 1;\n+\t\tentlen += base_len;\n+\t\tpfxlen += base_len;\n+\t}\n+\tent = xmalloc(sizeof(*ent) + entlen);\n+\n+\tif (*entry != '/' && relative_base) {\n+\t\tmemcpy(ent->base, relative_base, base_len - 1);\n+\t\tent->base[base_len - 1] = '/';\n+\t\tmemcpy(ent->base + base_len, entry, len);\n+\t}\n+\telse\n+\t\tmemcpy(ent->base, entry, pfxlen);\n+\n+\tent->name = ent->base + pfxlen + 1;\n+\tent->base[pfxlen + 3] = '/';\n+\tent->base[pfxlen] = ent->base[entlen-1] = 0;\n+\n+\t/* Detect cases where alternate disappeared */\n+\tif (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {\n+\t\terror(\"object directory %s does not exist; \"\n+\t\t      \"check .git/objects/info/alternates.\",\n+\t\t      ent->base);\n+\t\tfree(ent);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Prevent the common mistake of listing the same\n+\t * thing twice, or object directory itself.\n+\t */\n+\tfor (alt = alt_odb_list; alt; alt = alt->next) {\n+\t\tif (!memcmp(ent->base, alt->base, pfxlen)) {\n+\t\t\tfree(ent);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tif (!memcmp(ent->base, objdir, pfxlen)) {\n+\t\tfree(ent);\n+\t\treturn -1;\n+\t}\n+\n+\t/* add the alternate entry */\n+\t*alt_odb_tail = ent;\n+\talt_odb_tail = &(ent->next);\n+\tent->next = NULL;\n+\n+\t/* recursively add alternates */\n+\tread_info_alternates(ent->base, depth + 1);\n+\n+\tent->base[pfxlen] = '/';\n+\n+\treturn 0;\n+}\n+\n+static void link_alt_odb_entries(const char *alt, const char *ep, int sep,\n+\t\t\t\t const char *relative_base, int depth)\n+{\n+\tconst char *cp, *last;\n+\n+\tif (depth > 5) {\n+\t\terror(\"%s: ignoring alternate object stores, nesting too deep.\",\n+\t\t\t\trelative_base);\n+\t\treturn;\n+\t}\n+\n \tlast = alt;\n \twhile (last < ep) {\n \t\tcp = last;\n@@ -249,60 +322,15 @@ static void link_alt_odb_entries(const c\n \t\t\tlast = cp + 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tfor ( ; cp < ep && *cp != sep; cp++)\n-\t\t\t;\n+\t\twhile (cp < ep && *cp != sep)\n+\t\t\tcp++;\n \t\tif (last != cp) {\n-\t\t\tstruct stat st;\n-\t\t\tstruct alternate_object_database *alt;\n-\t\t\t/* 43 = 40-byte + 2 '/' + terminating NUL */\n-\t\t\tint pfxlen = cp - last;\n-\t\t\tint entlen = pfxlen + 43;\n-\n-\t\t\tif (*last != '/' && relative_base) {\n-\t\t\t\t/* Relative alt-odb */\n-\t\t\t\tif (base_len < 0)\n-\t\t\t\t\tbase_len = strlen(relative_base) + 1;\n-\t\t\t\tentlen += base_len;\n-\t\t\t\tpfxlen += base_len;\n-\t\t\t}\n-\t\t\tent = xmalloc(sizeof(*ent) + entlen);\n-\n-\t\t\tif (*last != '/' && relative_base) {\n-\t\t\t\tmemcpy(ent->base, relative_base, base_len - 1);\n-\t\t\t\tent->base[base_len - 1] = '/';\n-\t\t\t\tmemcpy(ent->base + base_len,\n-\t\t\t\t       last, cp - last);\n-\t\t\t}\n-\t\t\telse\n-\t\t\t\tmemcpy(ent->base, last, pfxlen);\n-\n-\t\t\tent->name = ent->base + pfxlen + 1;\n-\t\t\tent->base[pfxlen + 3] = '/';\n-\t\t\tent->base[pfxlen] = ent->base[entlen-1] = 0;\n-\n-\t\t\t/* Detect cases where alternate disappeared */\n-\t\t\tif (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {\n-\t\t\t\terror(\"object directory %s does not exist; \"\n-\t\t\t\t      \"check .git/objects/info/alternates.\",\n-\t\t\t\t      ent->base);\n-\t\t\t\tgoto bad;\n-\t\t\t}\n-\t\t\tent->base[pfxlen] = '/';\n-\n-\t\t\t/* Prevent the common mistake of listing the same\n-\t\t\t * thing twice, or object directory itself.\n-\t\t\t */\n-\t\t\tfor (alt = alt_odb_list; alt; alt = alt->next)\n-\t\t\t\tif (!memcmp(ent->base, alt->base, pfxlen))\n-\t\t\t\t\tgoto bad;\n-\t\t\tif (!memcmp(ent->base, objdir, pfxlen)) {\n-\t\t\tbad:\n-\t\t\t\tfree(ent);\n-\t\t\t}\n-\t\t\telse {\n-\t\t\t\t*alt_odb_tail = ent;\n-\t\t\t\talt_odb_tail = &(ent->next);\n-\t\t\t\tent->next = NULL;\n+\t\t\tif ((*last != '/') && depth) {\n+\t\t\t\terror(\"%s: ignoring relative alternate object store %s\",\n+\t\t\t\t\t\trelative_base, last);\n+\t\t\t} else {\n+\t\t\t\tlink_alt_odb_entry(last, cp - last,\n+\t\t\t\t\t\trelative_base, depth);\n \t\t\t}\n \t\t}\n \t\twhile (cp < ep && *cp == sep)\n@@ -311,23 +339,14 @@ static void link_alt_odb_entries(const c\n \t}\n }\n \n-void prepare_alt_odb(void)\n+static void read_info_alternates(const char * relative_base, int depth)\n {\n-\tchar path[PATH_MAX];\n \tchar *map;\n-\tint fd;\n \tstruct stat st;\n-\tchar *alt;\n-\n-\talt = getenv(ALTERNATE_DB_ENVIRONMENT);\n-\tif (!alt) alt = \"\";\n-\n-\tif (alt_odb_tail)\n-\t\treturn;\n-\talt_odb_tail = &alt_odb_list;\n-\tlink_alt_odb_entries(alt, alt + strlen(alt), ':', NULL);\n+\tchar path[PATH_MAX];\n+\tint fd;\n \n-\tsprintf(path, \"%s/info/alternates\", get_object_directory());\n+\tsprintf(path, \"%s/info/alternates\", relative_base);\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n \t\treturn;\n@@ -340,11 +359,26 @@ void prepare_alt_odb(void)\n \tif (map == MAP_FAILED)\n \t\treturn;\n \n-\tlink_alt_odb_entries(map, map + st.st_size, '\\n',\n-\t\t\t     get_object_directory());\n+\tlink_alt_odb_entries(map, map + st.st_size, '\\n', relative_base, depth);\n+\n \tmunmap(map, st.st_size);\n }\n \n+void prepare_alt_odb(void)\n+{\n+\tchar *alt;\n+\n+\talt = getenv(ALTERNATE_DB_ENVIRONMENT);\n+\tif (!alt) alt = \"\";\n+\n+\tif (alt_odb_tail)\n+\t\treturn;\n+\talt_odb_tail = &alt_odb_list;\n+\tlink_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);\n+\n+\tread_info_alternates(get_object_directory(), 0);\n+}\n+\n static char *find_sha1_file(const unsigned char *sha1, struct stat *st)\n {\n \tchar *name = sha1_file_name(sha1);\n-- \n1.3.1.g6ef7\n"},{"id":"19660","messageId":"e3le7q$eli$1@sea.gmane.org","threadId":"4094","inReplyTo":"20060507181920.GC23738@admingilde.org","subject":"Re: [PATCH] Transitively read alternatives","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-05-07T18:28:25Z","receivedAt":"2006-05-07T18:28:25Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Martin Waitz wrote:\n\n> When adding an alternate object store then add entries from its\n> info/alternates files, too.\n> Relative entries are only allowed in the current repository.\n> Loops and duplicate alternates through multiple repositories are ignored.\n> Just to be sure that nothing breaks it is not allow to build deep\n> nesting levels using info/alternates.\n\n> +     if (depth > 5) {\n> +             error(\"%s: ignoring alternate object stores, nesting too deep.\",\n> +                             relative_base);\n> +             return;\n> +     }\n\nPlease, no magic numbers. Use preprocesor \"constants\" for that.\n\n-- \nJakub Narebski\nWarsaw, Poland\n"}]}