Skip to content

Commit f2898cf

Browse files
committed
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 <[email protected]>
1 parent c0e809e commit f2898cf

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

builtin-unpack-objects.c

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ static unsigned int offset, len;
2121
static off_t consumed_bytes;
2222
static SHA_CTX ctx;
2323

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+
*/
2429
struct obj_buffer {
2530
char *buffer;
2631
unsigned long size;
@@ -155,6 +160,10 @@ struct obj_info {
155160
static struct obj_info *obj_list;
156161
unsigned nr_objects;
157162

163+
/*
164+
* Called only from check_object() after it verified this object
165+
* is Ok.
166+
*/
158167
static void write_cached_object(struct object *obj)
159168
{
160169
unsigned char sha1[20];
@@ -164,6 +173,11 @@ static void write_cached_object(struct object *obj)
164173
obj->flags |= FLAG_WRITTEN;
165174
}
166175

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+
*/
167181
static int check_object(struct object *obj, int type, void *data)
168182
{
169183
if (!obj)
@@ -202,35 +216,41 @@ static void write_rest(void)
202216
static void added_object(unsigned nr, enum object_type type,
203217
void *data, unsigned long size);
204218

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+
*/
205224
static void write_object(unsigned nr, enum object_type type,
206225
void *buf, unsigned long size)
207226
{
208-
added_object(nr, type, buf, size);
209227
if (!strict) {
210228
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
211229
die("failed to write object");
230+
added_object(nr, type, buf, size);
212231
free(buf);
213-
obj_list[nr].obj = 0;
232+
obj_list[nr].obj = NULL;
214233
} else if (type == OBJ_BLOB) {
215234
struct blob *blob;
216235
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
217236
die("failed to write object");
237+
added_object(nr, type, buf, size);
218238
free(buf);
219239

220240
blob = lookup_blob(obj_list[nr].sha1);
221241
if (blob)
222242
blob->object.flags |= FLAG_WRITTEN;
223243
else
224244
die("invalid blob object");
225-
obj_list[nr].obj = 0;
245+
obj_list[nr].obj = NULL;
226246
} else {
227247
struct object *obj;
228248
int eaten;
229249
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
250+
added_object(nr, type, buf, size);
230251
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
231252
if (!obj)
232253
die("invalid %s", typename(type));
233-
/* buf is stored via add_object_buffer and in obj, if its a tree or commit */
234254
add_object_buffer(obj, buf, size);
235255
obj->flags |= FLAG_OPEN;
236256
obj_list[nr].obj = obj;
@@ -253,6 +273,10 @@ static void resolve_delta(unsigned nr, enum object_type type,
253273
write_object(nr, type, result, result_size);
254274
}
255275

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+
*/
256280
static void added_object(unsigned nr, enum object_type type,
257281
void *data, unsigned long size)
258282
{
@@ -284,13 +308,28 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
284308
free(buf);
285309
}
286310

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+
287327
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
288328
unsigned nr)
289329
{
290330
void *delta_data, *base;
291331
unsigned long base_size;
292332
unsigned char base_sha1[20];
293-
struct object *obj;
294333

295334
if (type == OBJ_REF_DELTA) {
296335
hashcpy(base_sha1, fill(20));
@@ -300,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
300339
free(delta_data);
301340
return;
302341
}
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 */
304349
hashcpy(obj_list[nr].sha1, null_sha1);
305350
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
306351
return;
@@ -346,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
346391
}
347392
}
348393
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+
*/
351398
hashcpy(obj_list[nr].sha1, null_sha1);
352399
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
353400
return;
354401
}
355402
}
356403

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;
365406

366407
base = read_sha1_file(base_sha1, &type, &base_size);
367408
if (!base) {

t/t5300-pack-object.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ test_expect_success \
274274
packname_4=$(git pack-objects test-4 <obj-list) &&
275275
test 3 = $(ls test-4-*.pack | wc -l)'
276276

277-
test_expect_failure 'unpacking with --strict' '
277+
test_expect_success 'unpacking with --strict' '
278278
279279
git config --unset pack.packsizelimit &&
280280
for j in a b c d e f g

0 commit comments

Comments
 (0)