Blame libarchive/archive_write_set_format_xar.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2010-2012 Michihiro NAKAJIMA
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$");
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_LIMITS_H
Packit Service 1d0348
#include <limits.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#include <stdlib.h>
Packit Service 1d0348
#if HAVE_LIBXML_XMLWRITER_H
Packit Service 1d0348
#include <libxml/xmlwriter.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef HAVE_BZLIB_H
Packit Service 1d0348
#include <bzlib.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#if HAVE_LZMA_H
Packit Service 1d0348
#include <lzma.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_endian.h"
Packit Service 1d0348
#include "archive_entry.h"
Packit Service 1d0348
#include "archive_entry_locale.h"
Packit Service 1d0348
#include "archive_private.h"
Packit Service 1d0348
#include "archive_rb.h"
Packit Service 1d0348
#include "archive_string.h"
Packit Service 1d0348
#include "archive_write_private.h"
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Differences to xar utility.
Packit Service 1d0348
 * - Subdocument is not supported yet.
Packit Service 1d0348
 * - ACL is not supported yet.
Packit Service 1d0348
 * - When writing an XML element <link type="<file-type>">, <file-type>
Packit Service 1d0348
 *   which is a file type a symbolic link is referencing is always marked
Packit Service 1d0348
 *   as "broken". Xar utility uses stat(2) to get the file type, but, in
Packit Service 1d0348
 *   libarchive format writer, we should not use it; if it is needed, we
Packit Service 1d0348
 *   should get about it at archive_read_disk.c.
Packit Service 1d0348
 * - It is possible to appear both <flags> and <ext2> elements.
Packit Service 1d0348
 *   Xar utility generates <flags> on BSD platform and <ext2> on Linux
Packit Service 1d0348
 *   platform.
Packit Service 1d0348
 *
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
Packit Service 1d0348
	LIBXML_VERSION >= 20703) ||\
Packit Service 1d0348
	!defined(HAVE_ZLIB_H) || \
Packit Service 1d0348
	!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
Packit Service 1d0348
/*
Packit Service 1d0348
 * xar needs several external libraries.
Packit Service 1d0348
 *   o libxml2
Packit Service 1d0348
 *   o openssl or MD5/SHA1 hash function
Packit Service 1d0348
 *   o zlib
Packit Service 1d0348
 *   o bzlib2 (option)
Packit Service 1d0348
 *   o liblzma (option)
Packit Service 1d0348
 */
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_xar(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
Packit Service 1d0348
	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
	    "Xar not supported on this platform");
Packit Service 1d0348
	return (ARCHIVE_WARN);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#else	/* Support xar format */
