{"thread":{"id":"17320","subject":"[PATCH 2/7] replace_object: add mechanism to replace objects found in \"refs/replace/\"","startedAt":"2009-01-23T09:06:53Z","lastAt":"2009-01-23T09:06:53Z","messageCount":1,"participants":["Christian Couder"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"101637","messageId":"20090123100653.bc6311ae.chriscool@tuxfamily.org","threadId":"17320","inReplyTo":null,"subject":"[PATCH 2/7] replace_object: add mechanism to replace objects found in \"refs/replace/\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-01-23T09:06:53Z","receivedAt":"2009-01-23T09:06:53Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"The code implementing this mechanism has been copied from the commit\ngraft code.\n\nThis mechanism is used in \"read_sha1_file\". sha1 passed to this\nfunction that match a ref name in \"refs/replace/\" are replaced by\nthe sha1 that has been read in the ref.\n\nWe \"die\" if the replacement recursion depth is too high or if we\ncan't read the replacement object.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Makefile         |    1 +\n commit.h         |    2 +\n replace_object.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n sha1_file.c      |   14 +++++-\n 4 files changed, 131 insertions(+), 3 deletions(-)\n create mode 100644 replace_object.c\n\ndiff --git a/Makefile b/Makefile\nindex fa6c51c..953638f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -471,6 +471,7 @@ LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += remote.o\n+LIB_OBJS += replace_object.o\n LIB_OBJS += rerere.o\n LIB_OBJS += revision.o\n LIB_OBJS += run-command.o\ndiff --git a/commit.h b/commit.h\nindex 3a7b06a..37aa763 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -122,6 +122,8 @@ struct commit_graft *read_graft_line(char *buf, int len);\n int register_commit_graft(struct commit_graft *, int);\n struct commit_graft *lookup_commit_graft(const unsigned char *sha1);\n \n+const unsigned char *lookup_replace_object(const unsigned char *sha1);\n+\n extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);\n extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);\n extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);\ndiff --git a/replace_object.c b/replace_object.c\nnew file mode 100644\nindex 0000000..5b973ba\n--- /dev/null\n+++ b/replace_object.c\n@@ -0,0 +1,117 @@\n+#include \"cache.h\"\n+#include \"refs.h\"\n+\n+static struct replace_object {\n+\tunsigned char sha1[2][20];\n+} **replace_object;\n+\n+static int replace_object_alloc, replace_object_nr;\n+\n+static int replace_object_pos(const unsigned char *sha1)\n+{\n+\tint lo, hi;\n+\tlo = 0;\n+\thi = replace_object_nr;\n+\twhile (lo < hi) {\n+\t\tint mi = (lo + hi) / 2;\n+\t\tstruct replace_object *rep = replace_object[mi];\n+\t\tint cmp = hashcmp(sha1, rep->sha1[0]);\n+\t\tif (!cmp)\n+\t\t\treturn mi;\n+\t\tif (cmp < 0)\n+\t\t\thi = mi;\n+\t\telse\n+\t\t\tlo = mi + 1;\n+\t}\n+\treturn -lo - 1;\n+}\n+\n+static int register_replace_object(struct replace_object *replace,\n+\t\t\t\t   int ignore_dups)\n+{\n+\tint pos = replace_object_pos(replace->sha1[0]);\n+\n+\tif (0 <= pos) {\n+\t\tif (ignore_dups)\n+\t\t\tfree(replace);\n+\t\telse {\n+\t\t\tfree(replace_object[pos]);\n+\t\t\treplace_object[pos] = replace;\n+\t\t}\n+\t\treturn 1;\n+\t}\n+\tpos = -pos - 1;\n+\tif (replace_object_alloc <= ++replace_object_nr) {\n+\t\treplace_object_alloc = alloc_nr(replace_object_alloc);\n+\t\treplace_object = xrealloc(replace_object,\n+\t\t\t\t\t  sizeof(*replace_object) *\n+\t\t\t\t\t  replace_object_alloc);\n+\t}\n+\tif (pos < replace_object_nr)\n+\t\tmemmove(replace_object + pos + 1,\n+\t\t\treplace_object + pos,\n+\t\t\t(replace_object_nr - pos - 1) *\n+\t\t\tsizeof(*replace_object));\n+\treplace_object[pos] = replace;\n+\treturn 0;\n+}\n+\n+static int register_replace_ref(const char *refname,\n+\t\t\t\tconst unsigned char *sha1,\n+\t\t\t\tint flag, void *cb_data)\n+{\n+\t/* Get sha1 from refname */\n+\tconst char *slash = strrchr(refname, '/');\n+\tconst char *hash = slash ? slash + 1 : refname;\n+\tstruct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));\n+\n+\tif (strlen(hash) != 40 || get_sha1_hex(hash, repl_obj->sha1[0])) {\n+\t\tfree(repl_obj);\n+\t\twarning(\"bad replace ref name: %s\", refname);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Copy sha1 from the read ref */\n+\thashcpy(repl_obj->sha1[1], sha1);\n+\n+\t/* Register new object */\n+\tif (register_replace_object(repl_obj, 1))\n+\t\tdie(\"duplicate replace ref: %s\", refname);\n+\n+\treturn 0;\n+}\n+\n+static void prepare_replace_object(void)\n+{\n+\tstatic int replace_object_prepared;\n+\n+\tif (replace_object_prepared)\n+\t\treturn;\n+\n+\tfor_each_replace_ref(register_replace_ref, NULL);\n+\treplace_object_prepared = 1;\n+}\n+\n+/* We allow \"recursive\" replacement. Only within reason, though */\n+#define MAXREPLACEDEPTH 5\n+\n+const unsigned char *lookup_replace_object(const unsigned char *sha1)\n+{\n+\tint pos, depth = MAXREPLACEDEPTH;\n+\tconst unsigned char *cur = sha1;\n+\n+\tprepare_replace_object();\n+\n+\t/* Try to recursively replace the object */\n+\tdo {\n+\t\tif (--depth < 0)\n+\t\t\tdie(\"replace depth too high for object %s\",\n+\t\t\t    sha1_to_hex(sha1));\n+\n+\t\tpos = replace_object_pos(cur);\n+\t\tif (0 <= pos)\n+\t\t\tcur = replace_object[pos]->sha1[1];\n+\t} while (0 <= pos);\n+\n+\treturn cur;\n+}\ndiff --git a/sha1_file.c b/sha1_file.c\nindex f08493f..4f2fd10 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -2163,10 +2163,18 @@ static void *read_object(const unsigned char *sha1, enum object_type *type,\n void *read_sha1_file(const unsigned char *sha1, enum object_type *type,\n \t\t     unsigned long *size)\n {\n-\tvoid *data = read_object(sha1, type, size);\n+\tconst unsigned char *repl = lookup_replace_object(sha1);\n+\tvoid *data = read_object(repl, type, size);\n+\n+\t/* die if we replaced an object with one that does not exist */\n+\tif (!data && repl != sha1)\n+\t\tdie(\"replacement %s not found for %s\",\n+\t\t    sha1_to_hex(repl), sha1_to_hex(sha1));\n+\n \t/* legacy behavior is to die on corrupted objects */\n-\tif (!data && (has_loose_object(sha1) || has_packed_and_bad(sha1)))\n-\t\tdie(\"object %s is corrupted\", sha1_to_hex(sha1));\n+\tif (!data && (has_loose_object(repl) || has_packed_and_bad(repl)))\n+\t\tdie(\"object %s is corrupted\", sha1_to_hex(repl));\n+\n \treturn data;\n }\n \n-- \n1.6.1.231.g9c286\n"}]}