}
break;
}
- case 0x7461:
- /* Experimental 'at' field */
- if (datasize >= 2) {
- zip_entry->system
- = archive_le16dec(p + offset) >> 8;
- offset += 2;
- datasize -= 2;
+ case 0x414C:
+ /* Experimental 'LA' field */
+ if (datasize >= 1) {
+ // 1 byte system identifier
+ zip_entry->system = p[offset];
+ offset += 1;
+ datasize -= 1;
}
if (datasize >= 2) {
// 2 byte "internal file attributes"
datasize -= 2;
}
if (datasize >= 4) {
+ // 4 byte "external file attributes"
uint32_t external_attributes
= archive_le32dec(p + offset);
if (zip_entry->system == 3) {
memset(local_extra, 0, sizeof(local_extra));
e = local_extra;
+ /* First, extra blocks that are the same between
+ * the local file header and the central directory.
+ * We format them once and then duplicate them. */
+
/* UT timestamp, length depends on what timestamps are set. */
memcpy(e, "UT", 2);
archive_le16enc(e + 2,
e += 4;
/* Copy UT and ux into central directory as well. */
- /* (Zip64 extended data varies between local header and
- * central directory, so we cannot just copy it.) */
zip->file_header_extra_offset = zip->central_directory_bytes;
cd_extra = cd_alloc(zip, e - local_extra);
memcpy(cd_extra, local_extra, e - local_extra);
+ /*
+ * Following extra blocks vary between local header and
+ * central directory. These are the local header versions.
+ * Central directory versions get formatted in
+ * archive_write_zip_finish_entry() below.
+ */
+
/* "[Zip64 entry] in the local header MUST include BOTH
* original [uncompressed] and compressed size fields." */
if (zip->entry_uses_zip64) {
archive_le16enc(zip64_start + 2, e - (zip64_start + 4));
}
- { /* Experimental 'at' extension to support streaming. */
+ { /* Experimental 'LA' extension to improve streaming. */
unsigned char *external_info = e;
- memcpy(e, "at\000\000", 4);
+ memcpy(e, "LA\000\000", 4); // 0x414C + 2-byte length
e += 4;
- archive_le16enc(e, /* system + version written by */
- 3 * 256 + version_needed);
- e += 2;
+ e[0] = 3; /* system */
+ e += 1;
archive_le16enc(e, 0); /* internal file attributes */
e += 2;
archive_le32enc(e, /* external file attributes */
assertEqualInt(i4(q + 18), sizeof(file_data1) + sizeof(file_data2)); /* Compressed size */
assertEqualInt(i4(q + 22), sizeof(file_data1) + sizeof(file_data2)); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 40); /* Extra field length */
+ assertEqualInt(i2(q + 28), 39); /* Extra field length */
assertEqualMem(q + 30, file_name, strlen(file_name)); /* Pathname */
extra_start = q = q + 30 + strlen(file_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
assertEqualInt(i4(q + 11), file_gid); /* 'Ux' GID */
q = q + 4 + i2(q + 2);
- assertEqualInt(i2(q), 0x7461); /* 'at' experimental extension header */
- assertEqualInt(i2(q + 2), 8); /* 'at' size */
- assertEqualInt(i2(q + 4), 3 * 256 + 10); /* version made by */
- assertEqualInt(i2(q + 6), 0); /* internal file attributes */
- assertEqualInt(i4(q + 8) >> 16 & 01777, file_perm); /* external file attributes */
+ assertEqualInt(i2(q), 0x414c); /* 'LA' experimental extension header */
+ assertEqualInt(i2(q + 2), 7); /* size */
+ assertEqualInt(q[4], 3); /* system */
+ assertEqualInt(i2(q + 5), 0); /* internal file attributes */
+ assertEqualInt(i4(q + 7) >> 16 & 01777, file_perm); /* external file attributes */
q = q + 4 + i2(q + 2);
assert(q == extra_start + i2(local_header + 28));
assertEqualInt(i4(q + 18), 0); /* Compressed size */
assertEqualInt(i4(q + 22), 0); /* Uncompressed size */
assertEqualInt(i2(q + 26), strlen(folder_name)); /* Pathname length */
- assertEqualInt(i2(q + 28), 40); /* Extra field length */
+ assertEqualInt(i2(q + 28), 39); /* Extra field length */
assertEqualMem(q + 30, folder_name, strlen(folder_name)); /* Pathname */
extra_start = q = q + 30 + strlen(folder_name);
assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */
assertEqualInt(i4(q + 11), folder_gid); /* 'ux' GID */
q = q + 4 + i2(q + 2);
- assertEqualInt(i2(q), 0x7461); /* 'at' experimental extension header */
- assertEqualInt(i2(q + 2), 8); /* 'at' size */
- assertEqualInt(i2(q + 4), 3 * 256 + 20); /* version made by */
- assertEqualInt(i2(q + 6), 0); /* internal file attributes */
- assertEqualInt(i4(q + 8) >> 16 & 01777, folder_perm); /* external file attributes */
+ assertEqualInt(i2(q), 0x414c); /* 'LA' experimental extension header */
+ assertEqualInt(i2(q + 2), 7); /* size */
+ assertEqualInt(q[4], 3); /* system */
+ assertEqualInt(i2(q + 5), 0); /* internal file attributes */
+ assertEqualInt(i4(q + 7) >> 16 & 01777, folder_perm); /* external file attributes */
q = q + 4 + i2(q + 2);
assert(q == extra_start + i2(local_header + 28));
/* assertEqualInt(i4(p + 18), sizeof(file_data)); */ /* Compressed size */
/* assertEqualInt(i4(p + 22), sizeof(file_data)); */ /* Uncompressed size not stored because we're using length-at-end. */
assertEqualInt(i2(p + 26), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(p + 28), 36); /* Extra field length */
+ assertEqualInt(i2(p + 28), 35); /* Extra field length */
assertEqualMem(p + 30, file_name, strlen(file_name)); /* Pathname */
p = extension_start = local_header + 30 + strlen(file_name);
extension_end = extension_start + i2(local_header + 28);
assertEqualInt(i4(p + 11), file_gid); /* 'Ux' GID */
p += 4 + i2(p + 2);
- assertEqualInt(i2(p), 0x7461); /* 'at' experimental extension header */
- assertEqualInt(i2(p + 2), 8); /* 'at' size */
- assertEqualInt(i2(p + 4), 3 * 256 + 20); /* version made by */
- assertEqualInt(i2(p + 6), 0); /* internal file attributes */
- assertEqualInt(i4(p + 8) >> 16 & 01777, file_perm); /* external file attributes */
+ assertEqualInt(i2(p), 0x414c); /* 'LA' experimental extension header */
+ assertEqualInt(i2(p + 2), 7); /* 'at' size */
+ assertEqualInt(p[4], 3); /* system */
+ assertEqualInt(i2(p + 5), 0); /* internal file attributes */
+ assertEqualInt(i4(p + 7) >> 16 & 01777, file_perm); /* external file attributes */
p += 4 + i2(p + 2);
/* Just in case: Report any extra extensions. */
/* assertEqualInt(i4(p + 18), sizeof(file_data)); */ /* Compressed size */
/* assertEqualInt(i4(p + 22), sizeof(file_data)); */ /* Uncompressed size not stored because we're using length-at-end. */
assertEqualInt(i2(p + 26), strlen(file_name)); /* Pathname length */
- assertEqualInt(i2(p + 28), 56); /* Extra field length */
+ assertEqualInt(i2(p + 28), 55); /* Extra field length */
assertEqualMem(p + 30, file_name, strlen(file_name)); /* Pathname */
p = extension_start = local_header + 30 + strlen(file_name);
extension_end = extension_start + i2(local_header + 28);
/* compressed file size we can't verify here */
p += 4 + i2(p + 2);
- assertEqualInt(i2(p), 0x7461); /* 'at' experimental extension header */
- assertEqualInt(i2(p + 2), 8); /* 'at' size */
- assertEqualInt(i2(p + 4), 3 * 256 + 45); /* version made by */
- assertEqualInt(i2(p + 6), 0); /* internal file attributes */
- assertEqualInt(i4(p + 8) >> 16 & 01777, file_perm); /* external file attributes */
+ assertEqualInt(i2(p), 0x414c); /* 'LA' experimental extension header */
+ assertEqualInt(i2(p + 2), 7); /* 'at' size */
+ assertEqualInt(p[4], 3); /* system */
+ assertEqualInt(i2(p + 5), 0); /* internal file attributes */
+ assertEqualInt(i4(p + 7) >> 16 & 01777, file_perm); /* external file attributes */
p += 4 + i2(p + 2);
/* Just in case: Report any extra extensions. */