44#include "cache.h"
55#include "archive.h"
66#include "streaming.h"
7+ #include "utf8.h"
78
89static int zip_date ;
910static int zip_time ;
@@ -16,7 +17,8 @@ static unsigned int zip_dir_offset;
1617static unsigned int zip_dir_entries ;
1718
1819#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
19- #define ZIP_STREAM (8)
20+ #define ZIP_STREAM (1 << 3)
21+ #define ZIP_UTF8 (1 << 11)
2022
2123struct zip_local_header {
2224 unsigned char magic [4 ];
@@ -74,6 +76,14 @@ struct zip_dir_trailer {
7476 unsigned char _end [1 ];
7577};
7678
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+
7787/*
7888 * On ARM, padding is added at the end of the struct, so a simple
7989 * sizeof(struct ...) reports two bytes more than the payload size
@@ -83,6 +93,9 @@ struct zip_dir_trailer {
8393#define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end)
8494#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
8595#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))
8699
87100static void copy_le16 (unsigned char * dest , unsigned int n )
88101{
@@ -164,6 +177,17 @@ static void set_zip_header_data_desc(struct zip_local_header *header,
164177 copy_le32 (header -> size , size );
165178}
166179
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+
167191#define STREAM_BUFFER_SIZE (1024 * 16)
168192
169193static int write_zip_entry (struct archiver_args * args ,
@@ -173,6 +197,7 @@ static int write_zip_entry(struct archiver_args *args,
173197{
174198 struct zip_local_header header ;
175199 struct zip_dir_header dirent ;
200+ struct zip_extra_mtime extra ;
176201 unsigned long attr2 ;
177202 unsigned long compressed_size ;
178203 unsigned long crc ;
@@ -187,6 +212,13 @@ static int write_zip_entry(struct archiver_args *args,
187212
188213 crc = crc32 (0 , NULL , 0 );
189214
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+
190222 if (pathlen > 0xffff ) {
191223 return error ("path too long (%d chars, SHA1: %s): %s" ,
192224 (int )pathlen , sha1_to_hex (sha1 ), path );
@@ -246,8 +278,13 @@ static int write_zip_entry(struct archiver_args *args,
246278 }
247279 }
248280
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+
249286 /* 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 ;
251288 while (zip_dir_size < zip_dir_offset + direntsize ) {
252289 zip_dir_size += ZIP_DIRECTORY_MIN_SIZE ;
253290 zip_dir = xrealloc (zip_dir , zip_dir_size );
@@ -263,7 +300,7 @@ static int write_zip_entry(struct archiver_args *args,
263300 copy_le16 (dirent .mdate , zip_date );
264301 set_zip_dir_data_desc (& dirent , size , compressed_size , crc );
265302 copy_le16 (dirent .filename_length , pathlen );
266- copy_le16 (dirent .extra_length , 0 );
303+ copy_le16 (dirent .extra_length , ZIP_EXTRA_MTIME_SIZE );
267304 copy_le16 (dirent .comment_length , 0 );
268305 copy_le16 (dirent .disk , 0 );
269306 copy_le16 (dirent .attr1 , 0 );
@@ -281,11 +318,13 @@ static int write_zip_entry(struct archiver_args *args,
281318 else
282319 set_zip_header_data_desc (& header , size , compressed_size , crc );
283320 copy_le16 (header .filename_length , pathlen );
284- copy_le16 (header .extra_length , 0 );
321+ copy_le16 (header .extra_length , ZIP_EXTRA_MTIME_SIZE );
285322 write_or_die (1 , & header , ZIP_LOCAL_HEADER_SIZE );
286323 zip_offset += ZIP_LOCAL_HEADER_SIZE ;
287324 write_or_die (1 , path , pathlen );
288325 zip_offset += pathlen ;
326+ write_or_die (1 , & extra , ZIP_EXTRA_MTIME_SIZE );
327+ zip_offset += ZIP_EXTRA_MTIME_SIZE ;
289328 if (stream && method == 0 ) {
290329 unsigned char buf [STREAM_BUFFER_SIZE ];
291330 ssize_t readlen ;
@@ -382,6 +421,8 @@ static int write_zip_entry(struct archiver_args *args,
382421 zip_dir_offset += ZIP_DIR_HEADER_SIZE ;
383422 memcpy (zip_dir + zip_dir_offset , path , pathlen );
384423 zip_dir_offset += pathlen ;
424+ memcpy (zip_dir + zip_dir_offset , & extra , ZIP_EXTRA_MTIME_SIZE );
425+ zip_dir_offset += ZIP_EXTRA_MTIME_SIZE ;
385426 zip_dir_entries ++ ;
386427
387428 return 0 ;
0 commit comments