Blame libarchive/archive_read_support_format_zip.c

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