{"thread":{"id":"3051","subject":"[PATCH] convert-packs: futureproofing.","startedAt":"2006-01-12T00:05:15Z","lastAt":"2006-01-12T00:05:15Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"14518","messageId":"7voe2ijop0.fsf@assigned-by-dhcp.cox.net","threadId":"3051","inReplyTo":null,"subject":"[PATCH] convert-packs: futureproofing.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-12T00:05:15Z","receivedAt":"2006-01-12T00:05:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Names of packfiles are informally expected to be of the form\n\"pack-[0-9a-f]{40}.pack\", with corresponding .idx file (the\ncore-level only requires the files are named \".pack\" and \".idx\"\nrespectively).\n\nThe hexadecimal part should be what git-pack-objects computed\nwhen the pack was created originally, and it is the SHA1 sum\nover sorted object names (i.e. 20-byte binary SHA1 checksum\neach).  However, git-pack-objects before v0.99.9 computed a\nchecksum over object names without sorting (i.e. the order\ngit-rev-list fed the object names), just to make pack names\nunlikely to collide.  The current git-pack-objects computes the\nchecksum differently, so that two packfiles that contain the\nsame set of objects are always given the same name.  This was\ndone so that we can use the filename as an additional way to\nverify the integrity of the pack.\n\nMany packfiles in the wild were created with git before v0.99.9,\nand they will fail this verification.  The new command\ngit-convert-packs can be used to rename them to a name that\nwould have been given by git-pack-objects post v0.99.9.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n * Currently in \"pu\".\n\n .gitignore                          |    1 \n Documentation/git-convert-packs.txt |   41 +++++++++++++++++\n Makefile                            |    2 -\n convert-packs.c                     |   86 +++++++++++++++++++++++++++++++++++\n 4 files changed, 129 insertions(+), 1 deletions(-)\n create mode 100644 Documentation/git-convert-packs.txt\n create mode 100644 convert-packs.c\n\n004e17155fe0a739857851cffc5efd3407af389c\ndiff --git a/.gitignore b/.gitignore\nindex 1a9090b..0d50843 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -19,6 +19,7 @@ git-clone-pack\n git-commit\n git-commit-tree\n git-convert-objects\n+git-convert-packs\n git-count-objects\n git-cvsexportcommit\n git-cvsimport\ndiff --git a/Documentation/git-convert-packs.txt b/Documentation/git-convert-packs.txt\nnew file mode 100644\nindex 0000000..ba02641\n--- /dev/null\n+++ b/Documentation/git-convert-packs.txt\n@@ -0,0 +1,41 @@\n+git-convert-packs(1)\n+====================\n+\n+NAME\n+----\n+git-convert-packs - Renames packfiles created with pre 0.99.9 GIT\n+\n+\n+SYNOPSIS\n+--------\n+'git-convert-packs'\n+\n+DESCRIPTION\n+-----------\n+Older git-pack-objects named the resulting packfile with an SHA1\n+hash of the object names without sorting them first (i.e. random\n+unverifiable order), which meant that two packfiles that contain\n+the same set of objects can be named differently.  To make\n+packfile reliably verifiable, future versions of GIT will\n+require that the name of the packfile to match the SHA1 hash of\n+the object names contained within, after sorting them, and will\n+ignore packfiles whose names do not verify.\n+\n+This command takes no parameter; it inspects packfiles in the\n+local repository, and renames the ones whose names do not match\n+their contents.  You need to rename older packfiles using this\n+command before GIT starts complaining.\n+\n+\n+Author\n+------\n+Written by Junio C Hamano <junkio@cox.net>\n+\n+Documentation\n+--------------\n+Documentation by the git-list <git@vger.kernel.org>.\n+\n+GIT\n+---\n+Part of the gitlink:git[7] suite\n+\ndiff --git a/Makefile b/Makefile\nindex fa0cd83..6d5f293 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -123,7 +123,7 @@ SIMPLE_PROGRAMS = \\\n PROGRAMS = \\\n \tgit-apply$X git-cat-file$X \\\n \tgit-checkout-index$X git-clone-pack$X git-commit-tree$X \\\n-\tgit-convert-objects$X git-diff-files$X \\\n+\tgit-convert-objects$X git-convert-packs$X git-diff-files$X \\\n \tgit-diff-index$X git-diff-stages$X \\\n \tgit-diff-tree$X git-fetch-pack$X git-fsck-objects$X \\\n \tgit-hash-object$X git-index-pack$X git-init-db$X \\\ndiff --git a/convert-packs.c b/convert-packs.c\nnew file mode 100644\nindex 0000000..754599d\n--- /dev/null\n+++ b/convert-packs.c\n@@ -0,0 +1,86 @@\n+#include \"cache.h\"\n+\n+static int verify_pack_name(struct packed_git *p)\n+{\n+\tSHA_CTX ctx;\n+\tunsigned char sha1[20];\n+\tint i, nr, len, bad;\n+\tconst char *hex;\n+\tchar *base_name;\n+\n+\tnr = num_packed_objects(p);\n+\n+\tSHA1_Init(&ctx);\n+\tfor (i = 0; i < nr; i++) {\n+\t\tunsigned char *ent = (((unsigned char *)p->index_base) +\n+\t\t\t\t      4*256 + i * 24 + 4);\n+\t\tSHA1_Update(&ctx, ent, 20);\n+\t}\n+\tSHA1_Final(sha1, &ctx);\n+\thex = sha1_to_hex(sha1);\n+\t\n+\tbase_name = strrchr(p->pack_name, '/');\n+\tif (base_name)\n+\t\tbase_name++;\n+\telse\n+\t\tbase_name = p->pack_name;\n+\n+\tbad = 0;\n+\t/* We require \"pack-X{40}.pack\" these days before mapping\n+\t * the idx file, so the first two conditions of the if()\n+\t * statement are always false.\n+\t */\n+\tlen = strlen(base_name);\n+\tif ((len != 50) ||\n+\t    memcmp(base_name, \"pack-\", 5) ||\n+\t    memcmp(base_name + 5, hex, 40)) {\n+\t\tchar *newname;\n+\t\tint newlen;\n+\n+\t\tfprintf(stderr, \"pack '%s' does not match contents '%s'\\n\",\n+\t\t\tbase_name, hex);\n+\t\tnewname = xmalloc(base_name - p->pack_name + 52);\n+\t\tif (base_name != p->pack_name)\n+\t\t\tsprintf(newname, \"%.*spack-%s.pack\",\n+\t\t\t\t(base_name - p->pack_name), p->pack_name, hex);\n+\t\telse\n+\t\t\tsprintf(newname, \"pack-%s.pack\", hex);\n+\t\tnewlen = strlen(newname);\n+\n+\t\t/* Make sure there is no such pack and idx first. */\n+\t\tif (!access(newname, F_OK))\n+\t\t\treturn error(\"But there is a pack with that name!\");\n+\n+\t\tmemcpy(newname + newlen - 5, \".idx\", 5);\n+\t\tif (!access(newname, F_OK))\n+\t\t\treturn error(\"But there is an idx with that name!\");\n+\n+\t\tmemcpy(newname + newlen - 5, \".pack\", 5);\n+\t\tif (rename(p->pack_name, newname))\n+\t\t\treturn error(\"But the pack cannot renamed somehow!\");\n+\n+\t\t/* Now we have renamed the pack, so let's rename the index */\n+\t\tmemcpy(base_name + len - 5, \".idx\", 5);\n+\t\tmemcpy(newname + newlen - 5, \".idx\", 5);\n+\n+\t\tif (!access(newname, F_OK))\n+\t\t\treturn error(\"But there is an idx with that name!\");\n+\t\telse if (rename(p->pack_name, newname))\n+\t\t\treturn error(\"But the idx cannot be renamed somehow!\");\n+\n+\t\tfprintf(stderr, \"... renamed successfully.\\n\");\n+\t}\n+\treturn bad;\n+}\n+\n+int main(int ac, char **av)\n+{\n+\tstruct packed_git *p;\n+\n+\tsetup_git_directory();\n+\tprepare_packed_git();\n+\tfor (p = packed_git; p; p = p->next)\n+\t\tif (p->pack_local)\n+\t\t\tverify_pack_name(p);\n+\treturn 0;\n+}\n-- \n1.1.1-g8ecb\n"}]}