@matheusbsbs / matheus-bagliano / commits / 6809557029
Fork 0

replace_object: add mechanism to replace objects found in "refs/replace/"

The code implementing this mechanism has been copied more-or-less from the commit graft code. This mechanism is used in "read_sha1_file". sha1 passed to this function that match a ref name in "refs/replace/" are replaced by the sha1 that has been read in the ref. We "die" if the replacement recursion depth is too high or if we can't read the replacement object. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed Jan 23, 2009 at 10:06 UTC 680955702990c1d4bfb3c6feed6ae9c6cb5c3c07
4 files changed +125 -3
Makefile
+1
@@ -512,6 +512,7 @@ LIB_OBJS += read-cache.o
512 LIB_OBJS += reflog-walk.o
513 LIB_OBJS += refs.o
514 LIB_OBJS += remote.o
515 +LIB_OBJS += replace_object.o
516 LIB_OBJS += rerere.o
517 LIB_OBJS += revision.o
518 LIB_OBJS += run-command.o
commit.h
+2
@@ -124,6 +124,8 @@ struct commit_graft *read_graft_line(char *buf, int len);
124 int register_commit_graft(struct commit_graft *, int);
125 struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
126
127 +const unsigned char *lookup_replace_object(const unsigned char *sha1);
128 +
129 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
130 extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
131 extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
replace_object.c new
+111
@@ -0,0 +1,111 @@
1 +#include "cache.h"
2 +#include "sha1-lookup.h"
3 +#include "refs.h"
4 +
5 +static struct replace_object {
6 + unsigned char sha1[2][20];
7 +} **replace_object;
8 +
9 +static int replace_object_alloc, replace_object_nr;
10 +
11 +static const unsigned char *replace_sha1_access(size_t index, void *table)
12 +{
13 + struct replace_object **replace = table;
14 + return replace[index]->sha1[0];
15 +}
16 +
17 +static int replace_object_pos(const unsigned char *sha1)
18 +{
19 + return sha1_pos(sha1, replace_object, replace_object_nr,
20 + replace_sha1_access);
21 +}
22 +
23 +static int register_replace_object(struct replace_object *replace,
24 + int ignore_dups)
25 +{
26 + int pos = replace_object_pos(replace->sha1[0]);
27 +
28 + if (0 <= pos) {
29 + if (ignore_dups)
30 + free(replace);
31 + else {
32 + free(replace_object[pos]);
33 + replace_object[pos] = replace;
34 + }
35 + return 1;
36 + }
37 + pos = -pos - 1;
38 + if (replace_object_alloc <= ++replace_object_nr) {
39 + replace_object_alloc = alloc_nr(replace_object_alloc);
40 + replace_object = xrealloc(replace_object,
41 + sizeof(*replace_object) *
42 + replace_object_alloc);
43 + }
44 + if (pos < replace_object_nr)
45 + memmove(replace_object + pos + 1,
46 + replace_object + pos,
47 + (replace_object_nr - pos - 1) *
48 + sizeof(*replace_object));
49 + replace_object[pos] = replace;
50 + return 0;
51 +}
52 +
53 +static int register_replace_ref(const char *refname,
54 + const unsigned char *sha1,
55 + int flag, void *cb_data)
56 +{
57 + /* Get sha1 from refname */
58 + const char *slash = strrchr(refname, '/');
59 + const char *hash = slash ? slash + 1 : refname;
60 + struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));
61 +
62 + if (strlen(hash) != 40 || get_sha1_hex(hash, repl_obj->sha1[0])) {
63 + free(repl_obj);
64 + warning("bad replace ref name: %s", refname);
65 + return 0;
66 + }
67 +
68 + /* Copy sha1 from the read ref */
69 + hashcpy(repl_obj->sha1[1], sha1);
70 +
71 + /* Register new object */
72 + if (register_replace_object(repl_obj, 1))
73 + die("duplicate replace ref: %s", refname);
74 +
75 + return 0;
76 +}
77 +
78 +static void prepare_replace_object(void)
79 +{
80 + static int replace_object_prepared;
81 +
82 + if (replace_object_prepared)
83 + return;
84 +
85 + for_each_replace_ref(register_replace_ref, NULL);
86 + replace_object_prepared = 1;
87 +}
88 +
89 +/* We allow "recursive" replacement. Only within reason, though */
90 +#define MAXREPLACEDEPTH 5
91 +
92 +const unsigned char *lookup_replace_object(const unsigned char *sha1)
93 +{
94 + int pos, depth = MAXREPLACEDEPTH;
95 + const unsigned char *cur = sha1;
96 +
97 + prepare_replace_object();
98 +
99 + /* Try to recursively replace the object */
100 + do {
101 + if (--depth < 0)
102 + die("replace depth too high for object %s",
103 + sha1_to_hex(sha1));
104 +
105 + pos = replace_object_pos(cur);
106 + if (0 <= pos)
107 + cur = replace_object[pos]->sha1[1];
108 + } while (0 <= pos);
109 +
110 + return cur;
111 +}
sha1_file.c
+11 -3
@@ -2148,10 +2148,18 @@ static void *read_object(const unsigned char *sha1, enum object_type *type,
2148 void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
2149 unsigned long *size)
2150 {
2151 - void *data = read_object(sha1, type, size);
2151 + const unsigned char *repl = lookup_replace_object(sha1);
2152 + void *data = read_object(repl, type, size);
2153 +
2154 + /* die if we replaced an object with one that does not exist */
2155 + if (!data && repl != sha1)
2156 + die("replacement %s not found for %s",
2157 + sha1_to_hex(repl), sha1_to_hex(sha1));
2158 +
2159 /* legacy behavior is to die on corrupted objects */
2153 - if (!data && (has_loose_object(sha1) || has_packed_and_bad(sha1)))
2154 - die("object %s is corrupted", sha1_to_hex(sha1));
2160 + if (!data && (has_loose_object(repl) || has_packed_and_bad(repl)))
2161 + die("object %s is corrupted", sha1_to_hex(repl));
2162 +
2163 return data;
2164 }
2165