4
4
#include "cache.h"
5
5
#include "archive.h"
6
6
#include "streaming.h"
7
+ #include "utf8.h"
7
8
8
9
static int zip_date ;
9
10
static int zip_time ;
@@ -16,7 +17,8 @@ static unsigned int zip_dir_offset;
16
17
static unsigned int zip_dir_entries ;
17
18
18
19
#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
19
- #define ZIP_STREAM (8)
20
+ #define ZIP_STREAM (1 << 3)
21
+ #define ZIP_UTF8 (1 << 11)
20
22
21
23
struct zip_local_header {
22
24
unsigned char magic [4 ];
@@ -74,6 +76,14 @@ struct zip_dir_trailer {
74
76
unsigned char _end [1 ];
75
77
};
76
78
79
+ struct zip_extra_mtime {
80
+ unsigned char magic [2 ];
81
+ unsigned char extra_size [2 ];
82
+ unsigned char flags [1 ];
83
+ unsigned char mtime [4 ];
84
+ unsigned char _end [1 ];
85
+ };
86
+
77
87
/*
78
88
* On ARM, padding is added at the end of the struct, so a simple
79
89
* sizeof(struct ...) reports two bytes more than the payload size
@@ -83,6 +93,9 @@ struct zip_dir_trailer {
83
93
#define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end)
84
94
#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
85
95
#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
96
+ #define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end)
97
+ #define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
98
+ (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
86
99
87
100
static void copy_le16 (unsigned char * dest , unsigned int n )
88
101
{
@@ -164,6 +177,17 @@ static void set_zip_header_data_desc(struct zip_local_header *header,
164
177
copy_le32 (header -> size , size );
165
178
}
166
179
180
+ static int has_only_ascii (const char * s )
181
+ {
182
+ for (;;) {
183
+ int c = * s ++ ;
184
+ if (c == '\0' )
185
+ return 1 ;
186
+ if (!isascii (c ))
187
+ return 0 ;
188
+ }
189
+ }
190
+
167
191
#define STREAM_BUFFER_SIZE (1024 * 16)
168
192
169
193
static int write_zip_entry (struct archiver_args * args ,
@@ -173,6 +197,7 @@ static int write_zip_entry(struct archiver_args *args,
173
197
{
174
198
struct zip_local_header header ;
175
199
struct zip_dir_header dirent ;
200
+ struct zip_extra_mtime extra ;
176
201
unsigned long attr2 ;
177
202
unsigned long compressed_size ;
178
203
unsigned long crc ;
@@ -187,6 +212,13 @@ static int write_zip_entry(struct archiver_args *args,
187
212
188
213
crc = crc32 (0 , NULL , 0 );
189
214
215
+ if (!has_only_ascii (path )) {
216
+ if (is_utf8 (path ))
217
+ flags |= ZIP_UTF8 ;
218
+ else
219
+ warning ("Path is not valid UTF-8: %s" , path );
220
+ }
221
+
190
222
if (pathlen > 0xffff ) {
191
223
return error ("path too long (%d chars, SHA1: %s): %s" ,
192
224
(int )pathlen , sha1_to_hex (sha1 ), path );
@@ -246,8 +278,13 @@ static int write_zip_entry(struct archiver_args *args,
246
278
}
247
279
}
248
280
281
+ copy_le16 (extra .magic , 0x5455 );
282
+ copy_le16 (extra .extra_size , ZIP_EXTRA_MTIME_PAYLOAD_SIZE );
283
+ extra .flags [0 ] = 1 ; /* just mtime */
284
+ copy_le32 (extra .mtime , args -> time );
285
+
249
286
/* make sure we have enough free space in the dictionary */
250
- direntsize = ZIP_DIR_HEADER_SIZE + pathlen ;
287
+ direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE ;
251
288
while (zip_dir_size < zip_dir_offset + direntsize ) {
252
289
zip_dir_size += ZIP_DIRECTORY_MIN_SIZE ;
253
290
zip_dir = xrealloc (zip_dir , zip_dir_size );
@@ -263,7 +300,7 @@ static int write_zip_entry(struct archiver_args *args,
263
300
copy_le16 (dirent .mdate , zip_date );
264
301
set_zip_dir_data_desc (& dirent , size , compressed_size , crc );
265
302
copy_le16 (dirent .filename_length , pathlen );
266
- copy_le16 (dirent .extra_length , 0 );
303
+ copy_le16 (dirent .extra_length , ZIP_EXTRA_MTIME_SIZE );
267
304
copy_le16 (dirent .comment_length , 0 );
268
305
copy_le16 (dirent .disk , 0 );
269
306
copy_le16 (dirent .attr1 , 0 );
@@ -281,11 +318,13 @@ static int write_zip_entry(struct archiver_args *args,
281
318
else
282
319
set_zip_header_data_desc (& header , size , compressed_size , crc );
283
320
copy_le16 (header .filename_length , pathlen );
284
- copy_le16 (header .extra_length , 0 );
321
+ copy_le16 (header .extra_length , ZIP_EXTRA_MTIME_SIZE );
285
322
write_or_die (1 , & header , ZIP_LOCAL_HEADER_SIZE );
286
323
zip_offset += ZIP_LOCAL_HEADER_SIZE ;
287
324
write_or_die (1 , path , pathlen );
288
325
zip_offset += pathlen ;
326
+ write_or_die (1 , & extra , ZIP_EXTRA_MTIME_SIZE );
327
+ zip_offset += ZIP_EXTRA_MTIME_SIZE ;
289
328
if (stream && method == 0 ) {
290
329
unsigned char buf [STREAM_BUFFER_SIZE ];
291
330
ssize_t readlen ;
@@ -382,6 +421,8 @@ static int write_zip_entry(struct archiver_args *args,
382
421
zip_dir_offset += ZIP_DIR_HEADER_SIZE ;
383
422
memcpy (zip_dir + zip_dir_offset , path , pathlen );
384
423
zip_dir_offset += pathlen ;
424
+ memcpy (zip_dir + zip_dir_offset , & extra , ZIP_EXTRA_MTIME_SIZE );
425
+ zip_dir_offset += ZIP_EXTRA_MTIME_SIZE ;
385
426
zip_dir_entries ++ ;
386
427
387
428
return 0 ;
0 commit comments