static const char *compression_name(int compression);
static void process_extra(const char *, size_t, struct zip_entry *);
-int archive_read_support_format_zip_streamable(struct archive *);
-int archive_read_support_format_zip_seekable(struct archive *);
-
int
archive_read_support_format_zip_streamable(struct archive *_a)
{
/* Sanity-check the EOCD we've found. */
/* This must be the first volume. */
- if (archive_le16dec(p + 4) != 0) {
+ if (archive_le16dec(p + 4) != 0)
return 0;
- }
/* Central directory must be on this volume. */
- if (archive_le16dec(p + 4) != archive_le16dec(p + 6)) {
+ if (archive_le16dec(p + 4) != archive_le16dec(p + 6))
return 0;
- }
/* All central directory entries must be on this volume. */
if (archive_le16dec(p + 10) != archive_le16dec(p + 8))
return 0;
}
static int
-read_zip64_eocd(struct zip *zip, const char *p, int64_t current_offset)
+read_zip64_eocd(struct archive_read *a, struct zip *zip,
+ const char *p, int64_t current_offset)
{
- (void)zip; /* UNUSED */
- (void)p; /* UNUSED */
- (void)current_offset; /* UNUSED */
- /* Not yet supported. */
- return 0;
+ int64_t eocd64_offset;
+ int64_t eocd64_size;
+
+ /* Sanity-check the locator record. */
+
+ /* Central dir must be on first volume. */
+ if (archive_le32dec(p + 4) != 0)
+ return 0;
+ /* Must be only a single volume. */
+ if (archive_le32dec(p + 16) != 1)
+ return 0;
+
+ /* Find the Zip64 EOCD record. */
+ eocd64_offset = archive_le64dec(p + 8);
+ current_offset = __archive_read_seek(a, eocd64_offset, SEEK_SET);
+ if (current_offset < 0)
+ return 0;
+ if ((p = __archive_read_ahead(a, 56, NULL)) == NULL)
+ return 0;
+ /* Make sure we can read all of it. */
+ eocd64_size = archive_le64dec(p + 4) + 12;
+ if (eocd64_size < 56 || eocd64_size > 16384)
+ return 0;
+ if ((p = __archive_read_ahead(a, eocd64_size, NULL)) == NULL)
+ return 0;
+
+ /* Sanity-check the EOCD64 */
+ if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */
+ return 0;
+ if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */
+ return 0;
+ /* CD can't be split. */
+ if (archive_le64dec(p + 24) != archive_le64dec(p + 32))
+ return 0;
+
+ /* Save the central directory offset for later use. */
+ zip->central_directory_offset = archive_le64dec(p + 48);
+
+ return 32;
}
return 0;
if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
return 0;
+ /* TODO: Rework this to search backwards from the end. We
+ * normally expect the EOCD record to be at the very end, so
+ * that should be significantly faster. Tricky part: Make
+ * sure we still prefer the Zip64 locator if it's present. */
for (i = 0; i <= tail - 22;) {
switch (p[i + 3]) {
case 'P': i += 3; break;
break;
case 007:
if (memcmp(p + i, "PK\006\007", 4) == 0) {
- int ret = read_zip64_eocd(zip, p + i, current_offset + i);
+ int ret = read_zip64_eocd(a, zip,
+ p + i, current_offset + i);
if (ret > 0)
return (ret);
}
}
zip_read_consume(a, filename_length);
+ /* Work around a bug in Info-Zip: When reading from a pipe, it
+ * stats the pipe instead of synthesizing a file entry. */
+ if ((zip_entry->mode & AE_IFMT) == AE_IFIFO) {
+ zip_entry->mode &= ~ AE_IFMT;
+ zip_entry->mode |= AE_IFREG;
+ }
+
if ((zip_entry->mode & AE_IFMT) == 0) {
/* Especially in streaming mode, we can end up
here without having seen proper mode information.