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

unpack-objects: fix --strict handling

Earlier attempt (which was reverted) called added_object() (by the way, the function should be renamed to resolve_dependents() --- it is called when we have a complete object data, and is responsible to resolve pending deltified objects that use this object as their delta base object) without updating obj_list[nr].sha1 with the correct value. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Mar 4, 2008 at 23:46 UTC f2898cfadc85c763a4b8299ab833a2c733c8467a
2 files changed +58 -17
builtin-unpack-objects.c
+57 -16
@@ -21,6 +21,11 @@ static unsigned int offset, len;
21 static off_t consumed_bytes;
22 static SHA_CTX ctx;
23
24 +/*
25 + * When running under --strict mode, objects whose reachability are
26 + * suspect are kept in core without getting written in the object
27 + * store.
28 + */
29 struct obj_buffer {
30 char *buffer;
31 unsigned long size;
@@ -155,6 +160,10 @@ struct obj_info {
160 static struct obj_info *obj_list;
161 unsigned nr_objects;
162
163 +/*
164 + * Called only from check_object() after it verified this object
165 + * is Ok.
166 + */
167 static void write_cached_object(struct object *obj)
168 {
169 unsigned char sha1[20];
@@ -164,6 +173,11 @@ static void write_cached_object(struct object *obj)
173 obj->flags |= FLAG_WRITTEN;
174 }
175
176 +/*
177 + * At the very end of the processing, write_rest() scans the objects
178 + * that have reachability requirements and calls this function.
179 + * Verify its reachability and validity recursively and write it out.
180 + */
181 static int check_object(struct object *obj, int type, void *data)
182 {
183 if (!obj)
@@ -202,19 +216,25 @@ static void write_rest(void)
216 static void added_object(unsigned nr, enum object_type type,
217 void *data, unsigned long size);
218
219 +/*
220 + * Write out nr-th object from the list, now we know the contents
221 + * of it. Under --strict, this buffers structured objects in-core,
222 + * to be checked at the end.
223 + */
224 static void write_object(unsigned nr, enum object_type type,
225 void *buf, unsigned long size)
226 {
208 - added_object(nr, type, buf, size);
227 if (!strict) {
228 if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
229 die("failed to write object");
230 + added_object(nr, type, buf, size);
231 free(buf);
213 - obj_list[nr].obj = 0;
232 + obj_list[nr].obj = NULL;
233 } else if (type == OBJ_BLOB) {
234 struct blob *blob;
235 if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
236 die("failed to write object");
237 + added_object(nr, type, buf, size);
238 free(buf);
239
240 blob = lookup_blob(obj_list[nr].sha1);
@@ -222,15 +242,15 @@ static void write_object(unsigned nr, enum object_type type,
242 blob->object.flags |= FLAG_WRITTEN;
243 else
244 die("invalid blob object");
225 - obj_list[nr].obj = 0;
245 + obj_list[nr].obj = NULL;
246 } else {
247 struct object *obj;
248 int eaten;
249 hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
250 + added_object(nr, type, buf, size);
251 obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
252 if (!obj)
253 die("invalid %s", typename(type));
233 - /* buf is stored via add_object_buffer and in obj, if its a tree or commit */
254 add_object_buffer(obj, buf, size);
255 obj->flags |= FLAG_OPEN;
256 obj_list[nr].obj = obj;
@@ -253,6 +273,10 @@ static void resolve_delta(unsigned nr, enum object_type type,
273 write_object(nr, type, result, result_size);
274 }
275
276 +/*
277 + * We now know the contents of an object (which is nr-th in the pack);
278 + * resolve all the deltified objects that are based on it.
279 + */
280 static void added_object(unsigned nr, enum object_type type,
281 void *data, unsigned long size)
282 {
@@ -284,13 +308,28 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
308 free(buf);
309 }
310
311 +static int resolve_against_held(unsigned nr, const unsigned char *base,
312 + void *delta_data, unsigned long delta_size)
313 +{
314 + struct object *obj;
315 + struct obj_buffer *obj_buffer;
316 + obj = lookup_object(base);
317 + if (!obj)
318 + return 0;
319 + obj_buffer = lookup_object_buffer(obj);
320 + if (!obj_buffer)
321 + return 0;
322 + resolve_delta(nr, obj->type, obj_buffer->buffer,
323 + obj_buffer->size, delta_data, delta_size);
324 + return 1;
325 +}
326 +
327 static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
328 unsigned nr)
329 {
330 void *delta_data, *base;
331 unsigned long base_size;
332 unsigned char base_sha1[20];
293 - struct object *obj;
333
334 if (type == OBJ_REF_DELTA) {
335 hashcpy(base_sha1, fill(20));
@@ -300,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
339 free(delta_data);
340 return;
341 }
303 - if (!has_sha1_file(base_sha1)) {
342 + if (has_sha1_file(base_sha1))
343 + ; /* Ok we have this one */
344 + else if (resolve_against_held(nr, base_sha1,
345 + delta_data, delta_size))
346 + return; /* we are done */
347 + else {
348 + /* cannot resolve yet --- queue it */
349 hashcpy(obj_list[nr].sha1, null_sha1);
350 add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
351 return;
@@ -346,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
391 }
392 }
393 if (!base_found) {
349 - /* The delta base object is itself a delta that
350 - has not been resolved yet. */
394 + /*
395 + * The delta base object is itself a delta that
396 + * has not been resolved yet.
397 + */
398 hashcpy(obj_list[nr].sha1, null_sha1);
399 add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
400 return;
401 }
402 }
403
357 - obj = lookup_object(base_sha1);
358 - if (obj) {
359 - struct obj_buffer *obj_buf = lookup_object_buffer(obj);
360 - if (obj_buf) {
361 - resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
362 - return;
363 - }
364 - }
404 + if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
405 + return;
406
407 base = read_sha1_file(base_sha1, &type, &base_size);
408 if (!base) {
t/t5300-pack-object.sh
+1 -1
@@ -274,7 +274,7 @@ test_expect_success \
274 packname_4=$(git pack-objects test-4 <obj-list) &&
275 test 3 = $(ls test-4-*.pack | wc -l)'
276
277 -test_expect_failure 'unpacking with --strict' '
277 +test_expect_success 'unpacking with --strict' '
278
279 git config --unset pack.packsizelimit &&
280 for j in a b c d e f g