@@ -16,7 +16,9 @@ static unsigned int zip_dir_size;
16
16
17
17
static unsigned int zip_offset ;
18
18
static 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 ;
20
22
21
23
#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
22
24
#define ZIP_STREAM (1 << 3)
@@ -86,6 +88,28 @@ struct zip_extra_mtime {
86
88
unsigned char _end [1 ];
87
89
};
88
90
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
+
89
113
/*
90
114
* On ARM, padding is added at the end of the struct, so a simple
91
115
* sizeof(struct ...) reports two bytes more than the payload size
@@ -98,6 +122,12 @@ struct zip_extra_mtime {
98
122
#define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end)
99
123
#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
100
124
(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)
101
131
102
132
static void copy_le16 (unsigned char * dest , unsigned int n )
103
133
{
@@ -113,6 +143,31 @@ static void copy_le32(unsigned char *dest, unsigned int n)
113
143
dest [3 ] = 0xff & (n >> 030 );
114
144
}
115
145
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
+
116
171
static void * zlib_deflate_raw (void * data , unsigned long size ,
117
172
int compression_level ,
118
173
unsigned long * compressed_size )
@@ -282,6 +337,9 @@ static int write_zip_entry(struct archiver_args *args,
282
337
sha1_to_hex (sha1 ));
283
338
}
284
339
340
+ if (creator_version > max_creator_version )
341
+ max_creator_version = creator_version ;
342
+
285
343
if (buffer && method == 8 ) {
286
344
out = deflated = zlib_deflate_raw (buffer , size ,
287
345
args -> compression_level ,
@@ -439,20 +497,49 @@ static int write_zip_entry(struct archiver_args *args,
439
497
return 0 ;
440
498
}
441
499
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
+
442
525
static void write_zip_trailer (const unsigned char * sha1 )
443
526
{
444
527
struct zip_dir_trailer trailer ;
528
+ int clamped = 0 ;
445
529
446
530
copy_le32 (trailer .magic , 0x06054b50 );
447
531
copy_le16 (trailer .disk , 0 );
448
532
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 );
451
536
copy_le32 (trailer .size , zip_dir_offset );
452
537
copy_le32 (trailer .offset , zip_offset );
453
538
copy_le16 (trailer .comment_length , sha1 ? 40 : 0 );
454
539
455
540
write_or_die (1 , zip_dir , zip_dir_offset );
541
+ if (clamped )
542
+ write_zip64_trailer ();
456
543
write_or_die (1 , & trailer , ZIP_DIR_TRAILER_SIZE );
457
544
if (sha1 )
458
545
write_or_die (1 , sha1_to_hex (sha1 ), 40 );
0 commit comments