为什么解压会忽略我的zip64中央目录记录?

huangapple go评论95阅读模式
英文:

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:

  1. Check CRC Calculation: Ensure that the CRC-32 calculation is correct. Verify that the CRC values calculated match the expected values.

  2. 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.

  3. 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.

  4. 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.

  5. Padding: Ensure that there is proper padding for alignment when writing structures. ZIP format often requires specific byte alignments.

  6. 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.

  7. Debugging: Use debugging tools and print statements to inspect the data being written to the archive headers and compare it to the expected format.

  8. 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.

  9. File Permission Handling: Verify that the permissions you are using for the ASi UNIX extra field match the expected format in your target system.

  10. 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的 unzipzipinfo 可以处理它,但姊妹程序 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

huangapple
  • 本文由 发表于 2023年6月29日 22:06:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581811.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定