Blame libarchive/archive_read_support_format_zip.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2004-2013 Tim Kientzle
Packit 08bd4c
 * Copyright (c) 2011-2012,2014 Michihiro NAKAJIMA
Packit 08bd4c
 * Copyright (c) 2013 Konrad Kleine
Packit 08bd4c
 * All rights reserved.
Packit 08bd4c
 *
Packit 08bd4c
 * Redistribution and use in source and binary forms, with or without
Packit 08bd4c
 * modification, are permitted provided that the following conditions
Packit 08bd4c
 * are met:
Packit 08bd4c
 * 1. Redistributions of source code must retain the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer.
Packit 08bd4c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer in the
Packit 08bd4c
 *    documentation and/or other materials provided with the distribution.
Packit 08bd4c
 *
Packit 08bd4c
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit 08bd4c
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 08bd4c
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 08bd4c
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 08bd4c
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 08bd4c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 08bd4c
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 08bd4c
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 08bd4c
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 08bd4c
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#include "archive_platform.h"
Packit 08bd4c
__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * The definitive documentation of the Zip file format is:
Packit 08bd4c
 *   http://www.pkware.com/documents/casestudies/APPNOTE.TXT
Packit 08bd4c
 *
Packit 08bd4c
 * The Info-Zip project has pioneered various extensions to better
Packit 08bd4c
 * support Zip on Unix, including the 0x5455 "UT", 0x5855 "UX", 0x7855
Packit 08bd4c
 * "Ux", and 0x7875 "ux" extensions for time and ownership
Packit 08bd4c
 * information.
Packit 08bd4c
 *
Packit 08bd4c
 * History of this code: The streaming Zip reader was first added to
Packit 08bd4c
 * libarchive in January 2005.  Support for seekable input sources was
Packit 08bd4c
 * added in Nov 2011.  Zip64 support (including a significant code
Packit 08bd4c
 * refactoring) was added in 2014.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_ERRNO_H
