英文:
Why does unzip ignore my zip64 end of central directory record?
问题
It appears that you are facing issues with creating a ZIP archive with zip64 support in C++ using zlib, and you're encountering problems with both zip64 and the ASi UNIX extra field. Unfortunately, without seeing the full code and how these headers and fields are integrated into your archiving process, it can be challenging to pinpoint the exact problem.
However, here are some general suggestions and potential areas to investigate:
-
Check CRC Calculation: Ensure that the CRC-32 calculation is correct. Verify that the CRC values calculated match the expected values.
-
Endianess: Ensure that the byte order (endianness) of the data you are writing matches the expected byte order in the ZIP format. Different systems may have different endianness, and you may need to perform byte-order conversions if necessary.
-
Size and Offset Values: Double-check that the size and offset values written to the ZIP headers are correct. These values are crucial for the proper functioning of the ZIP archive.
-
ASi UNIX Extra Field: Verify that the ASi UNIX extra field is correctly formatted and that the data you are writing to it matches the expected format. Double-check that the field's size is correctly specified.
-
Padding: Ensure that there is proper padding for alignment when writing structures. ZIP format often requires specific byte alignments.
-
Testing: Since you mentioned that the code is too large to include everything, consider creating a minimal, reproducible example that focuses solely on creating a ZIP archive with zip64 support and the ASi UNIX extra field. This can help isolate and identify the issue.
-
Debugging: Use debugging tools and print statements to inspect the data being written to the archive headers and compare it to the expected format.
-
Library Versions: Ensure that you are using compatible versions of zlib and any other libraries you may be using. Compatibility issues between library versions can lead to unexpected behavior.
-
File Permission Handling: Verify that the permissions you are using for the ASi UNIX extra field match the expected format in your target system.
-
Testing with Other ZIP Tools: Test your generated ZIP archive with different ZIP tools and libraries to ensure that the issue is not specific to one tool.
Without the complete code and a detailed understanding of your specific use case, it's challenging to provide a precise solution. However, reviewing these aspects of your code and comparing them to the ZIP file format specifications may help you identify and resolve the issues you're facing.
英文:
My goal is create a zip64 supported archive in c++ with only zlib.
The current implementation works without zip64, but when I assign the zip64 EOCD and EOCL they are unused by unzip
and 7zip
. Though I have verified that my unzip
does support zip64.
What could be the cause of unzip
(and similairs) ignoring my zip64 EOCD? I believe the corresponding headers are correct?
I am aware that this example is not fully reproducible but the code is too large to include everything. The File
class can not be included but it is just a simple wrapper for FILE*
, SICE
is an alias for static inline constexpr
and String
is very similair to std::string
. All of the code that is not included is thoroughly tested and is not the cause of the issue.
These are the header structs:
// File header.
struct FHeader {
// Default headers.
SICE uint32_t signature = 0x04034b50;
uint16_t version = 45;
uint16_t general_flag = 0;
uint16_t compression_method = 8; // deflated.
uint16_t mod_time = 0;
uint16_t mod_date = 0;
uint32_t crc = 0; // TO ASSIGN.
uint32_t compressed_len = 0xFFFFFFFF;
uint32_t uncompressed_len = 0xFFFFFFFF;
uint16_t name_len = 0; // TO ASSIGN.
uint16_t extra_field_len = 24 + 4 + 14 + 4;
// File name.
String name; // TO ASSIGN.
// Zip64 extended info extra field.
SICE uint16_t extf_zip64_signature = 0x0001;
SICE uint16_t extf_zip64_size = 24;
uint64_t zip64_compressed_len = 0; // TO ASSIGN.
uint64_t zip64_uncompressed_len = 0; // TO ASSIGN.
uint64_t zip64_offset = 0; // TO ASSIGN.
// ASi UNIX extra field.
SICE uint16_t extf_unix_signature = 0x756e;
SICE uint16_t extf_unix_size = 14;
uint32_t extf_unix_crc = 0;
uint16_t permission = 0777; // TO ASSIGN.
uint32_t sizdev = 0;
uint16_t uid = 0; // TO ASSIGN.
uint16_t gid = 0; // TO ASSIGN.
// File data.
String data; // TO ASSIGN.
};
// Central dir header.
struct CDHeader {
// Default headers.
SICE uint32_t signature = 0x02014b50;
uint16_t made_version = 45;
uint16_t version = 45;
uint16_t general_flag = 0;
uint16_t compression_method = 8; // deflated.
uint16_t mod_time = 0;
uint16_t mod_date = 0;
uint32_t crc = 0; // TO ASSIGN.
uint32_t compressed_len = 0xFFFFFFFF;
uint32_t uncompressed_len = 0xFFFFFFFF;
uint16_t name_len = 0; // TO ASSIGN.
uint16_t extra_field_len = 24 + 4 + 14 + 4;
uint16_t comment_len = 0;
uint16_t disk = 0;
uint16_t internal_file_attr = 0;
uint32_t external_file_attr = 0;
uint32_t offset = 0xFFFFFFFF;
// File name.
String name; // TO ASSIGN.
// Zip64 extended info extra field.
SICE uint16_t extf_zip64_signature = 0x0001;
SICE uint16_t extf_zip64_size = 24;
uint64_t zip64_compressed_len = 0; // TO ASSIGN.
uint64_t zip64_uncompressed_len = 0; // TO ASSIGN.
uint64_t zip64_offset = 0; // TO ASSIGN.
// ASi UNIX extra field.
SICE uint16_t extf_unix_signature = 0x756e;
SICE uint16_t extf_unix_size = 14;
uint32_t extf_unix_crc = 0;
uint16_t permission = 0777; // TO ASSIGN.
uint32_t sizdev = 0;
uint16_t uid = 0; // TO ASSIGN.
uint16_t gid = 0; // TO ASSIGN.
};
// End of central directory record for ZIP64.
struct EOCD64 {
SICE uint32_t signature = 0x06064b50;
uint64_t remaining_size = 44;
uint16_t made_version = 45;
uint16_t version = 45;
uint32_t disk = 0;
uint32_t start_disk = 0;
uint64_t disk_entries = 0; // TO ASSIGN.
uint64_t entries = 0; // TO ASSIGN.
uint64_t size = 0; // TO ASSIGN.
uint64_t offset = 0; // TO ASSIGN.
};
// End of central directory locator for ZIP64.
struct EOCL64 {
SICE uint32_t signature = 0x07064b50;
uint16_t disk = 0;
uint64_t offset = 0; // TO ASSIGN.
uint32_t disks = 1;
};
// End of central directory record.
struct EOCD {
SICE uint32_t signature = 0x06054b50;
uint16_t disk = 0xFFFF;
uint16_t start_central_disk = 0xFFFF;
uint16_t disk_entries = 0xFFFF;
uint16_t entries = 0xFFFF;
uint32_t size = 0xFFFFFFFF;
uint32_t offset = 0xFFFFFFFF;
uint16_t comment_len = 0;
};
These are the functions used to write the headers to the archive file:
// Compute CRC-32.
static
uint32_t compute_crc32(const char* data, const ullong& len) {
uLong crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, (uchar*) data, len);
return (uint32_t) crc;
}
static
uint32_t compute_crc32(
const uint16_t permission,
const uint32_t sizdev,
const uint16_t uid,
const uint16_t gid
) {
uLong crc = crc32(0, nullptr, 0); // Initialize CRC-32 value to 0
crc = crc32_combine(crc, permission, sizeof(permission));
crc = crc32_combine(crc, sizdev, sizeof(sizdev));
crc = crc32_combine(crc, uid, sizeof(uid));
crc = crc32_combine(crc, gid, sizeof(gid));
return (uint32_t) crc;
}
// Write local file header for a file entry
void write_fheader(File& archive, const FHeader& header) const {
// Write header.
archive.write((char*) &header.signature, sizeof(header.signature));
archive.write((char*) &header.version, sizeof(header.version));
archive.write((char*) &header.general_flag, sizeof(header.general_flag));
archive.write((char*) &header.compression_method, sizeof(header.compression_method));
archive.write((char*) &header.mod_time, sizeof(header.mod_time));
archive.write((char*) &header.mod_date, sizeof(header.mod_date));
archive.write((char*) &header.crc, sizeof(header.crc));
archive.write((char*) &header.compressed_len, sizeof(header.compressed_len));
archive.write((char*) &header.uncompressed_len, sizeof(header.uncompressed_len));
archive.write((char*) &header.name_len, sizeof(header.name_len));
archive.write((char*) &header.extra_field_len, sizeof(header.extra_field_len));
// File name
archive.write(header.name.c_str(), header.name.len());
// ASi UNIX extra field.
archive.write((char*) &header.extf_unix_signature, sizeof(header.extf_unix_signature));
archive.write((char*) &header.extf_unix_size, sizeof(header.extf_unix_size));
archive.write((char*) &header.crc, sizeof(header.crc));
archive.write((char*) &header.permission, sizeof(header.permission));
archive.write((char*) &header.sizdev, sizeof(header.sizdev));
archive.write((char*) &header.uid, sizeof(header.uid));
archive.write((char*) &header.gid, sizeof(header.gid));
// Zip64 extented info.
// Should be last.
archive.write((char*) &header.extf_zip64_signature, sizeof(header.extf_zip64_signature));
archive.write((char*) &header.extf_zip64_size, sizeof(header.extf_zip64_size));
archive.write((char*) &header.zip64_uncompressed_len, sizeof(header.zip64_uncompressed_len));
archive.write((char*) &header.zip64_compressed_len, sizeof(header.zip64_compressed_len));
archive.write((char*) &header.zip64_offset, sizeof(header.zip64_offset));
// File data.
archive.write(header.data.data(), header.data.len());
}
// Write central directory file header for a file entry
void write_cdheader(File& archive, const CDHeader& header) const {
// Write header.
archive.write((char*) &header.signature, sizeof(header.signature));
archive.write((char*) &header.made_version, sizeof(header.made_version));
archive.write((char*) &header.version, sizeof(header.version));
archive.write((char*) &header.general_flag, sizeof(header.general_flag));
archive.write((char*) &header.compression_method, sizeof(header.compression_method));
archive.write((char*) &header.mod_time, sizeof(header.mod_time));
archive.write((char*) &header.mod_date, sizeof(header.mod_date));
archive.write((char*) &header.crc, sizeof(header.crc));
archive.write((char*) &header.compressed_len, sizeof(header.compressed_len));
archive.write((char*) &header.uncompressed_len, sizeof(header.uncompressed_len));
archive.write((char*) &header.name_len, sizeof(header.name_len));
archive.write((char*) &header.extra_field_len, sizeof(header.extra_field_len));
archive.write((char*) &header.comment_len, sizeof(header.comment_len));
archive.write((char*) &header.disk, sizeof(header.disk));
archive.write((char*) &header.internal_file_attr, sizeof(header.internal_file_attr));
archive.write((char*) &header.external_file_attr, sizeof(header.external_file_attr));
archive.write((char*) &header.offset, sizeof(header.offset));
// File name
archive.write(header.name.c_str(), header.name.len());
// ASi UNIX extra field.
archive.write((char*) &header.extf_unix_signature, sizeof(header.extf_unix_signature));
archive.write((char*) &header.extf_unix_size, sizeof(header.extf_unix_size));
archive.write((char*) &header.crc, sizeof(header.crc));
archive.write((char*) &header.permission, sizeof(header.permission));
archive.write((char*) &header.sizdev, sizeof(header.sizdev));
archive.write((char*) &header.uid, sizeof(header.uid));
archive.write((char*) &header.gid, sizeof(header.gid));
// Zip64 extented info.
// Should be last.
archive.write((char*) &header.extf_zip64_signature, sizeof(header.extf_zip64_signature));
archive.write((char*) &header.extf_zip64_size, sizeof(header.extf_zip64_size));
archive.write((char*) &header.zip64_uncompressed_len, sizeof(header.zip64_uncompressed_len));
archive.write((char*) &header.zip64_compressed_len, sizeof(header.zip64_compressed_len));
archive.write((char*) &header.zip64_offset, sizeof(header.zip64_offset));
}
// Write end of central directory record
void write_eocd(File& archive, const EOCD& header) const {
// Write header.
archive.write((char*) &header.signature, sizeof(header.signature));
archive.write((char*) &header.disk, sizeof(header.disk));
archive.write((char*) &header.start_central_disk, sizeof(header.start_central_disk));
archive.write((char*) &header.disk_entries, sizeof(header.disk_entries));
archive.write((char*) &header.entries, sizeof(header.entries));
archive.write((char*) &header.size, sizeof(header.size));
archive.write((char*) &header.offset, sizeof(header.offset));
archive.write((char*) &header.comment_len, sizeof(header.comment_len));
}
// Write end of central directory recod.
void write_eocd64(File& archive, const EOCD64& header) const {
archive.write((char*) &header.signature, sizeof(header.signature));
archive.write((char*) &header.remaining_size, sizeof(header.remaining_size));
archive.write((char*) &header.made_version, sizeof(header.made_version));
archive.write((char*) &header.version, sizeof(header.version));
archive.write((char*) &header.disk, sizeof(header.disk));
archive.write((char*) &header.start_disk, sizeof(header.start_disk));
archive.write((char*) &header.disk_entries, sizeof(header.disk_entries));
archive.write((char*) &header.entries, sizeof(header.entries));
archive.write((char*) &header.size, sizeof(header.size));
archive.write((char*) &header.offset, sizeof(header.offset));
}
// Write end of central directory locator.
void write_eocl64(File& archive, const EOCL64& header) const {
archive.write((char*) &header.signature, sizeof(header.signature));
archive.write((char*) &header.disk, sizeof(header.disk));
archive.write((char*) &header.offset, sizeof(header.offset));
archive.write((char*) &header.disks, sizeof(header.disks));
}
And this is how i write the headers:
...
// Write files.
for (auto& index: file_headers.indexes()) {
file_headers[index].zip64_offset = ftell(output.file());
central_dir_headers[index].zip64_offset = file_headers[index].zip64_offset;
// central_dir_headers[index].offset = ftell(output.file());
write_fheader(output, file_headers[index]);
}
// Write central dir.
ullong cd_offset = ftell(output.file());
for (auto& header: central_dir_headers) {
write_cdheader(output, header);
}
ullong eocd64_offset = ftell(output.file());
// Write zip64 EOCD.
eocd64.offset = cd_offset;
eocd64.disk_entries = file_headers.len();
eocd64.entries = file_headers.len();
eocd64.size = eocd64_offset - cd_offset;
write_eocd64(output, eocd64);
// Write zip64 EOCL.
eocl64.offset = eocd64_offset;
write_eocl64(output, eocl64);
// Write EOCD.
write_eocd(output, eocd);
But when trying to extract the archive with unzip
these error logs are encountered.
$ unzip -t ../archive.zip
Archive: ../archive.zip
warning [../archive.zip]: zipfile claims to be last disk of a multi-part archive;
attempting to process anyway, assuming all parts have been concatenated
together in order. Expect "errors" and warnings...true multi-part support
doesn't exist yet (coming soon).
error [../archive.zip]: missing 8589933224 bytes in zipfile
(attempting to process anyway)
error [../archive.zip]: attempt to seek before beginning of zipfile
(please check that you have transferred or created the zipfile in the
appropriate BINARY mode and that you have compiled UnZip properly)
And zipinfo:
$ zipinfo -v ../archive.zip
Archive: ../archive.zip
There is no zipfile comment.
End-of-central-directory record:
-------------------------------
Zip archive file size: 1388 (000000000000056Ch)
Actual end-cent-dir record offset: 1366 (0000000000000556h)
Expected end-cent-dir record offset: 8589934590 (00000001FFFFFFFEh)
(based on the length of the central directory and its expected offset)
This zipfile constitutes the sole disk of a single-part archive; its
central directory contains 65535 entries.
The central directory is 4294967295 (00000000FFFFFFFFh) bytes long,
and its (expected) offset in bytes from the beginning of the zipfile
is 4294967295 (00000000FFFFFFFFh).
error [../archive.zip]: missing 8589933224 bytes in zipfile
(attempting to process anyway)
error [../archive.zip]: attempt to seek before beginning of zipfile
(please check that you have transferred or created the zipfile in the
appropriate BINARY mode and that you have compiled UnZip properly)
I really appreciate any help given!
Edit
An example archive file created by this code can be found at: https://www.dropbox.com/s/14mu7q6hpi93cyc/dir.zip?dl=0
Edit
The ignoring of the zip64 is resolved but the ASi UNIX extra field is also ignored.
The uint32_t
permission is initialized with.
struct stat stat_info;
if (::lstat(path.c_str(), &stat_info) == -1) {
...
}
uint16_t permission = stat_info.st_mode;
// uint16_t permission = stat_info.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); // does also not work.
This is the code to create the ASi UNIX extra field.
Structure:
// Central dir header.
struct ... {
...
// ASi UNIX extra field.
SICE uint16_t extf_unix_signature = 0x756e;
SICE uint16_t extf_unix_size = 14;
uint32_t extf_unix_crc = 0; // TO ASSIGN
uint16_t permission = 0777; // TO ASSIGN.
uint32_t sizdev = 0;
uint16_t uid = 0; // TO ASSIGN.
uint16_t gid = 0; // TO ASSIGN.
};
CRC32:
static
uint32_t compute_crc32(
const uint16_t permission,
const uint32_t sizdev,
const uint16_t uid,
const uint16_t gid
) {
uLong crc = crc32(0, nullptr, 0); // Initialize CRC-32 value to 0
crc = crc32_combine(crc, permission, sizeof(permission));
crc = crc32_combine(crc, sizdev, sizeof(sizdev));
crc = crc32_combine(crc, uid, sizeof(uid));
crc = crc32_combine(crc, gid, sizeof(gid));
return (uint32_t) crc;
}
Writing the header:
// ASi UNIX extra field.
archive.write((char*) &header.extf_unix_signature, sizeof(header.extf_unix_signature));
archive.write((char*) &header.extf_unix_size, sizeof(header.extf_unix_size));
archive.write((char*) &header.extf_unix_crc, sizeof(header.extf_unix_crc,));
archive.write((char*) &header.permission, sizeof(header.permission));
archive.write((char*) &header.sizdev, sizeof(header.sizdev));
archive.write((char*) &header.uid, sizeof(header.uid));
archive.write((char*) &header.gid, sizeof(header.gid));
All variables are initialized but not posted here.
答案1
得分: 3
以下是由运行zipdetails创建的zip文件的转储。请注意,我不得不启用特殊的扫描模式才能使其找到zip64记录。
请注意,ZIP64 END CENTRAL DIR LOCATOR
中所有字段的值都很奇怪。另外,位于偏移量0546的Total no of Disks
的最后两个字节与END CENTRAL HEADER
重叠。
$ zipdetails -v archive.zip
找不到“Zip64中央目录定位符”的签名:0x07064b50
尝试使用--scan选项运行。
$ zipdetails --scan -v archive.zip
0000 0004 50 4B 03 04 LOCAL HEADER #1 04034B50
...(此处省略部分内容)...
004B 01A2 ... PAYLOAD
01F5 0004 50 4B 03 04 LOCAL HEADER #2 04034B50
...(此处省略部分内容)...
0444 0004 50 4B 01 02 CENTRAL HEADER #1 02014B50
...(此处省略部分内容)...
04A7 0004 50 4B 01 02 CENTRAL HEADER #2 02014B50
...(此处省略部分内容)...
050C 0004 50 4B 06 06 ZIP64 END CENTRAL DIR 06064B50
...(此处省略部分内容)...
0544 0004 50 4B 06 07 ZIP64 END CENTRAL DIR 07064B50
...(此处省略部分内容)...
0556 0004 50 4B 05 06 END CENTRAL HEADER 06054B50
...(此处省略部分内容)...
查看您的代码,disk
应该是一个32位的值
// ZIP64的中央目录定位符。
struct EOCL64 {
SICE uint32_t signature = 0x07064b50;
uint16_t disk = 0;
uint64_t offset = 0; // TO ASSIGN.
uint32_t disks = 1;
};
[编辑]
接下来要注意的是条目之间的间隙。本地头部1在0x4A + 0x1A2个有效负载字节 = 0x1ED结束。但是本地头部2从0x1F5开始。在其中没有内容的间隙。
本地头部2也是如此。
ZIP规范没有明确说明ZIP文件中不应该留下间隙,但在“4.3.6总体.ZIP文件格式”部分中暗示了这一点。为了与解压缩客户端的最大互操作性,我建议不要在条目之间留下空格。
英文:
Below is a dump of your zip file created by running zipdetails. Note I've had to enable a special scanning mode to get it to find the zip64 records.
Note the crazy values for all the fields in the ZIP64 END CENTRAL DIR LOCATOR
. Also the last two bytes (for the Total no of Disks
) at offset 0546 overlap with the END CENTRAL HEADER
$ zipdetails -v archive.zip
Cannot find signature for 'Zip64 end of central directory locator': 0x07064b50
Try running with --scan option.
$ zipdetails --scan -v archive.zip
0000 0004 50 4B 03 04 LOCAL HEADER #1 04034B50
0004 0001 2D Extract Zip Spec 2D '4.5'
0005 0001 00 Extract OS 00 'MS-DOS'
0006 0002 00 00 General Purpose Flag 0000
[Bits 1-2] 0 'Normal Compression'
0008 0002 08 00 Compression Method 0008 'Deflated'
000A 0004 00 00 00 00 Last Mod Time 00000000 'No Date/Time'
000E 0004 02 F5 0C 44 CRC 440CF502
0012 0004 FF FF FF FF Compressed Length FFFFFFFF
0016 0004 FF FF FF FF Uncompressed Length FFFFFFFF
001A 0002 07 00 Filename Length 0007
001C 0002 2E 00 Extra Length 002E
001E 0007 69 6E 73 74 Filename 'install'
61 6C 6C
0025 0002 6E 75 Extra ID #0001 756E 'nu: ASi Unix'
0027 0002 0E 00 Length 000E
0029 000E 02 F5 0C 44 Extra Payload 02 F5 0C 44 ED 01 00 00 00 00 F5 01
ED 01 00 00 00 00
00 00 F5 01
00 00
0037 0002 01 00 Extra ID #0002 0001 'ZIP64'
0039 0002 18 00 Length 0018
003B 0008 DA 04 00 00 Uncompressed Size 00000000000004DA
00 00 00 00
0043 0008 A2 01 00 00 Compressed Size 00000000000001A2
00 00 00 00
004B 01A2 ... PAYLOAD
01F5 0004 50 4B 03 04 LOCAL HEADER #2 04034B50
01F9 0001 2D Extract Zip Spec 2D '4.5'
01FA 0001 00 Extract OS 00 'MS-DOS'
01FB 0002 00 00 General Purpose Flag 0000
[Bits 1-2] 0 'Normal Compression'
01FD 0002 08 00 Compression Method 0008 'Deflated'
01FF 0004 00 00 00 00 Last Mod Time 00000000 'No Date/Time'
0203 0004 1A D9 B2 1D CRC 1DB2D91A
0207 0004 FF FF FF FF Compressed Length FFFFFFFF
020B 0004 FF FF FF FF Uncompressed Length FFFFFFFF
020F 0002 09 00 Filename Length 0009
0211 0002 2E 00 Extra Length 002E
0213 0009 52 45 41 44 Filename 'README.md'
4D 45 2E 6D
64
021C 0002 6E 75 Extra ID #0001 756E 'nu: ASi Unix'
021E 0002 0E 00 Length 000E
0220 000E 1A D9 B2 1D Extra Payload 1A D9 B2 1D ED 01 00 00 00 00 F5 01
ED 01 00 00 00 00
00 00 F5 01
00 00
022E 0002 01 00 Extra ID #0002 0001 'ZIP64'
0230 0002 18 00 Length 0018
0232 0008 95 03 00 00 Uncompressed Size 0000000000000395
00 00 00 00
023A 0008 FA 01 00 00 Compressed Size 00000000000001FA
00 00 00 00
0242 01FA ... PAYLOAD
0444 0004 50 4B 01 02 CENTRAL HEADER #1 02014B50
0448 0001 2D Created Zip Spec 2D '4.5'
0449 0001 00 Created OS 00 'MS-DOS'
044A 0001 2D Extract Zip Spec 2D '4.5'
044B 0001 00 Extract OS 00 'MS-DOS'
044C 0002 00 00 General Purpose Flag 0000
[Bits 1-2] 0 'Normal Compression'
044E 0002 08 00 Compression Method 0008 'Deflated'
0450 0004 00 00 00 00 Last Mod Time 00000000 'No Date/Time'
0454 0004 02 F5 0C 44 CRC 440CF502
0458 0004 FF FF FF FF Compressed Length FFFFFFFF
045C 0004 FF FF FF FF Uncompressed Length FFFFFFFF
0460 0002 07 00 Filename Length 0007
0462 0002 2E 00 Extra Length 002E
0464 0002 00 00 Comment Length 0000
0466 0002 00 00 Disk Start 0000
0468 0002 00 00 Int File Attributes 0000
[Bit 0] 0 'Binary Data'
046A 0004 00 00 00 00 Ext File Attributes 00000000
046E 0004 FF FF FF FF Local Header Offset FFFFFFFF
0472 0007 69 6E 73 74 Filename 'install'
61 6C 6C
0479 0002 6E 75 Extra ID #0001 756E 'nu: ASi Unix'
047B 0002 0E 00 Length 000E
047D 000E 02 F5 0C 44 Extra Payload 02 F5 0C 44 ED 01 00 00 00 00 F5 01
ED 01 00 00 00 00
00 00 F5 01
00 00
048B 0002 01 00 Extra ID #0002 0001 'ZIP64'
048D 0002 18 00 Length 0018
048F 0008 DA 04 00 00 Uncompressed Size 00000000000004DA
00 00 00 00
0497 0008 A2 01 00 00 Compressed Size 00000000000001A2
00 00 00 00
049F 0008 00 00 00 00 Offset to Local Dir 0000000000000000
00 00 00 00
04A7 0004 50 4B 01 02 CENTRAL HEADER #2 02014B50
04AB 0001 2D Created Zip Spec 2D '4.5'
04AC 0001 00 Created OS 00 'MS-DOS'
04AD 0001 2D Extract Zip Spec 2D '4.5'
04AE 0001 00 Extract OS 00 'MS-DOS'
04AF 0002 00 00 General Purpose Flag 0000
[Bits 1-2] 0 'Normal Compression'
04B1 0002 08 00 Compression Method 0008 'Deflated'
04B3 0004 00 00 00 00 Last Mod Time 00000000 'No Date/Time'
04B7 0004 1A D9 B2 1D CRC 1DB2D91A
04BB 0004 FF FF FF FF Compressed Length FFFFFFFF
04BF 0004 FF FF FF FF Uncompressed Length FFFFFFFF
04C3 0002 09 00 Filename Length 0009
04C5 0002 2E 00 Extra Length 002E
04C7 0002 00 00 Comment Length 0000
04C9 0002 00 00 Disk Start 0000
04CB 0002 00 00 Int File Attributes 0000
[Bit 0] 0 'Binary Data'
04CD 0004 00 00 00 00 Ext File Attributes 00000000
04D1 0004 FF FF FF FF Local Header Offset FFFFFFFF
04D5 0009 52 45 41 44 Filename 'README.md'
4D 45 2E 6D
64
04DE 0002 6E 75 Extra ID #0001 756E 'nu: ASi Unix'
04E0 0002 0E 00 Length 000E
04E2 000E 1A D9 B2 1D Extra Payload 1A D9 B2 1D ED 01 00 00 00 00 F5 01
ED 01 00 00 00 00
00 00 F5 01
00 00
04F0 0002 01 00 Extra ID #0002 0001 'ZIP64'
04F2 0002 18 00 Length 0018
04F4 0008 95 03 00 00 Uncompressed Size 0000000000000395
00 00 00 00
04FC 0008 FA 01 00 00 Compressed Size 00000000000001FA
00 00 00 00
0504 0008 F5 01 00 00 Offset to Local Dir 00000000000001F5
00 00 00 00
050C 0004 50 4B 06 06 ZIP64 END CENTRAL DIR 06064B50
RECORD
0510 0008 2C 00 00 00 Size of record 000000000000002C
00 00 00 00
0518 0001 2D Created Zip Spec 2D '4.5'
0519 0001 00 Created OS 00 'MS-DOS'
051A 0001 2D Extract Zip Spec 2D '4.5'
051B 0001 00 Extract OS 00 'MS-DOS'
051C 0004 00 00 00 00 Number of this disk 00000000
0520 0004 00 00 00 00 Central Dir Disk no 00000000
0524 0008 02 00 00 00 Entries in this disk 0000000000000002
00 00 00 00
052C 0008 02 00 00 00 Total Entries 0000000000000002
00 00 00 00
0534 0008 C8 00 00 00 Size of Central Dir 00000000000000C8
00 00 00 00
053C 0008 44 04 00 00 Offset to Central dir 0000000000000444
00 00 00 00
0544 0004 50 4B 06 07 ZIP64 END CENTRAL DIR 07064B50
LOCATOR
0548 0004 00 00 0C 05 Central Dir Disk no 050C0000
054C 0008 00 00 00 00 Offset to Central dir 0001000000000000
00 00 01 00
0554 0004 00 00 50 4B Total no of Disks 4B500000
0556 0004 50 4B 05 06 END CENTRAL HEADER 06054B50
055A 0002 FF FF Number of this disk FFFF
055C 0002 FF FF Central Dir Disk no FFFF
055E 0002 FF FF Entries in this disk FFFF
0560 0002 FF FF Total Entries FFFF
0562 0004 FF FF FF FF Size of Central Dir FFFFFFFF
0566 0004 FF FF FF FF Offset to Central Dir FFFFFFFF
056A 0002 00 00 Comment Length 0000
Done
Looking at your code, the disk
should be a 32-bit value
// End of central directory locator for ZIP64.
struct EOCL64 {
SICE uint32_t signature = 0x07064b50;
uint16_t disk = 0;
uint64_t offset = 0; // TO ASSIGN.
uint32_t disks = 1;
};
[EDIT]
Next thing to note is the gaps between entries. Local Header 1 ends at 0x4A + 0x1A2 payload bytes = 0x1ED. But Local header 2 starts at 0x1F5. You have a gap with nothing in it.
Same goes for local header 2.
The zip spec doesn't explicitly say you shouldn't have gaps in the zip file, but is is implied in section 4.3.6 Overall .ZIP file format
. For maximum interoperability with unzip clients I advise against leaving spaces between entries.
答案2
得分: 1
关于使用 ASi Unix Extra Field
0x756e。
我有很多zip文件,只找到一个使用这个字段的。我看到infozip的 unzip
和 zipinfo
可以处理它,但姊妹程序 zip
不行。我能找到的一个示例确实具有您提到的相同长度,即0x0E字节,所以您的长度计算可能是正确的。
这是一个很少使用的字段。除非您有特定的需要使用它,否则我建议使用 (0x5455) Extended Timestamp [UT]
和 (0x7875) Unix Extra type 3 [ux]
代替。
我快速修改了一下以转储一些关于您的额外字段的详细信息。这是我看到的 README.md
文件的内容。这是否与您期望看到的内容相符?
04DE 04DF 0002 6E 75 额外ID #1 30062 (0x756E) 'ASi Unix [un]'
04E0 04E1 0002 0E 00 长度 14 (0xE)
04E2 04E5 0004 1A D9 B2 1D CRC 498260250 (0x1DB2D91A)
04E6 04E7 0002 ED 01 模式 493 (0x1ED)
04E8 04EB 0004 00 00 00 00 SizDev 0 (0x0)
04EC 04ED 0002 F5 01 UID 501 (0x1F5)
04EE 04EF 0002 00 00 GID 0 (0x0)
看起来该模式是 rwxr-xr-x
。
英文:
Regarding the use of the ASi Unix Extra Field
0x756e.
I have a lot of zip files and I can only find one that uses this field. I do see that infozip's unzip
and zipinfo
can deal with it, but the sister program zip
does not. The one example I can find for it does have the same length you have, namely 0x0E bytes, so your length calculation is probably ok.
This is a field that isn't used in anger. Unless you have a specific need to use it I'd recommend using (0x5455) Extended Timestamp [UT]
and (0x7875) Unix Extra type 3 [ux]
instead.
I did a very quick hack to dump some details of one of your extra fields. This is what I see for the README.md
file. Does that match what you expect to see?
04DE 04DF 0002 6E 75 Extra ID #1 30062 (0x756E) 'ASi Unix [un]'
04E0 04E1 0002 0E 00 Length 14 (0xE)
04E2 04E5 0004 1A D9 B2 1D CRC 498260250 (0x1DB2D91A)
04E6 04E7 0002 ED 01 Mode 493 (0x1ED)
04E8 04EB 0004 00 00 00 00 SizDev 0 (0x0)
04EC 04ED 0002 F5 01 UID 501 (0x1F5)
04EE 04EF 0002 00 00 GID 0 (0x0)
Think that mode is rwxr-xr-x
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论