3
3
*/
4
4
#include "cache.h"
5
5
#include "archive.h"
6
+ #include "streaming.h"
6
7
7
8
static int zip_date ;
8
9
static int zip_time ;
@@ -15,6 +16,7 @@ static unsigned int zip_dir_offset;
15
16
static unsigned int zip_dir_entries ;
16
17
17
18
#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
19
+ #define ZIP_STREAM (8)
18
20
19
21
struct zip_local_header {
20
22
unsigned char magic [4 ];
@@ -31,6 +33,14 @@ struct zip_local_header {
31
33
unsigned char _end [1 ];
32
34
};
33
35
36
+ struct zip_data_desc {
37
+ unsigned char magic [4 ];
38
+ unsigned char crc32 [4 ];
39
+ unsigned char compressed_size [4 ];
40
+ unsigned char size [4 ];
41
+ unsigned char _end [1 ];
42
+ };
43
+
34
44
struct zip_dir_header {
35
45
unsigned char magic [4 ];
36
46
unsigned char creator_version [2 ];
@@ -70,6 +80,7 @@ struct zip_dir_trailer {
70
80
* we're interested in.
71
81
*/
72
82
#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end)
83
+ #define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end)
73
84
#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
74
85
#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
75
86
@@ -120,6 +131,19 @@ static void *zlib_deflate(void *data, unsigned long size,
120
131
return buffer ;
121
132
}
122
133
134
+ static void write_zip_data_desc (unsigned long size ,
135
+ unsigned long compressed_size ,
136
+ unsigned long crc )
137
+ {
138
+ struct zip_data_desc trailer ;
139
+
140
+ copy_le32 (trailer .magic , 0x08074b50 );
141
+ copy_le32 (trailer .crc32 , crc );
142
+ copy_le32 (trailer .compressed_size , compressed_size );
143
+ copy_le32 (trailer .size , size );
144
+ write_or_die (1 , & trailer , ZIP_DATA_DESC_SIZE );
145
+ }
146
+
123
147
static void set_zip_dir_data_desc (struct zip_dir_header * header ,
124
148
unsigned long size ,
125
149
unsigned long compressed_size ,
@@ -140,6 +164,8 @@ static void set_zip_header_data_desc(struct zip_local_header *header,
140
164
copy_le32 (header -> size , size );
141
165
}
142
166
167
+ #define STREAM_BUFFER_SIZE (1024 * 16)
168
+
143
169
static int write_zip_entry (struct archiver_args * args ,
144
170
const unsigned char * sha1 ,
145
171
const char * path , size_t pathlen ,
@@ -155,6 +181,8 @@ static int write_zip_entry(struct archiver_args *args,
155
181
unsigned char * out ;
156
182
void * deflated = NULL ;
157
183
void * buffer ;
184
+ struct git_istream * stream = NULL ;
185
+ unsigned long flags = 0 ;
158
186
unsigned long size ;
159
187
160
188
crc = crc32 (0 , NULL , 0 );
@@ -173,25 +201,38 @@ static int write_zip_entry(struct archiver_args *args,
173
201
buffer = NULL ;
174
202
size = 0 ;
175
203
} else if (S_ISREG (mode ) || S_ISLNK (mode )) {
176
- enum object_type type ;
177
- buffer = sha1_file_to_archive (args , path , sha1 , mode , & type , & size );
178
- if (!buffer )
179
- return error ("cannot read %s" , sha1_to_hex (sha1 ));
204
+ enum object_type type = sha1_object_info (sha1 , & size );
180
205
181
206
method = 0 ;
182
207
attr2 = S_ISLNK (mode ) ? ((mode | 0777 ) << 16 ) :
183
208
(mode & 0111 ) ? ((mode ) << 16 ) : 0 ;
184
- if (S_ISREG (mode ) && args -> compression_level != 0 )
209
+ if (S_ISREG (mode ) && args -> compression_level != 0 && size > 0 )
185
210
method = 8 ;
186
- crc = crc32 (crc , buffer , size );
187
- out = buffer ;
188
211
compressed_size = size ;
212
+
213
+ if (S_ISREG (mode ) && type == OBJ_BLOB && !args -> convert &&
214
+ size > big_file_threshold && method == 0 ) {
215
+ stream = open_istream (sha1 , & type , & size , NULL );
216
+ if (!stream )
217
+ return error ("cannot stream blob %s" ,
218
+ sha1_to_hex (sha1 ));
219
+ flags |= ZIP_STREAM ;
220
+ out = buffer = NULL ;
221
+ } else {
222
+ buffer = sha1_file_to_archive (args , path , sha1 , mode ,
223
+ & type , & size );
224
+ if (!buffer )
225
+ return error ("cannot read %s" ,
226
+ sha1_to_hex (sha1 ));
227
+ crc = crc32 (crc , buffer , size );
228
+ out = buffer ;
229
+ }
189
230
} else {
190
231
return error ("unsupported file mode: 0%o (SHA1: %s)" , mode ,
191
232
sha1_to_hex (sha1 ));
192
233
}
193
234
194
- if (method == 8 ) {
235
+ if (buffer && method == 8 ) {
195
236
deflated = zlib_deflate (buffer , size , args -> compression_level ,
196
237
& compressed_size );
197
238
if (deflated && compressed_size - 6 < size ) {
@@ -216,7 +257,7 @@ static int write_zip_entry(struct archiver_args *args,
216
257
copy_le16 (dirent .creator_version ,
217
258
S_ISLNK (mode ) || (S_ISREG (mode ) && (mode & 0111 )) ? 0x0317 : 0 );
218
259
copy_le16 (dirent .version , 10 );
219
- copy_le16 (dirent .flags , 0 );
260
+ copy_le16 (dirent .flags , flags );
220
261
copy_le16 (dirent .compression_method , method );
221
262
copy_le16 (dirent .mtime , zip_time );
222
263
copy_le16 (dirent .mdate , zip_date );
@@ -231,18 +272,43 @@ static int write_zip_entry(struct archiver_args *args,
231
272
232
273
copy_le32 (header .magic , 0x04034b50 );
233
274
copy_le16 (header .version , 10 );
234
- copy_le16 (header .flags , 0 );
275
+ copy_le16 (header .flags , flags );
235
276
copy_le16 (header .compression_method , method );
236
277
copy_le16 (header .mtime , zip_time );
237
278
copy_le16 (header .mdate , zip_date );
238
- set_zip_header_data_desc (& header , size , compressed_size , crc );
279
+ if (flags & ZIP_STREAM )
280
+ set_zip_header_data_desc (& header , 0 , 0 , 0 );
281
+ else
282
+ set_zip_header_data_desc (& header , size , compressed_size , crc );
239
283
copy_le16 (header .filename_length , pathlen );
240
284
copy_le16 (header .extra_length , 0 );
241
285
write_or_die (1 , & header , ZIP_LOCAL_HEADER_SIZE );
242
286
zip_offset += ZIP_LOCAL_HEADER_SIZE ;
243
287
write_or_die (1 , path , pathlen );
244
288
zip_offset += pathlen ;
245
- if (compressed_size > 0 ) {
289
+ if (stream && method == 0 ) {
290
+ unsigned char buf [STREAM_BUFFER_SIZE ];
291
+ ssize_t readlen ;
292
+
293
+ for (;;) {
294
+ readlen = read_istream (stream , buf , sizeof (buf ));
295
+ if (readlen <= 0 )
296
+ break ;
297
+ crc = crc32 (crc , buf , readlen );
298
+ write_or_die (1 , buf , readlen );
299
+ }
300
+ close_istream (stream );
301
+ if (readlen )
302
+ return readlen ;
303
+
304
+ compressed_size = size ;
305
+ zip_offset += compressed_size ;
306
+
307
+ write_zip_data_desc (size , compressed_size , crc );
308
+ zip_offset += ZIP_DATA_DESC_SIZE ;
309
+
310
+ set_zip_dir_data_desc (& dirent , size , compressed_size , crc );
311
+ } else if (compressed_size > 0 ) {
246
312
write_or_die (1 , out , compressed_size );
247
313
zip_offset += compressed_size ;
248
314
}
0 commit comments