Packit 08bd4c
#include <errno.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STDLIB_H
Packit 08bd4c
#include <stdlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
#include <zlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
#include "archive.h"
Packit 08bd4c
#include "archive_digest_private.h"
Packit 08bd4c
#include "archive_cryptor_private.h"
Packit 08bd4c
#include "archive_endian.h"
Packit 08bd4c
#include "archive_entry.h"
Packit 08bd4c
#include "archive_entry_locale.h"
Packit 08bd4c
#include "archive_hmac_private.h"
Packit 08bd4c
#include "archive_private.h"
Packit 08bd4c
#include "archive_rb.h"
Packit 08bd4c
#include "archive_read_private.h"
Packit 08bd4c
Packit 08bd4c
#ifndef HAVE_ZLIB_H
Packit 08bd4c
#include "archive_crc32.h"
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
struct zip_entry {
Packit 08bd4c
	struct archive_rb_node	node;
Packit 08bd4c
	struct zip_entry	*next;
Packit 08bd4c
	int64_t			local_header_offset;
Packit 08bd4c
	int64_t			compressed_size;
Packit 08bd4c
	int64_t			uncompressed_size;
Packit 08bd4c
	int64_t			gid;
Packit 08bd4c
	int64_t			uid;
Packit 08bd4c
	struct archive_string	rsrcname;
Packit 08bd4c
	time_t			mtime;
Packit 08bd4c
	time_t			atime;
Packit 08bd4c
	time_t			ctime;
Packit 08bd4c
	uint32_t		crc32;
Packit 08bd4c
	uint16_t		mode;
Packit 08bd4c
	uint16_t		zip_flags; /* From GP Flags Field */
Packit 08bd4c
	unsigned char		compression;
Packit 08bd4c
	unsigned char		system; /* From "version written by" */
Packit 08bd4c
	unsigned char		flags; /* Our extra markers. */
Packit 08bd4c
	unsigned char		decdat;/* Used for Decryption check */
Packit 08bd4c
Packit 08bd4c
	/* WinZip AES encryption extra field should be available
Packit 08bd4c
	 * when compression is 99. */
Packit 08bd4c
	struct {
Packit 08bd4c
		/* Vendor version: AE-1 - 0x0001, AE-2 - 0x0002 */
Packit 08bd4c
		unsigned	vendor;
Packit 08bd4c
#define AES_VENDOR_AE_1	0x0001
Packit 08bd4c
#define AES_VENDOR_AE_2	0x0002
Packit 08bd4c
		/* AES encryption strength:
Packit 08bd4c
		 * 1 - 128 bits, 2 - 192 bits, 2 - 256 bits. */
Packit 08bd4c
		unsigned	strength;
Packit 08bd4c
		/* Actual compression method. */
Packit 08bd4c
		unsigned char	compression;
Packit 08bd4c
	}			aes_extra;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct trad_enc_ctx {
Packit 08bd4c
	uint32_t	keys[3];
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/* Bits used in zip_flags. */
Packit 08bd4c
#define ZIP_ENCRYPTED	(1 << 0)
Packit 08bd4c
#define ZIP_LENGTH_AT_END	(1 << 3)
Packit 08bd4c
#define ZIP_STRONG_ENCRYPTED	(1 << 6)
Packit 08bd4c
#define ZIP_UTF8_NAME	(1 << 11)
Packit 08bd4c
/* See "7.2 Single Password Symmetric Encryption Method"
Packit 08bd4c
   in http://www.pkware.com/documents/casestudies/APPNOTE.TXT */
Packit 08bd4c
#define ZIP_CENTRAL_DIRECTORY_ENCRYPTED	(1 << 13)
Packit 08bd4c
Packit 08bd4c
/* Bits used in flags. */
Packit 08bd4c
#define LA_USED_ZIP64	(1 << 0)
Packit 08bd4c
#define LA_FROM_CENTRAL_DIRECTORY (1 << 1)
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * See "WinZip - AES Encryption Information"
Packit 08bd4c
 *     http://www.winzip.com/aes_info.htm
Packit 08bd4c
 */
Packit 08bd4c
/* Value used in compression method. */
Packit 08bd4c
#define WINZIP_AES_ENCRYPTION	99
Packit 08bd4c
/* Authentication code size. */
Packit 08bd4c
#define AUTH_CODE_SIZE	10
Packit 08bd4c
/**/
Packit 08bd4c
#define MAX_DERIVED_KEY_BUF_SIZE	(AES_MAX_KEY_SIZE * 2 + 2)
Packit 08bd4c
Packit 08bd4c
struct zip {
Packit 08bd4c
	/* Structural information about the archive. */
Packit 08bd4c
	struct archive_string	format_name;
Packit 08bd4c
	int64_t			central_directory_offset;
Packit 08bd4c
	size_t			central_directory_entries_total;
Packit 08bd4c
	size_t			central_directory_entries_on_this_disk;
Packit 08bd4c
	int			has_encrypted_entries;
Packit 08bd4c
Packit 08bd4c
	/* List of entries (seekable Zip only) */
Packit 08bd4c
	struct zip_entry	*zip_entries;
Packit 08bd4c
	struct archive_rb_tree	tree;
Packit 08bd4c
	struct archive_rb_tree	tree_rsrc;
Packit 08bd4c
Packit 08bd4c
	/* Bytes read but not yet consumed via __archive_read_consume() */
Packit 08bd4c
	size_t			unconsumed;
Packit 08bd4c
Packit 08bd4c
	/* Information about entry we're currently reading. */
Packit 08bd4c
	struct zip_entry	*entry;
Packit 08bd4c
	int64_t			entry_bytes_remaining;
Packit 08bd4c
Packit 08bd4c
	/* These count the number of bytes actually read for the entry. */
Packit 08bd4c
	int64_t			entry_compressed_bytes_read;
Packit 08bd4c
	int64_t			entry_uncompressed_bytes_read;
Packit 08bd4c
Packit 08bd4c
	/* Running CRC32 of the decompressed data */
Packit 08bd4c
	unsigned long		entry_crc32;
Packit 08bd4c
	unsigned long		(*crc32func)(unsigned long, const void *,
Packit 08bd4c
				    size_t);
Packit 08bd4c
	char			ignore_crc32;
Packit 08bd4c
Packit 08bd4c
	/* Flags to mark progress of decompression. */
Packit 08bd4c
	char			decompress_init;
Packit 08bd4c
	char			end_of_entry;
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	unsigned char 		*uncompressed_buffer;
Packit 08bd4c
	size_t 			uncompressed_buffer_size;
Packit 08bd4c
	z_stream		stream;
Packit 08bd4c
	char			stream_valid;
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
	struct archive_string_conv *sconv;
Packit 08bd4c
	struct archive_string_conv *sconv_default;
Packit 08bd4c
	struct archive_string_conv *sconv_utf8;
Packit 08bd4c
	int			init_default_conversion;
Packit 08bd4c
	int			process_mac_extensions;
Packit 08bd4c
Packit 08bd4c
	char			init_decryption;
Packit 08bd4c
Packit 08bd4c
	/* Decryption buffer. */
Packit 08bd4c
	/*
Packit 08bd4c
	 * The decrypted data starts at decrypted_ptr and
Packit 08bd4c
	 * extends for decrypted_bytes_remaining.  Decryption
Packit 08bd4c
	 * adds new data to the end of this block, data is returned
Packit 08bd4c
	 * to clients from the beginning.  When the block hits the
Packit 08bd4c
	 * end of decrypted_buffer, it has to be shuffled back to
Packit 08bd4c
	 * the beginning of the buffer.
Packit 08bd4c
	 */
Packit 08bd4c
	unsigned char 		*decrypted_buffer;
Packit 08bd4c
	unsigned char 		*decrypted_ptr;
Packit 08bd4c
	size_t 			decrypted_buffer_size;
Packit 08bd4c
	size_t 			decrypted_bytes_remaining;
Packit 08bd4c
	size_t 			decrypted_unconsumed_bytes;
Packit 08bd4c
Packit 08bd4c
	/* Traditional PKWARE decryption. */
Packit 08bd4c
	struct trad_enc_ctx	tctx;
Packit 08bd4c
	char			tctx_valid;
Packit 08bd4c
Packit 08bd4c
	/* WinZip AES decryption. */
Packit 08bd4c
	/* Contexts used for AES decryption. */
Packit 08bd4c
	archive_crypto_ctx	cctx;
Packit 08bd4c
	char			cctx_valid;
Packit 08bd4c
	archive_hmac_sha1_ctx	hctx;
Packit 08bd4c
	char			hctx_valid;
Packit 08bd4c
Packit 08bd4c
	/* Strong encryption's decryption header information. */
Packit 08bd4c
	unsigned		iv_size;
Packit 08bd4c
	unsigned		alg_id;
Packit 08bd4c
	unsigned		bit_len;
Packit 08bd4c
	unsigned		flags;
Packit 08bd4c
	unsigned		erd_size;
Packit 08bd4c
	unsigned		v_size;
Packit 08bd4c
	unsigned		v_crc32;
Packit 08bd4c
	uint8_t			*iv;
Packit 08bd4c
	uint8_t			*erd;
Packit 08bd4c
	uint8_t			*v_data;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/* Many systems define min or MIN, but not all. */
Packit 08bd4c
#define	zipmin(a,b) ((a) < (b) ? (a) : (b))
Packit 08bd4c
Packit 08bd4c
/* ------------------------------------------------------------------------ */
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
  Traditional PKWARE Decryption functions.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)
Packit 08bd4c
{
Packit 08bd4c
	uint8_t t;
Packit 08bd4c
#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)
Packit 08bd4c
Packit 08bd4c
	ctx->keys[0] = CRC32(ctx->keys[0], c);
Packit 08bd4c
	ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;
Packit 08bd4c
	t = (ctx->keys[1] >> 24) & 0xff;
Packit 08bd4c
	ctx->keys[2] = CRC32(ctx->keys[2], t);
Packit 08bd4c
#undef CRC32
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static uint8_t
Packit 08bd4c
trad_enc_decrypt_byte(struct trad_enc_ctx *ctx)
Packit 08bd4c
{
Packit 08bd4c
	unsigned temp = ctx->keys[2] | 2;
Packit 08bd4c
	return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
trad_enc_decrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in,
Packit 08bd4c
    size_t in_len, uint8_t *out, size_t out_len)
Packit 08bd4c
{
Packit 08bd4c
	unsigned i, max;
Packit 08bd4c
Packit 08bd4c
	max = (unsigned)((in_len < out_len)? in_len: out_len);
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < max; i++) {
Packit 08bd4c
		uint8_t t = in[i] ^ trad_enc_decrypt_byte(ctx);
Packit 08bd4c
		out[i] = t;
Packit 08bd4c
		trad_enc_update_keys(ctx, t);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len,
Packit 08bd4c
    const uint8_t *key, size_t key_len, uint8_t *crcchk)
Packit 08bd4c
{
Packit 08bd4c
	uint8_t header[12];
Packit 08bd4c
Packit 08bd4c
	if (key_len < 12) {
Packit 08bd4c
		*crcchk = 0xff;
Packit 08bd4c
		return -1;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	ctx->keys[0] = 305419896L;
Packit 08bd4c
	ctx->keys[1] = 591751049L;
Packit 08bd4c
	ctx->keys[2] = 878082192L;
Packit 08bd4c
Packit 08bd4c
	for (;pw_len; --pw_len)
Packit 08bd4c
		trad_enc_update_keys(ctx, *pw++);
Packit 08bd4c
Packit 08bd4c
	trad_enc_decrypt_update(ctx, key, 12, header, 12);
Packit 08bd4c
	/* Return the last byte for CRC check. */
Packit 08bd4c
	*crcchk = header[11];
Packit 08bd4c
	return 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#if 0
Packit 08bd4c
static void
Packit 08bd4c
crypt_derive_key_sha1(const void *p, int size, unsigned char *key,
Packit 08bd4c
    int key_size)
Packit 08bd4c
{
Packit 08bd4c
#define MD_SIZE 20
Packit 08bd4c
	archive_sha1_ctx ctx;
Packit 08bd4c
	unsigned char md1[MD_SIZE];
Packit 08bd4c
	unsigned char md2[MD_SIZE * 2];
Packit 08bd4c
	unsigned char mkb[64];
Packit 08bd4c
	int i;
Packit 08bd4c
Packit 08bd4c
	archive_sha1_init(&ctx;;
Packit 08bd4c
	archive_sha1_update(&ctx, p, size);
Packit 08bd4c
	archive_sha1_final(&ctx, md1);
Packit 08bd4c
Packit 08bd4c
	memset(mkb, 0x36, sizeof(mkb));
Packit 08bd4c
	for (i = 0; i < MD_SIZE; i++)
Packit 08bd4c
		mkb[i] ^= md1[i];
Packit 08bd4c
	archive_sha1_init(&ctx;;
Packit 08bd4c
	archive_sha1_update(&ctx, mkb, sizeof(mkb));
Packit 08bd4c
	archive_sha1_final(&ctx, md2);
Packit 08bd4c
Packit 08bd4c
	memset(mkb, 0x5C, sizeof(mkb));
Packit 08bd4c
	for (i = 0; i < MD_SIZE; i++)
Packit 08bd4c
		mkb[i] ^= md1[i];
Packit 08bd4c
	archive_sha1_init(&ctx;;
Packit 08bd4c
	archive_sha1_update(&ctx, mkb, sizeof(mkb));
Packit 08bd4c
	archive_sha1_final(&ctx, md2 + MD_SIZE);
Packit 08bd4c
Packit 08bd4c
	if (key_size > 32)
Packit 08bd4c
		key_size = 32;
Packit 08bd4c
	memcpy(key, md2, key_size);
Packit 08bd4c
#undef MD_SIZE
Packit 08bd4c
}
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Common code for streaming or seeking modes.
Packit 08bd4c
 *
Packit 08bd4c
 * Includes code to read local file headers, decompress data
Packit 08bd4c
 * from entry bodies, and common API.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
static unsigned long
Packit 08bd4c
real_crc32(unsigned long crc, const void *buff, size_t len)
Packit 08bd4c
{
Packit 08bd4c
	return crc32(crc, buff, (unsigned int)len);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Used by "ignorecrc32" option to speed up tests. */
Packit 08bd4c
static unsigned long
Packit 08bd4c
fake_crc32(unsigned long crc, const void *buff, size_t len)
Packit 08bd4c
{
Packit 08bd4c
	(void)crc; /* UNUSED */
Packit 08bd4c
	(void)buff; /* UNUSED */
Packit 08bd4c
	(void)len; /* UNUSED */
Packit 08bd4c
	return 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const struct {
Packit 08bd4c
	int id;
Packit 08bd4c
	const char * name;
Packit 08bd4c
} compression_methods[] = {
Packit 08bd4c
	{0, "uncompressed"}, /* The file is stored (no compression) */
Packit 08bd4c
	{1, "shrinking"}, /* The file is Shrunk */
Packit 08bd4c
	{2, "reduced-1"}, /* The file is Reduced with compression factor 1 */
Packit 08bd4c
	{3, "reduced-2"}, /* The file is Reduced with compression factor 2 */
Packit 08bd4c
	{4, "reduced-3"}, /* The file is Reduced with compression factor 3 */
Packit 08bd4c
	{5, "reduced-4"}, /* The file is Reduced with compression factor 4 */
Packit 08bd4c
	{6, "imploded"},  /* The file is Imploded */
Packit 08bd4c
	{7, "reserved"},  /* Reserved for Tokenizing compression algorithm */
Packit 08bd4c
	{8, "deflation"}, /* The file is Deflated */
Packit 08bd4c
	{9, "deflation-64-bit"}, /* Enhanced Deflating using Deflate64(tm) */
Packit 08bd4c
	{10, "ibm-terse"},/* PKWARE Data Compression Library Imploding
Packit 08bd4c
			   * (old IBM TERSE) */
Packit 08bd4c
	{11, "reserved"}, /* Reserved by PKWARE */
Packit 08bd4c
	{12, "bzip"},     /* File is compressed using BZIP2 algorithm */
Packit 08bd4c
	{13, "reserved"}, /* Reserved by PKWARE */
Packit 08bd4c
	{14, "lzma"},     /* LZMA (EFS) */
Packit 08bd4c
	{15, "reserved"}, /* Reserved by PKWARE */
Packit 08bd4c
	{16, "reserved"}, /* Reserved by PKWARE */
Packit 08bd4c
	{17, "reserved"}, /* Reserved by PKWARE */
Packit 08bd4c
	{18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */
Packit 08bd4c
	{19, "ibm-lz777"},/* IBM LZ77 z Architecture (PFS) */
Packit 08bd4c
	{97, "wav-pack"}, /* WavPack compressed data */
Packit 08bd4c
	{98, "ppmd-1"},   /* PPMd version I, Rev 1 */
Packit 08bd4c
	{99, "aes"}       /* WinZip AES encryption  */
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
compression_name(const int compression)
Packit 08bd4c
{
Packit 08bd4c
	static const int num_compression_methods =
Packit 08bd4c
		sizeof(compression_methods)/sizeof(compression_methods[0]);
Packit 08bd4c
	int i=0;
Packit 08bd4c
Packit 08bd4c
	while(compression >= 0 && i < num_compression_methods) {
Packit 08bd4c
		if (compression_methods[i].id == compression)
Packit 08bd4c
			return compression_methods[i].name;
Packit 08bd4c
		i++;
Packit 08bd4c
	}
Packit 08bd4c
	return "??";
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Convert an MSDOS-style date/time into Unix-style time. */
Packit 08bd4c
static time_t
Packit 08bd4c
zip_time(const char *p)
Packit 08bd4c
{
Packit 08bd4c
	int msTime, msDate;
Packit 08bd4c
	struct tm ts;
Packit 08bd4c
Packit 08bd4c
	msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
Packit 08bd4c
	msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
Packit 08bd4c
Packit 08bd4c
	memset(&ts, 0, sizeof(ts));
Packit 08bd4c
	ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
Packit 08bd4c
	ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
Packit 08bd4c
	ts.tm_mday = msDate & 0x1f; /* Day of month. */
Packit 08bd4c
	ts.tm_hour = (msTime >> 11) & 0x1f;
Packit 08bd4c
	ts.tm_min = (msTime >> 5) & 0x3f;
Packit 08bd4c
	ts.tm_sec = (msTime << 1) & 0x3e;
Packit 08bd4c
	ts.tm_isdst = -1;
Packit 08bd4c
	return mktime(&ts);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * The extra data is stored as a list of
Packit 08bd4c
 *	id1+size1+data1 + id2+size2+data2 ...
Packit 08bd4c
 *  triplets.  id and size are 2 bytes each.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
process_extra(struct archive_read *a, const char *p, size_t extra_length, struct zip_entry* zip_entry)
Packit 08bd4c
{
Packit 08bd4c
	unsigned offset = 0;
Packit 08bd4c
Packit 08bd4c
	if (extra_length == 0) {
Packit 08bd4c
		return ARCHIVE_OK;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (extra_length < 4) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
Packit 08bd4c
		return ARCHIVE_FAILED;
Packit 08bd4c
	}
Packit 08bd4c
	while (offset <= extra_length - 4) {
Packit 08bd4c
		unsigned short headerid = archive_le16dec(p + offset);
Packit 08bd4c
		unsigned short datasize = archive_le16dec(p + offset + 2);
Packit 08bd4c
Packit 08bd4c
		offset += 4;
Packit 08bd4c
		if (offset + datasize > extra_length) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Extra data overflow: Need %d bytes but only found %d bytes",
Packit 08bd4c
			    (int)datasize, (int)(extra_length - offset));
Packit 08bd4c
			return ARCHIVE_FAILED;
Packit 08bd4c
		}
Packit 08bd4c
#ifdef DEBUG
Packit 08bd4c
		fprintf(stderr, "Header id 0x%04x, length %d\n",
Packit 08bd4c
		    headerid, datasize);
Packit 08bd4c
#endif
Packit 08bd4c
		switch (headerid) {
Packit 08bd4c
		case 0x0001:
Packit 08bd4c
			/* Zip64 extended information extra field. */
Packit 08bd4c
			zip_entry->flags |= LA_USED_ZIP64;
Packit 08bd4c
			if (zip_entry->uncompressed_size == 0xffffffff) {
Packit 08bd4c
				uint64_t t = 0;
Packit 08bd4c
				if (datasize < 8
Packit 08bd4c
				    || (t = archive_le64dec(p + offset)) > INT64_MAX) {
Packit 08bd4c
					archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
					    "Malformed 64-bit uncompressed size");
Packit 08bd4c
					return ARCHIVE_FAILED;
Packit 08bd4c
				}
Packit 08bd4c
				zip_entry->uncompressed_size = t;
Packit 08bd4c
				offset += 8;
Packit 08bd4c
				datasize -= 8;
Packit 08bd4c
			}
Packit 08bd4c
			if (zip_entry->compressed_size == 0xffffffff) {
Packit 08bd4c
				uint64_t t = 0;
Packit 08bd4c
				if (datasize < 8
Packit 08bd4c
				    || (t = archive_le64dec(p + offset)) > INT64_MAX) {
Packit 08bd4c
					archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
					    "Malformed 64-bit compressed size");
Packit 08bd4c
					return ARCHIVE_FAILED;
Packit 08bd4c
				}
Packit 08bd4c
				zip_entry->compressed_size = t;
Packit 08bd4c
				offset += 8;
Packit 08bd4c
				datasize -= 8;
Packit 08bd4c
			}
Packit 08bd4c
			if (zip_entry->local_header_offset == 0xffffffff) {
Packit 08bd4c
				uint64_t t = 0;
Packit 08bd4c
				if (datasize < 8
Packit 08bd4c
				    || (t = archive_le64dec(p + offset)) > INT64_MAX) {
Packit 08bd4c
					archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
					    "Malformed 64-bit local header offset");
Packit 08bd4c
					return ARCHIVE_FAILED;
Packit 08bd4c
				}
Packit 08bd4c
				zip_entry->local_header_offset = t;
Packit 08bd4c
				offset += 8;
Packit 08bd4c
				datasize -= 8;
Packit 08bd4c
			}
Packit 08bd4c
			/* archive_le32dec(p + offset) gives disk
Packit 08bd4c
			 * on which file starts, but we don't handle
Packit 08bd4c
			 * multi-volume Zip files. */
Packit 08bd4c
			break;
Packit 08bd4c
#ifdef DEBUG
Packit 08bd4c
		case 0x0017:
Packit 08bd4c
		{
Packit 08bd4c
			/* Strong encryption field. */
Packit 08bd4c
			if (archive_le16dec(p + offset) == 2) {
Packit 08bd4c
				unsigned algId =
Packit 08bd4c
					archive_le16dec(p + offset + 2);
Packit 08bd4c
				unsigned bitLen =
Packit 08bd4c
					archive_le16dec(p + offset + 4);
Packit 08bd4c
				int	 flags =
Packit 08bd4c
					archive_le16dec(p + offset + 6);
Packit 08bd4c
				fprintf(stderr, "algId=0x%04x, bitLen=%u, "
Packit 08bd4c
				    "flgas=%d\n", algId, bitLen,flags);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
#endif
Packit 08bd4c
		case 0x5455:
Packit 08bd4c
		{
Packit 08bd4c
			/* Extended time field "UT". */
Packit 08bd4c
			int flags = p[offset];
Packit 08bd4c
			offset++;
Packit 08bd4c
			datasize--;
Packit 08bd4c
			/* Flag bits indicate which dates are present. */
Packit 08bd4c
			if (flags & 0x01)
Packit 08bd4c
			{
Packit 08bd4c
#ifdef DEBUG
Packit 08bd4c
				fprintf(stderr, "mtime: %lld -> %d\n",
Packit 08bd4c
				    (long long)zip_entry->mtime,
Packit 08bd4c
				    archive_le32dec(p + offset));
Packit 08bd4c
#endif
Packit 08bd4c
				if (datasize < 4)
Packit 08bd4c
					break;
Packit 08bd4c
				zip_entry->mtime = archive_le32dec(p + offset);
Packit 08bd4c
				offset += 4;
Packit 08bd4c
				datasize -= 4;
Packit 08bd4c
			}
Packit 08bd4c
			if (flags & 0x02)
Packit 08bd4c
			{
Packit 08bd4c
				if (datasize < 4)
Packit 08bd4c
					break;
Packit 08bd4c
				zip_entry->atime = archive_le32dec(p + offset);
Packit 08bd4c
				offset += 4;
Packit 08bd4c
				datasize -= 4;
Packit 08bd4c
			}
Packit 08bd4c
			if (flags & 0x04)
Packit 08bd4c
			{
Packit 08bd4c
				if (datasize < 4)
Packit 08bd4c
					break;
Packit 08bd4c
				zip_entry->ctime = archive_le32dec(p + offset);
Packit 08bd4c
				offset += 4;
Packit 08bd4c
				datasize -= 4;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		case 0x5855:
Packit 08bd4c
		{
Packit 08bd4c
			/* Info-ZIP Unix Extra Field (old version) "UX". */
Packit 08bd4c
			if (datasize >= 8) {
Packit 08bd4c
				zip_entry->atime = archive_le32dec(p + offset);
Packit 08bd4c
				zip_entry->mtime =
Packit 08bd4c
				    archive_le32dec(p + offset + 4);
Packit 08bd4c
			}
Packit 08bd4c
			if (datasize >= 12) {
Packit 08bd4c
				zip_entry->uid =
Packit 08bd4c
				    archive_le16dec(p + offset + 8);
Packit 08bd4c
				zip_entry->gid =
Packit 08bd4c
				    archive_le16dec(p + offset + 10);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		case 0x6c78:
Packit 08bd4c
		{
Packit 08bd4c
			/* Experimental 'xl' field */
Packit 08bd4c
			/*
Packit 08bd4c
			 * Introduced Dec 2013 to provide a way to
Packit 08bd4c
			 * include external file attributes (and other
Packit 08bd4c
			 * fields that ordinarily appear only in
Packit 08bd4c
			 * central directory) in local file header.
Packit 08bd4c
			 * This provides file type and permission
Packit 08bd4c
			 * information necessary to support full
Packit 08bd4c
			 * streaming extraction.  Currently being
Packit 08bd4c
			 * discussed with other Zip developers
Packit 08bd4c
			 * ... subject to change.
Packit 08bd4c
			 *
Packit 08bd4c
			 * Format:
Packit 08bd4c
			 *  The field starts with a bitmap that specifies
Packit 08bd4c
			 *  which additional fields are included.  The
Packit 08bd4c
			 *  bitmap is variable length and can be extended in
Packit 08bd4c
			 *  the future.
Packit 08bd4c
			 *
Packit 08bd4c
			 *  n bytes - feature bitmap: first byte has low-order
Packit 08bd4c
			 *    7 bits.  If high-order bit is set, a subsequent
Packit 08bd4c
			 *    byte holds the next 7 bits, etc.
Packit 08bd4c
			 *
Packit 08bd4c
			 *  if bitmap & 1, 2 byte "version made by"
Packit 08bd4c
			 *  if bitmap & 2, 2 byte "internal file attributes"
Packit 08bd4c
			 *  if bitmap & 4, 4 byte "external file attributes"
Packit 08bd4c
			 *  if bitmap & 8, 2 byte comment length + n byte comment
Packit 08bd4c
			 */
Packit 08bd4c
			int bitmap, bitmap_last;
Packit 08bd4c
Packit 08bd4c
			if (datasize < 1)
Packit 08bd4c
				break;
Packit 08bd4c
			bitmap_last = bitmap = 0xff & p[offset];
Packit 08bd4c
			offset += 1;
Packit 08bd4c
			datasize -= 1;
Packit 08bd4c
Packit 08bd4c
			/* We only support first 7 bits of bitmap; skip rest. */
Packit 08bd4c
			while ((bitmap_last & 0x80) != 0
Packit 08bd4c
			    && datasize >= 1) {
Packit 08bd4c
				bitmap_last = p[offset];
Packit 08bd4c
				offset += 1;
Packit 08bd4c
				datasize -= 1;
Packit 08bd4c
			}
Packit 08bd4c
Packit 08bd4c
			if (bitmap & 1) {
Packit 08bd4c
				/* 2 byte "version made by" */
Packit 08bd4c
				if (datasize < 2)
Packit 08bd4c
					break;
Packit 08bd4c
				zip_entry->system
Packit 08bd4c
				    = archive_le16dec(p + offset) >> 8;
Packit 08bd4c
				offset += 2;
Packit 08bd4c
				datasize -= 2;
Packit 08bd4c
			}
Packit 08bd4c
			if (bitmap & 2) {
Packit 08bd4c
				/* 2 byte "internal file attributes" */
Packit 08bd4c
				uint32_t internal_attributes;
Packit 08bd4c
				if (datasize < 2)
Packit 08bd4c
					break;
Packit 08bd4c
				internal_attributes
Packit 08bd4c
				    = archive_le16dec(p + offset);
Packit 08bd4c
				/* Not used by libarchive at present. */
Packit 08bd4c
				(void)internal_attributes; /* UNUSED */
Packit 08bd4c
				offset += 2;
Packit 08bd4c
				datasize -= 2;
Packit 08bd4c
			}
Packit 08bd4c
			if (bitmap & 4) {
Packit 08bd4c
				/* 4 byte "external file attributes" */
Packit 08bd4c
				uint32_t external_attributes;
Packit 08bd4c
				if (datasize < 4)
Packit 08bd4c
					break;
Packit 08bd4c
				external_attributes
Packit 08bd4c
				    = archive_le32dec(p + offset);
Packit 08bd4c
				if (zip_entry->system == 3) {
Packit 08bd4c
					zip_entry->mode
Packit 08bd4c
					    = external_attributes >> 16;
Packit 08bd4c
				} else if (zip_entry->system == 0) {
Packit 08bd4c
					// Interpret MSDOS directory bit
Packit 08bd4c
					if (0x10 == (external_attributes & 0x10)) {
Packit 08bd4c
						zip_entry->mode = AE_IFDIR | 0775;
Packit 08bd4c
					} else {
Packit 08bd4c
						zip_entry->mode = AE_IFREG | 0664;
Packit 08bd4c
					}
Packit 08bd4c
					if (0x01 == (external_attributes & 0x01)) {
Packit 08bd4c
						// Read-only bit; strip write permissions
Packit 08bd4c
						zip_entry->mode &= 0555;
Packit 08bd4c
					}
Packit 08bd4c
				} else {
Packit 08bd4c
					zip_entry->mode = 0;
Packit 08bd4c
				}
Packit 08bd4c
				offset += 4;
Packit 08bd4c
				datasize -= 4;
Packit 08bd4c
			}
Packit 08bd4c
			if (bitmap & 8) {
Packit 08bd4c
				/* 2 byte comment length + comment */
Packit 08bd4c
				uint32_t comment_length;
Packit 08bd4c
				if (datasize < 2)
Packit 08bd4c
					break;
Packit 08bd4c
				comment_length
Packit 08bd4c
				    = archive_le16dec(p + offset);
Packit 08bd4c
				offset += 2;
Packit 08bd4c
				datasize -= 2;
Packit 08bd4c
Packit 08bd4c
				if (datasize < comment_length)
Packit 08bd4c
					break;
Packit 08bd4c
				/* Comment is not supported by libarchive */
Packit 08bd4c
				offset += comment_length;
Packit 08bd4c
				datasize -= comment_length;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		case 0x7855:
Packit 08bd4c
			/* Info-ZIP Unix Extra Field (type 2) "Ux". */
Packit 08bd4c
#ifdef DEBUG
Packit 08bd4c
			fprintf(stderr, "uid %d gid %d\n",
Packit 08bd4c
			    archive_le16dec(p + offset),
Packit 08bd4c
			    archive_le16dec(p + offset + 2));
Packit 08bd4c
#endif
Packit 08bd4c
			if (datasize >= 2)
Packit 08bd4c
				zip_entry->uid = archive_le16dec(p + offset);
Packit 08bd4c
			if (datasize >= 4)
Packit 08bd4c
				zip_entry->gid =
Packit 08bd4c
				    archive_le16dec(p + offset + 2);
Packit 08bd4c
			break;
Packit 08bd4c
		case 0x7875:
Packit 08bd4c
		{
Packit 08bd4c
			/* Info-Zip Unix Extra Field (type 3) "ux". */
Packit 08bd4c
			int uidsize = 0, gidsize = 0;
Packit 08bd4c
Packit 08bd4c
			/* TODO: support arbitrary uidsize/gidsize. */
Packit 08bd4c
			if (datasize >= 1 && p[offset] == 1) {/* version=1 */
Packit 08bd4c
				if (datasize >= 4) {
Packit 08bd4c
					/* get a uid size. */
Packit 08bd4c
					uidsize = 0xff & (int)p[offset+1];
Packit 08bd4c
					if (uidsize == 2)
Packit 08bd4c
						zip_entry->uid =
Packit 08bd4c
						    archive_le16dec(
Packit 08bd4c
						        p + offset + 2);
Packit 08bd4c
					else if (uidsize == 4 && datasize >= 6)
Packit 08bd4c
						zip_entry->uid =
Packit 08bd4c
						    archive_le32dec(
Packit 08bd4c
						        p + offset + 2);
Packit 08bd4c
				}
Packit 08bd4c
				if (datasize >= (2 + uidsize + 3)) {
Packit 08bd4c
					/* get a gid size. */
Packit 08bd4c
					gidsize = 0xff & (int)p[offset+2+uidsize];
Packit 08bd4c
					if (gidsize == 2)
Packit 08bd4c
						zip_entry->gid =
Packit 08bd4c
						    archive_le16dec(
Packit 08bd4c
						        p+offset+2+uidsize+1);
Packit 08bd4c
					else if (gidsize == 4 &&
Packit 08bd4c
					    datasize >= (2 + uidsize + 5))
Packit 08bd4c
						zip_entry->gid =
Packit 08bd4c
						    archive_le32dec(
Packit 08bd4c
						        p+offset+2+uidsize+1);
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		case 0x9901:
Packit 08bd4c
			/* WinZip AES extra data field. */
Packit 08bd4c
			if (p[offset + 2] == 'A' && p[offset + 3] == 'E') {
Packit 08bd4c
				/* Vendor version. */
Packit 08bd4c
				zip_entry->aes_extra.vendor =
Packit 08bd4c
				    archive_le16dec(p + offset);
Packit 08bd4c
				/* AES encryption strength. */
Packit 08bd4c
				zip_entry->aes_extra.strength = p[offset + 4];
Packit 08bd4c
				/* Actual compression method. */
Packit 08bd4c
				zip_entry->aes_extra.compression =
Packit 08bd4c
				    p[offset + 5];
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		default:
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		offset += datasize;
Packit 08bd4c
	}
Packit 08bd4c
	if (offset != extra_length) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Malformed extra data: Consumed %d bytes of %d bytes",
Packit 08bd4c
		    (int)offset, (int)extra_length);
Packit 08bd4c
		return ARCHIVE_FAILED;
Packit 08bd4c
	}
Packit 08bd4c
	return ARCHIVE_OK;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Assumes file pointer is at beginning of local file header.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
Packit 08bd4c
    struct zip *zip)
Packit 08bd4c
{
Packit 08bd4c
	const char *p;
Packit 08bd4c
	const void *h;
Packit 08bd4c
	const wchar_t *wp;
Packit 08bd4c
	const char *cp;
Packit 08bd4c
	size_t len, filename_length, extra_length;
Packit 08bd4c
	struct archive_string_conv *sconv;
Packit 08bd4c
	struct zip_entry *zip_entry = zip->entry;
Packit 08bd4c
	struct zip_entry zip_entry_central_dir;
Packit 08bd4c
	int ret = ARCHIVE_OK;
Packit 08bd4c
	char version;
Packit 08bd4c
Packit 08bd4c
	/* Save a copy of the original for consistency checks. */
Packit 08bd4c
	zip_entry_central_dir = *zip_entry;
Packit 08bd4c
Packit 08bd4c
	zip->decompress_init = 0;
Packit 08bd4c
	zip->end_of_entry = 0;
Packit 08bd4c
	zip->entry_uncompressed_bytes_read = 0;
Packit 08bd4c
	zip->entry_compressed_bytes_read = 0;
Packit 08bd4c
	zip->entry_crc32 = zip->crc32func(0, NULL, 0);
Packit 08bd4c
Packit 08bd4c
	/* Setup default conversion. */
Packit 08bd4c
	if (zip->sconv == NULL && !zip->init_default_conversion) {
Packit 08bd4c
		zip->sconv_default =
Packit 08bd4c
		    archive_string_default_conversion_for_read(&(a->archive));
Packit 08bd4c
		zip->init_default_conversion = 1;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file header");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (memcmp(p, "PK\003\004", 4) != 0) {
Packit 08bd4c
		archive_set_error(&a->archive, -1, "Damaged Zip archive");
Packit 08bd4c
		return ARCHIVE_FATAL;
Packit 08bd4c
	}
Packit 08bd4c
	version = p[4];
Packit 08bd4c
	zip_entry->system = p[5];
Packit 08bd4c
	zip_entry->zip_flags = archive_le16dec(p + 6);
Packit 08bd4c
	if (zip_entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
Packit 08bd4c
		zip->has_encrypted_entries = 1;
Packit 08bd4c
		archive_entry_set_is_data_encrypted(entry, 1);
Packit 08bd4c
		if (zip_entry->zip_flags & ZIP_CENTRAL_DIRECTORY_ENCRYPTED &&
Packit 08bd4c
			zip_entry->zip_flags & ZIP_ENCRYPTED &&
Packit 08bd4c
			zip_entry->zip_flags & ZIP_STRONG_ENCRYPTED) {
Packit 08bd4c
			archive_entry_set_is_metadata_encrypted(entry, 1);
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);
Packit 08bd4c
	zip_entry->compression = (char)archive_le16dec(p + 8);
Packit 08bd4c
	zip_entry->mtime = zip_time(p + 10);
Packit 08bd4c
	zip_entry->crc32 = archive_le32dec(p + 14);
Packit 08bd4c
	if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
		zip_entry->decdat = p[11];
Packit 08bd4c
	else
Packit 08bd4c
		zip_entry->decdat = p[17];
Packit 08bd4c
	zip_entry->compressed_size = archive_le32dec(p + 18);
Packit 08bd4c
	zip_entry->uncompressed_size = archive_le32dec(p + 22);
Packit 08bd4c
	filename_length = archive_le16dec(p + 26);
Packit 08bd4c
	extra_length = archive_le16dec(p + 28);
Packit 08bd4c
Packit 08bd4c
	__archive_read_consume(a, 30);
Packit 08bd4c
Packit 08bd4c
	/* Read the filename. */
Packit 08bd4c
	if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file header");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (zip_entry->zip_flags & ZIP_UTF8_NAME) {
Packit 08bd4c
		/* The filename is stored to be UTF-8. */
Packit 08bd4c
		if (zip->sconv_utf8 == NULL) {
Packit 08bd4c
			zip->sconv_utf8 =
Packit 08bd4c
			    archive_string_conversion_from_charset(
Packit 08bd4c
				&a->archive, "UTF-8", 1);
Packit 08bd4c
			if (zip->sconv_utf8 == NULL)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		sconv = zip->sconv_utf8;
Packit 08bd4c
	} else if (zip->sconv != NULL)
Packit 08bd4c
		sconv = zip->sconv;
Packit 08bd4c
	else
Packit 08bd4c
		sconv = zip->sconv_default;
Packit 08bd4c
Packit 08bd4c
	if (archive_entry_copy_pathname_l(entry,
Packit 08bd4c
	    h, filename_length, sconv) != 0) {
Packit 08bd4c
		if (errno == ENOMEM) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "Can't allocate memory for Pathname");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Pathname cannot be converted "
Packit 08bd4c
		    "from %s to current locale.",
Packit 08bd4c
		    archive_string_conversion_charset_name(sconv));
Packit 08bd4c
		ret = ARCHIVE_WARN;
Packit 08bd4c
	}
Packit 08bd4c
	__archive_read_consume(a, filename_length);
Packit 08bd4c
Packit 08bd4c
	/* Read the extra data. */
Packit 08bd4c
	if ((h = __archive_read_ahead(a, extra_length, NULL)) == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file header");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (ARCHIVE_OK != process_extra(a, h, extra_length, zip_entry)) {
Packit 08bd4c
		return ARCHIVE_FATAL;
Packit 08bd4c
	}
Packit 08bd4c
	__archive_read_consume(a, extra_length);
Packit 08bd4c
Packit 08bd4c
	/* Work around a bug in Info-Zip: When reading from a pipe, it
Packit 08bd4c
	 * stats the pipe instead of synthesizing a file entry. */
Packit 08bd4c
	if ((zip_entry->mode & AE_IFMT) == AE_IFIFO) {
Packit 08bd4c
		zip_entry->mode &= ~ AE_IFMT;
Packit 08bd4c
		zip_entry->mode |= AE_IFREG;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* If the mode is totally empty, set some sane default. */
Packit 08bd4c
	if (zip_entry->mode == 0) {
Packit 08bd4c
		zip_entry->mode |= 0664;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Make sure that entries with a trailing '/' are marked as directories
Packit 08bd4c
	 * even if the External File Attributes contains bogus values.  If this
Packit 08bd4c
	 * is not a directory and there is no type, assume regularfile. */
Packit 08bd4c
	if ((zip_entry->mode & AE_IFMT) != AE_IFDIR) {
Packit 08bd4c
		int has_slash;
Packit 08bd4c
Packit 08bd4c
		wp = archive_entry_pathname_w(entry);
Packit 08bd4c
		if (wp != NULL) {
Packit 08bd4c
			len = wcslen(wp);
Packit 08bd4c
			has_slash = len > 0 && wp[len - 1] == L'/';
Packit 08bd4c
		} else {
Packit 08bd4c
			cp = archive_entry_pathname(entry);
Packit 08bd4c
			len = (cp != NULL)?strlen(cp):0;
Packit 08bd4c
			has_slash = len > 0 && cp[len - 1] == '/';
Packit 08bd4c
		}
Packit 08bd4c
		/* Correct file type as needed. */
Packit 08bd4c
		if (has_slash) {
Packit 08bd4c
			zip_entry->mode &= ~AE_IFMT;
Packit 08bd4c
			zip_entry->mode |= AE_IFDIR;
Packit 08bd4c
			zip_entry->mode |= 0111;
Packit 08bd4c
		} else if ((zip_entry->mode & AE_IFMT) == 0) {
Packit 08bd4c
			zip_entry->mode |= AE_IFREG;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Make sure directories end in '/' */
Packit 08bd4c
	if ((zip_entry->mode & AE_IFMT) == AE_IFDIR) {
Packit 08bd4c
		wp = archive_entry_pathname_w(entry);
Packit 08bd4c
		if (wp != NULL) {
Packit 08bd4c
			len = wcslen(wp);
Packit 08bd4c
			if (len > 0 && wp[len - 1] != L'/') {
Packit 08bd4c
				struct archive_wstring s;
Packit 08bd4c
				archive_string_init(&s);
Packit 08bd4c
				archive_wstrcat(&s, wp);
Packit 08bd4c
				archive_wstrappend_wchar(&s, L'/');
Packit 08bd4c
				archive_entry_copy_pathname_w(entry, s.s);
Packit 08bd4c
				archive_wstring_free(&s);
Packit 08bd4c
			}
Packit 08bd4c
		} else {
Packit 08bd4c
			cp = archive_entry_pathname(entry);
Packit 08bd4c
			len = (cp != NULL)?strlen(cp):0;
Packit 08bd4c
			if (len > 0 && cp[len - 1] != '/') {
Packit 08bd4c
				struct archive_string s;
Packit 08bd4c
				archive_string_init(&s);
Packit 08bd4c
				archive_strcat(&s, cp);
Packit 08bd4c
				archive_strappend_char(&s, '/');
Packit 08bd4c
				archive_entry_set_pathname(entry, s.s);
Packit 08bd4c
				archive_string_free(&s);
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (zip_entry->flags & LA_FROM_CENTRAL_DIRECTORY) {
Packit 08bd4c
		/* If this came from the central dir, it's size info
Packit 08bd4c
		 * is definitive, so ignore the length-at-end flag. */
Packit 08bd4c
		zip_entry->zip_flags &= ~ZIP_LENGTH_AT_END;
Packit 08bd4c
		/* If local header is missing a value, use the one from
Packit 08bd4c
		   the central directory.  If both have it, warn about
Packit 08bd4c
		   mismatches. */
Packit 08bd4c
		if (zip_entry->crc32 == 0) {
Packit 08bd4c
			zip_entry->crc32 = zip_entry_central_dir.crc32;
Packit 08bd4c
		} else if (!zip->ignore_crc32
Packit 08bd4c
		    && zip_entry->crc32 != zip_entry_central_dir.crc32) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Inconsistent CRC32 values");
Packit 08bd4c
			ret = ARCHIVE_WARN;
Packit 08bd4c
		}
Packit 08bd4c
		if (zip_entry->compressed_size == 0) {
Packit 08bd4c
			zip_entry->compressed_size
Packit 08bd4c
			    = zip_entry_central_dir.compressed_size;
Packit 08bd4c
		} else if (zip_entry->compressed_size
Packit 08bd4c
		    != zip_entry_central_dir.compressed_size) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Inconsistent compressed size: "
Packit 08bd4c
			    "%jd in central directory, %jd in local header",
Packit 08bd4c
			    (intmax_t)zip_entry_central_dir.compressed_size,
Packit 08bd4c
			    (intmax_t)zip_entry->compressed_size);
Packit 08bd4c
			ret = ARCHIVE_WARN;
Packit 08bd4c
		}
Packit 08bd4c
		if (zip_entry->uncompressed_size == 0) {
Packit 08bd4c
			zip_entry->uncompressed_size
Packit 08bd4c
			    = zip_entry_central_dir.uncompressed_size;
Packit 08bd4c
		} else if (zip_entry->uncompressed_size
Packit 08bd4c
		    != zip_entry_central_dir.uncompressed_size) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Inconsistent uncompressed size: "
Packit 08bd4c
			    "%jd in central directory, %jd in local header",
Packit 08bd4c
			    (intmax_t)zip_entry_central_dir.uncompressed_size,
Packit 08bd4c
			    (intmax_t)zip_entry->uncompressed_size);
Packit 08bd4c
			ret = ARCHIVE_WARN;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Populate some additional entry fields: */
Packit 08bd4c
	archive_entry_set_mode(entry, zip_entry->mode);
Packit 08bd4c
	archive_entry_set_uid(entry, zip_entry->uid);
Packit 08bd4c
	archive_entry_set_gid(entry, zip_entry->gid);
Packit 08bd4c
	archive_entry_set_mtime(entry, zip_entry->mtime, 0);
Packit 08bd4c
	archive_entry_set_ctime(entry, zip_entry->ctime, 0);
Packit 08bd4c
	archive_entry_set_atime(entry, zip_entry->atime, 0);
Packit 08bd4c
Packit 08bd4c
	if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
Packit 08bd4c
		size_t linkname_length;
Packit 08bd4c
Packit 08bd4c
		if (zip_entry->compressed_size > 64 * 1024) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Zip file with oversized link entry");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		linkname_length = (size_t)zip_entry->compressed_size;
Packit 08bd4c
Packit 08bd4c
		archive_entry_set_size(entry, 0);
Packit 08bd4c
		p = __archive_read_ahead(a, linkname_length, NULL);
Packit 08bd4c
		if (p == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Truncated Zip file");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		sconv = zip->sconv;
Packit 08bd4c
		if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
Packit 08bd4c
			sconv = zip->sconv_utf8;
Packit 08bd4c
		if (sconv == NULL)
Packit 08bd4c
			sconv = zip->sconv_default;
Packit 08bd4c
		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
Packit 08bd4c
		    sconv) != 0) {
Packit 08bd4c
			if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
Packit 08bd4c
			    (zip->entry->zip_flags & ZIP_UTF8_NAME))
Packit 08bd4c
			    archive_entry_copy_symlink_l(entry, p,
Packit 08bd4c
				linkname_length, NULL);
Packit 08bd4c
			if (errno == ENOMEM) {
Packit 08bd4c
				archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
				    "Can't allocate memory for Symlink");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			/*
Packit 08bd4c
			 * Since there is no character-set regulation for
Packit 08bd4c
			 * symlink name, do not report the conversion error
Packit 08bd4c
			 * in an automatic conversion.
Packit 08bd4c
			 */
Packit 08bd4c
			if (sconv != zip->sconv_utf8 ||
Packit 08bd4c
			    (zip->entry->zip_flags & ZIP_UTF8_NAME) == 0) {
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
				    "Symlink cannot be converted "
Packit 08bd4c
				    "from %s to current locale.",
Packit 08bd4c
				    archive_string_conversion_charset_name(
Packit 08bd4c
					sconv));
Packit 08bd4c
				ret = ARCHIVE_WARN;
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
		zip_entry->uncompressed_size = zip_entry->compressed_size = 0;
Packit 08bd4c
Packit 08bd4c
		if (__archive_read_consume(a, linkname_length) < 0) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Read error skipping symlink target name");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
	} else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    || zip_entry->uncompressed_size > 0) {
Packit 08bd4c
		/* Set the size only if it's meaningful. */
Packit 08bd4c
		archive_entry_set_size(entry, zip_entry->uncompressed_size);
Packit 08bd4c
	}
Packit 08bd4c
	zip->entry_bytes_remaining = zip_entry->compressed_size;
Packit 08bd4c
Packit 08bd4c
	/* If there's no body, force read_data() to return EOF immediately. */
Packit 08bd4c
	if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    && zip->entry_bytes_remaining < 1)
Packit 08bd4c
		zip->end_of_entry = 1;
Packit 08bd4c
Packit 08bd4c
	/* Set up a more descriptive format name. */
Packit 08bd4c
	archive_string_sprintf(&zip->format_name, "ZIP %d.%d (%s)",
Packit 08bd4c
	    version / 10, version % 10,
Packit 08bd4c
	    compression_name(zip->entry->compression));
Packit 08bd4c
	a->archive.archive_format_name = zip->format_name.s;
Packit 08bd4c
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
check_authentication_code(struct archive_read *a, const void *_p)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	/* Check authentication code. */
Packit 08bd4c
	if (zip->hctx_valid) {
Packit 08bd4c
		const void *p;
Packit 08bd4c
		uint8_t hmac[20];
Packit 08bd4c
		size_t hmac_len = 20;
Packit 08bd4c
		int cmp;
Packit 08bd4c
Packit 08bd4c
		archive_hmac_sha1_final(&zip->hctx, hmac, &hmac_len);
Packit 08bd4c
		if (_p == NULL) {
Packit 08bd4c
			/* Read authentication code. */
Packit 08bd4c
			p = __archive_read_ahead(a, AUTH_CODE_SIZE, NULL);
Packit 08bd4c
			if (p == NULL) {
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
				    "Truncated ZIP file data");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
		} else {
Packit 08bd4c
			p = _p;
Packit 08bd4c
		}
Packit 08bd4c
		cmp = memcmp(hmac, p, AUTH_CODE_SIZE);
Packit 08bd4c
		__archive_read_consume(a, AUTH_CODE_SIZE);
Packit 08bd4c
		if (cmp != 0) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "ZIP bad Authentication code");
Packit 08bd4c
			return (ARCHIVE_WARN);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read "uncompressed" data.  There are three cases:
Packit 08bd4c
 *  1) We know the size of the data.  This is always true for the
Packit 08bd4c
 * seeking reader (we've examined the Central Directory already).
Packit 08bd4c
 *  2) ZIP_LENGTH_AT_END was set, but only the CRC was deferred.
Packit 08bd4c
 * Info-ZIP seems to do this; we know the size but have to grab
Packit 08bd4c
 * the CRC from the data descriptor afterwards.
Packit 08bd4c
 *  3) We're streaming and ZIP_LENGTH_AT_END was specified and
Packit 08bd4c
 * we have no size information.  In this case, we can do pretty
Packit 08bd4c
 * well by watching for the data descriptor record.  The data
Packit 08bd4c
 * descriptor is 16 bytes and includes a computed CRC that should
Packit 08bd4c
 * provide a strong check.
Packit 08bd4c
 *
Packit 08bd4c
 * TODO: Technically, the PK\007\010 signature is optional.
Packit 08bd4c
 * In the original spec, the data descriptor contained CRC
Packit 08bd4c
 * and size fields but had no leading signature.  In practice,
Packit 08bd4c
 * newer writers seem to provide the signature pretty consistently.
Packit 08bd4c
 *
Packit 08bd4c
 * For uncompressed data, the PK\007\010 marker seems essential
Packit 08bd4c
 * to be sure we've actually seen the end of the entry.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
Packit 08bd4c
 * zip->end_of_entry if it consumes all of the data.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
zip_read_data_none(struct archive_read *a, const void **_buff,
Packit 08bd4c
    size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	const char *buff;
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	(void)offset; /* UNUSED */
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {
Packit 08bd4c
		const char *p;
Packit 08bd4c
		ssize_t grabbing_bytes = 24;
Packit 08bd4c
Packit 08bd4c
		if (zip->hctx_valid)
Packit 08bd4c
			grabbing_bytes += AUTH_CODE_SIZE;
Packit 08bd4c
		/* Grab at least 24 bytes. */
Packit 08bd4c
		buff = __archive_read_ahead(a, grabbing_bytes, &bytes_avail);
Packit 08bd4c
		if (bytes_avail < grabbing_bytes) {
Packit 08bd4c
			/* Zip archives have end-of-archive markers
Packit 08bd4c
			   that are longer than this, so a failure to get at
Packit 08bd4c
			   least 24 bytes really does indicate a truncated
Packit 08bd4c
			   file. */
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated ZIP file data");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		/* Check for a complete PK\007\010 signature, followed
Packit 08bd4c
		 * by the correct 4-byte CRC. */
Packit 08bd4c
		p = buff;
Packit 08bd4c
		if (zip->hctx_valid)
Packit 08bd4c
			p += AUTH_CODE_SIZE;
Packit 08bd4c
		if (p[0] == 'P' && p[1] == 'K'
Packit 08bd4c
		    && p[2] == '\007' && p[3] == '\010'
Packit 08bd4c
		    && (archive_le32dec(p + 4) == zip->entry_crc32
Packit 08bd4c
			|| zip->ignore_crc32
Packit 08bd4c
			|| (zip->hctx_valid
Packit 08bd4c
			 && zip->entry->aes_extra.vendor == AES_VENDOR_AE_2))) {
Packit 08bd4c
			if (zip->entry->flags & LA_USED_ZIP64) {
Packit 08bd4c
				uint64_t compressed, uncompressed;
Packit 08bd4c
				zip->entry->crc32 = archive_le32dec(p + 4);
Packit 08bd4c
				compressed = archive_le64dec(p + 8);
Packit 08bd4c
				uncompressed = archive_le64dec(p + 16);
Packit 08bd4c
				if (compressed > INT64_MAX || uncompressed > INT64_MAX) {
Packit 08bd4c
					archive_set_error(&a->archive,
Packit 08bd4c
					    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
					    "Overflow of 64-bit file sizes");
Packit 08bd4c
					return ARCHIVE_FAILED;
Packit 08bd4c
				}
Packit 08bd4c
				zip->entry->compressed_size = compressed;
Packit 08bd4c
				zip->entry->uncompressed_size = uncompressed;
Packit 08bd4c
				zip->unconsumed = 24;
Packit 08bd4c
			} else {
Packit 08bd4c
				zip->entry->crc32 = archive_le32dec(p + 4);
Packit 08bd4c
				zip->entry->compressed_size =
Packit 08bd4c
					archive_le32dec(p + 8);
Packit 08bd4c
				zip->entry->uncompressed_size =
Packit 08bd4c
					archive_le32dec(p + 12);
Packit 08bd4c
				zip->unconsumed = 16;
Packit 08bd4c
			}
Packit 08bd4c
			if (zip->hctx_valid) {
Packit 08bd4c
				r = check_authentication_code(a, buff);
Packit 08bd4c
				if (r != ARCHIVE_OK)
Packit 08bd4c
					return (r);
Packit 08bd4c
			}
Packit 08bd4c
			zip->end_of_entry = 1;
Packit 08bd4c
			return (ARCHIVE_OK);
Packit 08bd4c
		}
Packit 08bd4c
		/* If not at EOF, ensure we consume at least one byte. */
Packit 08bd4c
		++p;
Packit 08bd4c
Packit 08bd4c
		/* Scan forward until we see where a PK\007\010 signature
Packit 08bd4c
		 * might be. */
Packit 08bd4c
		/* Return bytes up until that point.  On the next call,
Packit 08bd4c
		 * the code above will verify the data descriptor. */
Packit 08bd4c
		while (p < buff + bytes_avail - 4) {
Packit 08bd4c
			if (p[3] == 'P') { p += 3; }
Packit 08bd4c
			else if (p[3] == 'K') { p += 2; }
Packit 08bd4c
			else if (p[3] == '\007') { p += 1; }
Packit 08bd4c
			else if (p[3] == '\010' && p[2] == '\007'
Packit 08bd4c
			    && p[1] == 'K' && p[0] == 'P') {
Packit 08bd4c
				if (zip->hctx_valid)
Packit 08bd4c
					p -= AUTH_CODE_SIZE;
Packit 08bd4c
				break;
Packit 08bd4c
			} else { p += 4; }
Packit 08bd4c
		}
Packit 08bd4c
		bytes_avail = p - buff;
Packit 08bd4c
	} else {
Packit 08bd4c
		if (zip->entry_bytes_remaining == 0) {
Packit 08bd4c
			zip->end_of_entry = 1;
Packit 08bd4c
			if (zip->hctx_valid) {
Packit 08bd4c
				r = check_authentication_code(a, NULL);
Packit 08bd4c
				if (r != ARCHIVE_OK)
Packit 08bd4c
					return (r);
Packit 08bd4c
			}
Packit 08bd4c
			return (ARCHIVE_OK);
Packit 08bd4c
		}
Packit 08bd4c
		/* Grab a bunch of bytes. */
Packit 08bd4c
		buff = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
		if (bytes_avail <= 0) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated ZIP file data");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		if (bytes_avail > zip->entry_bytes_remaining)
Packit 08bd4c
			bytes_avail = (ssize_t)zip->entry_bytes_remaining;
Packit 08bd4c
	}
Packit 08bd4c
	if (zip->tctx_valid || zip->cctx_valid) {
Packit 08bd4c
		size_t dec_size = bytes_avail;
Packit 08bd4c
Packit 08bd4c
		if (dec_size > zip->decrypted_buffer_size)
Packit 08bd4c
			dec_size = zip->decrypted_buffer_size;
Packit 08bd4c
		if (zip->tctx_valid) {
Packit 08bd4c
			trad_enc_decrypt_update(&zip->tctx,
Packit 08bd4c
			    (const uint8_t *)buff, dec_size,
Packit 08bd4c
			    zip->decrypted_buffer, dec_size);
Packit 08bd4c
		} else {
Packit 08bd4c
			size_t dsize = dec_size;
Packit 08bd4c
			archive_hmac_sha1_update(&zip->hctx,
Packit 08bd4c
			    (const uint8_t *)buff, dec_size);
Packit 08bd4c
			archive_decrypto_aes_ctr_update(&zip->cctx,
Packit 08bd4c
			    (const uint8_t *)buff, dec_size,
Packit 08bd4c
			    zip->decrypted_buffer, &dsize);
Packit 08bd4c
		}
Packit 08bd4c
		bytes_avail = dec_size;
Packit 08bd4c
		buff = (const char *)zip->decrypted_buffer;
Packit 08bd4c
	}
Packit 08bd4c
	*size = bytes_avail;
Packit 08bd4c
	zip->entry_bytes_remaining -= bytes_avail;
Packit 08bd4c
	zip->entry_uncompressed_bytes_read += bytes_avail;
Packit 08bd4c
	zip->entry_compressed_bytes_read += bytes_avail;
Packit 08bd4c
	zip->unconsumed += bytes_avail;
Packit 08bd4c
	*_buff = buff;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
static int
Packit 08bd4c
zip_deflate_init(struct archive_read *a, struct zip *zip)
Packit 08bd4c
{
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	/* If we haven't yet read any data, initialize the decompressor. */
Packit 08bd4c
	if (!zip->decompress_init) {
Packit 08bd4c
		if (zip->stream_valid)
Packit 08bd4c
			r = inflateReset(&zip->stream);
Packit 08bd4c
		else
Packit 08bd4c
			r = inflateInit2(&zip->stream,
Packit 08bd4c
			    -15 /* Don't check for zlib header */);
Packit 08bd4c
		if (r != Z_OK) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Can't initialize ZIP decompression.");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		/* Stream structure has been set up. */
Packit 08bd4c
		zip->stream_valid = 1;
Packit 08bd4c
		/* We've initialized decompression for this stream. */
Packit 08bd4c
		zip->decompress_init = 1;
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
zip_read_data_deflate(struct archive_read *a, const void **buff,
Packit 08bd4c
    size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
	const void *compressed_buff, *sp;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	(void)offset; /* UNUSED */
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	/* If the buffer hasn't been allocated, allocate it now. */
Packit 08bd4c
	if (zip->uncompressed_buffer == NULL) {
Packit 08bd4c
		zip->uncompressed_buffer_size = 256 * 1024;
Packit 08bd4c
		zip->uncompressed_buffer
Packit 08bd4c
		    = (unsigned char *)malloc(zip->uncompressed_buffer_size);
Packit 08bd4c
		if (zip->uncompressed_buffer == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "No memory for ZIP decompression");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	r = zip_deflate_init(a, zip);
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		return (r);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Note: '1' here is a performance optimization.
Packit 08bd4c
	 * Recall that the decompression layer returns a count of
Packit 08bd4c
	 * available bytes; asking for more than that forces the
Packit 08bd4c
	 * decompressor to combine reads by copying data.
Packit 08bd4c
	 */
Packit 08bd4c
	compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    && bytes_avail > zip->entry_bytes_remaining) {
Packit 08bd4c
		bytes_avail = (ssize_t)zip->entry_bytes_remaining;
Packit 08bd4c
	}
Packit 08bd4c
	if (bytes_avail < 0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file body");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (zip->tctx_valid || zip->cctx_valid) {
Packit 08bd4c
		if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
Packit 08bd4c
			size_t buff_remaining =
Packit 08bd4c
			    (zip->decrypted_buffer + zip->decrypted_buffer_size)
Packit 08bd4c
			    - (zip->decrypted_ptr + zip->decrypted_bytes_remaining);
Packit 08bd4c
Packit 08bd4c
			if (buff_remaining > (size_t)bytes_avail)
Packit 08bd4c
				buff_remaining = (size_t)bytes_avail;
Packit 08bd4c
Packit 08bd4c
			if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
Packit 08bd4c
			      zip->entry_bytes_remaining > 0) {
Packit 08bd4c
				if ((int64_t)(zip->decrypted_bytes_remaining
Packit 08bd4c
				    + buff_remaining)
Packit 08bd4c
				      > zip->entry_bytes_remaining) {
Packit 08bd4c
					if (zip->entry_bytes_remaining <
Packit 08bd4c
					      (int64_t)zip->decrypted_bytes_remaining)
Packit 08bd4c
						buff_remaining = 0;
Packit 08bd4c
					else
Packit 08bd4c
						buff_remaining =
Packit 08bd4c
						    (size_t)zip->entry_bytes_remaining
Packit 08bd4c
						      - zip->decrypted_bytes_remaining;
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			if (buff_remaining > 0) {
Packit 08bd4c
				if (zip->tctx_valid) {
Packit 08bd4c
					trad_enc_decrypt_update(&zip->tctx,
Packit 08bd4c
					    compressed_buff, buff_remaining,
Packit 08bd4c
					    zip->decrypted_ptr
Packit 08bd4c
					      + zip->decrypted_bytes_remaining,
Packit 08bd4c
					    buff_remaining);
Packit 08bd4c
				} else {
Packit 08bd4c
					size_t dsize = buff_remaining;
Packit 08bd4c
					archive_decrypto_aes_ctr_update(
Packit 08bd4c
					    &zip->cctx,
Packit 08bd4c
					    compressed_buff, buff_remaining,
Packit 08bd4c
					    zip->decrypted_ptr
Packit 08bd4c
					      + zip->decrypted_bytes_remaining,
Packit 08bd4c
					    &dsize);
Packit 08bd4c
				}
Packit 08bd4c
				zip->decrypted_bytes_remaining += buff_remaining;
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
		bytes_avail = zip->decrypted_bytes_remaining;
Packit 08bd4c
		compressed_buff = (const char *)zip->decrypted_ptr;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * A bug in zlib.h: stream.next_in should be marked 'const'
Packit 08bd4c
	 * but isn't (the library never alters data through the
Packit 08bd4c
	 * next_in pointer, only reads it).  The result: this ugly
Packit 08bd4c
	 * cast to remove 'const'.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;
Packit 08bd4c
	zip->stream.avail_in = (uInt)bytes_avail;
Packit 08bd4c
	zip->stream.total_in = 0;
Packit 08bd4c
	zip->stream.next_out = zip->uncompressed_buffer;
Packit 08bd4c
	zip->stream.avail_out = (uInt)zip->uncompressed_buffer_size;
Packit 08bd4c
	zip->stream.total_out = 0;
Packit 08bd4c
Packit 08bd4c
	r = inflate(&zip->stream, 0);
Packit 08bd4c
	switch (r) {
Packit 08bd4c
	case Z_OK:
Packit 08bd4c
		break;
Packit 08bd4c
	case Z_STREAM_END:
Packit 08bd4c
		zip->end_of_entry = 1;
Packit 08bd4c
		break;
Packit 08bd4c
	case Z_MEM_ERROR:
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Out of memory for ZIP decompression");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "ZIP decompression failed (%d)", r);
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Consume as much as the compressor actually used. */
Packit 08bd4c
	bytes_avail = zip->stream.total_in;
Packit 08bd4c
	if (zip->tctx_valid || zip->cctx_valid) {
Packit 08bd4c
		zip->decrypted_bytes_remaining -= bytes_avail;
Packit 08bd4c
		if (zip->decrypted_bytes_remaining == 0)
Packit 08bd4c
			zip->decrypted_ptr = zip->decrypted_buffer;
Packit 08bd4c
		else
Packit 08bd4c
			zip->decrypted_ptr += bytes_avail;
Packit 08bd4c
	}
Packit 08bd4c
	/* Calculate compressed data as much as we used.*/
Packit 08bd4c
	if (zip->hctx_valid)
Packit 08bd4c
		archive_hmac_sha1_update(&zip->hctx, sp, bytes_avail);
Packit 08bd4c
	__archive_read_consume(a, bytes_avail);
Packit 08bd4c
	zip->entry_bytes_remaining -= bytes_avail;
Packit 08bd4c
	zip->entry_compressed_bytes_read += bytes_avail;
Packit 08bd4c
Packit 08bd4c
	*size = zip->stream.total_out;
Packit 08bd4c
	zip->entry_uncompressed_bytes_read += zip->stream.total_out;
Packit 08bd4c
	*buff = zip->uncompressed_buffer;
Packit 08bd4c
Packit 08bd4c
	if (zip->end_of_entry && zip->hctx_valid) {
Packit 08bd4c
		r = check_authentication_code(a, NULL);
Packit 08bd4c
		if (r != ARCHIVE_OK)
Packit 08bd4c
			return (r);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (zip->end_of_entry && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
Packit 08bd4c
		const char *p;
Packit 08bd4c
Packit 08bd4c
		if (NULL == (p = __archive_read_ahead(a, 24, NULL))) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated ZIP end-of-file record");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		/* Consume the optional PK\007\010 marker. */
Packit 08bd4c
		if (p[0] == 'P' && p[1] == 'K' &&
Packit 08bd4c
		    p[2] == '\007' && p[3] == '\010') {
Packit 08bd4c
			p += 4;
Packit 08bd4c
			zip->unconsumed = 4;
Packit 08bd4c
		}
Packit 08bd4c
		if (zip->entry->flags & LA_USED_ZIP64) {
Packit 08bd4c
			uint64_t compressed, uncompressed;
Packit 08bd4c
			zip->entry->crc32 = archive_le32dec(p);
Packit 08bd4c
			compressed = archive_le64dec(p + 4);
Packit 08bd4c
			uncompressed = archive_le64dec(p + 12);
Packit 08bd4c
			if (compressed > INT64_MAX || uncompressed > INT64_MAX) {
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
				    "Overflow of 64-bit file sizes");
Packit 08bd4c
				return ARCHIVE_FAILED;
Packit 08bd4c
			}
Packit 08bd4c
			zip->entry->compressed_size = compressed;
Packit 08bd4c
			zip->entry->uncompressed_size = uncompressed;
Packit 08bd4c
			zip->unconsumed += 20;
Packit 08bd4c
		} else {
Packit 08bd4c
			zip->entry->crc32 = archive_le32dec(p);
Packit 08bd4c
			zip->entry->compressed_size = archive_le32dec(p + 4);
Packit 08bd4c
			zip->entry->uncompressed_size = archive_le32dec(p + 8);
Packit 08bd4c
			zip->unconsumed += 12;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
read_decryption_header(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
	const char *p;
Packit 08bd4c
	unsigned int remaining_size;
Packit 08bd4c
	unsigned int ts;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read an initialization vector data field.
Packit 08bd4c
	 */
Packit 08bd4c
	p = __archive_read_ahead(a, 2, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	ts = zip->iv_size;
Packit 08bd4c
	zip->iv_size = archive_le16dec(p);
Packit 08bd4c
	__archive_read_consume(a, 2);
Packit 08bd4c
	if (ts < zip->iv_size) {
Packit 08bd4c
		free(zip->iv);
Packit 08bd4c
		zip->iv = NULL;
Packit 08bd4c
	}
Packit 08bd4c
	p = __archive_read_ahead(a, zip->iv_size, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	if (zip->iv == NULL) {
Packit 08bd4c
		zip->iv = malloc(zip->iv_size);
Packit 08bd4c
		if (zip->iv == NULL)
Packit 08bd4c
			goto nomem;
Packit 08bd4c
	}
Packit 08bd4c
	memcpy(zip->iv, p, zip->iv_size);
Packit 08bd4c
	__archive_read_consume(a, zip->iv_size);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a size of remaining decryption header field.
Packit 08bd4c
	 */
Packit 08bd4c
	p = __archive_read_ahead(a, 14, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	remaining_size = archive_le32dec(p);
Packit 08bd4c
	if (remaining_size < 16 || remaining_size > (1 << 18))
Packit 08bd4c
		goto corrupted;
Packit 08bd4c
Packit 08bd4c
	/* Check if format version is supported. */
Packit 08bd4c
	if (archive_le16dec(p+4) != 3) {
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unsupported encryption format version: %u",
Packit 08bd4c
		    archive_le16dec(p+4));
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read an encryption algorithm field.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->alg_id = archive_le16dec(p+6);
Packit 08bd4c
	switch (zip->alg_id) {
Packit 08bd4c
	case 0x6601:/* DES */
Packit 08bd4c
	case 0x6602:/* RC2 */
Packit 08bd4c
	case 0x6603:/* 3DES 168 */
Packit 08bd4c
	case 0x6609:/* 3DES 112 */
Packit 08bd4c
	case 0x660E:/* AES 128 */
Packit 08bd4c
	case 0x660F:/* AES 192 */
Packit 08bd4c
	case 0x6610:/* AES 256 */
Packit 08bd4c
	case 0x6702:/* RC2 (version >= 5.2) */
Packit 08bd4c
	case 0x6720:/* Blowfish */
Packit 08bd4c
	case 0x6721:/* Twofish */
Packit 08bd4c
	case 0x6801:/* RC4 */
Packit 08bd4c
		/* Supported encryption algorithm. */
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unknown encryption algorithm: %u", zip->alg_id);
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a bit length field.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->bit_len = archive_le16dec(p+8);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a flags field.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->flags = archive_le16dec(p+10);
Packit 08bd4c
	switch (zip->flags & 0xf000) {
Packit 08bd4c
	case 0x0001: /* Password is required to decrypt. */
Packit 08bd4c
	case 0x0002: /* Certificates only. */
Packit 08bd4c
	case 0x0003: /* Password or certificate required to decrypt. */
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unknown encryption flag: %u", zip->flags);
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
	if ((zip->flags & 0xf000) == 0 ||
Packit 08bd4c
	    (zip->flags & 0xf000) == 0x4000) {
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unknown encryption flag: %u", zip->flags);
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read an encrypted random data field.
Packit 08bd4c
	 */
Packit 08bd4c
	ts = zip->erd_size;
Packit 08bd4c
	zip->erd_size = archive_le16dec(p+12);
Packit 08bd4c
	__archive_read_consume(a, 14);
Packit 08bd4c
	if ((zip->erd_size & 0xf) != 0 ||
Packit 08bd4c
	    (zip->erd_size + 16) > remaining_size ||
Packit 08bd4c
	    (zip->erd_size + 16) < zip->erd_size)
Packit 08bd4c
		goto corrupted;
Packit 08bd4c
Packit 08bd4c
	if (ts < zip->erd_size) {
Packit 08bd4c
		free(zip->erd);
Packit 08bd4c
		zip->erd = NULL;
Packit 08bd4c
	}
Packit 08bd4c
	p = __archive_read_ahead(a, zip->erd_size, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	if (zip->erd == NULL) {
Packit 08bd4c
		zip->erd = malloc(zip->erd_size);
Packit 08bd4c
		if (zip->erd == NULL)
Packit 08bd4c
			goto nomem;
Packit 08bd4c
	}
Packit 08bd4c
	memcpy(zip->erd, p, zip->erd_size);
Packit 08bd4c
	__archive_read_consume(a, zip->erd_size);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a reserved data field.
Packit 08bd4c
	 */
Packit 08bd4c
	p = __archive_read_ahead(a, 4, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	/* Reserved data size should be zero. */
Packit 08bd4c
	if (archive_le32dec(p) != 0)
Packit 08bd4c
		goto corrupted;
Packit 08bd4c
	__archive_read_consume(a, 4);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a password validation data field.
Packit 08bd4c
	 */
Packit 08bd4c
	p = __archive_read_ahead(a, 2, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	ts = zip->v_size;
Packit 08bd4c
	zip->v_size = archive_le16dec(p);
Packit 08bd4c
	__archive_read_consume(a, 2);
Packit 08bd4c
	if ((zip->v_size & 0x0f) != 0 ||
Packit 08bd4c
	    (zip->erd_size + zip->v_size + 16) > remaining_size ||
Packit 08bd4c
	    (zip->erd_size + zip->v_size + 16) < (zip->erd_size + zip->v_size))
Packit 08bd4c
		goto corrupted;
Packit 08bd4c
	if (ts < zip->v_size) {
Packit 08bd4c
		free(zip->v_data);
Packit 08bd4c
		zip->v_data = NULL;
Packit 08bd4c
	}
Packit 08bd4c
	p = __archive_read_ahead(a, zip->v_size, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	if (zip->v_data == NULL) {
Packit 08bd4c
		zip->v_data = malloc(zip->v_size);
Packit 08bd4c
		if (zip->v_data == NULL)
Packit 08bd4c
			goto nomem;
Packit 08bd4c
	}
Packit 08bd4c
	memcpy(zip->v_data, p, zip->v_size);
Packit 08bd4c
	__archive_read_consume(a, zip->v_size);
Packit 08bd4c
Packit 08bd4c
	p = __archive_read_ahead(a, 4, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
	zip->v_crc32 = archive_le32dec(p);
Packit 08bd4c
	__archive_read_consume(a, 4);
Packit 08bd4c
Packit 08bd4c
	/*return (ARCHIVE_OK);
Packit 08bd4c
	 * This is not fully implemented yet.*/
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Encrypted file is unsupported");
Packit 08bd4c
	return (ARCHIVE_FAILED);
Packit 08bd4c
truncated:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Truncated ZIP file data");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
corrupted:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Corrupted ZIP file data");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
nomem:
Packit 08bd4c
	archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
	    "No memory for ZIP decryption");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
zip_alloc_decryption_buffer(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
	size_t bs = 256 * 1024;
Packit 08bd4c
Packit 08bd4c
	if (zip->decrypted_buffer == NULL) {
Packit 08bd4c
		zip->decrypted_buffer_size = bs;
Packit 08bd4c
		zip->decrypted_buffer = malloc(bs);
Packit 08bd4c
		if (zip->decrypted_buffer == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "No memory for ZIP decryption");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	zip->decrypted_ptr = zip->decrypted_buffer;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
init_traditional_PKWARE_decryption(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
	const void *p;
Packit 08bd4c
	int retry;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	if (zip->tctx_valid)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	   Read the 12 bytes encryption header stored at
Packit 08bd4c
	   the start of the data area.
Packit 08bd4c
	 */
Packit 08bd4c
#define ENC_HEADER_SIZE	12
Packit 08bd4c
	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    && zip->entry_bytes_remaining < ENC_HEADER_SIZE) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated Zip encrypted body: only %jd bytes available",
Packit 08bd4c
		    (intmax_t)zip->entry_bytes_remaining);
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	p = __archive_read_ahead(a, ENC_HEADER_SIZE, NULL);
Packit 08bd4c
	if (p == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	for (retry = 0;; retry++) {
Packit 08bd4c
		const char *passphrase;
Packit 08bd4c
		uint8_t crcchk;
Packit 08bd4c
Packit 08bd4c
		passphrase = __archive_read_next_passphrase(a);
Packit 08bd4c
		if (passphrase == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    (retry > 0)?
Packit 08bd4c
				"Incorrect passphrase":
Packit 08bd4c
				"Passphrase required for this entry");
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Initialize ctx for Traditional PKWARE Decryption.
Packit 08bd4c
		 */
Packit 08bd4c
		r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase),
Packit 08bd4c
			p, ENC_HEADER_SIZE, &crcchk);
Packit 08bd4c
		if (r == 0 && crcchk == zip->entry->decdat)
Packit 08bd4c
			break;/* The passphrase is OK. */
Packit 08bd4c
		if (retry > 10000) {
Packit 08bd4c
			/* Avoid infinity loop. */
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Too many incorrect passphrases");
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	__archive_read_consume(a, ENC_HEADER_SIZE);
Packit 08bd4c
	zip->tctx_valid = 1;
Packit 08bd4c
	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
Packit 08bd4c
	    zip->entry_bytes_remaining -= ENC_HEADER_SIZE;
Packit 08bd4c
	}
Packit 08bd4c
	/*zip->entry_uncompressed_bytes_read += ENC_HEADER_SIZE;*/
Packit 08bd4c
	zip->entry_compressed_bytes_read += ENC_HEADER_SIZE;
Packit 08bd4c
	zip->decrypted_bytes_remaining = 0;
Packit 08bd4c
Packit 08bd4c
	return (zip_alloc_decryption_buffer(a));
Packit 08bd4c
#undef ENC_HEADER_SIZE
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
init_WinZip_AES_decryption(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
	const void *p;
Packit 08bd4c
	const uint8_t *pv;
Packit 08bd4c
	size_t key_len, salt_len;
Packit 08bd4c
	uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];
Packit 08bd4c
	int retry;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	if (zip->cctx_valid || zip->hctx_valid)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	switch (zip->entry->aes_extra.strength) {
Packit 08bd4c
	case 1: salt_len = 8;  key_len = 16; break;
Packit 08bd4c
	case 2: salt_len = 12; key_len = 24; break;
Packit 08bd4c
	case 3: salt_len = 16; key_len = 32; break;
Packit 08bd4c
	default: goto corrupted;
Packit 08bd4c
	}
Packit 08bd4c
	p = __archive_read_ahead(a, salt_len + 2, NULL);
Packit 08bd4c
	if (p == NULL)
Packit 08bd4c
		goto truncated;
Packit 08bd4c
Packit 08bd4c
	for (retry = 0;; retry++) {
Packit 08bd4c
		const char *passphrase;
Packit 08bd4c
Packit 08bd4c
		passphrase = __archive_read_next_passphrase(a);
Packit 08bd4c
		if (passphrase == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    (retry > 0)?
Packit 08bd4c
				"Incorrect passphrase":
Packit 08bd4c
				"Passphrase required for this entry");
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
		memset(derived_key, 0, sizeof(derived_key));
Packit 08bd4c
		r = archive_pbkdf2_sha1(passphrase, strlen(passphrase),
Packit 08bd4c
		    p, salt_len, 1000, derived_key, key_len * 2 + 2);
Packit 08bd4c
		if (r != 0) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Decryption is unsupported due to lack of "
Packit 08bd4c
			    "crypto library");
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/* Check password verification value. */
Packit 08bd4c
		pv = ((const uint8_t *)p) + salt_len;
Packit 08bd4c
		if (derived_key[key_len * 2] == pv[0] &&
Packit 08bd4c
		    derived_key[key_len * 2 + 1] == pv[1])
Packit 08bd4c
			break;/* The passphrase is OK. */
Packit 08bd4c
		if (retry > 10000) {
Packit 08bd4c
			/* Avoid infinity loop. */
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Too many incorrect passphrases");
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	r = archive_decrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);
Packit 08bd4c
	if (r != 0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Decryption is unsupported due to lack of crypto library");
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
	r = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len, key_len);
Packit 08bd4c
	if (r != 0) {
Packit 08bd4c
		archive_decrypto_aes_ctr_release(&zip->cctx);
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Failed to initialize HMAC-SHA1");
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
	zip->cctx_valid = zip->hctx_valid = 1;
Packit 08bd4c
	__archive_read_consume(a, salt_len + 2);
Packit 08bd4c
	zip->entry_bytes_remaining -= salt_len + 2 + AUTH_CODE_SIZE;
Packit 08bd4c
	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    && zip->entry_bytes_remaining < 0)
Packit 08bd4c
		goto corrupted;
Packit 08bd4c
	zip->entry_compressed_bytes_read += salt_len + 2 + AUTH_CODE_SIZE;
Packit 08bd4c
	zip->decrypted_bytes_remaining = 0;
Packit 08bd4c
Packit 08bd4c
	zip->entry->compression = zip->entry->aes_extra.compression;
Packit 08bd4c
	return (zip_alloc_decryption_buffer(a));
Packit 08bd4c
Packit 08bd4c
truncated:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Truncated ZIP file data");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
corrupted:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Corrupted ZIP file data");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_read_data(struct archive_read *a,
Packit 08bd4c
    const void **buff, size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	int r;
Packit 08bd4c
	struct zip *zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	if (zip->has_encrypted_entries ==
Packit 08bd4c
			ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
Packit 08bd4c
		zip->has_encrypted_entries = 0;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	*offset = zip->entry_uncompressed_bytes_read;
Packit 08bd4c
	*size = 0;
Packit 08bd4c
	*buff = NULL;
Packit 08bd4c
Packit 08bd4c
	/* If we hit end-of-entry last time, return ARCHIVE_EOF. */
Packit 08bd4c
	if (zip->end_of_entry)
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
Packit 08bd4c
	/* Return EOF immediately if this is a non-regular file. */
Packit 08bd4c
	if (AE_IFREG != (zip->entry->mode & AE_IFMT))
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
Packit 08bd4c
	__archive_read_consume(a, zip->unconsumed);
Packit 08bd4c
	zip->unconsumed = 0;
Packit 08bd4c
Packit 08bd4c
	if (zip->init_decryption) {
Packit 08bd4c
		zip->has_encrypted_entries = 1;
Packit 08bd4c
		if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)
Packit 08bd4c
			r = read_decryption_header(a);
Packit 08bd4c
		else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)
Packit 08bd4c
			r = init_WinZip_AES_decryption(a);
Packit 08bd4c
		else
Packit 08bd4c
			r = init_traditional_PKWARE_decryption(a);
Packit 08bd4c
		if (r != ARCHIVE_OK)
Packit 08bd4c
			return (r);
Packit 08bd4c
		zip->init_decryption = 0;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	switch(zip->entry->compression) {
Packit 08bd4c
	case 0:  /* No compression. */
Packit 08bd4c
		r =  zip_read_data_none(a, buff, size, offset);
Packit 08bd4c
		break;
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	case 8: /* Deflate compression. */
Packit 08bd4c
		r =  zip_read_data_deflate(a, buff, size, offset);
Packit 08bd4c
		break;
Packit 08bd4c
#endif
Packit 08bd4c
	default: /* Unsupported compression. */
Packit 08bd4c
		/* Return a warning. */
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unsupported ZIP compression method (%s)",
Packit 08bd4c
		    compression_name(zip->entry->compression));
Packit 08bd4c
		/* We can't decompress this entry, but we will
Packit 08bd4c
		 * be able to skip() it and try the next entry. */
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		return (r);
Packit 08bd4c
	/* Update checksum */
Packit 08bd4c
	if (*size)
Packit 08bd4c
		zip->entry_crc32 = zip->crc32func(zip->entry_crc32, *buff,
Packit 08bd4c
		    (unsigned)*size);
Packit 08bd4c
	/* If we hit the end, swallow any end-of-data marker. */
Packit 08bd4c
	if (zip->end_of_entry) {
Packit 08bd4c
		/* Check file size, CRC against these values. */
Packit 08bd4c
		if (zip->entry->compressed_size !=
Packit 08bd4c
		    zip->entry_compressed_bytes_read) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "ZIP compressed data is wrong size "
Packit 08bd4c
			    "(read %jd, expected %jd)",
Packit 08bd4c
			    (intmax_t)zip->entry_compressed_bytes_read,
Packit 08bd4c
			    (intmax_t)zip->entry->compressed_size);
Packit 08bd4c
			return (ARCHIVE_WARN);
Packit 08bd4c
		}
Packit 08bd4c
		/* Size field only stores the lower 32 bits of the actual
Packit 08bd4c
		 * size. */
Packit 08bd4c
		if ((zip->entry->uncompressed_size & UINT32_MAX)
Packit 08bd4c
		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "ZIP uncompressed data is wrong size "
Packit 08bd4c
			    "(read %jd, expected %jd)\n",
Packit 08bd4c
			    (intmax_t)zip->entry_uncompressed_bytes_read,
Packit 08bd4c
			    (intmax_t)zip->entry->uncompressed_size);
Packit 08bd4c
			return (ARCHIVE_WARN);
Packit 08bd4c
		}
Packit 08bd4c
		/* Check computed CRC against header */
Packit 08bd4c
		if ((!zip->hctx_valid ||
Packit 08bd4c
		      zip->entry->aes_extra.vendor != AES_VENDOR_AE_2) &&
Packit 08bd4c
		   zip->entry->crc32 != zip->entry_crc32
Packit 08bd4c
		    && !zip->ignore_crc32) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "ZIP bad CRC: 0x%lx should be 0x%lx",
Packit 08bd4c
			    (unsigned long)zip->entry_crc32,
Packit 08bd4c
			    (unsigned long)zip->entry->crc32);
Packit 08bd4c
			return (ARCHIVE_WARN);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_cleanup(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	struct zip_entry *zip_entry, *next_zip_entry;
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	if (zip->stream_valid)
Packit 08bd4c
		inflateEnd(&zip->stream);
Packit 08bd4c
	free(zip->uncompressed_buffer);
Packit 08bd4c
#endif
Packit 08bd4c
	if (zip->zip_entries) {
Packit 08bd4c
		zip_entry = zip->zip_entries;
Packit 08bd4c
		while (zip_entry != NULL) {
Packit 08bd4c
			next_zip_entry = zip_entry->next;
Packit 08bd4c
			archive_string_free(&zip_entry->rsrcname);
Packit 08bd4c
			free(zip_entry);
Packit 08bd4c
			zip_entry = next_zip_entry;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	free(zip->decrypted_buffer);
Packit 08bd4c
	if (zip->cctx_valid)
Packit 08bd4c
		archive_decrypto_aes_ctr_release(&zip->cctx);
Packit 08bd4c
	if (zip->hctx_valid)
Packit 08bd4c
		archive_hmac_sha1_cleanup(&zip->hctx);
Packit 08bd4c
	free(zip->iv);
Packit 08bd4c
	free(zip->erd);
Packit 08bd4c
	free(zip->v_data);
Packit 08bd4c
	archive_string_free(&zip->format_name);
Packit 08bd4c
	free(zip);
Packit 08bd4c
	(a->format->data) = NULL;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_has_encrypted_entries(struct archive_read *_a)
Packit 08bd4c
{
Packit 08bd4c
	if (_a && _a->format) {
Packit 08bd4c
		struct zip * zip = (struct zip *)_a->format->data;
Packit 08bd4c
		if (zip) {
Packit 08bd4c
			return zip->has_encrypted_entries;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_options(struct archive_read *a,
Packit 08bd4c
    const char *key, const char *val)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	int ret = ARCHIVE_FAILED;
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
	if (strcmp(key, "compat-2x")  == 0) {
Packit 08bd4c
		/* Handle filenames as libarchive 2.x */
Packit 08bd4c
		zip->init_default_conversion = (val != NULL) ? 1 : 0;
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	} else if (strcmp(key, "hdrcharset")  == 0) {
Packit 08bd4c
		if (val == NULL || val[0] == 0)
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "zip: hdrcharset option needs a character-set name"
Packit 08bd4c
			);
Packit 08bd4c
		else {
Packit 08bd4c
			zip->sconv = archive_string_conversion_from_charset(
Packit 08bd4c
			    &a->archive, val, 0);
Packit 08bd4c
			if (zip->sconv != NULL) {
Packit 08bd4c
				if (strcmp(val, "UTF-8") == 0)
Packit 08bd4c
					zip->sconv_utf8 = zip->sconv;
Packit 08bd4c
				ret = ARCHIVE_OK;
Packit 08bd4c
			} else
Packit 08bd4c
				ret = ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
		return (ret);
Packit 08bd4c
	} else if (strcmp(key, "ignorecrc32") == 0) {
Packit 08bd4c
		/* Mostly useful for testing. */
Packit 08bd4c
		if (val == NULL || val[0] == 0) {
Packit 08bd4c
			zip->crc32func = real_crc32;
Packit 08bd4c
			zip->ignore_crc32 = 0;
Packit 08bd4c
		} else {
Packit 08bd4c
			zip->crc32func = fake_crc32;
Packit 08bd4c
			zip->ignore_crc32 = 1;
Packit 08bd4c
		}
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	} else if (strcmp(key, "mac-ext") == 0) {
Packit 08bd4c
		zip->process_mac_extensions = (val != NULL && val[0] != 0);
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Note: The "warn" return is just to inform the options
Packit 08bd4c
	 * supervisor that we didn't handle it.  It will generate
Packit 08bd4c
	 * a suitable error if no one used this option. */
Packit 08bd4c
	return (ARCHIVE_WARN);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_read_support_format_zip(struct archive *a)
Packit 08bd4c
{
Packit 08bd4c
	int r;
Packit 08bd4c
	r = archive_read_support_format_zip_streamable(a);
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		return r;
Packit 08bd4c
	return (archive_read_support_format_zip_seekable(a));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* ------------------------------------------------------------------------ */
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Streaming-mode support
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_support_format_zip_capabilities_streamable(struct archive_read * a)
Packit 08bd4c
{
Packit 08bd4c
	(void)a; /* UNUSED */
Packit 08bd4c
	return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
Packit 08bd4c
		ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
Packit 08bd4c
{
Packit 08bd4c
	const char *p;
Packit 08bd4c
Packit 08bd4c
	(void)best_bid; /* UNUSED */
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Bid of 29 here comes from:
Packit 08bd4c
	 *  + 16 bits for "PK",
Packit 08bd4c
	 *  + next 16-bit field has 6 options so contributes
Packit 08bd4c
	 *    about 16 - log_2(6) ~= 16 - 2.6 ~= 13 bits
Packit 08bd4c
	 *
Packit 08bd4c
	 * So we've effectively verified ~29 total bits of check data.
Packit 08bd4c
	 */
Packit 08bd4c
	if (p[0] == 'P' && p[1] == 'K') {
Packit 08bd4c
		if ((p[2] == '\001' && p[3] == '\002')
Packit 08bd4c
		    || (p[2] == '\003' && p[3] == '\004')
Packit 08bd4c
		    || (p[2] == '\005' && p[3] == '\006')
Packit 08bd4c
		    || (p[2] == '\006' && p[3] == '\006')
Packit 08bd4c
		    || (p[2] == '\007' && p[3] == '\010')
Packit 08bd4c
		    || (p[2] == '0' && p[3] == '0'))
Packit 08bd4c
			return (29);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* TODO: It's worth looking ahead a little bit for a valid
Packit 08bd4c
	 * PK signature.  In particular, that would make it possible
Packit 08bd4c
	 * to read some UUEncoded SFX files or SFX files coming from
Packit 08bd4c
	 * a network socket. */
Packit 08bd4c
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_streamable_read_header(struct archive_read *a,
Packit 08bd4c
    struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
Packit 08bd4c
	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
Packit 08bd4c
	if (a->archive.archive_format_name == NULL)
Packit 08bd4c
		a->archive.archive_format_name = "ZIP";
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * It should be sufficient to call archive_read_next_header() for
Packit 08bd4c
	 * a reader to determine if an entry is encrypted or not. If the
Packit 08bd4c
	 * encryption of an entry is only detectable when calling
Packit 08bd4c
	 * archive_read_data(), so be it. We'll do the same check there
Packit 08bd4c
	 * as well.
Packit 08bd4c
	 */
Packit 08bd4c
	if (zip->has_encrypted_entries ==
Packit 08bd4c
			ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)
Packit 08bd4c
		zip->has_encrypted_entries = 0;
Packit 08bd4c
Packit 08bd4c
	/* Make sure we have a zip_entry structure to use. */
Packit 08bd4c
	if (zip->zip_entries == NULL) {
Packit 08bd4c
		zip->zip_entries = malloc(sizeof(struct zip_entry));
Packit 08bd4c
		if (zip->zip_entries == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "Out  of memory");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	zip->entry = zip->zip_entries;
Packit 08bd4c
	memset(zip->entry, 0, sizeof(struct zip_entry));
Packit 08bd4c
Packit 08bd4c
	if (zip->cctx_valid)
Packit 08bd4c
		archive_decrypto_aes_ctr_release(&zip->cctx);
Packit 08bd4c
	if (zip->hctx_valid)
Packit 08bd4c
		archive_hmac_sha1_cleanup(&zip->hctx);
Packit 08bd4c
	zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;
Packit 08bd4c
	__archive_read_reset_passphrase(a);
Packit 08bd4c
Packit 08bd4c
	/* Search ahead for the next local file header. */
Packit 08bd4c
	__archive_read_consume(a, zip->unconsumed);
Packit 08bd4c
	zip->unconsumed = 0;
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		int64_t skipped = 0;
Packit 08bd4c
		const char *p, *end;
Packit 08bd4c
		ssize_t bytes;
Packit 08bd4c
Packit 08bd4c
		p = __archive_read_ahead(a, 4, &bytes);
Packit 08bd4c
		if (p == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		end = p + bytes;
Packit 08bd4c
Packit 08bd4c
		while (p + 4 <= end) {
Packit 08bd4c
			if (p[0] == 'P' && p[1] == 'K') {
Packit 08bd4c
				if (p[2] == '\003' && p[3] == '\004') {
Packit 08bd4c
					/* Regular file entry. */
Packit 08bd4c
					__archive_read_consume(a, skipped);
Packit 08bd4c
					return zip_read_local_file_header(a,
Packit 08bd4c
					    entry, zip);
Packit 08bd4c
				}
Packit 08bd4c
Packit 08bd4c
                              /*
Packit 08bd4c
                               * TODO: We cannot restore permissions
Packit 08bd4c
                               * based only on the local file headers.
Packit 08bd4c
                               * Consider scanning the central
Packit 08bd4c
                               * directory and returning additional
Packit 08bd4c
                               * entries for at least directories.
Packit 08bd4c
                               * This would allow us to properly set
Packit 08bd4c
                               * directory permissions.
Packit 08bd4c
			       *
Packit 08bd4c
			       * This won't help us fix symlinks
Packit 08bd4c
			       * and may not help with regular file
Packit 08bd4c
			       * permissions, either.  <sigh>
Packit 08bd4c
                               */
Packit 08bd4c
                              if (p[2] == '\001' && p[3] == '\002') {
Packit 08bd4c
                                      return (ARCHIVE_EOF);
Packit 08bd4c
                              }
Packit 08bd4c
Packit 08bd4c
                              /* End of central directory?  Must be an
Packit 08bd4c
                               * empty archive. */
Packit 08bd4c
                              if ((p[2] == '\005' && p[3] == '\006')
Packit 08bd4c
                                  || (p[2] == '\006' && p[3] == '\006'))
Packit 08bd4c
                                      return (ARCHIVE_EOF);
Packit 08bd4c
			}
Packit 08bd4c
			++p;
Packit 08bd4c
			++skipped;
Packit 08bd4c
		}
Packit 08bd4c
		__archive_read_consume(a, skipped);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_read_data_skip_streamable(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	int64_t bytes_skipped;
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
	bytes_skipped = __archive_read_consume(a, zip->unconsumed);
Packit 08bd4c
	zip->unconsumed = 0;
Packit 08bd4c
	if (bytes_skipped < 0)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* If we've already read to end of data, we're done. */
Packit 08bd4c
	if (zip->end_of_entry)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	/* So we know we're streaming... */
Packit 08bd4c
	if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
	    || zip->entry->compressed_size > 0) {
Packit 08bd4c
		/* We know the compressed length, so we can just skip. */
Packit 08bd4c
		bytes_skipped = __archive_read_consume(a,
Packit 08bd4c
					zip->entry_bytes_remaining);
Packit 08bd4c
		if (bytes_skipped < 0)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (zip->init_decryption) {
Packit 08bd4c
		int r;
Packit 08bd4c
Packit 08bd4c
		zip->has_encrypted_entries = 1;
Packit 08bd4c
		if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)
Packit 08bd4c
			r = read_decryption_header(a);
Packit 08bd4c
		else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)
Packit 08bd4c
			r = init_WinZip_AES_decryption(a);
Packit 08bd4c
		else
Packit 08bd4c
			r = init_traditional_PKWARE_decryption(a);
Packit 08bd4c
		if (r != ARCHIVE_OK)
Packit 08bd4c
			return (r);
Packit 08bd4c
		zip->init_decryption = 0;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* We're streaming and we don't know the length. */
Packit 08bd4c
	/* If the body is compressed and we know the format, we can
Packit 08bd4c
	 * find an exact end-of-entry by decompressing it. */
Packit 08bd4c
	switch (zip->entry->compression) {
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	case 8: /* Deflate compression. */
Packit 08bd4c
		while (!zip->end_of_entry) {
Packit 08bd4c
			int64_t offset = 0;
Packit 08bd4c
			const void *buff = NULL;
Packit 08bd4c
			size_t size = 0;
Packit 08bd4c
			int r;
Packit 08bd4c
			r =  zip_read_data_deflate(a, &buff, &size, &offset);
Packit 08bd4c
			if (r != ARCHIVE_OK)
Packit 08bd4c
				return (r);
Packit 08bd4c
		}
Packit 08bd4c
		return ARCHIVE_OK;
Packit 08bd4c
#endif
Packit 08bd4c
	default: /* Uncompressed or unknown. */
Packit 08bd4c
		/* Scan for a PK\007\010 signature. */
Packit 08bd4c
		for (;;) {
Packit 08bd4c
			const char *p, *buff;
Packit 08bd4c
			ssize_t bytes_avail;
Packit 08bd4c
			buff = __archive_read_ahead(a, 16, &bytes_avail);
Packit 08bd4c
			if (bytes_avail < 16) {
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
				    "Truncated ZIP file data");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			p = buff;
Packit 08bd4c
			while (p <= buff + bytes_avail - 16) {
Packit 08bd4c
				if (p[3] == 'P') { p += 3; }
Packit 08bd4c
				else if (p[3] == 'K') { p += 2; }
Packit 08bd4c
				else if (p[3] == '\007') { p += 1; }
Packit 08bd4c
				else if (p[3] == '\010' && p[2] == '\007'
Packit 08bd4c
				    && p[1] == 'K' && p[0] == 'P') {
Packit 08bd4c
					if (zip->entry->flags & LA_USED_ZIP64)
Packit 08bd4c
						__archive_read_consume(a,
Packit 08bd4c
						    p - buff + 24);
Packit 08bd4c
					else
Packit 08bd4c
						__archive_read_consume(a,
Packit 08bd4c
						    p - buff + 16);
Packit 08bd4c
					return ARCHIVE_OK;
Packit 08bd4c
				} else { p += 4; }
Packit 08bd4c
			}
Packit 08bd4c
			__archive_read_consume(a, p - buff);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_read_support_format_zip_streamable(struct archive *_a)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_read *a = (struct archive_read *)_a;
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
Packit 08bd4c
	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip");
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)calloc(1, sizeof(*zip));
Packit 08bd4c
	if (zip == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Can't allocate zip data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Streamable reader doesn't support mac extensions. */
Packit 08bd4c
	zip->process_mac_extensions = 0;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Until enough data has been read, we cannot tell about
Packit 08bd4c
	 * any encrypted entries yet.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
Packit 08bd4c
	zip->crc32func = real_crc32;
Packit 08bd4c
Packit 08bd4c
	r = __archive_read_register_format(a,
Packit 08bd4c
	    zip,
Packit 08bd4c
	    "zip",
Packit 08bd4c
	    archive_read_format_zip_streamable_bid,
Packit 08bd4c
	    archive_read_format_zip_options,
Packit 08bd4c
	    archive_read_format_zip_streamable_read_header,
Packit 08bd4c
	    archive_read_format_zip_read_data,
Packit 08bd4c
	    archive_read_format_zip_read_data_skip_streamable,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    archive_read_format_zip_cleanup,
Packit 08bd4c
	    archive_read_support_format_zip_capabilities_streamable,
Packit 08bd4c
	    archive_read_format_zip_has_encrypted_entries);
Packit 08bd4c
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		free(zip);
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* ------------------------------------------------------------------------ */
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Seeking-mode support
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_support_format_zip_capabilities_seekable(struct archive_read * a)
Packit 08bd4c
{
Packit 08bd4c
	(void)a; /* UNUSED */
Packit 08bd4c
	return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
Packit 08bd4c
		ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * TODO: This is a performance sink because it forces the read core to
Packit 08bd4c
 * drop buffered data from the start of file, which will then have to
Packit 08bd4c
 * be re-read again if this bidder loses.
Packit 08bd4c
 *
Packit 08bd4c
 * We workaround this a little by passing in the best bid so far so
Packit 08bd4c
 * that later bidders can do nothing if they know they'll never
Packit 08bd4c
 * outbid.  But we can certainly do better...
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
read_eocd(struct zip *zip, const char *p, int64_t current_offset)
Packit 08bd4c
{
Packit 08bd4c
	/* Sanity-check the EOCD we've found. */
Packit 08bd4c
Packit 08bd4c
	/* This must be the first volume. */
Packit 08bd4c
	if (archive_le16dec(p + 4) != 0)
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* Central directory must be on this volume. */
Packit 08bd4c
	if (archive_le16dec(p + 4) != archive_le16dec(p + 6))
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* All central directory entries must be on this volume. */
Packit 08bd4c
	if (archive_le16dec(p + 10) != archive_le16dec(p + 8))
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* Central directory can't extend beyond start of EOCD record. */
Packit 08bd4c
	if (archive_le32dec(p + 16) + archive_le32dec(p + 12)
Packit 08bd4c
	    > current_offset)
Packit 08bd4c
		return 0;
Packit 08bd4c
Packit 08bd4c
	/* Save the central directory location for later use. */
Packit 08bd4c
	zip->central_directory_offset = archive_le32dec(p + 16);
Packit 08bd4c
Packit 08bd4c
	/* This is just a tiny bit higher than the maximum
Packit 08bd4c
	   returned by the streaming Zip bidder.  This ensures
Packit 08bd4c
	   that the more accurate seeking Zip parser wins
Packit 08bd4c
	   whenever seek is available. */
Packit 08bd4c
	return 32;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Examine Zip64 EOCD locator:  If it's valid, store the information
Packit 08bd4c
 * from it.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
Packit 08bd4c
{
Packit 08bd4c
	int64_t eocd64_offset;
Packit 08bd4c
	int64_t eocd64_size;
Packit 08bd4c
Packit 08bd4c
	/* Sanity-check the locator record. */
Packit 08bd4c
Packit 08bd4c
	/* Central dir must be on first volume. */
Packit 08bd4c
	if (archive_le32dec(p + 4) != 0)
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* Must be only a single volume. */
Packit 08bd4c
	if (archive_le32dec(p + 16) != 1)
Packit 08bd4c
		return 0;
Packit 08bd4c
Packit 08bd4c
	/* Find the Zip64 EOCD record. */
Packit 08bd4c
	eocd64_offset = archive_le64dec(p + 8);
Packit 08bd4c
	if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0)
Packit 08bd4c
		return 0;
Packit 08bd4c
	if ((p = __archive_read_ahead(a, 56, NULL)) == NULL)
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* Make sure we can read all of it. */
Packit 08bd4c
	eocd64_size = archive_le64dec(p + 4) + 12;
Packit 08bd4c
	if (eocd64_size < 56 || eocd64_size > 16384)
Packit 08bd4c
		return 0;
Packit 08bd4c
	if ((p = __archive_read_ahead(a, (size_t)eocd64_size, NULL)) == NULL)
Packit 08bd4c
		return 0;
Packit 08bd4c
Packit 08bd4c
	/* Sanity-check the EOCD64 */
Packit 08bd4c
	if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */
Packit 08bd4c
		return 0;
Packit 08bd4c
	if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* CD can't be split. */
Packit 08bd4c
	if (archive_le64dec(p + 24) != archive_le64dec(p + 32))
Packit 08bd4c
		return 0;
Packit 08bd4c
Packit 08bd4c
	/* Save the central directory offset for later use. */
Packit 08bd4c
	zip->central_directory_offset = archive_le64dec(p + 48);
Packit 08bd4c
Packit 08bd4c
	return 32;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)a->format->data;
Packit 08bd4c
	int64_t file_size, current_offset;
Packit 08bd4c
	const char *p;
Packit 08bd4c
	int i, tail;
Packit 08bd4c
Packit 08bd4c
	/* If someone has already bid more than 32, then avoid
Packit 08bd4c
	   trashing the look-ahead buffers with a seek. */
Packit 08bd4c
	if (best_bid > 32)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	file_size = __archive_read_seek(a, 0, SEEK_END);
Packit 08bd4c
	if (file_size <= 0)
Packit 08bd4c
		return 0;
Packit 08bd4c
Packit 08bd4c
	/* Search last 16k of file for end-of-central-directory
Packit 08bd4c
	 * record (which starts with PK\005\006) */
Packit 08bd4c
	tail = (int)zipmin(1024 * 16, file_size);
Packit 08bd4c
	current_offset = __archive_read_seek(a, -tail, SEEK_END);
Packit 08bd4c
	if (current_offset < 0)
Packit 08bd4c
		return 0;
Packit 08bd4c
	if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
Packit 08bd4c
		return 0;
Packit 08bd4c
	/* Boyer-Moore search backwards from the end, since we want
Packit 08bd4c
	 * to match the last EOCD in the file (there can be more than
Packit 08bd4c
	 * one if there is an uncompressed Zip archive as a member
Packit 08bd4c
	 * within this Zip archive). */
Packit 08bd4c
	for (i = tail - 22; i > 0;) {
Packit 08bd4c
		switch (p[i]) {
Packit 08bd4c
		case 'P':
Packit 08bd4c
			if (memcmp(p + i, "PK\005\006", 4) == 0) {
Packit 08bd4c
				int ret = read_eocd(zip, p + i,
Packit 08bd4c
				    current_offset + i);
Packit 08bd4c
				/* Zip64 EOCD locator precedes
Packit 08bd4c
				 * regular EOCD if present. */
Packit 08bd4c
				if (i >= 20 && memcmp(p + i - 20, "PK\006\007", 4) == 0) {
Packit 08bd4c
					int ret_zip64 = read_zip64_eocd(a, zip, p + i - 20);
Packit 08bd4c
					if (ret_zip64 > ret)
Packit 08bd4c
						ret = ret_zip64;
Packit 08bd4c
				}
Packit 08bd4c
				return (ret);
Packit 08bd4c
			}
Packit 08bd4c
			i -= 4;
Packit 08bd4c
			break;
Packit 08bd4c
		case 'K': i -= 1; break;
Packit 08bd4c
		case 005: i -= 2; break;
Packit 08bd4c
		case 006: i -= 3; break;
Packit 08bd4c
		default: i -= 4; break;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* The red-black trees are only used in seeking mode to manage
Packit 08bd4c
 * the in-memory copy of the central directory. */
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
Packit 08bd4c
{
Packit 08bd4c
	const struct zip_entry *e1 = (const struct zip_entry *)n1;
Packit 08bd4c
	const struct zip_entry *e2 = (const struct zip_entry *)n2;
Packit 08bd4c
Packit 08bd4c
	if (e1->local_header_offset > e2->local_header_offset)
Packit 08bd4c
		return -1;
Packit 08bd4c
	if (e1->local_header_offset < e2->local_header_offset)
Packit 08bd4c
		return 1;
Packit 08bd4c
	return 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
cmp_key(const struct archive_rb_node *n, const void *key)
Packit 08bd4c
{
Packit 08bd4c
	/* This function won't be called */
Packit 08bd4c
	(void)n; /* UNUSED */
Packit 08bd4c
	(void)key; /* UNUSED */
Packit 08bd4c
	return 1;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const struct archive_rb_tree_ops rb_ops = {
Packit 08bd4c
	&cmp_node, &cmp_key
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
rsrc_cmp_node(const struct archive_rb_node *n1,
Packit 08bd4c
    const struct archive_rb_node *n2)
Packit 08bd4c
{
Packit 08bd4c
	const struct zip_entry *e1 = (const struct zip_entry *)n1;
Packit 08bd4c
	const struct zip_entry *e2 = (const struct zip_entry *)n2;
Packit 08bd4c
Packit 08bd4c
	return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
Packit 08bd4c
{
Packit 08bd4c
	const struct zip_entry *e = (const struct zip_entry *)n;
Packit 08bd4c
	return (strcmp((const char *)key, e->rsrcname.s));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const struct archive_rb_tree_ops rb_rsrc_ops = {
Packit 08bd4c
	&rsrc_cmp_node, &rsrc_cmp_key
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static const char *
Packit 08bd4c
rsrc_basename(const char *name, size_t name_length)
Packit 08bd4c
{
Packit 08bd4c
	const char *s, *r;
Packit 08bd4c
Packit 08bd4c
	r = s = name;
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		s = memchr(s, '/', name_length - (s - name));
Packit 08bd4c
		if (s == NULL)
Packit 08bd4c
			break;
Packit 08bd4c
		r = ++s;
Packit 08bd4c
	}
Packit 08bd4c
	return (r);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_string str;
Packit 08bd4c
	struct zip_entry *dir;
Packit 08bd4c
	char *s;
Packit 08bd4c
Packit 08bd4c
	archive_string_init(&str);
Packit 08bd4c
	archive_strncpy(&str, name, name_length);
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		s = strrchr(str.s, '/');
Packit 08bd4c
		if (s == NULL)
Packit 08bd4c
			break;
Packit 08bd4c
		*s = '\0';
Packit 08bd4c
		/* Transfer the parent directory from zip->tree_rsrc RB
Packit 08bd4c
		 * tree to zip->tree RB tree to expose. */
Packit 08bd4c
		dir = (struct zip_entry *)
Packit 08bd4c
		    __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
Packit 08bd4c
		if (dir == NULL)
Packit 08bd4c
			break;
Packit 08bd4c
		__archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
Packit 08bd4c
		archive_string_free(&dir->rsrcname);
Packit 08bd4c
		__archive_rb_tree_insert_node(&zip->tree, &dir->node);
Packit 08bd4c
	}
Packit 08bd4c
	archive_string_free(&str);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
slurp_central_directory(struct archive_read *a, struct zip *zip)
Packit 08bd4c
{
Packit 08bd4c
	ssize_t i;
Packit 08bd4c
	unsigned found;
Packit 08bd4c
	int64_t correction;
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
	const char *p;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Find the start of the central directory.  The end-of-CD
Packit 08bd4c
	 * record has our starting point, but there are lots of
Packit 08bd4c
	 * Zip archives which have had other data prepended to the
Packit 08bd4c
	 * file, which makes the recorded offsets all too small.
Packit 08bd4c
	 * So we search forward from the specified offset until we
Packit 08bd4c
	 * find the real start of the central directory.  Then we
Packit 08bd4c
	 * know the correction we need to apply to account for leading
Packit 08bd4c
	 * padding.
Packit 08bd4c
	 */
Packit 08bd4c
	if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0)
Packit 08bd4c
		return ARCHIVE_FATAL;
Packit 08bd4c
Packit 08bd4c
	found = 0;
Packit 08bd4c
	while (!found) {
Packit 08bd4c
		if ((p = __archive_read_ahead(a, 20, &bytes_avail)) == NULL)
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		for (found = 0, i = 0; !found && i < bytes_avail - 4;) {
Packit 08bd4c
			switch (p[i + 3]) {
Packit 08bd4c
			case 'P': i += 3; break;
Packit 08bd4c
			case 'K': i += 2; break;
Packit 08bd4c
			case 001: i += 1; break;
Packit 08bd4c
			case 002:
Packit 08bd4c
				if (memcmp(p + i, "PK\001\002", 4) == 0) {
Packit 08bd4c
					p += i;
Packit 08bd4c
					found = 1;
Packit 08bd4c
				} else
Packit 08bd4c
					i += 4;
Packit 08bd4c
				break;
Packit 08bd4c
			case 005: i += 1; break;
Packit 08bd4c
			case 006:
Packit 08bd4c
				if (memcmp(p + i, "PK\005\006", 4) == 0) {
Packit 08bd4c
					p += i;
Packit 08bd4c
					found = 1;
Packit 08bd4c
				} else if (memcmp(p + i, "PK\006\006", 4) == 0) {
Packit 08bd4c
					p += i;
Packit 08bd4c
					found = 1;
Packit 08bd4c
				} else
Packit 08bd4c
					i += 1;
Packit 08bd4c
				break;
Packit 08bd4c
			default: i += 4; break;
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
		__archive_read_consume(a, i);
Packit 08bd4c
	}
Packit 08bd4c
	correction = archive_filter_bytes(&a->archive, 0)
Packit 08bd4c
			- zip->central_directory_offset;
Packit 08bd4c
Packit 08bd4c
	__archive_rb_tree_init(&zip->tree, &rb_ops);
Packit 08bd4c
	__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
Packit 08bd4c
Packit 08bd4c
	zip->central_directory_entries_total = 0;
Packit 08bd4c
	while (1) {
Packit 08bd4c
		struct zip_entry *zip_entry;
Packit 08bd4c
		size_t filename_length, extra_length, comment_length;
Packit 08bd4c
		uint32_t external_attributes;
Packit 08bd4c
		const char *name, *r;
Packit 08bd4c
Packit 08bd4c
		if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		if (memcmp(p, "PK\006\006", 4) == 0
Packit 08bd4c
		    || memcmp(p, "PK\005\006", 4) == 0) {
Packit 08bd4c
			break;
Packit 08bd4c
		} else if (memcmp(p, "PK\001\002", 4) != 0) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    -1, "Invalid central directory signature");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
		if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
Packit 08bd4c
		zip_entry = calloc(1, sizeof(struct zip_entry));
Packit 08bd4c
		zip_entry->next = zip->zip_entries;
Packit 08bd4c
		zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY;
Packit 08bd4c
		zip->zip_entries = zip_entry;
Packit 08bd4c
		zip->central_directory_entries_total++;
Packit 08bd4c
Packit 08bd4c
		/* version = p[4]; */
Packit 08bd4c
		zip_entry->system = p[5];
Packit 08bd4c
		/* version_required = archive_le16dec(p + 6); */
Packit 08bd4c
		zip_entry->zip_flags = archive_le16dec(p + 8);
Packit 08bd4c
		if (zip_entry->zip_flags
Packit 08bd4c
		      & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)){
Packit 08bd4c
			zip->has_encrypted_entries = 1;
Packit 08bd4c
		}
Packit 08bd4c
		zip_entry->compression = (char)archive_le16dec(p + 10);
Packit 08bd4c
		zip_entry->mtime = zip_time(p + 12);
Packit 08bd4c
		zip_entry->crc32 = archive_le32dec(p + 16);
Packit 08bd4c
		if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
Packit 08bd4c
			zip_entry->decdat = p[13];
Packit 08bd4c
		else
Packit 08bd4c
			zip_entry->decdat = p[19];
Packit 08bd4c
		zip_entry->compressed_size = archive_le32dec(p + 20);
Packit 08bd4c
		zip_entry->uncompressed_size = archive_le32dec(p + 24);
Packit 08bd4c
		filename_length = archive_le16dec(p + 28);
Packit 08bd4c
		extra_length = archive_le16dec(p + 30);
Packit 08bd4c
		comment_length = archive_le16dec(p + 32);
Packit 08bd4c
		/* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */
Packit 08bd4c
		/* internal_attributes = archive_le16dec(p + 36); */ /* text bit */
Packit 08bd4c
		external_attributes = archive_le32dec(p + 38);
Packit 08bd4c
		zip_entry->local_header_offset =
Packit 08bd4c
		    archive_le32dec(p + 42) + correction;
Packit 08bd4c
Packit 08bd4c
		/* If we can't guess the mode, leave it zero here;
Packit 08bd4c
		   when we read the local file header we might get
Packit 08bd4c
		   more information. */
Packit 08bd4c
		if (zip_entry->system == 3) {
Packit 08bd4c
			zip_entry->mode = external_attributes >> 16;
Packit 08bd4c
		} else if (zip_entry->system == 0) {
Packit 08bd4c
			// Interpret MSDOS directory bit
Packit 08bd4c
			if (0x10 == (external_attributes & 0x10)) {
Packit 08bd4c
				zip_entry->mode = AE_IFDIR | 0775;
Packit 08bd4c
			} else {
Packit 08bd4c
				zip_entry->mode = AE_IFREG | 0664;
Packit 08bd4c
			}
Packit 08bd4c
			if (0x01 == (external_attributes & 0x01)) {
Packit 08bd4c
				// Read-only bit; strip write permissions
Packit 08bd4c
				zip_entry->mode &= 0555;
Packit 08bd4c
			}
Packit 08bd4c
		} else {
Packit 08bd4c
			zip_entry->mode = 0;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/* We're done with the regular data; get the filename and
Packit 08bd4c
		 * extra data. */
Packit 08bd4c
		__archive_read_consume(a, 46);
Packit 08bd4c
		p = __archive_read_ahead(a, filename_length + extra_length,
Packit 08bd4c
			NULL);
Packit 08bd4c
		if (p == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated ZIP file header");
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
		if (ARCHIVE_OK != process_extra(a, p + filename_length, extra_length, zip_entry)) {
Packit 08bd4c
			return ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Mac resource fork files are stored under the
Packit 08bd4c
		 * "__MACOSX/" directory, so we should check if
Packit 08bd4c
		 * it is.
Packit 08bd4c
		 */
Packit 08bd4c
		if (!zip->process_mac_extensions) {
Packit 08bd4c
			/* Treat every entry as a regular entry. */
Packit 08bd4c
			__archive_rb_tree_insert_node(&zip->tree,
Packit 08bd4c
			    &zip_entry->node);
Packit 08bd4c
		} else {
Packit 08bd4c
			name = p;
Packit 08bd4c
			r = rsrc_basename(name, filename_length);
Packit 08bd4c
			if (filename_length >= 9 &&
Packit 08bd4c
			    strncmp("__MACOSX/", name, 9) == 0) {
Packit 08bd4c
				/* If this file is not a resource fork nor
Packit 08bd4c
				 * a directory. We should treat it as a non
Packit 08bd4c
				 * resource fork file to expose it. */
Packit 08bd4c
				if (name[filename_length-1] != '/' &&
Packit 08bd4c
				    (r - name < 3 || r[0] != '.' || r[1] != '_')) {
Packit 08bd4c
					__archive_rb_tree_insert_node(
Packit 08bd4c
					    &zip->tree, &zip_entry->node);
Packit 08bd4c
					/* Expose its parent directories. */
Packit 08bd4c
					expose_parent_dirs(zip, name,
Packit 08bd4c
					    filename_length);
Packit 08bd4c
				} else {
Packit 08bd4c
					/* This file is a resource fork file or
Packit 08bd4c
					 * a directory. */
Packit 08bd4c
					archive_strncpy(&(zip_entry->rsrcname),
Packit 08bd4c
					     name, filename_length);
Packit 08bd4c
					__archive_rb_tree_insert_node(
Packit 08bd4c
					    &zip->tree_rsrc, &zip_entry->node);
Packit 08bd4c
				}
Packit 08bd4c
			} else {
Packit 08bd4c
				/* Generate resource fork name to find its
Packit 08bd4c
				 * resource file at zip->tree_rsrc. */
Packit 08bd4c
				archive_strcpy(&(zip_entry->rsrcname),
Packit 08bd4c
				    "__MACOSX/");
Packit 08bd4c
				archive_strncat(&(zip_entry->rsrcname),
Packit 08bd4c
				    name, r - name);
Packit 08bd4c
				archive_strcat(&(zip_entry->rsrcname), "._");
Packit 08bd4c
				archive_strncat(&(zip_entry->rsrcname),
Packit 08bd4c
				    name + (r - name),
Packit 08bd4c
				    filename_length - (r - name));
Packit 08bd4c
				/* Register an entry to RB tree to sort it by
Packit 08bd4c
				 * file offset. */
Packit 08bd4c
				__archive_rb_tree_insert_node(&zip->tree,
Packit 08bd4c
				    &zip_entry->node);
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/* Skip the comment too ... */
Packit 08bd4c
		__archive_read_consume(a,
Packit 08bd4c
		    filename_length + extra_length + comment_length);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return ARCHIVE_OK;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static ssize_t
Packit 08bd4c
zip_get_local_file_header_size(struct archive_read *a, size_t extra)
Packit 08bd4c
{
Packit 08bd4c
	const char *p;
Packit 08bd4c
	ssize_t filename_length, extra_length;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated ZIP file header");
Packit 08bd4c
		return (ARCHIVE_WARN);
Packit 08bd4c
	}
Packit 08bd4c
	p += extra;
Packit 08bd4c
Packit 08bd4c
	if (memcmp(p, "PK\003\004", 4) != 0) {
Packit 08bd4c
		archive_set_error(&a->archive, -1, "Damaged Zip archive");
Packit 08bd4c
		return ARCHIVE_WARN;
Packit 08bd4c
	}
Packit 08bd4c
	filename_length = archive_le16dec(p + 26);
Packit 08bd4c
	extra_length = archive_le16dec(p + 28);
Packit 08bd4c
Packit 08bd4c
	return (30 + filename_length + extra_length);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
Packit 08bd4c
    struct zip_entry *rsrc)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)a->format->data;
Packit 08bd4c
	unsigned char *metadata, *mp;
Packit 08bd4c
	int64_t offset = archive_filter_bytes(&a->archive, 0);
Packit 08bd4c
	size_t remaining_bytes, metadata_bytes;
Packit 08bd4c
	ssize_t hsize;
Packit 08bd4c
	int ret = ARCHIVE_OK, eof;
Packit 08bd4c
Packit 08bd4c
	switch(rsrc->compression) {
Packit 08bd4c
	case 0:  /* No compression. */
Packit 08bd4c
		if (rsrc->uncompressed_size != rsrc->compressed_size) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Malformed OS X metadata entry: inconsistent size");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	case 8: /* Deflate compression. */
Packit 08bd4c
#endif
Packit 08bd4c
		break;
Packit 08bd4c
	default: /* Unsupported compression. */
Packit 08bd4c
		/* Return a warning. */
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unsupported ZIP compression method (%s)",
Packit 08bd4c
		    compression_name(rsrc->compression));
Packit 08bd4c
		/* We can't decompress this entry, but we will
Packit 08bd4c
		 * be able to skip() it and try the next entry. */
Packit 08bd4c
		return (ARCHIVE_WARN);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (rsrc->uncompressed_size > (4 * 1024 * 1024)) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Mac metadata is too large: %jd > 4M bytes",
Packit 08bd4c
		    (intmax_t)rsrc->uncompressed_size);
Packit 08bd4c
		return (ARCHIVE_WARN);
Packit 08bd4c
	}
Packit 08bd4c
	if (rsrc->compressed_size > (4 * 1024 * 1024)) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Mac metadata is too large: %jd > 4M bytes",
Packit 08bd4c
		    (intmax_t)rsrc->compressed_size);
Packit 08bd4c
		return (ARCHIVE_WARN);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	metadata = malloc((size_t)rsrc->uncompressed_size);
Packit 08bd4c
	if (metadata == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Can't allocate memory for Mac metadata");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (offset < rsrc->local_header_offset)
Packit 08bd4c
		__archive_read_consume(a, rsrc->local_header_offset - offset);
Packit 08bd4c
	else if (offset != rsrc->local_header_offset) {
Packit 08bd4c
		__archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	hsize = zip_get_local_file_header_size(a, 0);
Packit 08bd4c
	__archive_read_consume(a, hsize);
Packit 08bd4c
Packit 08bd4c
	remaining_bytes = (size_t)rsrc->compressed_size;
Packit 08bd4c
	metadata_bytes = (size_t)rsrc->uncompressed_size;
Packit 08bd4c
	mp = metadata;
Packit 08bd4c
	eof = 0;
Packit 08bd4c
	while (!eof && remaining_bytes) {
Packit 08bd4c
		const unsigned char *p;
Packit 08bd4c
		ssize_t bytes_avail;
Packit 08bd4c
		size_t bytes_used;
Packit 08bd4c
Packit 08bd4c
		p = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
		if (p == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated ZIP file header");
Packit 08bd4c
			ret = ARCHIVE_WARN;
Packit 08bd4c
			goto exit_mac_metadata;
Packit 08bd4c
		}
Packit 08bd4c
		if ((size_t)bytes_avail > remaining_bytes)
Packit 08bd4c
			bytes_avail = remaining_bytes;
Packit 08bd4c
		switch(rsrc->compression) {
Packit 08bd4c
		case 0:  /* No compression. */
Packit 08bd4c
			if ((size_t)bytes_avail > metadata_bytes)
Packit 08bd4c
				bytes_avail = metadata_bytes;
Packit 08bd4c
			memcpy(mp, p, bytes_avail);
Packit 08bd4c
			bytes_used = (size_t)bytes_avail;
Packit 08bd4c
			metadata_bytes -= bytes_used;
Packit 08bd4c
			mp += bytes_used;
Packit 08bd4c
			if (metadata_bytes == 0)
Packit 08bd4c
				eof = 1;
Packit 08bd4c
			break;
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
		case 8: /* Deflate compression. */
Packit 08bd4c
		{
Packit 08bd4c
			int r;
Packit 08bd4c
Packit 08bd4c
			ret = zip_deflate_init(a, zip);
Packit 08bd4c
			if (ret != ARCHIVE_OK)
Packit 08bd4c
				goto exit_mac_metadata;
Packit 08bd4c
			zip->stream.next_in =
Packit 08bd4c
			    (Bytef *)(uintptr_t)(const void *)p;
Packit 08bd4c
			zip->stream.avail_in = (uInt)bytes_avail;
Packit 08bd4c
			zip->stream.total_in = 0;
Packit 08bd4c
			zip->stream.next_out = mp;
Packit 08bd4c
			zip->stream.avail_out = (uInt)metadata_bytes;
Packit 08bd4c
			zip->stream.total_out = 0;
Packit 08bd4c
Packit 08bd4c
			r = inflate(&zip->stream, 0);
Packit 08bd4c
			switch (r) {
Packit 08bd4c
			case Z_OK:
Packit 08bd4c
				break;
Packit 08bd4c
			case Z_STREAM_END:
Packit 08bd4c
				eof = 1;
Packit 08bd4c
				break;
Packit 08bd4c
			case Z_MEM_ERROR:
Packit 08bd4c
				archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
				    "Out of memory for ZIP decompression");
Packit 08bd4c
				ret = ARCHIVE_FATAL;
Packit 08bd4c
				goto exit_mac_metadata;
Packit 08bd4c
			default:
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_MISC,
Packit 08bd4c
				    "ZIP decompression failed (%d)", r);
Packit 08bd4c
				ret = ARCHIVE_FATAL;
Packit 08bd4c
				goto exit_mac_metadata;
Packit 08bd4c
			}
Packit 08bd4c
			bytes_used = zip->stream.total_in;
Packit 08bd4c
			metadata_bytes -= zip->stream.total_out;
Packit 08bd4c
			mp += zip->stream.total_out;
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
#endif
Packit 08bd4c
		default:
Packit 08bd4c
			bytes_used = 0;
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		__archive_read_consume(a, bytes_used);
Packit 08bd4c
		remaining_bytes -= bytes_used;
Packit 08bd4c
	}
Packit 08bd4c
	archive_entry_copy_mac_metadata(entry, metadata,
Packit 08bd4c
	    (size_t)rsrc->uncompressed_size - metadata_bytes);
Packit 08bd4c
Packit 08bd4c
exit_mac_metadata:
Packit 08bd4c
	__archive_read_seek(a, offset, SEEK_SET);
Packit 08bd4c
	zip->decompress_init = 0;
Packit 08bd4c
	free(metadata);
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_seekable_read_header(struct archive_read *a,
Packit 08bd4c
	struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip = (struct zip *)a->format->data;
Packit 08bd4c
	struct zip_entry *rsrc;
Packit 08bd4c
	int64_t offset;
Packit 08bd4c
	int r, ret = ARCHIVE_OK;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * It should be sufficient to call archive_read_next_header() for
Packit 08bd4c
	 * a reader to determine if an entry is encrypted or not. If the
Packit 08bd4c
	 * encryption of an entry is only detectable when calling
Packit 08bd4c
	 * archive_read_data(), so be it. We'll do the same check there
Packit 08bd4c
	 * as well.
Packit 08bd4c
	 */
Packit 08bd4c
	if (zip->has_encrypted_entries ==
Packit 08bd4c
			ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)
Packit 08bd4c
		zip->has_encrypted_entries = 0;
Packit 08bd4c
Packit 08bd4c
	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
Packit 08bd4c
	if (a->archive.archive_format_name == NULL)
Packit 08bd4c
		a->archive.archive_format_name = "ZIP";
Packit 08bd4c
Packit 08bd4c
	if (zip->zip_entries == NULL) {
Packit 08bd4c
		r = slurp_central_directory(a, zip);
Packit 08bd4c
		if (r != ARCHIVE_OK)
Packit 08bd4c
			return r;
Packit 08bd4c
		/* Get first entry whose local header offset is lower than
Packit 08bd4c
		 * other entries in the archive file. */
Packit 08bd4c
		zip->entry =
Packit 08bd4c
		    (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
Packit 08bd4c
	} else if (zip->entry != NULL) {
Packit 08bd4c
		/* Get next entry in local header offset order. */
Packit 08bd4c
		zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
Packit 08bd4c
		    &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (zip->entry == NULL)
Packit 08bd4c
		return ARCHIVE_EOF;
Packit 08bd4c
Packit 08bd4c
	if (zip->entry->rsrcname.s)
Packit 08bd4c
		rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
Packit 08bd4c
		    &zip->tree_rsrc, zip->entry->rsrcname.s);
Packit 08bd4c
	else
Packit 08bd4c
		rsrc = NULL;
Packit 08bd4c
Packit 08bd4c
	if (zip->cctx_valid)
Packit 08bd4c
		archive_decrypto_aes_ctr_release(&zip->cctx);
Packit 08bd4c
	if (zip->hctx_valid)
Packit 08bd4c
		archive_hmac_sha1_cleanup(&zip->hctx);
Packit 08bd4c
	zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;
Packit 08bd4c
	__archive_read_reset_passphrase(a);
Packit 08bd4c
Packit 08bd4c
	/* File entries are sorted by the header offset, we should mostly
Packit 08bd4c
	 * use __archive_read_consume to advance a read point to avoid redundant
Packit 08bd4c
	 * data reading.  */
Packit 08bd4c
	offset = archive_filter_bytes(&a->archive, 0);
Packit 08bd4c
	if (offset < zip->entry->local_header_offset)
Packit 08bd4c
		__archive_read_consume(a,
Packit 08bd4c
		    zip->entry->local_header_offset - offset);
Packit 08bd4c
	else if (offset != zip->entry->local_header_offset) {
Packit 08bd4c
		__archive_read_seek(a, zip->entry->local_header_offset,
Packit 08bd4c
		    SEEK_SET);
Packit 08bd4c
	}
Packit 08bd4c
	zip->unconsumed = 0;
Packit 08bd4c
	r = zip_read_local_file_header(a, entry, zip);
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		return r;
Packit 08bd4c
	if (rsrc) {
Packit 08bd4c
		int ret2 = zip_read_mac_metadata(a, entry, rsrc);
Packit 08bd4c
		if (ret2 < ret)
Packit 08bd4c
			ret = ret2;
Packit 08bd4c
	}
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * We're going to seek for the next header anyway, so we don't
Packit 08bd4c
 * need to bother doing anything here.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_zip_read_data_skip_seekable(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	zip = (struct zip *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	zip->unconsumed = 0;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_read_support_format_zip_seekable(struct archive *_a)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_read *a = (struct archive_read *)_a;
Packit 08bd4c
	struct zip *zip;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
Packit 08bd4c
	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");
Packit 08bd4c
Packit 08bd4c
	zip = (struct zip *)calloc(1, sizeof(*zip));
Packit 08bd4c
	if (zip == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Can't allocate zip data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_COPYFILE_H
Packit 08bd4c
	/* Set this by default on Mac OS. */
Packit 08bd4c
	zip->process_mac_extensions = 1;
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Until enough data has been read, we cannot tell about
Packit 08bd4c
	 * any encrypted entries yet.
Packit 08bd4c
	 */
Packit 08bd4c
	zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
Packit 08bd4c
	zip->crc32func = real_crc32;
Packit 08bd4c
Packit 08bd4c
	r = __archive_read_register_format(a,
Packit 08bd4c
	    zip,
Packit 08bd4c
	    "zip",
Packit 08bd4c
	    archive_read_format_zip_seekable_bid,
Packit 08bd4c
	    archive_read_format_zip_options,
Packit 08bd4c
	    archive_read_format_zip_seekable_read_header,
Packit 08bd4c
	    archive_read_format_zip_read_data,
Packit 08bd4c
	    archive_read_format_zip_read_data_skip_seekable,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    archive_read_format_zip_cleanup,
Packit 08bd4c
	    archive_read_support_format_zip_capabilities_seekable,
Packit 08bd4c
	    archive_read_format_zip_has_encrypted_entries);
Packit 08bd4c
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		free(zip);
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}