Packit Service 1d0348
Packit Service 1d0348
/*#define DEBUG_PRINT_TOC		1 */
Packit Service 1d0348
Packit Service 1d0348
#define BAD_CAST_CONST (const xmlChar *)
Packit Service 1d0348
Packit Service 1d0348
#define HEADER_MAGIC	0x78617221
Packit Service 1d0348
#define HEADER_SIZE	28
Packit Service 1d0348
#define HEADER_VERSION	1
Packit Service 1d0348
Packit Service 1d0348
enum sumalg {
Packit Service 1d0348
	CKSUM_NONE = 0,
Packit Service 1d0348
	CKSUM_SHA1 = 1,
Packit Service 1d0348
	CKSUM_MD5 = 2
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
#define MD5_SIZE	16
Packit Service 1d0348
#define SHA1_SIZE	20
Packit Service 1d0348
#define MAX_SUM_SIZE	20
Packit Service 1d0348
#define MD5_NAME	"md5"
Packit Service 1d0348
#define SHA1_NAME	"sha1"
Packit Service 1d0348
Packit Service 1d0348
enum enctype {
Packit Service 1d0348
	NONE,
Packit Service 1d0348
	GZIP,
Packit Service 1d0348
	BZIP2,
Packit Service 1d0348
	LZMA,
Packit Service 1d0348
	XZ,
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct chksumwork {
Packit Service 1d0348
	enum sumalg		 alg;
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	archive_md5_ctx		 md5ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	archive_sha1_ctx	 sha1ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
enum la_zaction {
Packit Service 1d0348
	ARCHIVE_Z_FINISH,
Packit Service 1d0348
	ARCHIVE_Z_RUN
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Universal zstream.
Packit Service 1d0348
 */
Packit Service 1d0348
struct la_zstream {
Packit Service 1d0348
	const unsigned char	*next_in;
Packit Service 1d0348
	size_t			 avail_in;
Packit Service 1d0348
	uint64_t		 total_in;
Packit Service 1d0348
Packit Service 1d0348
	unsigned char		*next_out;
Packit Service 1d0348
	size_t			 avail_out;
Packit Service 1d0348
	uint64_t		 total_out;
Packit Service 1d0348
Packit Service 1d0348
	int			 valid;
Packit Service 1d0348
	void			*real_stream;
Packit Service 1d0348
	int			 (*code) (struct archive *a,
Packit Service 1d0348
				    struct la_zstream *lastrm,
Packit Service 1d0348
				    enum la_zaction action);
Packit Service 1d0348
	int			 (*end)(struct archive *a,
Packit Service 1d0348
				    struct la_zstream *lastrm);
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct chksumval {
Packit Service 1d0348
	enum sumalg		 alg;
Packit Service 1d0348
	size_t			 len;
Packit Service 1d0348
	unsigned char		 val[MAX_SUM_SIZE];
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct heap_data {
Packit Service 1d0348
	int			 id;
Packit Service 1d0348
	struct heap_data	*next;
Packit Service 1d0348
	uint64_t		 temp_offset;
Packit Service 1d0348
	uint64_t		 length;	/* archived size.	*/
Packit Service 1d0348
	uint64_t		 size;		/* extracted size.	*/
Packit Service 1d0348
	enum enctype		 compression;
Packit Service 1d0348
	struct chksumval	 a_sum;		/* archived checksum.	*/
Packit Service 1d0348
	struct chksumval	 e_sum;		/* extracted checksum.	*/
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct file {
Packit Service 1d0348
	struct archive_rb_node	 rbnode;
Packit Service 1d0348
Packit Service 1d0348
	int			 id;
Packit Service 1d0348
	struct archive_entry	*entry;
Packit Service 1d0348
Packit Service 1d0348
	struct archive_rb_tree	 rbtree;
Packit Service 1d0348
	struct file		*next;
Packit Service 1d0348
	struct file		*chnext;
Packit Service 1d0348
	struct file		*hlnext;
Packit Service 1d0348
	/* For hardlinked files.
Packit Service 1d0348
	 * Use only when archive_entry_nlink() > 1 */
Packit Service 1d0348
	struct file		*hardlink_target;
Packit Service 1d0348
	struct file		*parent;	/* parent directory entry */
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * To manage sub directory files.
Packit Service 1d0348
	 * We use 'chnext' (a member of struct file) to chain.
Packit Service 1d0348
	 */
Packit Service 1d0348
	struct {
Packit Service 1d0348
		struct file	*first;
Packit Service 1d0348
		struct file	**last;
Packit Service 1d0348
	}			 children;
Packit Service 1d0348
Packit Service 1d0348
	/* For making a directory tree. */
Packit Service 1d0348
        struct archive_string    parentdir;
Packit Service 1d0348
        struct archive_string    basename;
Packit Service 1d0348
        struct archive_string    symlink;
Packit Service 1d0348
Packit Service 1d0348
	int			 ea_idx;
Packit Service 1d0348
	struct {
Packit Service 1d0348
		struct heap_data *first;
Packit Service 1d0348
		struct heap_data **last;
Packit Service 1d0348
	}			 xattr;
Packit Service 1d0348
	struct heap_data	 data;
Packit Service 1d0348
        struct archive_string    script;
Packit Service 1d0348
Packit Service 1d0348
	int			 virtual:1;
Packit Service 1d0348
	int			 dir:1;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct hardlink {
Packit Service 1d0348
	struct archive_rb_node	 rbnode;
Packit Service 1d0348
	int			 nlink;
Packit Service 1d0348
	struct {
Packit Service 1d0348
		struct file	*first;
Packit Service 1d0348
		struct file	**last;
Packit Service 1d0348
	}			 file_list;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct xar {
Packit Service 1d0348
	int			 temp_fd;
Packit Service 1d0348
	uint64_t		 temp_offset;
Packit Service 1d0348
Packit Service 1d0348
	int			 file_idx;
Packit Service 1d0348
	struct file		*root;
Packit Service 1d0348
	struct file		*cur_dirent;
Packit Service 1d0348
	struct archive_string	 cur_dirstr;
Packit Service 1d0348
	struct file		*cur_file;
Packit Service 1d0348
	uint64_t		 bytes_remaining;
Packit Service 1d0348
	struct archive_string	 tstr;
Packit Service 1d0348
	struct archive_string	 vstr;
Packit Service 1d0348
Packit Service 1d0348
	enum sumalg		 opt_toc_sumalg;
Packit Service 1d0348
	enum sumalg		 opt_sumalg;
Packit Service 1d0348
	enum enctype		 opt_compression;
Packit Service 1d0348
	int			 opt_compression_level;
Packit Service 1d0348
	uint32_t		 opt_threads;
Packit Service 1d0348
Packit Service 1d0348
	struct chksumwork	 a_sumwrk;	/* archived checksum.	*/
Packit Service 1d0348
	struct chksumwork	 e_sumwrk;	/* extracted checksum.	*/
Packit Service 1d0348
	struct la_zstream	 stream;
Packit Service 1d0348
	struct archive_string_conv *sconv;
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Compressed data buffer.
Packit Service 1d0348
	 */
Packit Service 1d0348
	unsigned char		 wbuff[1024 * 64];
Packit Service 1d0348
	size_t			 wbuff_remaining;
Packit Service 1d0348
Packit Service 1d0348
	struct heap_data	 toc;
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * The list of all file entries is used to manage struct file
Packit Service 1d0348
	 * objects.
Packit Service 1d0348
	 * We use 'next' (a member of struct file) to chain.
Packit Service 1d0348
	 */
Packit Service 1d0348
	struct {
Packit Service 1d0348
		struct file	*first;
Packit Service 1d0348
		struct file	**last;
Packit Service 1d0348
	}			 file_list;
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * The list of hard-linked file entries.
Packit Service 1d0348
	 * We use 'hlnext' (a member of struct file) to chain.
Packit Service 1d0348
	 */
Packit Service 1d0348
	struct archive_rb_tree	 hardlink_rbtree;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static int	xar_options(struct archive_write *,
Packit Service 1d0348
		    const char *, const char *);
Packit Service 1d0348
static int	xar_write_header(struct archive_write *,
Packit Service 1d0348
		    struct archive_entry *);
Packit Service 1d0348
static ssize_t	xar_write_data(struct archive_write *,
Packit Service 1d0348
		    const void *, size_t);
Packit Service 1d0348
static int	xar_finish_entry(struct archive_write *);
Packit Service 1d0348
static int	xar_close(struct archive_write *);
Packit Service 1d0348
static int	xar_free(struct archive_write *);
Packit Service 1d0348
Packit Service 1d0348
static struct file *file_new(struct archive_write *a, struct archive_entry *);
Packit Service 1d0348
static void	file_free(struct file *);
Packit Service 1d0348
static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
Packit Service 1d0348
		    const char *);
Packit Service 1d0348
static int	file_add_child_tail(struct file *, struct file *);
Packit Service 1d0348
static struct file *file_find_child(struct file *, const char *);
Packit Service 1d0348
static int	file_gen_utility_names(struct archive_write *,
Packit Service 1d0348
		    struct file *);
Packit Service 1d0348
static int	get_path_component(char *, int, const char *);
Packit Service 1d0348
static int	file_tree(struct archive_write *, struct file **);
Packit Service 1d0348
static void	file_register(struct xar *, struct file *);
Packit Service 1d0348
static void	file_init_register(struct xar *);
Packit Service 1d0348
static void	file_free_register(struct xar *);
Packit Service 1d0348
static int	file_register_hardlink(struct archive_write *,
Packit Service 1d0348
		    struct file *);
Packit Service 1d0348
static void	file_connect_hardlink_files(struct xar *);
Packit Service 1d0348
static void	file_init_hardlinks(struct xar *);
Packit Service 1d0348
static void	file_free_hardlinks(struct xar *);
Packit Service 1d0348
Packit Service 1d0348
static void	checksum_init(struct chksumwork *, enum sumalg);
Packit Service 1d0348
static void	checksum_update(struct chksumwork *, const void *, size_t);
Packit Service 1d0348
static void	checksum_final(struct chksumwork *, struct chksumval *);
Packit Service 1d0348
static int	compression_init_encoder_gzip(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, int, int);
Packit Service 1d0348
static int	compression_code_gzip(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, enum la_zaction);
Packit Service 1d0348
static int	compression_end_gzip(struct archive *, struct la_zstream *);
Packit Service 1d0348
static int	compression_init_encoder_bzip2(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, int);
Packit Service 1d0348
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
Packit Service 1d0348
static int	compression_code_bzip2(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, enum la_zaction);
Packit Service 1d0348
static int	compression_end_bzip2(struct archive *, struct la_zstream *);
Packit Service 1d0348
#endif
Packit Service 1d0348
static int	compression_init_encoder_lzma(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, int);
Packit Service 1d0348
static int	compression_init_encoder_xz(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, int, int);
Packit Service 1d0348
#if defined(HAVE_LZMA_H)
Packit Service 1d0348
static int	compression_code_lzma(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, enum la_zaction);
Packit Service 1d0348
static int	compression_end_lzma(struct archive *, struct la_zstream *);
Packit Service 1d0348
#endif
Packit Service 1d0348
static int	xar_compression_init_encoder(struct archive_write *);
Packit Service 1d0348
static int	compression_code(struct archive *,
Packit Service 1d0348
		    struct la_zstream *, enum la_zaction);
Packit Service 1d0348
static int	compression_end(struct archive *,
Packit Service 1d0348
		    struct la_zstream *);
Packit Service 1d0348
static int	save_xattrs(struct archive_write *, struct file *);
Packit Service 1d0348
static int	getalgsize(enum sumalg);
Packit Service 1d0348
static const char *getalgname(enum sumalg);
Packit Service 1d0348
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_xar(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
Packit Service 1d0348
	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
Packit Service 1d0348
	    ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
Packit Service 1d0348
Packit Service 1d0348
	/* If another format was already registered, unregister it. */
Packit Service 1d0348
	if (a->format_free != NULL)
Packit Service 1d0348
		(a->format_free)(a);
Packit Service 1d0348
Packit Service 1d0348
	xar = calloc(1, sizeof(*xar));
Packit Service 1d0348
	if (xar == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate xar data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	xar->temp_fd = -1;
Packit Service 1d0348
	file_init_register(xar);
Packit Service 1d0348
	file_init_hardlinks(xar);
Packit Service 1d0348
	archive_string_init(&(xar->tstr));
Packit Service 1d0348
	archive_string_init(&(xar->vstr));
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Create the root directory.
Packit Service 1d0348
	 */
Packit Service 1d0348
	xar->root = file_create_virtual_dir(a, xar, "");
Packit Service 1d0348
	if (xar->root == NULL) {
Packit Service 1d0348
		free(xar);
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate xar data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	xar->root->parent = xar->root;
Packit Service 1d0348
	file_register(xar, xar->root);
Packit Service 1d0348
	xar->cur_dirent = xar->root;
Packit Service 1d0348
	archive_string_init(&(xar->cur_dirstr));
Packit Service 1d0348
	archive_string_ensure(&(xar->cur_dirstr), 1);
Packit Service 1d0348
	xar->cur_dirstr.s[0] = 0;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Initialize option.
Packit Service 1d0348
	 */
Packit Service 1d0348
	/* Set default checksum type. */
Packit Service 1d0348
	xar->opt_toc_sumalg = CKSUM_SHA1;
Packit Service 1d0348
	xar->opt_sumalg = CKSUM_SHA1;
Packit Service 1d0348
	/* Set default compression type, level, and number of threads. */
Packit Service 1d0348
	xar->opt_compression = GZIP;
Packit Service 1d0348
	xar->opt_compression_level = 6;
Packit Service 1d0348
	xar->opt_threads = 1;
Packit Service 1d0348
Packit Service 1d0348
	a->format_data = xar;
Packit Service 1d0348
Packit Service 1d0348
	a->format_name = "xar";
Packit Service 1d0348
	a->format_options = xar_options;
Packit Service 1d0348
	a->format_write_header = xar_write_header;
Packit Service 1d0348
	a->format_write_data = xar_write_data;
Packit Service 1d0348
	a->format_finish_entry = xar_finish_entry;
Packit Service 1d0348
	a->format_close = xar_close;
Packit Service 1d0348
	a->format_free = xar_free;
Packit Service 1d0348
	a->archive.archive_format = ARCHIVE_FORMAT_XAR;
Packit Service 1d0348
	a->archive.archive_format_name = "xar";
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xar_options(struct archive_write *a, const char *key, const char *value)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	if (strcmp(key, "checksum") == 0) {
Packit Service 1d0348
		if (value == NULL)
Packit Service 1d0348
			xar->opt_sumalg = CKSUM_NONE;
Packit Service 1d0348
		else if (strcmp(value, "sha1") == 0)
Packit Service 1d0348
			xar->opt_sumalg = CKSUM_SHA1;
Packit Service 1d0348
		else if (strcmp(value, "md5") == 0)
Packit Service 1d0348
			xar->opt_sumalg = CKSUM_MD5;
Packit Service 1d0348
		else {
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Unknown checksum name: `%s'",
Packit Service 1d0348
			    value);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (strcmp(key, "compression") == 0) {
Packit Service 1d0348
		const char *name = NULL;
Packit Service 1d0348
Packit Service 1d0348
		if (value == NULL)
Packit Service 1d0348
			xar->opt_compression = NONE;
Packit Service 1d0348
		else if (strcmp(value, "gzip") == 0)
Packit Service 1d0348
			xar->opt_compression = GZIP;
Packit Service 1d0348
		else if (strcmp(value, "bzip2") == 0)
Packit Service 1d0348
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
Packit Service 1d0348
			xar->opt_compression = BZIP2;
Packit Service 1d0348
#else
Packit Service 1d0348
			name = "bzip2";
Packit Service 1d0348
#endif
Packit Service 1d0348
		else if (strcmp(value, "lzma") == 0)
Packit Service 1d0348
#if HAVE_LZMA_H
Packit Service 1d0348
			xar->opt_compression = LZMA;
Packit Service 1d0348
#else
Packit Service 1d0348
			name = "lzma";
Packit Service 1d0348
#endif
Packit Service 1d0348
		else if (strcmp(value, "xz") == 0)
Packit Service 1d0348
#if HAVE_LZMA_H
Packit Service 1d0348
			xar->opt_compression = XZ;
Packit Service 1d0348
#else
Packit Service 1d0348
			name = "xz";
Packit Service 1d0348
#endif
Packit Service 1d0348
		else {
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Unknown compression name: `%s'",
Packit Service 1d0348
			    value);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (name != NULL) {
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "`%s' compression not supported "
Packit Service 1d0348
			    "on this platform",
Packit Service 1d0348
			    name);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (strcmp(key, "compression-level") == 0) {
Packit Service 1d0348
		if (value == NULL ||
Packit Service 1d0348
		    !(value[0] >= '0' && value[0] <= '9') ||
Packit Service 1d0348
		    value[1] != '\0') {
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Illegal value `%s'",
Packit Service 1d0348
			    value);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		xar->opt_compression_level = value[0] - '0';
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (strcmp(key, "toc-checksum") == 0) {
Packit Service 1d0348
		if (value == NULL)
Packit Service 1d0348
			xar->opt_toc_sumalg = CKSUM_NONE;
Packit Service 1d0348
		else if (strcmp(value, "sha1") == 0)
Packit Service 1d0348
			xar->opt_toc_sumalg = CKSUM_SHA1;
Packit Service 1d0348
		else if (strcmp(value, "md5") == 0)
Packit Service 1d0348
			xar->opt_toc_sumalg = CKSUM_MD5;
Packit Service 1d0348
		else {
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Unknown checksum name: `%s'",
Packit Service 1d0348
			    value);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (strcmp(key, "threads") == 0) {
Packit Service 1d0348
		if (value == NULL)
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		xar->opt_threads = (int)strtoul(value, NULL, 10);
Packit Service 1d0348
		if (xar->opt_threads == 0 && errno != 0) {
Packit Service 1d0348
			xar->opt_threads = 1;
Packit Service 1d0348
			archive_set_error(&(a->archive),
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "Illegal value `%s'",
Packit Service 1d0348
			    value);
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (xar->opt_threads == 0) {
Packit Service 1d0348
#ifdef HAVE_LZMA_STREAM_ENCODER_MT
Packit Service 1d0348
			xar->opt_threads = lzma_cputhreads();
Packit Service 1d0348
#else
Packit Service 1d0348
			xar->opt_threads = 1;
Packit Service 1d0348
#endif
Packit Service 1d0348
		}
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
static int
Packit Service 1d0348
xar_write_header(struct archive_write *a, struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	struct file *file;
Packit Service 1d0348
	struct archive_entry *file_entry;
Packit Service 1d0348
	int r, r2;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	xar->cur_file = NULL;
Packit Service 1d0348
	xar->bytes_remaining = 0;
Packit Service 1d0348
Packit Service 1d0348
	if (xar->sconv == NULL) {
Packit Service 1d0348
		xar->sconv = archive_string_conversion_to_charset(
Packit Service 1d0348
		    &a->archive, "UTF-8", 1);
Packit Service 1d0348
		if (xar->sconv == NULL)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	file = file_new(a, entry);
Packit Service 1d0348
	if (file == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	r2 = file_gen_utility_names(a, file);
Packit Service 1d0348
	if (r2 < ARCHIVE_WARN)
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Ignore a path which looks like the top of directory name
Packit Service 1d0348
	 * since we have already made the root directory of an Xar archive.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_strlen(&(file->parentdir)) == 0 &&
Packit Service 1d0348
	    archive_strlen(&(file->basename)) == 0) {
Packit Service 1d0348
		file_free(file);
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Add entry into tree */
Packit Service 1d0348
	file_entry = file->entry;
Packit Service 1d0348
	r = file_tree(a, &file;;
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	/* There is the same file in tree and
Packit Service 1d0348
	 * the current file is older than the file in tree.
Packit Service 1d0348
	 * So we don't need the current file data anymore. */
Packit Service 1d0348
	if (file->entry != file_entry)
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
	if (file->id == 0)
Packit Service 1d0348
		file_register(xar, file);
Packit Service 1d0348
Packit Service 1d0348
	/* A virtual file, which is a directory, does not have
Packit Service 1d0348
	 * any contents and we won't store it into a archive
Packit Service 1d0348
	 * file other than its name. */
Packit Service 1d0348
	if (file->virtual)
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Prepare to save the contents of the file.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (xar->temp_fd == -1) {
Packit Service 1d0348
		int algsize;
Packit Service 1d0348
		xar->temp_offset = 0;
Packit Service 1d0348
		xar->temp_fd = __archive_mktemp(NULL);
Packit Service 1d0348
		if (xar->temp_fd < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive, errno,
Packit Service 1d0348
			    "Couldn't create temporary file");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		algsize = getalgsize(xar->opt_toc_sumalg);
Packit Service 1d0348
		if (algsize > 0) {
Packit Service 1d0348
			if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
Packit Service 1d0348
				archive_set_error(&(a->archive), errno,
Packit Service 1d0348
				    "lseek failed");
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			xar->temp_offset = algsize;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_hardlink(file->entry) == NULL) {
Packit Service 1d0348
		r = save_xattrs(a, file);
Packit Service 1d0348
		if (r != ARCHIVE_OK)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Non regular files contents are unneeded to be saved to
Packit Service 1d0348
	 * a temporary file. */
Packit Service 1d0348
	if (archive_entry_filetype(file->entry) != AE_IFREG)
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Set the current file to cur_file to read its contents.
Packit Service 1d0348
	 */
Packit Service 1d0348
	xar->cur_file = file;
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_nlink(file->entry) > 1) {
Packit Service 1d0348
		r = file_register_hardlink(a, file);
Packit Service 1d0348
		if (r != ARCHIVE_OK)
Packit Service 1d0348
			return (r);
Packit Service 1d0348
		if (archive_entry_hardlink(file->entry) != NULL) {
Packit Service 1d0348
			archive_entry_unset_size(file->entry);
Packit Service 1d0348
			return (r2);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Save a offset of current file in temporary file. */
Packit Service 1d0348
	file->data.temp_offset = xar->temp_offset;
Packit Service 1d0348
	file->data.size = archive_entry_size(file->entry);
Packit Service 1d0348
	file->data.compression = xar->opt_compression;
Packit Service 1d0348
	xar->bytes_remaining = archive_entry_size(file->entry);
Packit Service 1d0348
	checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
Packit Service 1d0348
	checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
Packit Service 1d0348
	r = xar_compression_init_encoder(a);
Packit Service 1d0348
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	else
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
write_to_temp(struct archive_write *a, const void *buff, size_t s)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	const unsigned char *p;
Packit Service 1d0348
	ssize_t ws;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	p = (const unsigned char *)buff;
Packit Service 1d0348
	while (s) {
Packit Service 1d0348
		ws = write(xar->temp_fd, p, s);
Packit Service 1d0348
		if (ws < 0) {
Packit Service 1d0348
			archive_set_error(&(a->archive), errno,
Packit Service 1d0348
			    "fwrite function failed");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		s -= ws;
Packit Service 1d0348
		p += ws;
Packit Service 1d0348
		xar->temp_offset += ws;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static ssize_t
Packit Service 1d0348
xar_write_data(struct archive_write *a, const void *buff, size_t s)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	enum la_zaction run;
Packit Service 1d0348
	size_t size, rsize;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	if (s > xar->bytes_remaining)
Packit Service 1d0348
		s = (size_t)xar->bytes_remaining;
Packit Service 1d0348
	if (s == 0 || xar->cur_file == NULL)
Packit Service 1d0348
		return (0);
Packit Service 1d0348
	if (xar->cur_file->data.compression == NONE) {
Packit Service 1d0348
		checksum_update(&(xar->e_sumwrk), buff, s);
Packit Service 1d0348
		checksum_update(&(xar->a_sumwrk), buff, s);
Packit Service 1d0348
		size = rsize = s;
Packit Service 1d0348
	} else {
Packit Service 1d0348
		xar->stream.next_in = (const unsigned char *)buff;
Packit Service 1d0348
		xar->stream.avail_in = s;
Packit Service 1d0348
		if (xar->bytes_remaining > s)
Packit Service 1d0348
			run = ARCHIVE_Z_RUN;
Packit Service 1d0348
		else
Packit Service 1d0348
			run = ARCHIVE_Z_FINISH;
Packit Service 1d0348
		/* Compress file data. */
Packit Service 1d0348
		r = compression_code(&(a->archive), &(xar->stream), run);
Packit Service 1d0348
		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		rsize = s - xar->stream.avail_in;
Packit Service 1d0348
		checksum_update(&(xar->e_sumwrk), buff, rsize);
Packit Service 1d0348
		size = sizeof(xar->wbuff) - xar->stream.avail_out;
Packit Service 1d0348
		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
Packit Service 1d0348
	}
Packit Service 1d0348
#if !defined(_WIN32) || defined(__CYGWIN__)
Packit Service 1d0348
	if (xar->bytes_remaining ==
Packit Service 1d0348
	    (uint64_t)archive_entry_size(xar->cur_file->entry)) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Get the path of a shell script if so.
Packit Service 1d0348
		 */
Packit Service 1d0348
		const unsigned char *b = (const unsigned char *)buff;
Packit Service 1d0348
Packit Service 1d0348
		archive_string_empty(&(xar->cur_file->script));
Packit Service 1d0348
		if (rsize > 2 && b[0] == '#' && b[1] == '!') {
Packit Service 1d0348
			size_t i, end, off;
Packit Service 1d0348
Packit Service 1d0348
			off = 2;
Packit Service 1d0348
			if (b[off] == ' ')
Packit Service 1d0348
				off++;
Packit Service 1d0348
#ifdef PATH_MAX
Packit Service 1d0348
			if ((rsize - off) > PATH_MAX)
Packit Service 1d0348
				end = off + PATH_MAX;
Packit Service 1d0348
			else
Packit Service 1d0348
#endif
Packit Service 1d0348
				end = rsize;
Packit Service 1d0348
			/* Find the end of a script path. */
Packit Service 1d0348
			for (i = off; i < end && b[i] != '\0' &&
Packit Service 1d0348
			    b[i] != '\n' && b[i] != '\r' &&
Packit Service 1d0348
			    b[i] != ' ' && b[i] != '\t'; i++)
Packit Service 1d0348
				;
Packit Service 1d0348
			archive_strncpy(&(xar->cur_file->script), b + off,
Packit Service 1d0348
			    i - off);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
	if (xar->cur_file->data.compression == NONE) {
Packit Service 1d0348
		if (write_to_temp(a, buff, size) != ARCHIVE_OK)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	} else {
Packit Service 1d0348
		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	xar->bytes_remaining -= rsize;
Packit Service 1d0348
	xar->cur_file->data.length += size;
Packit Service 1d0348
Packit Service 1d0348
	return (rsize);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xar_finish_entry(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	struct file *file;
Packit Service 1d0348
	size_t s;
Packit Service 1d0348
	ssize_t w;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	if (xar->cur_file == NULL)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	while (xar->bytes_remaining > 0) {
Packit Service 1d0348
		s = (size_t)xar->bytes_remaining;
Packit Service 1d0348
		if (s > a->null_length)
Packit Service 1d0348
			s = a->null_length;
Packit Service 1d0348
		w = xar_write_data(a, a->nulls, s);
Packit Service 1d0348
		if (w > 0)
Packit Service 1d0348
			xar->bytes_remaining -= w;
Packit Service 1d0348
		else
Packit Service 1d0348
			return (w);
Packit Service 1d0348
	}
Packit Service 1d0348
	file = xar->cur_file;
Packit Service 1d0348
	checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
Packit Service 1d0348
	checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
Packit Service 1d0348
	xar->cur_file = NULL;
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, const char *value,
Packit Service 1d0348
	const char *attrkey, const char *attrvalue)
Packit Service 1d0348
{
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (attrkey != NULL && attrvalue != NULL) {
Packit Service 1d0348
		r = xmlTextWriterWriteAttribute(writer,
Packit Service 1d0348
		    BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteAttribute() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (value != NULL) {
Packit Service 1d0348
		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteString() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, const char *value)
Packit Service 1d0348
{
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	if (value == NULL)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (value != NULL) {
Packit Service 1d0348
		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteString() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, const char *fmt, ...)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	va_list ap;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	va_start(ap, fmt);
Packit Service 1d0348
	archive_string_empty(&xar->vstr);
Packit Service 1d0348
	archive_string_vsprintf(&xar->vstr, fmt, ap);
Packit Service 1d0348
	va_end(ap);
Packit Service 1d0348
	return (xmlwrite_string(a, writer, key, xar->vstr.s));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, time_t t, int z)
Packit Service 1d0348
{
Packit Service 1d0348
	char timestr[100];
Packit Service 1d0348
	struct tm tm;
Packit Service 1d0348
Packit Service 1d0348
#if defined(HAVE_GMTIME_R)
Packit Service 1d0348
	gmtime_r(&t, &tm;;
Packit Service 1d0348
#elif defined(HAVE__GMTIME64_S)
Packit Service 1d0348
	_gmtime64_s(&tm, &t);
Packit Service 1d0348
#else
Packit Service 1d0348
	memcpy(&tm, gmtime(&t), sizeof(tm));
Packit Service 1d0348
#endif
Packit Service 1d0348
	memset(&timestr, 0, sizeof(timestr));
Packit Service 1d0348
	/* Do not use %F and %T for portability. */
Packit Service 1d0348
	strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm;;
Packit Service 1d0348
	if (z)
Packit Service 1d0348
		strcat(timestr, "Z");
Packit Service 1d0348
	return (xmlwrite_string(a, writer, key, timestr));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, mode_t mode)
Packit Service 1d0348
{
Packit Service 1d0348
	char ms[5];
Packit Service 1d0348
Packit Service 1d0348
	ms[0] = '0';
Packit Service 1d0348
	ms[1] = '0' + ((mode >> 6) & 07);
Packit Service 1d0348
	ms[2] = '0' + ((mode >> 3) & 07);
Packit Service 1d0348
	ms[3] = '0' + (mode & 07);
Packit Service 1d0348
	ms[4] = '\0';
Packit Service 1d0348
Packit Service 1d0348
	return (xmlwrite_string(a, writer, key, ms));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	const char *key, struct chksumval *sum)
Packit Service 1d0348
{
Packit Service 1d0348
	const char *algname;
Packit Service 1d0348
	int algsize;
Packit Service 1d0348
	char buff[MAX_SUM_SIZE*2 + 1];
Packit Service 1d0348
	char *p;
Packit Service 1d0348
	unsigned char *s;
Packit Service 1d0348
	int i, r;
Packit Service 1d0348
Packit Service 1d0348
	if (sum->len > 0) {
Packit Service 1d0348
		algname = getalgname(sum->alg);
Packit Service 1d0348
		algsize = getalgsize(sum->alg);
Packit Service 1d0348
		if (algname != NULL) {
Packit Service 1d0348
			const char *hex = "0123456789abcdef";
Packit Service 1d0348
			p = buff;
Packit Service 1d0348
			s = sum->val;
Packit Service 1d0348
			for (i = 0; i < algsize; i++) {
Packit Service 1d0348
				*p++ = hex[(*s >> 4)];
Packit Service 1d0348
				*p++ = hex[(*s & 0x0f)];
Packit Service 1d0348
				s++;
Packit Service 1d0348
			}
Packit Service 1d0348
			*p = '\0';
Packit Service 1d0348
			r = xmlwrite_string_attr(a, writer,
Packit Service 1d0348
			    key, buff,
Packit Service 1d0348
			    "style", algname);
Packit Service 1d0348
			if (r < 0)
Packit Service 1d0348
				return (ARCHIVE_FATAL);
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
xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
	struct heap_data *heap)
Packit Service 1d0348
{
Packit Service 1d0348
	const char *encname;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	switch (heap->compression) {
Packit Service 1d0348
	case GZIP:
Packit Service 1d0348
		encname = "application/x-gzip"; break;
Packit Service 1d0348
	case BZIP2:
Packit Service 1d0348
		encname = "application/x-bzip2"; break;
Packit Service 1d0348
	case LZMA:
Packit Service 1d0348
		encname = "application/x-lzma"; break;
Packit Service 1d0348
	case XZ:
Packit Service 1d0348
		encname = "application/x-xz"; break;
Packit Service 1d0348
	default:
Packit Service 1d0348
		encname = "application/octet-stream"; break;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlwrite_string_attr(a, writer, "encoding", NULL,
Packit Service 1d0348
	    "style", encname);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * xar utility records fflags as following xml elements:
Packit Service 1d0348
 *   <flags>
Packit Service 1d0348
 *     <UserNoDump/>
Packit Service 1d0348
 *     .....
Packit Service 1d0348
 *   </flags>
Packit Service 1d0348
 * or
Packit Service 1d0348
 *   <ext2>
Packit Service 1d0348
 *     <NoDump/>
Packit Service 1d0348
 *     .....
Packit Service 1d0348
 *   </ext2>
Packit Service 1d0348
 * If xar is running on BSD platform, records <flags>..</flags>;
Packit Service 1d0348
 * if xar is running on linux platform, records <ext2>..</ext2>;
Packit Service 1d0348
 * otherwise does not record.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Our implements records both <flags> and <ext2> if it's necessary.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
    const char *element, const char *fflags_text)
Packit Service 1d0348
{
Packit Service 1d0348
	static const struct flagentry {
Packit Service 1d0348
		const char	*name;
Packit Service 1d0348
		const char	*xarname;
Packit Service 1d0348
	}
Packit Service 1d0348
	flagbsd[] = {
Packit Service 1d0348
		{ "sappnd",	"SystemAppend"},
Packit Service 1d0348
		{ "sappend",	"SystemAppend"},
Packit Service 1d0348
		{ "arch",	"SystemArchived"},
Packit Service 1d0348
		{ "archived",	"SystemArchived"},
Packit Service 1d0348
		{ "schg",	"SystemImmutable"},
Packit Service 1d0348
		{ "schange",	"SystemImmutable"},
Packit Service 1d0348
		{ "simmutable",	"SystemImmutable"},
Packit Service 1d0348
		{ "nosunlnk",	"SystemNoUnlink"},
Packit Service 1d0348
		{ "nosunlink",	"SystemNoUnlink"},
Packit Service 1d0348
		{ "snapshot",	"SystemSnapshot"},
Packit Service 1d0348
		{ "uappnd",	"UserAppend"},
Packit Service 1d0348
		{ "uappend",	"UserAppend"},
Packit Service 1d0348
		{ "uchg",	"UserImmutable"},
Packit Service 1d0348
		{ "uchange",	"UserImmutable"},
Packit Service 1d0348
		{ "uimmutable",	"UserImmutable"},
Packit Service 1d0348
		{ "nodump",	"UserNoDump"},
Packit Service 1d0348
		{ "noopaque",	"UserOpaque"},
Packit Service 1d0348
		{ "nouunlnk",	"UserNoUnlink"},
Packit Service 1d0348
		{ "nouunlink",	"UserNoUnlink"},
Packit Service 1d0348
		{ NULL, NULL}
Packit Service 1d0348
	},
Packit Service 1d0348
	flagext2[] = {
Packit Service 1d0348
		{ "sappnd",	"AppendOnly"},
Packit Service 1d0348
		{ "sappend",	"AppendOnly"},
Packit Service 1d0348
		{ "schg",	"Immutable"},
Packit Service 1d0348
		{ "schange",	"Immutable"},
Packit Service 1d0348
		{ "simmutable",	"Immutable"},
Packit Service 1d0348
		{ "nodump",	"NoDump"},
Packit Service 1d0348
		{ "nouunlnk",	"Undelete"},
Packit Service 1d0348
		{ "nouunlink",	"Undelete"},
Packit Service 1d0348
		{ "btree",	"BTree"},
Packit Service 1d0348
		{ "comperr",	"CompError"},
Packit Service 1d0348
		{ "compress",	"Compress"},
Packit Service 1d0348
		{ "noatime",	"NoAtime"},
Packit Service 1d0348
		{ "compdirty",	"CompDirty"},
Packit Service 1d0348
		{ "comprblk",	"CompBlock"},
Packit Service 1d0348
		{ "dirsync",	"DirSync"},
Packit Service 1d0348
		{ "hashidx",	"HashIndexed"},
Packit Service 1d0348
		{ "imagic",	"iMagic"},
Packit Service 1d0348
		{ "journal",	"Journaled"},
Packit Service 1d0348
		{ "securedeletion",	"SecureDeletion"},
Packit Service 1d0348
		{ "sync",	"Synchronous"},
Packit Service 1d0348
		{ "notail",	"NoTail"},
Packit Service 1d0348
		{ "topdir",	"TopDir"},
Packit Service 1d0348
		{ "reserved",	"Reserved"},
Packit Service 1d0348
		{ NULL, NULL}
Packit Service 1d0348
	};
Packit Service 1d0348
	const struct flagentry *fe, *flagentry;
Packit Service 1d0348
#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
Packit Service 1d0348
	const struct flagentry *avail[FLAGENTRY_MAXSIZE];
Packit Service 1d0348
	const char *p;
Packit Service 1d0348
	int i, n, r;
Packit Service 1d0348
Packit Service 1d0348
	if (strcmp(element, "ext2") == 0)
Packit Service 1d0348
		flagentry = flagext2;
Packit Service 1d0348
	else
Packit Service 1d0348
		flagentry = flagbsd;
Packit Service 1d0348
	n = 0;
Packit Service 1d0348
	p = fflags_text;
Packit Service 1d0348
	do {
Packit Service 1d0348
		const char *cp;
Packit Service 1d0348
Packit Service 1d0348
		cp = strchr(p, ',');
Packit Service 1d0348
		if (cp == NULL)
Packit Service 1d0348
			cp = p + strlen(p);
Packit Service 1d0348
Packit Service 1d0348
		for (fe = flagentry; fe->name != NULL; fe++) {
Packit Service 1d0348
			if (fe->name[cp - p] != '\0'
Packit Service 1d0348
			    || p[0] != fe->name[0])
Packit Service 1d0348
				continue;
Packit Service 1d0348
			if (strncmp(p, fe->name, cp - p) == 0) {
Packit Service 1d0348
				avail[n++] = fe;
Packit Service 1d0348
				break;
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
		if (*cp == ',')
Packit Service 1d0348
			p = cp + 1;
Packit Service 1d0348
		else
Packit Service 1d0348
			p = NULL;
Packit Service 1d0348
	} while (p != NULL);
Packit Service 1d0348
Packit Service 1d0348
	if (n > 0) {
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		for (i = 0; i < n; i++) {
Packit Service 1d0348
			r = xmlwrite_string(a, writer,
Packit Service 1d0348
			    avail[i]->xarname, NULL);
Packit Service 1d0348
			if (r != ARCHIVE_OK)
Packit Service 1d0348
				return (r);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
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
make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
Packit Service 1d0348
    struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	const char *filetype, *filelink, *fflags;
Packit Service 1d0348
	struct archive_string linkto;
Packit Service 1d0348
	struct heap_data *heap;
Packit Service 1d0348
	unsigned char *tmp;
Packit Service 1d0348
	const char *p;
Packit Service 1d0348
	size_t len;
Packit Service 1d0348
	int r, r2, l, ll;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	r2 = ARCHIVE_OK;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a file name entry, "<name>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	l = ll = archive_strlen(&(file->basename));
Packit Service 1d0348
	tmp = malloc(l);
Packit Service 1d0348
	if (tmp == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
Packit Service 1d0348
	free(tmp);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlTextWriterWriteAttribute(writer,
Packit Service 1d0348
		    BAD_CAST("enctype"), BAD_CAST("base64"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteAttribute() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlTextWriterWriteBase64(writer, file->basename.s,
Packit Service 1d0348
		    0, archive_strlen(&(file->basename)));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteBase64() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	} else {
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "name", file->basename.s);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a file type entry, "<type>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	filelink = NULL;
Packit Service 1d0348
	archive_string_init(&linkto);
Packit Service 1d0348
	switch (archive_entry_filetype(file->entry)) {
Packit Service 1d0348
	case AE_IFDIR:
Packit Service 1d0348
		filetype = "directory"; break;
Packit Service 1d0348
	case AE_IFLNK:
Packit Service 1d0348
		filetype = "symlink"; break;
Packit Service 1d0348
	case AE_IFCHR:
Packit Service 1d0348
		filetype = "character special"; break;
Packit Service 1d0348
	case AE_IFBLK:
Packit Service 1d0348
		filetype = "block special"; break;
Packit Service 1d0348
	case AE_IFSOCK:
Packit Service 1d0348
		filetype = "socket"; break;
Packit Service 1d0348
	case AE_IFIFO:
Packit Service 1d0348
		filetype = "fifo"; break;
Packit Service 1d0348
	case AE_IFREG:
Packit Service 1d0348
	default:
Packit Service 1d0348
		if (file->hardlink_target != NULL) {
Packit Service 1d0348
			filetype = "hardlink";
Packit Service 1d0348
			filelink = "link";
Packit Service 1d0348
			if (file->hardlink_target == file)
Packit Service 1d0348
				archive_strcpy(&linkto, "original");
Packit Service 1d0348
			else
Packit Service 1d0348
				archive_string_sprintf(&linkto, "%d",
Packit Service 1d0348
				    file->hardlink_target->id);
Packit Service 1d0348
		} else
Packit Service 1d0348
			filetype = "file";
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlwrite_string_attr(a, writer, "type", filetype,
Packit Service 1d0348
	    filelink, linkto.s);
Packit Service 1d0348
	archive_string_free(&linkto);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * On a virtual directory, we record "name" and "type" only.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (file->virtual)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	switch (archive_entry_filetype(file->entry)) {
Packit Service 1d0348
	case AE_IFLNK:
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * xar utility has checked a file type, which
Packit Service 1d0348
		 * a symbolic-link file has referenced.
Packit Service 1d0348
		 * For example:
Packit Service 1d0348
		 *   <link type="directory">../ref/</link>
Packit Service 1d0348
		 *   The symlink target file is "../ref/" and its
Packit Service 1d0348
		 *   file type is a directory.
Packit Service 1d0348
		 *
Packit Service 1d0348
		 *   <link type="file">../f</link>
Packit Service 1d0348
		 *   The symlink target file is "../f" and its
Packit Service 1d0348
		 *   file type is a regular file.
Packit Service 1d0348
		 *
Packit Service 1d0348
		 * But our implementation cannot do it, and then we
Packit Service 1d0348
		 * always record that a attribute "type" is "broken",
Packit Service 1d0348
		 * for example:
Packit Service 1d0348
		 *   <link type="broken">foo/bar</link>
Packit Service 1d0348
		 *   It means "foo/bar" is not reachable.
Packit Service 1d0348
		 */
Packit Service 1d0348
		r = xmlwrite_string_attr(a, writer, "link",
Packit Service 1d0348
		    file->symlink.s,
Packit Service 1d0348
		    "type", "broken");
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFCHR:
Packit Service 1d0348
	case AE_IFBLK:
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlwrite_fstring(a, writer, "major",
Packit Service 1d0348
		    "%d", archive_entry_rdevmajor(file->entry));
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		r = xmlwrite_fstring(a, writer, "minor",
Packit Service 1d0348
		    "%d", archive_entry_rdevminor(file->entry));
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	default:
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a inode entry, "<inode>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "inode",
Packit Service 1d0348
	    "%jd", archive_entry_ino64(file->entry));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	if (archive_entry_dev(file->entry) != 0) {
Packit Service 1d0348
		r = xmlwrite_fstring(a, writer, "deviceno",
Packit Service 1d0348
		    "%d", archive_entry_dev(file->entry));
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a file mode entry, "<mode>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlwrite_mode(a, writer, "mode",
Packit Service 1d0348
	    archive_entry_mode(file->entry));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a user entry, "<uid>" and "<user>.
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "uid",
Packit Service 1d0348
	    "%d", archive_entry_uid(file->entry));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Uname");
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
		    "Can't translate uname '%s' to UTF-8",
Packit Service 1d0348
		    archive_entry_uname(file->entry));
Packit Service 1d0348
		r2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (len > 0) {
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "user", p);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a group entry, "<gid>" and "<group>.
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlwrite_fstring(a, writer, "gid",
Packit Service 1d0348
	    "%d", archive_entry_gid(file->entry));
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
Packit Service 1d0348
	if (r != 0) {
Packit Service 1d0348
		if (errno == ENOMEM) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for Gname");
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
		    "Can't translate gname '%s' to UTF-8",
Packit Service 1d0348
		    archive_entry_gname(file->entry));
Packit Service 1d0348
		r2 = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (len > 0) {
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "group", p);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a ctime entry, "<ctime>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_entry_ctime_is_set(file->entry)) {
Packit Service 1d0348
		r = xmlwrite_time(a, writer, "ctime",
Packit Service 1d0348
		    archive_entry_ctime(file->entry), 1);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a mtime entry, "<mtime>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_entry_mtime_is_set(file->entry)) {
Packit Service 1d0348
		r = xmlwrite_time(a, writer, "mtime",
Packit Service 1d0348
		    archive_entry_mtime(file->entry), 1);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a atime entry, "<atime>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_entry_atime_is_set(file->entry)) {
Packit Service 1d0348
		r = xmlwrite_time(a, writer, "atime",
Packit Service 1d0348
		    archive_entry_atime(file->entry), 1);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make fflags entries, "<flags>" and "<ext2>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	fflags = archive_entry_fflags_text(file->entry);
Packit Service 1d0348
	if (fflags != NULL) {
Packit Service 1d0348
		r = make_fflags_entry(a, writer, "flags", fflags);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (r);
Packit Service 1d0348
		r = make_fflags_entry(a, writer, "ext2", fflags);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (r);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make extended attribute entries, "<ea>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	archive_entry_xattr_reset(file->entry);
Packit Service 1d0348
	for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
Packit Service 1d0348
		const char *name;
Packit Service 1d0348
		const void *value;
Packit Service 1d0348
		size_t size;
Packit Service 1d0348
Packit Service 1d0348
		archive_entry_xattr_next(file->entry,
Packit Service 1d0348
		    &name, &value, &size);
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlTextWriterWriteFormatAttribute(writer,
Packit Service 1d0348
		    BAD_CAST("id"), "%d", heap->id);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteAttribute() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlwrite_heap(a, writer, heap);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "name", name);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a file data entry, "<data>".
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (file->data.length > 0) {
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		r = xmlwrite_heap(a, writer, &(file->data));
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (archive_strlen(&file->script) > 0) {
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		r = xmlwrite_string(a, writer,
Packit Service 1d0348
		    "interpreter", file->script.s);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "type", "script");
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return (r2);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Make the TOC
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
make_toc(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	struct file *np;
Packit Service 1d0348
	xmlBufferPtr bp;
Packit Service 1d0348
	xmlTextWriterPtr writer;
Packit Service 1d0348
	int algsize;
Packit Service 1d0348
	int r, ret;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	ret = ARCHIVE_FATAL;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Initialize xml writer.
Packit Service 1d0348
	 */
Packit Service 1d0348
	writer = NULL;
Packit Service 1d0348
	bp = xmlBufferCreate();
Packit Service 1d0348
	if (bp == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "xmlBufferCreate() "
Packit Service 1d0348
		    "couldn't create xml buffer");
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
	writer = xmlNewTextWriterMemory(bp, 0);
Packit Service 1d0348
	if (writer == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlNewTextWriterMemory() "
Packit Service 1d0348
		    "couldn't create xml writer");
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterStartDocument() failed: %d", r);
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlTextWriterSetIndent(writer, 4);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterSetIndent() failed: %d", r);
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Start recording TOC
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
	r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterStartDocument() failed: %d", r);
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Record the creation time of the archive file.
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
Packit Service 1d0348
	if (r < 0)
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Record the checksum value of TOC
Packit Service 1d0348
	 */
Packit Service 1d0348
	algsize = getalgsize(xar->opt_toc_sumalg);
Packit Service 1d0348
	if (algsize) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Record TOC checksum
Packit Service 1d0348
		 */
Packit Service 1d0348
		r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterStartElement() failed: %d", r);
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
		}
Packit Service 1d0348
		r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
Packit Service 1d0348
		    BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterWriteAttribute() failed: %d", r);
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Record the offset of the value of checksum of TOC
Packit Service 1d0348
		 */
Packit Service 1d0348
		r = xmlwrite_string(a, writer, "offset", "0");
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Record the size of the value of checksum of TOC
Packit Service 1d0348
		 */
Packit Service 1d0348
		r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
Packit Service 1d0348
		if (r < 0)
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
Packit Service 1d0348
		r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
		if (r < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "xmlTextWriterEndElement() failed: %d", r);
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	np = xar->root;
Packit Service 1d0348
	do {
Packit Service 1d0348
		if (np != np->parent) {
Packit Service 1d0348
			r = make_file_entry(a, writer, np);
Packit Service 1d0348
			if (r != ARCHIVE_OK)
Packit Service 1d0348
				goto exit_toc;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if (np->dir && np->children.first != NULL) {
Packit Service 1d0348
			/* Enter to sub directories. */
Packit Service 1d0348
			np = np->children.first;
Packit Service 1d0348
			r = xmlTextWriterStartElement(writer,
Packit Service 1d0348
			    BAD_CAST("file"));
Packit Service 1d0348
			if (r < 0) {
Packit Service 1d0348
				archive_set_error(&a->archive,
Packit Service 1d0348
				    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
				    "xmlTextWriterStartElement() "
Packit Service 1d0348
				    "failed: %d", r);
Packit Service 1d0348
				goto exit_toc;
Packit Service 1d0348
			}
Packit Service 1d0348
			r = xmlTextWriterWriteFormatAttribute(
Packit Service 1d0348
			    writer, BAD_CAST("id"), "%d", np->id);
Packit Service 1d0348
			if (r < 0) {
Packit Service 1d0348
				archive_set_error(&a->archive,
Packit Service 1d0348
				    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
				    "xmlTextWriterWriteAttribute() "
Packit Service 1d0348
				    "failed: %d", r);
Packit Service 1d0348
				goto exit_toc;
Packit Service 1d0348
			}
Packit Service 1d0348
			continue;
Packit Service 1d0348
		}
Packit Service 1d0348
		while (np != np->parent) {
Packit Service 1d0348
			r = xmlTextWriterEndElement(writer);
Packit Service 1d0348
			if (r < 0) {
Packit Service 1d0348
				archive_set_error(&a->archive,
Packit Service 1d0348
				    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
				    "xmlTextWriterEndElement() "
Packit Service 1d0348
				    "failed: %d", r);
Packit Service 1d0348
				goto exit_toc;
Packit Service 1d0348
			}
Packit Service 1d0348
			if (np->chnext == NULL) {
Packit Service 1d0348
				/* Return to the parent directory. */
Packit Service 1d0348
				np = np->parent;
Packit Service 1d0348
			} else {
Packit Service 1d0348
				np = np->chnext;
Packit Service 1d0348
				r = xmlTextWriterStartElement(writer,
Packit Service 1d0348
				    BAD_CAST("file"));
Packit Service 1d0348
				if (r < 0) {
Packit Service 1d0348
					archive_set_error(&a->archive,
Packit Service 1d0348
					    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
					    "xmlTextWriterStartElement() "
Packit Service 1d0348
					    "failed: %d", r);
Packit Service 1d0348
					goto exit_toc;
Packit Service 1d0348
				}
Packit Service 1d0348
				r = xmlTextWriterWriteFormatAttribute(
Packit Service 1d0348
				    writer, BAD_CAST("id"), "%d", np->id);
Packit Service 1d0348
				if (r < 0) {
Packit Service 1d0348
					archive_set_error(&a->archive,
Packit Service 1d0348
					    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
					    "xmlTextWriterWriteAttribute() "
Packit Service 1d0348
					    "failed: %d", r);
Packit Service 1d0348
					goto exit_toc;
Packit Service 1d0348
				}
Packit Service 1d0348
				break;
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
	} while (np != np->parent);
Packit Service 1d0348
Packit Service 1d0348
	r = xmlTextWriterEndDocument(writer);
Packit Service 1d0348
	if (r < 0) {
Packit Service 1d0348
		archive_set_error(&a->archive,
Packit Service 1d0348
		    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "xmlTextWriterEndDocument() failed: %d", r);
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	}
Packit Service 1d0348
#if DEBUG_PRINT_TOC
Packit Service 1d0348
	fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
Packit Service 1d0348
	    strlen((const char *)bp->content), bp->content);
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Compress the TOC and calculate the sum of the TOC.
Packit Service 1d0348
	 */
Packit Service 1d0348
	xar->toc.temp_offset = xar->temp_offset;
Packit Service 1d0348
	xar->toc.size = bp->use;
Packit Service 1d0348
	checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
Packit Service 1d0348
Packit Service 1d0348
	r = compression_init_encoder_gzip(&(a->archive),
Packit Service 1d0348
	    &(xar->stream), 6, 1);
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	xar->stream.next_in = bp->content;
Packit Service 1d0348
	xar->stream.avail_in = bp->use;
Packit Service 1d0348
	xar->stream.total_in = 0;
Packit Service 1d0348
	xar->stream.next_out = xar->wbuff;
Packit Service 1d0348
	xar->stream.avail_out = sizeof(xar->wbuff);
Packit Service 1d0348
	xar->stream.total_out = 0;
Packit Service 1d0348
	for (;;) {
Packit Service 1d0348
		size_t size;
Packit Service 1d0348
Packit Service 1d0348
		r = compression_code(&(a->archive),
Packit Service 1d0348
		    &(xar->stream), ARCHIVE_Z_FINISH);
Packit Service 1d0348
		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
		size = sizeof(xar->wbuff) - xar->stream.avail_out;
Packit Service 1d0348
		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
Packit Service 1d0348
		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
Packit Service 1d0348
			goto exit_toc;
Packit Service 1d0348
		if (r == ARCHIVE_EOF)
Packit Service 1d0348
			break;
Packit Service 1d0348
		xar->stream.next_out = xar->wbuff;
Packit Service 1d0348
		xar->stream.avail_out = sizeof(xar->wbuff);
Packit Service 1d0348
	}
Packit Service 1d0348
	r = compression_end(&(a->archive), &(xar->stream));
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		goto exit_toc;
Packit Service 1d0348
	xar->toc.length = xar->stream.total_out;
Packit Service 1d0348
	xar->toc.compression = GZIP;
Packit Service 1d0348
	checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
Packit Service 1d0348
Packit Service 1d0348
	ret = ARCHIVE_OK;
Packit Service 1d0348
exit_toc:
Packit Service 1d0348
	if (writer)
Packit Service 1d0348
		xmlFreeTextWriter(writer);
Packit Service 1d0348
	if (bp)
Packit Service 1d0348
		xmlBufferFree(bp);
Packit Service 1d0348
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
flush_wbuff(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	int r;
Packit Service 1d0348
	size_t s;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	s = sizeof(xar->wbuff) - xar->wbuff_remaining;
Packit Service 1d0348
	r = __archive_write_output(a, xar->wbuff, s);
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	xar->wbuff_remaining = sizeof(xar->wbuff);
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
Packit Service 1d0348
		archive_set_error(&(a->archive), errno, "lseek failed");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	while (length) {
Packit Service 1d0348
		size_t rsize;
Packit Service 1d0348
		ssize_t rs;
Packit Service 1d0348
		unsigned char *wb;
Packit Service 1d0348
Packit Service 1d0348
		if (length > xar->wbuff_remaining)
Packit Service 1d0348
			rsize = xar->wbuff_remaining;
Packit Service 1d0348
		else
Packit Service 1d0348
			rsize = (size_t)length;
Packit Service 1d0348
		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
Packit Service 1d0348
		rs = read(xar->temp_fd, wb, rsize);
Packit Service 1d0348
		if (rs < 0) {
Packit Service 1d0348
			archive_set_error(&(a->archive), errno,
Packit Service 1d0348
			    "Can't read temporary file(%jd)",
Packit Service 1d0348
			    (intmax_t)rs);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (rs == 0) {
Packit Service 1d0348
			archive_set_error(&(a->archive), 0,
Packit Service 1d0348
			    "Truncated xar archive");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		xar->wbuff_remaining -= rs;
Packit Service 1d0348
		length -= rs;
Packit Service 1d0348
		if (xar->wbuff_remaining == 0) {
Packit Service 1d0348
			r = flush_wbuff(a);
Packit Service 1d0348
			if (r != ARCHIVE_OK)
Packit Service 1d0348
				return (r);
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
xar_close(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	unsigned char *wb;
Packit Service 1d0348
	uint64_t length;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	/* Empty! */
Packit Service 1d0348
	if (xar->root->children.first == NULL)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	/* Save the length of all file extended attributes and contents. */
Packit Service 1d0348
	length = xar->temp_offset;
Packit Service 1d0348
Packit Service 1d0348
	/* Connect hardlinked files */
Packit Service 1d0348
	file_connect_hardlink_files(xar);
Packit Service 1d0348
Packit Service 1d0348
	/* Make the TOC */
Packit Service 1d0348
	r = make_toc(a);
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make the xar header on wbuff(write buffer).
Packit Service 1d0348
	 */
Packit Service 1d0348
	wb = xar->wbuff;
Packit Service 1d0348
	xar->wbuff_remaining = sizeof(xar->wbuff);
Packit Service 1d0348
	archive_be32enc(&wb[0], HEADER_MAGIC);
Packit Service 1d0348
	archive_be16enc(&wb[4], HEADER_SIZE);
Packit Service 1d0348
	archive_be16enc(&wb[6], HEADER_VERSION);
Packit Service 1d0348
	archive_be64enc(&wb[8], xar->toc.length);
Packit Service 1d0348
	archive_be64enc(&wb[16], xar->toc.size);
Packit Service 1d0348
	archive_be32enc(&wb[24], xar->toc.a_sum.alg);
Packit Service 1d0348
	xar->wbuff_remaining -= HEADER_SIZE;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Write the TOC
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
Packit Service 1d0348
	/* Write the checksum value of the TOC. */
Packit Service 1d0348
	if (xar->toc.a_sum.len) {
Packit Service 1d0348
		if (xar->wbuff_remaining < xar->toc.a_sum.len) {
Packit Service 1d0348
			r = flush_wbuff(a);
Packit Service 1d0348
			if (r != ARCHIVE_OK)
Packit Service 1d0348
				return (r);
Packit Service 1d0348
		}
Packit Service 1d0348
		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
Packit Service 1d0348
		memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
Packit Service 1d0348
		xar->wbuff_remaining -= xar->toc.a_sum.len;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Write all file extended attributes and contents.
Packit Service 1d0348
	 */
Packit Service 1d0348
	r = copy_out(a, xar->toc.a_sum.len, length);
Packit Service 1d0348
	if (r != ARCHIVE_OK)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	r = flush_wbuff(a);
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xar_free(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	/* Close the temporary file. */
Packit Service 1d0348
	if (xar->temp_fd >= 0)
Packit Service 1d0348
		close(xar->temp_fd);
Packit Service 1d0348
Packit Service 1d0348
	archive_string_free(&(xar->cur_dirstr));
Packit Service 1d0348
	archive_string_free(&(xar->tstr));
Packit Service 1d0348
	archive_string_free(&(xar->vstr));
Packit Service 1d0348
	file_free_hardlinks(xar);
Packit Service 1d0348
	file_free_register(xar);
Packit Service 1d0348
	compression_end(&(a->archive), &(xar->stream));
Packit Service 1d0348
	free(xar);
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
file_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 file *f1 = (const struct file *)n1;
Packit Service 1d0348
	const struct file *f2 = (const struct file *)n2;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp(f1->basename.s, f2->basename.s));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
file_cmp_key(const struct archive_rb_node *n, const void *key)
Packit Service 1d0348
{
Packit Service 1d0348
	const struct file *f = (const struct file *)n;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp(f->basename.s, (const char *)key));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static struct file *
Packit Service 1d0348
file_new(struct archive_write *a, struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	struct file *file;
Packit Service 1d0348
	static const struct archive_rb_tree_ops rb_ops = {
Packit Service 1d0348
		file_cmp_node, file_cmp_key
Packit Service 1d0348
	};
Packit Service 1d0348
Packit Service 1d0348
	file = calloc(1, sizeof(*file));
Packit Service 1d0348
	if (file == NULL)
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
Packit Service 1d0348
	if (entry != NULL)
Packit Service 1d0348
		file->entry = archive_entry_clone(entry);
Packit Service 1d0348
	else
Packit Service 1d0348
		file->entry = archive_entry_new2(&a->archive);
Packit Service 1d0348
	if (file->entry == NULL) {
Packit Service 1d0348
		free(file);
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	}
Packit Service 1d0348
	__archive_rb_tree_init(&(file->rbtree), &rb_ops);
Packit Service 1d0348
	file->children.first = NULL;
Packit Service 1d0348
	file->children.last = &(file->children.first);
Packit Service 1d0348
	file->xattr.first = NULL;
Packit Service 1d0348
	file->xattr.last = &(file->xattr.first);
Packit Service 1d0348
	archive_string_init(&(file->parentdir));
Packit Service 1d0348
	archive_string_init(&(file->basename));
Packit Service 1d0348
	archive_string_init(&(file->symlink));
Packit Service 1d0348
	archive_string_init(&(file->script));
Packit Service 1d0348
	if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
Packit Service 1d0348
		file->dir = 1;
Packit Service 1d0348
Packit Service 1d0348
	return (file);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_free(struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	struct heap_data *heap, *next_heap;
Packit Service 1d0348
Packit Service 1d0348
	heap = file->xattr.first;
Packit Service 1d0348
	while (heap != NULL) {
Packit Service 1d0348
		next_heap = heap->next;
Packit Service 1d0348
		free(heap);
Packit Service 1d0348
		heap = next_heap;
Packit Service 1d0348
	}
Packit Service 1d0348
	archive_string_free(&(file->parentdir));
Packit Service 1d0348
	archive_string_free(&(file->basename));
Packit Service 1d0348
	archive_string_free(&(file->symlink));
Packit Service 1d0348
	archive_string_free(&(file->script));
Packit Service 1d0348
	archive_entry_free(file->entry);
Packit Service 1d0348
	free(file);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static struct file *
Packit Service 1d0348
file_create_virtual_dir(struct archive_write *a, struct xar *xar,
Packit Service 1d0348
    const char *pathname)
Packit Service 1d0348
{
Packit Service 1d0348
	struct file *file;
Packit Service 1d0348
Packit Service 1d0348
	(void)xar; /* UNUSED */
Packit Service 1d0348
Packit Service 1d0348
	file = file_new(a, NULL);
Packit Service 1d0348
	if (file == NULL)
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	archive_entry_set_pathname(file->entry, pathname);
Packit Service 1d0348
	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
Packit Service 1d0348
Packit Service 1d0348
	file->dir = 1;
Packit Service 1d0348
	file->virtual = 1;
Packit Service 1d0348
Packit Service 1d0348
	return (file);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
file_add_child_tail(struct file *parent, struct file *child)
Packit Service 1d0348
{
Packit Service 1d0348
	if (!__archive_rb_tree_insert_node(
Packit Service 1d0348
	    &(parent->rbtree), (struct archive_rb_node *)child))
Packit Service 1d0348
		return (0);
Packit Service 1d0348
	child->chnext = NULL;
Packit Service 1d0348
	*parent->children.last = child;
Packit Service 1d0348
	parent->children.last = &(child->chnext);
Packit Service 1d0348
	child->parent = parent;
Packit Service 1d0348
	return (1);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Find a entry from `parent'
Packit Service 1d0348
 */
Packit Service 1d0348
static struct file *
Packit Service 1d0348
file_find_child(struct file *parent, const char *child_name)
Packit Service 1d0348
{
Packit Service 1d0348
	struct file *np;
Packit Service 1d0348
Packit Service 1d0348
	np = (struct file *)__archive_rb_tree_find_node(
Packit Service 1d0348
	    &(parent->rbtree), child_name);
Packit Service 1d0348
	return (np);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#if defined(_WIN32) || defined(__CYGWIN__)
Packit Service 1d0348
static void
Packit Service 1d0348
cleanup_backslash(char *utf8, size_t len)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	/* Convert a path-separator from '\' to  '/' */
Packit Service 1d0348
	while (*utf8 != '\0' && len) {
Packit Service 1d0348
		if (*utf8 == '\\')
Packit Service 1d0348
			*utf8 = '/';
Packit Service 1d0348
		++utf8;
Packit Service 1d0348
		--len;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
#else
Packit Service 1d0348
#define cleanup_backslash(p, len)	/* nop */
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Generate a parent directory name and a base name from a pathname.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
file_gen_utility_names(struct archive_write *a, struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	const char *pp;
Packit Service 1d0348
	char *p, *dirname, *slash;
Packit Service 1d0348
	size_t len;
Packit Service 1d0348
	int r = ARCHIVE_OK;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	archive_string_empty(&(file->parentdir));
Packit Service 1d0348
	archive_string_empty(&(file->basename));
Packit Service 1d0348
	archive_string_empty(&(file->symlink));
Packit Service 1d0348
Packit Service 1d0348
	if (file->parent == file)/* virtual root */
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)
Packit Service 1d0348
	    != 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
		    "Can't translate pathname '%s' to UTF-8",
Packit Service 1d0348
		    archive_entry_pathname(file->entry));
Packit Service 1d0348
		r = ARCHIVE_WARN;
Packit Service 1d0348
	}
Packit Service 1d0348
	archive_strncpy(&(file->parentdir), pp, len);
Packit Service 1d0348
	len = file->parentdir.length;
Packit Service 1d0348
	p = dirname = file->parentdir.s;
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Convert a path-separator from '\' to  '/'
Packit Service 1d0348
	 */
Packit Service 1d0348
	cleanup_backslash(p, len);
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Remove leading '/', '../' and './' elements
Packit Service 1d0348
	 */
Packit Service 1d0348
	while (*p) {
Packit Service 1d0348
		if (p[0] == '/') {
Packit Service 1d0348
			p++;
Packit Service 1d0348
			len--;
Packit Service 1d0348
		} else if (p[0] != '.')
Packit Service 1d0348
			break;
Packit Service 1d0348
		else if (p[1] == '.' && p[2] == '/') {
Packit Service 1d0348
			p += 3;
Packit Service 1d0348
			len -= 3;
Packit Service 1d0348
		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
Packit Service 1d0348
			p += 2;
Packit Service 1d0348
			len -= 2;
Packit Service 1d0348
		} else if (p[1] == '\0') {
Packit Service 1d0348
			p++;
Packit Service 1d0348
			len--;
Packit Service 1d0348
		} else
Packit Service 1d0348
			break;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (p != dirname) {
Packit Service 1d0348
		memmove(dirname, p, len+1);
Packit Service 1d0348
		p = dirname;
Packit Service 1d0348
	}
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Remove "/","/." and "/.." elements from tail.
Packit Service 1d0348
	 */
Packit Service 1d0348
	while (len > 0) {
Packit Service 1d0348
		size_t ll = len;
Packit Service 1d0348
Packit Service 1d0348
		if (len > 0 && p[len-1] == '/') {
Packit Service 1d0348
			p[len-1] = '\0';
Packit Service 1d0348
			len--;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
Packit Service 1d0348
			p[len-2] = '\0';
Packit Service 1d0348
			len -= 2;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
Packit Service 1d0348
		    p[len-1] == '.') {
Packit Service 1d0348
			p[len-3] = '\0';
Packit Service 1d0348
			len -= 3;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (ll == len)
Packit Service 1d0348
			break;
Packit Service 1d0348
	}
Packit Service 1d0348
	while (*p) {
Packit Service 1d0348
		if (p[0] == '/') {
Packit Service 1d0348
			if (p[1] == '/')
Packit Service 1d0348
				/* Convert '//' --> '/' */
Packit Service 1d0348
				strcpy(p, p+1);
Packit Service 1d0348
			else if (p[1] == '.' && p[2] == '/')
Packit Service 1d0348
				/* Convert '/./' --> '/' */
Packit Service 1d0348
				strcpy(p, p+2);
Packit Service 1d0348
			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
Packit Service 1d0348
				/* Convert 'dir/dir1/../dir2/'
Packit Service 1d0348
				 *     --> 'dir/dir2/'
Packit Service 1d0348
				 */
Packit Service 1d0348
				char *rp = p -1;
Packit Service 1d0348
				while (rp >= dirname) {
Packit Service 1d0348
					if (*rp == '/')
Packit Service 1d0348
						break;
Packit Service 1d0348
					--rp;
Packit Service 1d0348
				}
Packit Service 1d0348
				if (rp > dirname) {
Packit Service 1d0348
					strcpy(rp, p+3);
Packit Service 1d0348
					p = rp;
Packit Service 1d0348
				} else {
Packit Service 1d0348
					strcpy(dirname, p+4);
Packit Service 1d0348
					p = dirname;
Packit Service 1d0348
				}
Packit Service 1d0348
			} else
Packit Service 1d0348
				p++;
Packit Service 1d0348
		} else
Packit Service 1d0348
			p++;
Packit Service 1d0348
	}
Packit Service 1d0348
	p = dirname;
Packit Service 1d0348
	len = strlen(p);
Packit Service 1d0348
Packit Service 1d0348
	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
Packit Service 1d0348
		size_t len2;
Packit Service 1d0348
		/* Convert symlink name too. */
Packit Service 1d0348
		if (archive_entry_symlink_l(file->entry, &pp, &len2,
Packit Service 1d0348
		    xar->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 Linkname");
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
			    "Can't translate symlink '%s' to UTF-8",
Packit Service 1d0348
			    archive_entry_symlink(file->entry));
Packit Service 1d0348
			r = ARCHIVE_WARN;
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_strncpy(&(file->symlink), pp, len2);
Packit Service 1d0348
		cleanup_backslash(file->symlink.s, file->symlink.length);
Packit Service 1d0348
	}
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * - Count up directory elements.
Packit Service 1d0348
	 * - Find out the position which points the last position of
Packit Service 1d0348
	 *   path separator('/').
Packit Service 1d0348
	 */
Packit Service 1d0348
	slash = NULL;
Packit Service 1d0348
	for (; *p != '\0'; p++)
Packit Service 1d0348
		if (*p == '/')
Packit Service 1d0348
			slash = p;
Packit Service 1d0348
	if (slash == NULL) {
Packit Service 1d0348
		/* The pathname doesn't have a parent directory. */
Packit Service 1d0348
		file->parentdir.length = len;
Packit Service 1d0348
		archive_string_copy(&(file->basename), &(file->parentdir));
Packit Service 1d0348
		archive_string_empty(&(file->parentdir));
Packit Service 1d0348
		*file->parentdir.s = '\0';
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Make a basename from dirname and slash */
Packit Service 1d0348
	*slash  = '\0';
Packit Service 1d0348
	file->parentdir.length = slash - dirname;
Packit Service 1d0348
	archive_strcpy(&(file->basename),  slash + 1);
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
get_path_component(char *name, int n, const char *fn)
Packit Service 1d0348
{
Packit Service 1d0348
	char *p;
Packit Service 1d0348
	int l;
Packit Service 1d0348
Packit Service 1d0348
	p = strchr(fn, '/');
Packit Service 1d0348
	if (p == NULL) {
Packit Service 1d0348
		if ((l = strlen(fn)) == 0)
Packit Service 1d0348
			return (0);
Packit Service 1d0348
	} else
Packit Service 1d0348
		l = p - fn;
Packit Service 1d0348
	if (l > n -1)
Packit Service 1d0348
		return (-1);
Packit Service 1d0348
	memcpy(name, fn, l);
Packit Service 1d0348
	name[l] = '\0';
Packit Service 1d0348
Packit Service 1d0348
	return (l);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Add a new entry into the tree.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
file_tree(struct archive_write *a, struct file **filepp)
Packit Service 1d0348
{
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
	char name[_MAX_FNAME];/* Included null terminator size. */
Packit Service 1d0348
#elif defined(NAME_MAX) && NAME_MAX >= 255
Packit Service 1d0348
	char name[NAME_MAX+1];
Packit Service 1d0348
#else
Packit Service 1d0348
	char name[256];
Packit Service 1d0348
#endif
Packit Service 1d0348
	struct xar *xar = (struct xar *)a->format_data;
Packit Service 1d0348
	struct file *dent, *file, *np;
Packit Service 1d0348
	struct archive_entry *ent;
Packit Service 1d0348
	const char *fn, *p;
Packit Service 1d0348
	int l;
Packit Service 1d0348
Packit Service 1d0348
	file = *filepp;
Packit Service 1d0348
	dent = xar->root;
Packit Service 1d0348
	if (file->parentdir.length > 0)
Packit Service 1d0348
		fn = p = file->parentdir.s;
Packit Service 1d0348
	else
Packit Service 1d0348
		fn = p = "";
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * If the path of the parent directory of `file' entry is
Packit Service 1d0348
	 * the same as the path of `cur_dirent', add isoent to
Packit Service 1d0348
	 * `cur_dirent'.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_strlen(&(xar->cur_dirstr))
Packit Service 1d0348
	      == archive_strlen(&(file->parentdir)) &&
Packit Service 1d0348
	    strcmp(xar->cur_dirstr.s, fn) == 0) {
Packit Service 1d0348
		if (!file_add_child_tail(xar->cur_dirent, file)) {
Packit Service 1d0348
			np = (struct file *)__archive_rb_tree_find_node(
Packit Service 1d0348
			    &(xar->cur_dirent->rbtree),
Packit Service 1d0348
			    file->basename.s);
Packit Service 1d0348
			goto same_entry;
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	for (;;) {
Packit Service 1d0348
		l = get_path_component(name, sizeof(name), fn);
Packit Service 1d0348
		if (l == 0) {
Packit Service 1d0348
			np = NULL;
Packit Service 1d0348
			break;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (l < 0) {
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "A name buffer is too small");
Packit Service 1d0348
			file_free(file);
Packit Service 1d0348
			*filepp = NULL;
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		np = file_find_child(dent, name);
Packit Service 1d0348
		if (np == NULL || fn[0] == '\0')
Packit Service 1d0348
			break;
Packit Service 1d0348
Packit Service 1d0348
		/* Find next subdirectory. */
Packit Service 1d0348
		if (!np->dir) {
Packit Service 1d0348
			/* NOT Directory! */
Packit Service 1d0348
			archive_set_error(&a->archive,
Packit Service 1d0348
			    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
			    "`%s' is not directory, we cannot insert `%s' ",
Packit Service 1d0348
			    archive_entry_pathname(np->entry),
Packit Service 1d0348
			    archive_entry_pathname(file->entry));
Packit Service 1d0348
			file_free(file);
Packit Service 1d0348
			*filepp = NULL;
Packit Service 1d0348
			return (ARCHIVE_FAILED);
Packit Service 1d0348
		}
Packit Service 1d0348
		fn += l;
Packit Service 1d0348
		if (fn[0] == '/')
Packit Service 1d0348
			fn++;
Packit Service 1d0348
		dent = np;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (np == NULL) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Create virtual parent directories.
Packit Service 1d0348
		 */
Packit Service 1d0348
		while (fn[0] != '\0') {
Packit Service 1d0348
			struct file *vp;
Packit Service 1d0348
			struct archive_string as;
Packit Service 1d0348
Packit Service 1d0348
			archive_string_init(&as);
Packit Service 1d0348
			archive_strncat(&as, p, fn - p + l);
Packit Service 1d0348
			if (as.s[as.length-1] == '/') {
Packit Service 1d0348
				as.s[as.length-1] = '\0';
Packit Service 1d0348
				as.length--;
Packit Service 1d0348
			}
Packit Service 1d0348
			vp = file_create_virtual_dir(a, xar, as.s);
Packit Service 1d0348
			if (vp == NULL) {
Packit Service 1d0348
				archive_string_free(&as);
Packit Service 1d0348
				archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
				    "Can't allocate memory");
Packit Service 1d0348
				file_free(file);
Packit Service 1d0348
				*filepp = NULL;
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			archive_string_free(&as);
Packit Service 1d0348
			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			file_add_child_tail(dent, vp);
Packit Service 1d0348
			file_register(xar, vp);
Packit Service 1d0348
			np = vp;
Packit Service 1d0348
Packit Service 1d0348
			fn += l;
Packit Service 1d0348
			if (fn[0] == '/')
Packit Service 1d0348
				fn++;
Packit Service 1d0348
			l = get_path_component(name, sizeof(name), fn);
Packit Service 1d0348
			if (l < 0) {
Packit Service 1d0348
				archive_string_free(&as);
Packit Service 1d0348
				archive_set_error(&a->archive,
Packit Service 1d0348
				    ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
				    "A name buffer is too small");
Packit Service 1d0348
				file_free(file);
Packit Service 1d0348
				*filepp = NULL;
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			dent = np;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		/* Found out the parent directory where isoent can be
Packit Service 1d0348
		 * inserted. */
Packit Service 1d0348
		xar->cur_dirent = dent;
Packit Service 1d0348
		archive_string_empty(&(xar->cur_dirstr));
Packit Service 1d0348
		archive_string_ensure(&(xar->cur_dirstr),
Packit Service 1d0348
		    archive_strlen(&(dent->parentdir)) +
Packit Service 1d0348
		    archive_strlen(&(dent->basename)) + 2);
Packit Service 1d0348
		if (archive_strlen(&(dent->parentdir)) +
Packit Service 1d0348
		    archive_strlen(&(dent->basename)) == 0)
Packit Service 1d0348
			xar->cur_dirstr.s[0] = 0;
Packit Service 1d0348
		else {
Packit Service 1d0348
			if (archive_strlen(&(dent->parentdir)) > 0) {
Packit Service 1d0348
				archive_string_copy(&(xar->cur_dirstr),
Packit Service 1d0348
				    &(dent->parentdir));
Packit Service 1d0348
				archive_strappend_char(&(xar->cur_dirstr), '/');
Packit Service 1d0348
			}
Packit Service 1d0348
			archive_string_concat(&(xar->cur_dirstr),
Packit Service 1d0348
			    &(dent->basename));
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if (!file_add_child_tail(dent, file)) {
Packit Service 1d0348
			np = (struct file *)__archive_rb_tree_find_node(
Packit Service 1d0348
			    &(dent->rbtree), file->basename.s);
Packit Service 1d0348
			goto same_entry;
Packit Service 1d0348
		}
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
same_entry:
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * We have already has the entry the filename of which is
Packit Service 1d0348
	 * the same.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_entry_filetype(np->entry) !=
Packit Service 1d0348
	    archive_entry_filetype(file->entry)) {
Packit Service 1d0348
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Found duplicate entries `%s' and its file type is "
Packit Service 1d0348
		    "different",
Packit Service 1d0348
		    archive_entry_pathname(np->entry));
Packit Service 1d0348
		file_free(file);
Packit Service 1d0348
		*filepp = NULL;
Packit Service 1d0348
		return (ARCHIVE_FAILED);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Swap files. */
Packit Service 1d0348
	ent = np->entry;
Packit Service 1d0348
	np->entry = file->entry;
Packit Service 1d0348
	file->entry = ent;
Packit Service 1d0348
	np->virtual = 0;
Packit Service 1d0348
Packit Service 1d0348
	file_free(file);
Packit Service 1d0348
	*filepp = np;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_register(struct xar *xar, struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	file->id = xar->file_idx++;
Packit Service 1d0348
        file->next = NULL;
Packit Service 1d0348
        *xar->file_list.last = file;
Packit Service 1d0348
        xar->file_list.last = &(file->next);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_init_register(struct xar *xar)
Packit Service 1d0348
{
Packit Service 1d0348
	xar->file_list.first = NULL;
Packit Service 1d0348
	xar->file_list.last = &(xar->file_list.first);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_free_register(struct xar *xar)
Packit Service 1d0348
{
Packit Service 1d0348
	struct file *file, *file_next;
Packit Service 1d0348
Packit Service 1d0348
	file = xar->file_list.first;
Packit Service 1d0348
	while (file != NULL) {
Packit Service 1d0348
		file_next = file->next;
Packit Service 1d0348
		file_free(file);
Packit Service 1d0348
		file = file_next;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Register entry to get a hardlink target.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
file_register_hardlink(struct archive_write *a, struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar = (struct xar *)a->format_data;
Packit Service 1d0348
	struct hardlink *hl;
Packit Service 1d0348
	const char *pathname;
Packit Service 1d0348
Packit Service 1d0348
	archive_entry_set_nlink(file->entry, 1);
Packit Service 1d0348
	pathname = archive_entry_hardlink(file->entry);
Packit Service 1d0348
	if (pathname == NULL) {
Packit Service 1d0348
		/* This `file` is a hardlink target. */
Packit Service 1d0348
		hl = malloc(sizeof(*hl));
Packit Service 1d0348
		if (hl == NULL) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		hl->nlink = 1;
Packit Service 1d0348
		/* A hardlink target must be the first position. */
Packit Service 1d0348
		file->hlnext = NULL;
Packit Service 1d0348
		hl->file_list.first = file;
Packit Service 1d0348
		hl->file_list.last = &(file->hlnext);
Packit Service 1d0348
		__archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
Packit Service 1d0348
		    (struct archive_rb_node *)hl);
Packit Service 1d0348
	} else {
Packit Service 1d0348
		hl = (struct hardlink *)__archive_rb_tree_find_node(
Packit Service 1d0348
		    &(xar->hardlink_rbtree), pathname);
Packit Service 1d0348
		if (hl != NULL) {
Packit Service 1d0348
			/* Insert `file` entry into the tail. */
Packit Service 1d0348
			file->hlnext = NULL;
Packit Service 1d0348
			*hl->file_list.last = file;
Packit Service 1d0348
			hl->file_list.last = &(file->hlnext);
Packit Service 1d0348
			hl->nlink++;
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_entry_unset_size(file->entry);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Hardlinked files have to have the same location of extent.
Packit Service 1d0348
 * We have to find out hardlink target entries for entries which
Packit Service 1d0348
 * have a hardlink target name.
Packit Service 1d0348
 */
Packit Service 1d0348
static void
Packit Service 1d0348
file_connect_hardlink_files(struct xar *xar)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_rb_node *n;
Packit Service 1d0348
	struct hardlink *hl;
Packit Service 1d0348
	struct file *target, *nf;
Packit Service 1d0348
Packit Service 1d0348
	ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
Packit Service 1d0348
		hl = (struct hardlink *)n;
Packit Service 1d0348
Packit Service 1d0348
		/* The first entry must be a hardlink target. */
Packit Service 1d0348
		target = hl->file_list.first;
Packit Service 1d0348
		archive_entry_set_nlink(target->entry, hl->nlink);
Packit Service 1d0348
		if (hl->nlink > 1)
Packit Service 1d0348
			/* It means this file is a hardlink
Packit Service 1d0348
			 * target itself. */
Packit Service 1d0348
			target->hardlink_target = target;
Packit Service 1d0348
		for (nf = target->hlnext;
Packit Service 1d0348
		    nf != NULL; nf = nf->hlnext) {
Packit Service 1d0348
			nf->hardlink_target = target;
Packit Service 1d0348
			archive_entry_set_nlink(nf->entry, hl->nlink);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
file_hd_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 hardlink *h1 = (const struct hardlink *)n1;
Packit Service 1d0348
	const struct hardlink *h2 = (const struct hardlink *)n2;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
Packit Service 1d0348
		       archive_entry_pathname(h2->file_list.first->entry)));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
Packit Service 1d0348
{
Packit Service 1d0348
	const struct hardlink *h = (const struct hardlink *)n;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
Packit Service 1d0348
		       (const char *)key));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_init_hardlinks(struct xar *xar)
Packit Service 1d0348
{
Packit Service 1d0348
	static const struct archive_rb_tree_ops rb_ops = {
Packit Service 1d0348
		file_hd_cmp_node, file_hd_cmp_key,
Packit Service 1d0348
	};
Packit Service 1d0348
Packit Service 1d0348
	__archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
file_free_hardlinks(struct xar *xar)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_rb_node *n, *next;
Packit Service 1d0348
Packit Service 1d0348
	for (n = ARCHIVE_RB_TREE_MIN(&(xar->hardlink_rbtree)); n;) {
Packit Service 1d0348
		next = __archive_rb_tree_iterate(&(xar->hardlink_rbtree),
Packit Service 1d0348
		    n, ARCHIVE_RB_DIR_RIGHT);
Packit Service 1d0348
		free(n);
Packit Service 1d0348
		n = next;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
Packit Service 1d0348
{
Packit Service 1d0348
	sumwrk->alg = sum_alg;
Packit Service 1d0348
	switch (sum_alg) {
Packit Service 1d0348
	case CKSUM_NONE:
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_SHA1:
Packit Service 1d0348
		archive_sha1_init(&(sumwrk->sha1ctx));
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_MD5:
Packit Service 1d0348
		archive_md5_init(&(sumwrk->md5ctx));
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	switch (sumwrk->alg) {
Packit Service 1d0348
	case CKSUM_NONE:
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_SHA1:
Packit Service 1d0348
		archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_MD5:
Packit Service 1d0348
		archive_md5_update(&(sumwrk->md5ctx), buff, size);
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	switch (sumwrk->alg) {
Packit Service 1d0348
	case CKSUM_NONE:
Packit Service 1d0348
		sumval->len = 0;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_SHA1:
Packit Service 1d0348
		archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
Packit Service 1d0348
		sumval->len = SHA1_SIZE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case CKSUM_MD5:
Packit Service 1d0348
		archive_md5_final(&(sumwrk->md5ctx), sumval->val);
Packit Service 1d0348
		sumval->len = MD5_SIZE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	sumval->alg = sumwrk->alg;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
Packit Service 1d0348
static int
Packit Service 1d0348
compression_unsupported_encoder(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, const char *name)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
	    "%s compression not supported on this platform", name);
Packit Service 1d0348
	lastrm->valid = 0;
Packit Service 1d0348
	lastrm->real_stream = NULL;
Packit Service 1d0348
	return (ARCHIVE_FAILED);
Packit Service 1d0348
}
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_gzip(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level, int withheader)
Packit Service 1d0348
{
Packit Service 1d0348
	z_stream *strm;
Packit Service 1d0348
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	strm = calloc(1, sizeof(*strm));
Packit Service 1d0348
	if (strm == NULL) {
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory for gzip stream");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	/* zlib.h is not const-correct, so we need this one bit
Packit Service 1d0348
	 * of ugly hackery to convert a const * pointer to
Packit Service 1d0348
	 * a non-const pointer. */
Packit Service 1d0348
	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
Packit Service 1d0348
	strm->avail_in = lastrm->avail_in;
Packit Service 1d0348
	strm->total_in = (uLong)lastrm->total_in;
Packit Service 1d0348
	strm->next_out = lastrm->next_out;
Packit Service 1d0348
	strm->avail_out = lastrm->avail_out;
Packit Service 1d0348
	strm->total_out = (uLong)lastrm->total_out;
Packit Service 1d0348
	if (deflateInit2(strm, level, Z_DEFLATED,
Packit Service 1d0348
	    (withheader)?15:-15,
Packit Service 1d0348
	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal error initializing compression library");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	lastrm->real_stream = strm;
Packit Service 1d0348
	lastrm->valid = 1;
Packit Service 1d0348
	lastrm->code = compression_code_gzip;
Packit Service 1d0348
	lastrm->end = compression_end_gzip;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_code_gzip(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, enum la_zaction action)
Packit Service 1d0348
{
Packit Service 1d0348
	z_stream *strm;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	strm = (z_stream *)lastrm->real_stream;
Packit Service 1d0348
	/* zlib.h is not const-correct, so we need this one bit
Packit Service 1d0348
	 * of ugly hackery to convert a const * pointer to
Packit Service 1d0348
	 * a non-const pointer. */
Packit Service 1d0348
	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
Packit Service 1d0348
	strm->avail_in = lastrm->avail_in;
Packit Service 1d0348
	strm->total_in = (uLong)lastrm->total_in;
Packit Service 1d0348
	strm->next_out = lastrm->next_out;
Packit Service 1d0348
	strm->avail_out = lastrm->avail_out;
Packit Service 1d0348
	strm->total_out = (uLong)lastrm->total_out;
Packit Service 1d0348
	r = deflate(strm,
Packit Service 1d0348
	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
Packit Service 1d0348
	lastrm->next_in = strm->next_in;
Packit Service 1d0348
	lastrm->avail_in = strm->avail_in;
Packit Service 1d0348
	lastrm->total_in = strm->total_in;
Packit Service 1d0348
	lastrm->next_out = strm->next_out;
Packit Service 1d0348
	lastrm->avail_out = strm->avail_out;
Packit Service 1d0348
	lastrm->total_out = strm->total_out;
Packit Service 1d0348
	switch (r) {
Packit Service 1d0348
	case Z_OK:
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	case Z_STREAM_END:
Packit Service 1d0348
		return (ARCHIVE_EOF);
Packit Service 1d0348
	default:
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "GZip compression failed:"
Packit Service 1d0348
		    " deflate() call returned status %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_end_gzip(struct archive *a, struct la_zstream *lastrm)
Packit Service 1d0348
{
Packit Service 1d0348
	z_stream *strm;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	strm = (z_stream *)lastrm->real_stream;
Packit Service 1d0348
	r = deflateEnd(strm);
Packit Service 1d0348
	free(strm);
Packit Service 1d0348
	lastrm->real_stream = NULL;
Packit Service 1d0348
	lastrm->valid = 0;
Packit Service 1d0348
	if (r != Z_OK) {
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Failed to clean up compressor");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_bzip2(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level)
Packit Service 1d0348
{
Packit Service 1d0348
	bz_stream *strm;
Packit Service 1d0348
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	strm = calloc(1, sizeof(*strm));
Packit Service 1d0348
	if (strm == NULL) {
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory for bzip2 stream");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	/* bzlib.h is not const-correct, so we need this one bit
Packit Service 1d0348
	 * of ugly hackery to convert a const * pointer to
Packit Service 1d0348
	 * a non-const pointer. */
Packit Service 1d0348
	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
Packit Service 1d0348
	strm->avail_in = lastrm->avail_in;
Packit Service 1d0348
	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
Packit Service 1d0348
	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
Packit Service 1d0348
	strm->next_out = (char *)lastrm->next_out;
Packit Service 1d0348
	strm->avail_out = lastrm->avail_out;
Packit Service 1d0348
	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
Packit Service 1d0348
	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
Packit Service 1d0348
	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal error initializing compression library");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	lastrm->real_stream = strm;
Packit Service 1d0348
	lastrm->valid = 1;
Packit Service 1d0348
	lastrm->code = compression_code_bzip2;
Packit Service 1d0348
	lastrm->end = compression_end_bzip2;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_code_bzip2(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, enum la_zaction action)
Packit Service 1d0348
{
Packit Service 1d0348
	bz_stream *strm;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	strm = (bz_stream *)lastrm->real_stream;
Packit Service 1d0348
	/* bzlib.h is not const-correct, so we need this one bit
Packit Service 1d0348
	 * of ugly hackery to convert a const * pointer to
Packit Service 1d0348
	 * a non-const pointer. */
Packit Service 1d0348
	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
Packit Service 1d0348
	strm->avail_in = lastrm->avail_in;
Packit Service 1d0348
	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
Packit Service 1d0348
	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
Packit Service 1d0348
	strm->next_out = (char *)lastrm->next_out;
Packit Service 1d0348
	strm->avail_out = lastrm->avail_out;
Packit Service 1d0348
	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
Packit Service 1d0348
	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
Packit Service 1d0348
	r = BZ2_bzCompress(strm,
Packit Service 1d0348
	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
Packit Service 1d0348
	lastrm->next_in = (const unsigned char *)strm->next_in;
Packit Service 1d0348
	lastrm->avail_in = strm->avail_in;
Packit Service 1d0348
	lastrm->total_in =
Packit Service 1d0348
	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
Packit Service 1d0348
	    + (uint64_t)(uint32_t)strm->total_in_lo32;
Packit Service 1d0348
	lastrm->next_out = (unsigned char *)strm->next_out;
Packit Service 1d0348
	lastrm->avail_out = strm->avail_out;
Packit Service 1d0348
	lastrm->total_out =
Packit Service 1d0348
	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
Packit Service 1d0348
	    + (uint64_t)(uint32_t)strm->total_out_lo32;
Packit Service 1d0348
	switch (r) {
Packit Service 1d0348
	case BZ_RUN_OK:     /* Non-finishing */
Packit Service 1d0348
	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	case BZ_STREAM_END: /* Finishing: all done */
Packit Service 1d0348
		/* Only occurs in finishing case */
Packit Service 1d0348
		return (ARCHIVE_EOF);
Packit Service 1d0348
	default:
Packit Service 1d0348
		/* Any other return value indicates an error */
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Bzip2 compression failed:"
Packit Service 1d0348
		    " BZ2_bzCompress() call returned status %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
Packit Service 1d0348
{
Packit Service 1d0348
	bz_stream *strm;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	strm = (bz_stream *)lastrm->real_stream;
Packit Service 1d0348
	r = BZ2_bzCompressEnd(strm);
Packit Service 1d0348
	free(strm);
Packit Service 1d0348
	lastrm->real_stream = NULL;
Packit Service 1d0348
	lastrm->valid = 0;
Packit Service 1d0348
	if (r != BZ_OK) {
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Failed to clean up compressor");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#else
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_bzip2(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	(void) level; /* UNUSED */
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
Packit Service 1d0348
}
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
#if defined(HAVE_LZMA_H)
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_lzma(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level)
Packit Service 1d0348
{
Packit Service 1d0348
	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
Packit Service 1d0348
	lzma_stream *strm;
Packit Service 1d0348
	lzma_options_lzma lzma_opt;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	if (lzma_lzma_preset(&lzma_opt, level)) {
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Internal error initializing compression library");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	strm = calloc(1, sizeof(*strm));
Packit Service 1d0348
	if (strm == NULL) {
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory for lzma stream");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	*strm = lzma_init_data;
Packit Service 1d0348
	r = lzma_alone_encoder(strm, &lzma_opt);
Packit Service 1d0348
	switch (r) {
Packit Service 1d0348
	case LZMA_OK:
Packit Service 1d0348
		lastrm->real_stream = strm;
Packit Service 1d0348
		lastrm->valid = 1;
Packit Service 1d0348
		lastrm->code = compression_code_lzma;
Packit Service 1d0348
		lastrm->end = compression_end_lzma;
Packit Service 1d0348
		r = ARCHIVE_OK;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case LZMA_MEM_ERROR:
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Internal error initializing compression library: "
Packit Service 1d0348
		    "Cannot allocate memory");
Packit Service 1d0348
		r =  ARCHIVE_FATAL;
Packit Service 1d0348
		break;
Packit Service 1d0348
        default:
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal error initializing compression library: "
Packit Service 1d0348
		    "It's a bug in liblzma");
Packit Service 1d0348
		r =  ARCHIVE_FATAL;
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_xz(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level, int threads)
Packit Service 1d0348
{
Packit Service 1d0348
	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
Packit Service 1d0348
	lzma_stream *strm;
Packit Service 1d0348
	lzma_filter *lzmafilters;
Packit Service 1d0348
	lzma_options_lzma lzma_opt;
Packit Service 1d0348
	int r;
Packit Service 1d0348
#ifdef HAVE_LZMA_STREAM_ENCODER_MT
Packit Service 1d0348
	lzma_mt mt_options;
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
	(void)threads; /* UNUSED (if multi-threaded LZMA library not avail) */
Packit Service 1d0348
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
Packit Service 1d0348
	if (strm == NULL) {
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory for xz stream");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	lzmafilters = (lzma_filter *)(strm+1);
Packit Service 1d0348
	if (level > 6)
Packit Service 1d0348
		level = 6;
Packit Service 1d0348
	if (lzma_lzma_preset(&lzma_opt, level)) {
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Internal error initializing compression library");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	lzmafilters[0].id = LZMA_FILTER_LZMA2;
Packit Service 1d0348
	lzmafilters[0].options = &lzma_opt;
Packit Service 1d0348
	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
Packit Service 1d0348
Packit Service 1d0348
	*strm = lzma_init_data;
Packit Service 1d0348
#ifdef HAVE_LZMA_STREAM_ENCODER_MT
Packit Service 1d0348
	if (threads > 1) {
Packit Service 1d0348
		memset(&mt_options, 0, sizeof(mt_options));
Packit Service 1d0348
		mt_options.threads = threads;
Packit Service 1d0348
		mt_options.timeout = 300;
Packit Service 1d0348
		mt_options.filters = lzmafilters;
Packit Service 1d0348
		mt_options.check = LZMA_CHECK_CRC64;
Packit Service 1d0348
		r = lzma_stream_encoder_mt(strm, &mt_options);
Packit Service 1d0348
	} else
Packit Service 1d0348
#endif
Packit Service 1d0348
		r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
Packit Service 1d0348
	switch (r) {
Packit Service 1d0348
	case LZMA_OK:
Packit Service 1d0348
		lastrm->real_stream = strm;
Packit Service 1d0348
		lastrm->valid = 1;
Packit Service 1d0348
		lastrm->code = compression_code_lzma;
Packit Service 1d0348
		lastrm->end = compression_end_lzma;
Packit Service 1d0348
		r = ARCHIVE_OK;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case LZMA_MEM_ERROR:
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "Internal error initializing compression library: "
Packit Service 1d0348
		    "Cannot allocate memory");
Packit Service 1d0348
		r =  ARCHIVE_FATAL;
Packit Service 1d0348
		break;
Packit Service 1d0348
        default:
Packit Service 1d0348
		free(strm);
Packit Service 1d0348
		lastrm->real_stream = NULL;
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal error initializing compression library: "
Packit Service 1d0348
		    "It's a bug in liblzma");
Packit Service 1d0348
		r =  ARCHIVE_FATAL;
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_code_lzma(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, enum la_zaction action)
Packit Service 1d0348
{
Packit Service 1d0348
	lzma_stream *strm;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	strm = (lzma_stream *)lastrm->real_stream;
Packit Service 1d0348
	strm->next_in = lastrm->next_in;
Packit Service 1d0348
	strm->avail_in = lastrm->avail_in;
Packit Service 1d0348
	strm->total_in = lastrm->total_in;
Packit Service 1d0348
	strm->next_out = lastrm->next_out;
Packit Service 1d0348
	strm->avail_out = lastrm->avail_out;
Packit Service 1d0348
	strm->total_out = lastrm->total_out;
Packit Service 1d0348
	r = lzma_code(strm,
Packit Service 1d0348
	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
Packit Service 1d0348
	lastrm->next_in = strm->next_in;
Packit Service 1d0348
	lastrm->avail_in = strm->avail_in;
Packit Service 1d0348
	lastrm->total_in = strm->total_in;
Packit Service 1d0348
	lastrm->next_out = strm->next_out;
Packit Service 1d0348
	lastrm->avail_out = strm->avail_out;
Packit Service 1d0348
	lastrm->total_out = strm->total_out;
Packit Service 1d0348
	switch (r) {
Packit Service 1d0348
	case LZMA_OK:
Packit Service 1d0348
		/* Non-finishing case */
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	case LZMA_STREAM_END:
Packit Service 1d0348
		/* This return can only occur in finishing case. */
Packit Service 1d0348
		return (ARCHIVE_EOF);
Packit Service 1d0348
	case LZMA_MEMLIMIT_ERROR:
Packit Service 1d0348
		archive_set_error(a, ENOMEM,
Packit Service 1d0348
		    "lzma compression error:"
Packit Service 1d0348
		    " %ju MiB would have been needed",
Packit Service 1d0348
		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
Packit Service 1d0348
			/ (1024 * 1024)));
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	default:
Packit Service 1d0348
		/* Any other return value indicates an error */
Packit Service 1d0348
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "lzma compression failed:"
Packit Service 1d0348
		    " lzma_code() call returned status %d", r);
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
Packit Service 1d0348
{
Packit Service 1d0348
	lzma_stream *strm;
Packit Service 1d0348
Packit Service 1d0348
	(void)a; /* UNUSED */
Packit Service 1d0348
	strm = (lzma_stream *)lastrm->real_stream;
Packit Service 1d0348
	lzma_end(strm);
Packit Service 1d0348
	free(strm);
Packit Service 1d0348
	lastrm->valid = 0;
Packit Service 1d0348
	lastrm->real_stream = NULL;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
#else
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_lzma(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	(void) level; /* UNUSED */
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	return (compression_unsupported_encoder(a, lastrm, "lzma"));
Packit Service 1d0348
}
Packit Service 1d0348
static int
Packit Service 1d0348
compression_init_encoder_xz(struct archive *a,
Packit Service 1d0348
    struct la_zstream *lastrm, int level, int threads)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	(void) level; /* UNUSED */
Packit Service 1d0348
	(void) threads; /* UNUSED */
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		compression_end(a, lastrm);
Packit Service 1d0348
	return (compression_unsupported_encoder(a, lastrm, "xz"));
Packit Service 1d0348
}
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
xar_compression_init_encoder(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	switch (xar->opt_compression) {
Packit Service 1d0348
	case GZIP:
Packit Service 1d0348
		r = compression_init_encoder_gzip(
Packit Service 1d0348
		    &(a->archive), &(xar->stream),
Packit Service 1d0348
		    xar->opt_compression_level, 1);
Packit Service 1d0348
		break;
Packit Service 1d0348
	case BZIP2:
Packit Service 1d0348
		r = compression_init_encoder_bzip2(
Packit Service 1d0348
		    &(a->archive), &(xar->stream),
Packit Service 1d0348
		    xar->opt_compression_level);
Packit Service 1d0348
		break;
Packit Service 1d0348
	case LZMA:
Packit Service 1d0348
		r = compression_init_encoder_lzma(
Packit Service 1d0348
		    &(a->archive), &(xar->stream),
Packit Service 1d0348
		    xar->opt_compression_level);
Packit Service 1d0348
		break;
Packit Service 1d0348
	case XZ:
Packit Service 1d0348
		r = compression_init_encoder_xz(
Packit Service 1d0348
		    &(a->archive), &(xar->stream),
Packit Service 1d0348
		    xar->opt_compression_level, xar->opt_threads);
Packit Service 1d0348
		break;
Packit Service 1d0348
	default:
Packit Service 1d0348
		r = ARCHIVE_OK;
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (r == ARCHIVE_OK) {
Packit Service 1d0348
		xar->stream.total_in = 0;
Packit Service 1d0348
		xar->stream.next_out = xar->wbuff;
Packit Service 1d0348
		xar->stream.avail_out = sizeof(xar->wbuff);
Packit Service 1d0348
		xar->stream.total_out = 0;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_code(struct archive *a, struct la_zstream *lastrm,
Packit Service 1d0348
    enum la_zaction action)
Packit Service 1d0348
{
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		return (lastrm->code(a, lastrm, action));
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
compression_end(struct archive *a, struct la_zstream *lastrm)
Packit Service 1d0348
{
Packit Service 1d0348
	if (lastrm->valid)
Packit Service 1d0348
		return (lastrm->end(a, lastrm));
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
save_xattrs(struct archive_write *a, struct file *file)
Packit Service 1d0348
{
Packit Service 1d0348
	struct xar *xar;
Packit Service 1d0348
	const char *name;
Packit Service 1d0348
	const void *value;
Packit Service 1d0348
	struct heap_data *heap;
Packit Service 1d0348
	size_t size;
Packit Service 1d0348
	int count, r;
Packit Service 1d0348
Packit Service 1d0348
	xar = (struct xar *)a->format_data;
Packit Service 1d0348
	count = archive_entry_xattr_reset(file->entry);
Packit Service 1d0348
	if (count == 0)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	while (count--) {
Packit Service 1d0348
		archive_entry_xattr_next(file->entry,
Packit Service 1d0348
		    &name, &value, &size);
Packit Service 1d0348
		checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
Packit Service 1d0348
		checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
Packit Service 1d0348
Packit Service 1d0348
		heap = calloc(1, sizeof(*heap));
Packit Service 1d0348
		if (heap == NULL) {
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for xattr");
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		heap->id = file->ea_idx++;
Packit Service 1d0348
		heap->temp_offset = xar->temp_offset;
Packit Service 1d0348
		heap->size = size;/* save a extracted size */
Packit Service 1d0348
		heap->compression = xar->opt_compression;
Packit Service 1d0348
		/* Get a extracted sumcheck value. */
Packit Service 1d0348
		checksum_update(&(xar->e_sumwrk), value, size);
Packit Service 1d0348
		checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
Packit Service 1d0348
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Not compression to xattr is simple way.
Packit Service 1d0348
		 */
Packit Service 1d0348
		if (heap->compression == NONE) {
Packit Service 1d0348
			checksum_update(&(xar->a_sumwrk), value, size);
Packit Service 1d0348
			checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
Packit Service 1d0348
			if (write_to_temp(a, value, size)
Packit Service 1d0348
			    != ARCHIVE_OK) {
Packit Service 1d0348
				free(heap);
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			heap->length = size;
Packit Service 1d0348
			/* Add heap to the tail of file->xattr. */
Packit Service 1d0348
			heap->next = NULL;
Packit Service 1d0348
			*file->xattr.last = heap;
Packit Service 1d0348
			file->xattr.last = &(heap->next);
Packit Service 1d0348
			/* Next xattr */
Packit Service 1d0348
			continue;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Init compression library.
Packit Service 1d0348
		 */
Packit Service 1d0348
		r = xar_compression_init_encoder(a);
Packit Service 1d0348
		if (r != ARCHIVE_OK) {
Packit Service 1d0348
			free(heap);
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		xar->stream.next_in = (const unsigned char *)value;
Packit Service 1d0348
		xar->stream.avail_in = size;
Packit Service 1d0348
		for (;;) {
Packit Service 1d0348
			r = compression_code(&(a->archive),
Packit Service 1d0348
			    &(xar->stream), ARCHIVE_Z_FINISH);
Packit Service 1d0348
			if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
Packit Service 1d0348
				free(heap);
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
			size = sizeof(xar->wbuff) - xar->stream.avail_out;
Packit Service 1d0348
			checksum_update(&(xar->a_sumwrk),
Packit Service 1d0348
			    xar->wbuff, size);
Packit Service 1d0348
			if (write_to_temp(a, xar->wbuff, size)
Packit Service 1d0348
			    != ARCHIVE_OK)
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
			if (r == ARCHIVE_OK) {
Packit Service 1d0348
				xar->stream.next_out = xar->wbuff;
Packit Service 1d0348
				xar->stream.avail_out = sizeof(xar->wbuff);
Packit Service 1d0348
			} else {
Packit Service 1d0348
				checksum_final(&(xar->a_sumwrk),
Packit Service 1d0348
				    &(heap->a_sum));
Packit Service 1d0348
				heap->length = xar->stream.total_out;
Packit Service 1d0348
				/* Add heap to the tail of file->xattr. */
Packit Service 1d0348
				heap->next = NULL;
Packit Service 1d0348
				*file->xattr.last = heap;
Packit Service 1d0348
				file->xattr.last = &(heap->next);
Packit Service 1d0348
				break;
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
		/* Clean up compression library. */
Packit Service 1d0348
		r = compression_end(&(a->archive), &(xar->stream));
Packit Service 1d0348
		if (r != ARCHIVE_OK)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
getalgsize(enum sumalg sumalg)
Packit Service 1d0348
{
Packit Service 1d0348
	switch (sumalg) {
Packit Service 1d0348
	default:
Packit Service 1d0348
	case CKSUM_NONE:
Packit Service 1d0348
		return (0);
Packit Service 1d0348
	case CKSUM_SHA1:
Packit Service 1d0348
		return (SHA1_SIZE);
Packit Service 1d0348
	case CKSUM_MD5:
Packit Service 1d0348
		return (MD5_SIZE);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static const char *
Packit Service 1d0348
getalgname(enum sumalg sumalg)
Packit Service 1d0348
{
Packit Service 1d0348
	switch (sumalg) {
Packit Service 1d0348
	default:
Packit Service 1d0348
	case CKSUM_NONE:
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	case CKSUM_SHA1:
Packit Service 1d0348
		return (SHA1_NAME);
Packit Service 1d0348
	case CKSUM_MD5:
Packit Service 1d0348
		return (MD5_NAME);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#endif /* Support xar format */