@@ -97,15 +97,27 @@ static void use(int bytes)
97
97
display_throughput (progress , consumed_bytes );
98
98
}
99
99
100
+ /*
101
+ * Decompress zstream from the standard input into a newly
102
+ * allocated buffer of specified size and return the buffer.
103
+ * The caller is responsible to free the returned buffer.
104
+ *
105
+ * But for dry_run mode, "get_data()" is only used to check the
106
+ * integrity of data, and the returned buffer is not used at all.
107
+ * Therefore, in dry_run mode, "get_data()" will release the small
108
+ * allocated buffer which is reused to hold temporary zstream output
109
+ * and return NULL instead of returning garbage data.
110
+ */
100
111
static void * get_data (unsigned long size )
101
112
{
102
113
git_zstream stream ;
103
- void * buf = xmallocz (size );
114
+ unsigned long bufsize = dry_run && size > 8192 ? 8192 : size ;
115
+ void * buf = xmallocz (bufsize );
104
116
105
117
memset (& stream , 0 , sizeof (stream ));
106
118
107
119
stream .next_out = buf ;
108
- stream .avail_out = size ;
120
+ stream .avail_out = bufsize ;
109
121
stream .next_in = fill (1 );
110
122
stream .avail_in = len ;
111
123
git_inflate_init (& stream );
@@ -125,8 +137,17 @@ static void *get_data(unsigned long size)
125
137
}
126
138
stream .next_in = fill (1 );
127
139
stream .avail_in = len ;
140
+ if (dry_run ) {
141
+ /* reuse the buffer in dry_run mode */
142
+ stream .next_out = buf ;
143
+ stream .avail_out = bufsize > size - stream .total_out ?
144
+ size - stream .total_out :
145
+ bufsize ;
146
+ }
128
147
}
129
148
git_inflate_end (& stream );
149
+ if (dry_run )
150
+ FREE_AND_NULL (buf );
130
151
return buf ;
131
152
}
132
153
@@ -326,10 +347,70 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
326
347
{
327
348
void * buf = get_data (size );
328
349
329
- if (! dry_run && buf )
350
+ if (buf )
330
351
write_object (nr , type , buf , size );
331
- else
332
- free (buf );
352
+ }
353
+
354
+ struct input_zstream_data {
355
+ git_zstream * zstream ;
356
+ unsigned char buf [8192 ];
357
+ int status ;
358
+ };
359
+
360
+ static const void * feed_input_zstream (struct input_stream * in_stream ,
361
+ unsigned long * readlen )
362
+ {
363
+ struct input_zstream_data * data = in_stream -> data ;
364
+ git_zstream * zstream = data -> zstream ;
365
+ void * in = fill (1 );
366
+
367
+ if (in_stream -> is_finished ) {
368
+ * readlen = 0 ;
369
+ return NULL ;
370
+ }
371
+
372
+ zstream -> next_out = data -> buf ;
373
+ zstream -> avail_out = sizeof (data -> buf );
374
+ zstream -> next_in = in ;
375
+ zstream -> avail_in = len ;
376
+
377
+ data -> status = git_inflate (zstream , 0 );
378
+
379
+ in_stream -> is_finished = data -> status != Z_OK ;
380
+ use (len - zstream -> avail_in );
381
+ * readlen = sizeof (data -> buf ) - zstream -> avail_out ;
382
+
383
+ return data -> buf ;
384
+ }
385
+
386
+ static void stream_blob (unsigned long size , unsigned nr )
387
+ {
388
+ git_zstream zstream = { 0 };
389
+ struct input_zstream_data data = { 0 };
390
+ struct input_stream in_stream = {
391
+ .read = feed_input_zstream ,
392
+ .data = & data ,
393
+ };
394
+ struct obj_info * info = & obj_list [nr ];
395
+
396
+ data .zstream = & zstream ;
397
+ git_inflate_init (& zstream );
398
+
399
+ if (stream_loose_object (& in_stream , size , & info -> oid ))
400
+ die (_ ("failed to write object in stream" ));
401
+
402
+ if (data .status != Z_STREAM_END )
403
+ die (_ ("inflate returned (%d)" ), data .status );
404
+ git_inflate_end (& zstream );
405
+
406
+ if (strict ) {
407
+ struct blob * blob = lookup_blob (the_repository , & info -> oid );
408
+
409
+ if (!blob )
410
+ die (_ ("invalid blob object from stream" ));
411
+ blob -> object .flags |= FLAG_WRITTEN ;
412
+ }
413
+ info -> obj = NULL ;
333
414
}
334
415
335
416
static int resolve_against_held (unsigned nr , const struct object_id * base ,
@@ -359,10 +440,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
359
440
oidread (& base_oid , fill (the_hash_algo -> rawsz ));
360
441
use (the_hash_algo -> rawsz );
361
442
delta_data = get_data (delta_size );
362
- if (dry_run || !delta_data ) {
363
- free (delta_data );
443
+ if (!delta_data )
364
444
return ;
365
- }
366
445
if (has_object_file (& base_oid ))
367
446
; /* Ok we have this one */
368
447
else if (resolve_against_held (nr , & base_oid ,
@@ -398,10 +477,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
398
477
die ("offset value out of bound for delta base object" );
399
478
400
479
delta_data = get_data (delta_size );
401
- if (dry_run || !delta_data ) {
402
- free (delta_data );
480
+ if (!delta_data )
403
481
return ;
404
- }
405
482
lo = 0 ;
406
483
hi = nr ;
407
484
while (lo < hi ) {
@@ -468,9 +545,14 @@ static void unpack_one(unsigned nr)
468
545
}
469
546
470
547
switch (type ) {
548
+ case OBJ_BLOB :
549
+ if (!dry_run && size > big_file_threshold ) {
550
+ stream_blob (size , nr );
551
+ return ;
552
+ }
553
+ /* fallthrough */
471
554
case OBJ_COMMIT :
472
555
case OBJ_TREE :
473
- case OBJ_BLOB :
474
556
case OBJ_TAG :
475
557
unpack_non_delta_entry (type , size , nr );
476
558
return ;
0 commit comments