@@ -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 )
@@ -282,6 +337,9 @@ static int write_zip_entry(struct archiver_args *args,
282337 sha1_to_hex (sha1 ));
283338 }
284339
340+ if (creator_version > max_creator_version )
341+ max_creator_version = creator_version ;
342+
285343 if (buffer && method == 8 ) {
286344 out = deflated = zlib_deflate_raw (buffer , size ,
287345 args -> compression_level ,
@@ -439,20 +497,49 @@ static int write_zip_entry(struct archiver_args *args,
439497 return 0 ;
440498}
441499
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+
442525static void write_zip_trailer (const unsigned char * sha1 )
443526{
444527 struct zip_dir_trailer trailer ;
528+ int clamped = 0 ;
445529
446530 copy_le32 (trailer .magic , 0x06054b50 );
447531 copy_le16 (trailer .disk , 0 );
448532 copy_le16 (trailer .directory_start_disk , 0 );
449- copy_le16 (trailer .entries_on_this_disk , zip_dir_entries );
450- 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 );
451536 copy_le32 (trailer .size , zip_dir_offset );
452537 copy_le32 (trailer .offset , zip_offset );
453538 copy_le16 (trailer .comment_length , sha1 ? 40 : 0 );
454539
455540 write_or_die (1 , zip_dir , zip_dir_offset );
541+ if (clamped )
542+ write_zip64_trailer ();
456543 write_or_die (1 , & trailer , ZIP_DIR_TRAILER_SIZE );
457544 if (sha1 )
458545 write_or_die (1 , sha1_to_hex (sha1 ), 40 );
0 commit comments