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