@@ -16,7 +16,9 @@ static unsigned int zip_dir_size;
1616
1717static unsigned int zip_offset ;
1818static unsigned int zip_dir_offset ;
19- static unsigned int zip_dir_entries ;
19+ static uint64_t zip_dir_entries ;
20+
21+ static unsigned int max_creator_version ;
2022
2123#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
2224#define ZIP_STREAM (1 << 3)
@@ -86,6 +88,28 @@ struct zip_extra_mtime {
8688 unsigned char _end [1 ];
8789};
8890
91+ struct zip64_dir_trailer {
92+ unsigned char magic [4 ];
93+ unsigned char record_size [8 ];
94+ unsigned char creator_version [2 ];
95+ unsigned char version [2 ];
96+ unsigned char disk [4 ];
97+ unsigned char directory_start_disk [4 ];
98+ unsigned char entries_on_this_disk [8 ];
99+ unsigned char entries [8 ];
100+ unsigned char size [8 ];
101+ unsigned char offset [8 ];
102+ unsigned char _end [1 ];
103+ };
104+
105+ struct zip64_dir_trailer_locator {
106+ unsigned char magic [4 ];
107+ unsigned char disk [4 ];
108+ unsigned char offset [8 ];
109+ unsigned char number_of_disks [4 ];
110+ unsigned char _end [1 ];
111+ };
112+
89113/*
90114 * On ARM, padding is added at the end of the struct, so a simple
91115 * sizeof(struct ...) reports two bytes more than the payload size
@@ -98,6 +122,12 @@ struct zip_extra_mtime {
98122#define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end)
99123#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
100124 (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
125+ #define ZIP64_DIR_TRAILER_SIZE offsetof(struct zip64_dir_trailer, _end)
126+ #define ZIP64_DIR_TRAILER_RECORD_SIZE \
127+ (ZIP64_DIR_TRAILER_SIZE - \
128+ offsetof(struct zip64_dir_trailer, creator_version))
129+ #define ZIP64_DIR_TRAILER_LOCATOR_SIZE \
130+ offsetof(struct zip64_dir_trailer_locator, _end)
101131
102132static void copy_le16 (unsigned char * dest , unsigned int n )
103133{
@@ -113,6 +143,31 @@ static void copy_le32(unsigned char *dest, unsigned int n)
113143 dest [3 ] = 0xff & (n >> 030 );
114144}
115145
146+ static void copy_le64 (unsigned char * dest , uint64_t n )
147+ {
148+ dest [0 ] = 0xff & n ;
149+ dest [1 ] = 0xff & (n >> 010 );
150+ dest [2 ] = 0xff & (n >> 020 );
151+ dest [3 ] = 0xff & (n >> 030 );
152+ dest [4 ] = 0xff & (n >> 040 );
153+ dest [5 ] = 0xff & (n >> 050 );
154+ dest [6 ] = 0xff & (n >> 060 );
155+ dest [7 ] = 0xff & (n >> 070 );
156+ }
157+
158+ static uint64_t clamp_max (uint64_t n , uint64_t max , int * clamped )
159+ {
160+ if (n <= max )
161+ return n ;
162+ * clamped = 1 ;
163+ return max ;
164+ }
165+
166+ static void copy_le16_clamp (unsigned char * dest , uint64_t n , int * clamped )
167+ {
168+ copy_le16 (dest , clamp_max (n , 0xffff , clamped ));
169+ }
170+
116171static void * zlib_deflate_raw (void * data , unsigned long size ,
117172 int compression_level ,
118173 unsigned long * compressed_size )
@@ -223,6 +278,7 @@ static int write_zip_entry(struct archiver_args *args,
223278 unsigned long size ;
224279 int is_binary = -1 ;
225280 const char * path_without_prefix = path + args -> baselen ;
281+ unsigned int creator_version = 0 ;
226282
227283 crc = crc32 (0 , NULL , 0 );
228284
@@ -251,6 +307,8 @@ static int write_zip_entry(struct archiver_args *args,
251307 method = 0 ;
252308 attr2 = S_ISLNK (mode ) ? ((mode | 0777 ) << 16 ) :
253309 (mode & 0111 ) ? ((mode ) << 16 ) : 0 ;
310+ if (S_ISLNK (mode ) || (mode & 0111 ))
311+ creator_version = 0x0317 ;
254312 if (S_ISREG (mode ) && args -> compression_level != 0 && size > 0 )
255313 method = 8 ;
256314
@@ -279,6 +337,9 @@ static int write_zip_entry(struct archiver_args *args,
279337 sha1_to_hex (sha1 ));
280338 }
281339
340+ if (creator_version > max_creator_version )
341+ max_creator_version = creator_version ;
342+
282343 if (buffer && method == 8 ) {
283344 out = deflated = zlib_deflate_raw (buffer , size ,
284345 args -> compression_level ,
@@ -303,8 +364,7 @@ static int write_zip_entry(struct archiver_args *args,
303364 }
304365
305366 copy_le32 (dirent .magic , 0x02014b50 );
306- copy_le16 (dirent .creator_version ,
307- S_ISLNK (mode ) || (S_ISREG (mode ) && (mode & 0111 )) ? 0x0317 : 0 );
367+ copy_le16 (dirent .creator_version , creator_version );
308368 copy_le16 (dirent .version , 10 );
309369 copy_le16 (dirent .flags , flags );
310370 copy_le16 (dirent .compression_method , method );
@@ -437,20 +497,49 @@ static int write_zip_entry(struct archiver_args *args,
437497 return 0 ;
438498}
439499
500+ static void write_zip64_trailer (void )
501+ {
502+ struct zip64_dir_trailer trailer64 ;
503+ struct zip64_dir_trailer_locator locator64 ;
504+
505+ copy_le32 (trailer64 .magic , 0x06064b50 );
506+ copy_le64 (trailer64 .record_size , ZIP64_DIR_TRAILER_RECORD_SIZE );
507+ copy_le16 (trailer64 .creator_version , max_creator_version );
508+ copy_le16 (trailer64 .version , 45 );
509+ copy_le32 (trailer64 .disk , 0 );
510+ copy_le32 (trailer64 .directory_start_disk , 0 );
511+ copy_le64 (trailer64 .entries_on_this_disk , zip_dir_entries );
512+ copy_le64 (trailer64 .entries , zip_dir_entries );
513+ copy_le64 (trailer64 .size , zip_dir_offset );
514+ copy_le64 (trailer64 .offset , zip_offset );
515+
516+ copy_le32 (locator64 .magic , 0x07064b50 );
517+ copy_le32 (locator64 .disk , 0 );
518+ copy_le64 (locator64 .offset , zip_offset + zip_dir_offset );
519+ copy_le32 (locator64 .number_of_disks , 1 );
520+
521+ write_or_die (1 , & trailer64 , ZIP64_DIR_TRAILER_SIZE );
522+ write_or_die (1 , & locator64 , ZIP64_DIR_TRAILER_LOCATOR_SIZE );
523+ }
524+
440525static void write_zip_trailer (const unsigned char * sha1 )
441526{
442527 struct zip_dir_trailer trailer ;
528+ int clamped = 0 ;
443529
444530 copy_le32 (trailer .magic , 0x06054b50 );
445531 copy_le16 (trailer .disk , 0 );
446532 copy_le16 (trailer .directory_start_disk , 0 );
447- copy_le16 (trailer .entries_on_this_disk , zip_dir_entries );
448- copy_le16 (trailer .entries , zip_dir_entries );
533+ copy_le16_clamp (trailer .entries_on_this_disk , zip_dir_entries ,
534+ & clamped );
535+ copy_le16_clamp (trailer .entries , zip_dir_entries , & clamped );
449536 copy_le32 (trailer .size , zip_dir_offset );
450537 copy_le32 (trailer .offset , zip_offset );
451538 copy_le16 (trailer .comment_length , sha1 ? GIT_SHA1_HEXSZ : 0 );
452539
453540 write_or_die (1 , zip_dir , zip_dir_offset );
541+ if (clamped )
542+ write_zip64_trailer ();
454543 write_or_die (1 , & trailer , ZIP_DIR_TRAILER_SIZE );
455544 if (sha1 )
456545 write_or_die (1 , sha1_to_hex (sha1 ), GIT_SHA1_HEXSZ );
0 commit comments