Blame libarchive/archive_write_set_format_mtree.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2008 Joerg Sonnenberger
Packit Service 1d0348
 * Copyright (c) 2009-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: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
Packit Service 1d0348
Packit Service 1d0348
#ifdef HAVE_SYS_TYPES_H
Packit Service 1d0348
#include <sys/types.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#include <errno.h>
Packit Service 1d0348
#include <stdlib.h>
Packit Service 1d0348
#include <string.h>
Packit Service 1d0348
Packit Service 1d0348
#include "archive.h"
Packit Service 1d0348
#include "archive_digest_private.h"
Packit Service 1d0348
#include "archive_entry.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
#define INDENTNAMELEN	15
Packit Service 1d0348
#define MAXLINELEN	80
Packit Service 1d0348
#define SET_KEYS	\
Packit Service 1d0348
	(F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)
Packit Service 1d0348
Packit Service 1d0348
struct attr_counter {
Packit Service 1d0348
	struct attr_counter *prev;
Packit Service 1d0348
	struct attr_counter *next;
Packit Service 1d0348
	struct mtree_entry *m_entry;
Packit Service 1d0348
	int count;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct att_counter_set {
Packit Service 1d0348
	struct attr_counter *uid_list;
Packit Service 1d0348
	struct attr_counter *gid_list;
Packit Service 1d0348
	struct attr_counter *mode_list;
Packit Service 1d0348
	struct attr_counter *flags_list;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct mtree_chain {
Packit Service 1d0348
	struct mtree_entry *first;
Packit Service 1d0348
	struct mtree_entry **last;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * The Data only for a directory file.
Packit Service 1d0348
 */
Packit Service 1d0348
struct dir_info {
Packit Service 1d0348
	struct archive_rb_tree rbtree;
Packit Service 1d0348
	struct mtree_chain children;
Packit Service 1d0348
	struct mtree_entry *chnext;
Packit Service 1d0348
	int virtual;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * The Data only for a regular file.
Packit Service 1d0348
 */
Packit Service 1d0348
struct reg_info {
Packit Service 1d0348
	int compute_sum;
Packit Service 1d0348
	uint32_t crc;
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	unsigned char buf_md5[16];
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	unsigned char buf_rmd160[20];
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	unsigned char buf_sha1[20];
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	unsigned char buf_sha256[32];
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	unsigned char buf_sha384[48];
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	unsigned char buf_sha512[64];
Packit Service 1d0348
#endif
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct mtree_entry {
Packit Service 1d0348
	struct archive_rb_node rbnode;
Packit Service 1d0348
	struct mtree_entry *next;
Packit Service 1d0348
	struct mtree_entry *parent;
Packit Service 1d0348
	struct dir_info *dir_info;
Packit Service 1d0348
	struct reg_info *reg_info;
Packit Service 1d0348
Packit Service 1d0348
	struct archive_string parentdir;
Packit Service 1d0348
	struct archive_string basename;
Packit Service 1d0348
	struct archive_string pathname;
Packit Service 1d0348
	struct archive_string symlink;
Packit Service 1d0348
	struct archive_string uname;
Packit Service 1d0348
	struct archive_string gname;
Packit Service 1d0348
	struct archive_string fflags_text;
Packit Service 1d0348
	unsigned int nlink;
Packit Service 1d0348
	mode_t filetype;
Packit Service 1d0348
	mode_t mode;
Packit Service 1d0348
	int64_t size;
Packit Service 1d0348
	int64_t uid;
Packit Service 1d0348
	int64_t gid;
Packit Service 1d0348
	time_t mtime;
Packit Service 1d0348
	long mtime_nsec;
Packit Service 1d0348
	unsigned long fflags_set;
Packit Service 1d0348
	unsigned long fflags_clear;
Packit Service 1d0348
	dev_t rdevmajor;
Packit Service 1d0348
	dev_t rdevminor;
Packit Service 1d0348
	dev_t devmajor;
Packit Service 1d0348
	dev_t devminor;
Packit Service 1d0348
	int64_t ino;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
struct mtree_writer {
Packit Service 1d0348
	struct mtree_entry *mtree_entry;
Packit Service 1d0348
	struct mtree_entry *root;
Packit Service 1d0348
	struct mtree_entry *cur_dirent;
Packit Service 1d0348
	struct archive_string cur_dirstr;
Packit Service 1d0348
	struct mtree_chain file_list;
Packit Service 1d0348
Packit Service 1d0348
	struct archive_string ebuf;
Packit Service 1d0348
	struct archive_string buf;
Packit Service 1d0348
	int first;
Packit Service 1d0348
	uint64_t entry_bytes_remaining;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Set global value.
Packit Service 1d0348
	 */
Packit Service 1d0348
	struct {
Packit Service 1d0348
		int		processing;
Packit Service 1d0348
		mode_t		type;
Packit Service 1d0348
		int		keys;
Packit Service 1d0348
		int64_t		uid;
Packit Service 1d0348
		int64_t		gid;
Packit Service 1d0348
		mode_t		mode;
Packit Service 1d0348
		unsigned long	fflags_set;
Packit Service 1d0348
		unsigned long	fflags_clear;
Packit Service 1d0348
	} set;
Packit Service 1d0348
	struct att_counter_set	acs;
Packit Service 1d0348
	int classic;
Packit Service 1d0348
	int depth;
Packit Service 1d0348
Packit Service 1d0348
	/* check sum */
Packit Service 1d0348
	int compute_sum;
Packit Service 1d0348
	uint32_t crc;
Packit Service 1d0348
	uint64_t crc_len;
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	archive_md5_ctx md5ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	archive_rmd160_ctx rmd160ctx;
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
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	archive_sha256_ctx sha256ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	archive_sha384_ctx sha384ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	archive_sha512_ctx sha512ctx;
Packit Service 1d0348
#endif
Packit Service 1d0348
	/* Keyword options */
Packit Service 1d0348
	int keys;
Packit Service 1d0348
#define	F_CKSUM		0x00000001		/* check sum */
Packit Service 1d0348
#define	F_DEV		0x00000002		/* device type */
Packit Service 1d0348
#define	F_DONE		0x00000004		/* directory done */
Packit Service 1d0348
#define	F_FLAGS		0x00000008		/* file flags */
Packit Service 1d0348
#define	F_GID		0x00000010		/* gid */
Packit Service 1d0348
#define	F_GNAME		0x00000020		/* group name */
Packit Service 1d0348
#define	F_IGN		0x00000040		/* ignore */
Packit Service 1d0348
#define	F_MAGIC		0x00000080		/* name has magic chars */
Packit Service 1d0348
#define	F_MD5		0x00000100		/* MD5 digest */
Packit Service 1d0348
#define	F_MODE		0x00000200		/* mode */
Packit Service 1d0348
#define	F_NLINK		0x00000400		/* number of links */
Packit Service 1d0348
#define	F_NOCHANGE 	0x00000800		/* If owner/mode "wrong", do
Packit Service 1d0348
						 * not change */
Packit Service 1d0348
#define	F_OPT		0x00001000		/* existence optional */
Packit Service 1d0348
#define	F_RMD160 	0x00002000		/* RIPEMD160 digest */
Packit Service 1d0348
#define	F_SHA1		0x00004000		/* SHA-1 digest */
Packit Service 1d0348
#define	F_SIZE		0x00008000		/* size */
Packit Service 1d0348
#define	F_SLINK		0x00010000		/* symbolic link */
Packit Service 1d0348
#define	F_TAGS		0x00020000		/* tags */
Packit Service 1d0348
#define	F_TIME		0x00040000		/* modification time */
Packit Service 1d0348
#define	F_TYPE		0x00080000		/* file type */
Packit Service 1d0348
#define	F_UID		0x00100000		/* uid */
Packit Service 1d0348
#define	F_UNAME		0x00200000		/* user name */
Packit Service 1d0348
#define	F_VISIT		0x00400000		/* file visited */
Packit Service 1d0348
#define	F_SHA256	0x00800000		/* SHA-256 digest */
Packit Service 1d0348
#define	F_SHA384	0x01000000		/* SHA-384 digest */
Packit Service 1d0348
#define	F_SHA512	0x02000000		/* SHA-512 digest */
Packit Service 1d0348
#define	F_INO		0x04000000		/* inode number */
Packit Service 1d0348
#define	F_RESDEV	0x08000000		/* device ID on which the
Packit Service 1d0348
						 * entry resides */
Packit Service 1d0348
Packit Service 1d0348
	/* Options */
Packit Service 1d0348
	int dironly;		/* If it is set, ignore all files except
Packit Service 1d0348
				 * directory files, like mtree(8) -d option. */
Packit Service 1d0348
	int indent;		/* If it is set, indent output data. */
Packit Service 1d0348
	int output_global_set;	/* If it is set, use /set keyword to set
Packit Service 1d0348
				 * global values. When generating mtree
Packit Service 1d0348
				 * classic format, it is set by default. */
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
#define DEFAULT_KEYS	(F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
Packit Service 1d0348
			 | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
Packit Service 1d0348
			 | F_UNAME)
Packit Service 1d0348
#define attr_counter_set_reset	attr_counter_set_free
Packit Service 1d0348
Packit Service 1d0348
static void attr_counter_free(struct attr_counter **);
Packit Service 1d0348
static int attr_counter_inc(struct attr_counter **, struct attr_counter *,
Packit Service 1d0348
	struct attr_counter *, struct mtree_entry *);
Packit Service 1d0348
static struct attr_counter * attr_counter_new(struct mtree_entry *,
Packit Service 1d0348
	struct attr_counter *);
Packit Service 1d0348
static int attr_counter_set_collect(struct mtree_writer *,
Packit Service 1d0348
	struct mtree_entry *);
Packit Service 1d0348
static void attr_counter_set_free(struct mtree_writer *);
Packit Service 1d0348
static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);
Packit Service 1d0348
static int mtree_entry_add_child_tail(struct mtree_entry *,
Packit Service 1d0348
	struct mtree_entry *);
Packit Service 1d0348
static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,
Packit Service 1d0348
	struct mtree_entry **);
Packit Service 1d0348
static int mtree_entry_cmp_node(const struct archive_rb_node *,
Packit Service 1d0348
	const struct archive_rb_node *);
Packit Service 1d0348
static int mtree_entry_cmp_key(const struct archive_rb_node *, const void *);
Packit Service 1d0348
static int mtree_entry_exchange_same_entry(struct archive_write *,
Packit Service 1d0348
    struct mtree_entry *, struct mtree_entry *);
Packit Service 1d0348
static void mtree_entry_free(struct mtree_entry *);
Packit Service 1d0348
static int mtree_entry_new(struct archive_write *, struct archive_entry *,
Packit Service 1d0348
	struct mtree_entry **);
Packit Service 1d0348
static void mtree_entry_register_free(struct mtree_writer *);
Packit Service 1d0348
static void mtree_entry_register_init(struct mtree_writer *);
Packit Service 1d0348
static int mtree_entry_setup_filenames(struct archive_write *,
Packit Service 1d0348
	struct mtree_entry *, struct archive_entry *);
Packit Service 1d0348
static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);
Packit Service 1d0348
static void sum_init(struct mtree_writer *);
Packit Service 1d0348
static void sum_update(struct mtree_writer *, const void *, size_t);
Packit Service 1d0348
static void sum_final(struct mtree_writer *, struct reg_info *);
Packit Service 1d0348
static void sum_write(struct archive_string *, struct reg_info *);
Packit Service 1d0348
static int write_mtree_entry(struct archive_write *, struct mtree_entry *);
Packit Service 1d0348
static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);
Packit Service 1d0348
Packit Service 1d0348
#define	COMPUTE_CRC(var, ch)	(var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
Packit Service 1d0348
static const uint32_t crctab[] = {
Packit Service 1d0348
	0x0,
Packit Service 1d0348
	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
Packit Service 1d0348
	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
Packit Service 1d0348
	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
Packit Service 1d0348
	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
Packit Service 1d0348
	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
Packit Service 1d0348
	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
Packit Service 1d0348
	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
Packit Service 1d0348
	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
Packit Service 1d0348
	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
Packit Service 1d0348
	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
Packit Service 1d0348
	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
Packit Service 1d0348
	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
Packit Service 1d0348
	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
Packit Service 1d0348
	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
Packit Service 1d0348
	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
Packit Service 1d0348
	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
Packit Service 1d0348
	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
Packit Service 1d0348
	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
Packit Service 1d0348
	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
Packit Service 1d0348
	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
Packit Service 1d0348
	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
Packit Service 1d0348
	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
Packit Service 1d0348
	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
Packit Service 1d0348
	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
Packit Service 1d0348
	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
Packit Service 1d0348
	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
Packit Service 1d0348
	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
Packit Service 1d0348
	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
Packit Service 1d0348
	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
Packit Service 1d0348
	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
Packit Service 1d0348
	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
Packit Service 1d0348
	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
Packit Service 1d0348
	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
Packit Service 1d0348
	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
Packit Service 1d0348
	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
Packit Service 1d0348
	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
Packit Service 1d0348
	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
Packit Service 1d0348
	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
Packit Service 1d0348
	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
Packit Service 1d0348
	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
Packit Service 1d0348
	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
Packit Service 1d0348
	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
Packit Service 1d0348
	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
Packit Service 1d0348
	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
Packit Service 1d0348
	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
Packit Service 1d0348
	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
Packit Service 1d0348
	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
Packit Service 1d0348
	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
Packit Service 1d0348
	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
Packit Service 1d0348
	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
Packit Service 1d0348
	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static const unsigned char safe_char[256] = {
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
Packit Service 1d0348
	/* !"$%&'()*+,-./  EXCLUSION:0x20( ) 0x23(#) */
Packit Service 1d0348
	0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
Packit Service 1d0348
	/* 0123456789:;<>?  EXCLUSION:0x3d(=) */
Packit Service 1d0348
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
Packit Service 1d0348
	/* @ABCDEFGHIJKLMNO */
Packit Service 1d0348
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
Packit Service 1d0348
	/* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\)  */
Packit Service 1d0348
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */
Packit Service 1d0348
	/* `abcdefghijklmno */
Packit Service 1d0348
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
Packit Service 1d0348
	/* pqrstuvwxyz{|}~ */
Packit Service 1d0348
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
Packit Service 1d0348
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_quote(struct archive_string *s, const char *str)
Packit Service 1d0348
{
Packit Service 1d0348
	const char *start;
Packit Service 1d0348
	char buf[4];
Packit Service 1d0348
	unsigned char c;
Packit Service 1d0348
Packit Service 1d0348
	for (start = str; *str != '\0'; ++str) {
Packit Service 1d0348
		if (safe_char[*(const unsigned char *)str])
Packit Service 1d0348
			continue;
Packit Service 1d0348
		if (start != str)
Packit Service 1d0348
			archive_strncat(s, start, str - start);
Packit Service 1d0348
		c = (unsigned char)*str;
Packit Service 1d0348
		buf[0] = '\\';
Packit Service 1d0348
		buf[1] = (c / 64) + '0';
Packit Service 1d0348
		buf[2] = (c / 8 % 8) + '0';
Packit Service 1d0348
		buf[3] = (c % 8) + '0';
Packit Service 1d0348
		archive_strncat(s, buf, 4);
Packit Service 1d0348
		start = str + 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (start != str)
Packit Service 1d0348
		archive_strncat(s, start, str - start);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Indent a line as mtree utility to be readable for people.
Packit Service 1d0348
 */
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_indent(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
	int i, fn, nd, pd;
Packit Service 1d0348
	const char *r, *s, *x;
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->classic) {
Packit Service 1d0348
		if (mtree->indent) {
Packit Service 1d0348
			nd = 0;
Packit Service 1d0348
			pd = mtree->depth * 4;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			nd = mtree->depth?4:0;
Packit Service 1d0348
			pd = 0;
Packit Service 1d0348
		}
Packit Service 1d0348
	} else
Packit Service 1d0348
		nd = pd = 0;
Packit Service 1d0348
	fn = 1;
Packit Service 1d0348
	s = r = mtree->ebuf.s;
Packit Service 1d0348
	x = NULL;
Packit Service 1d0348
	while (*r == ' ')
Packit Service 1d0348
		r++;
Packit Service 1d0348
	while ((r = strchr(r, ' ')) != NULL) {
Packit Service 1d0348
		if (fn) {
Packit Service 1d0348
			fn = 0;
Packit Service 1d0348
			for (i = 0; i < nd + pd; i++)
Packit Service 1d0348
				archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
			archive_strncat(&mtree->buf, s, r - s);
Packit Service 1d0348
			if (nd + (r -s) > INDENTNAMELEN) {
Packit Service 1d0348
				archive_strncat(&mtree->buf, " \\\n", 3);
Packit Service 1d0348
				for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
Packit Service 1d0348
					archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
			} else {
Packit Service 1d0348
				for (i = (int)(r -s + nd);
Packit Service 1d0348
				    i < (INDENTNAMELEN + 1); i++)
Packit Service 1d0348
					archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
			}
Packit Service 1d0348
			s = ++r;
Packit Service 1d0348
			x = NULL;
Packit Service 1d0348
			continue;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN)
Packit Service 1d0348
			x = r++;
Packit Service 1d0348
		else {
Packit Service 1d0348
			if (x == NULL)
Packit Service 1d0348
				x = r;
Packit Service 1d0348
			archive_strncat(&mtree->buf, s, x - s);
Packit Service 1d0348
			archive_strncat(&mtree->buf, " \\\n", 3);
Packit Service 1d0348
			for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
Packit Service 1d0348
				archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
			s = r = ++x;
Packit Service 1d0348
			x = NULL;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (fn) {
Packit Service 1d0348
		for (i = 0; i < nd + pd; i++)
Packit Service 1d0348
			archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
		archive_strcat(&mtree->buf, s);
Packit Service 1d0348
		s += strlen(s);
Packit Service 1d0348
	}
Packit Service 1d0348
	if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
Packit Service 1d0348
		/* Last keyword is longer. */
Packit Service 1d0348
		archive_strncat(&mtree->buf, s, x - s);
Packit Service 1d0348
		archive_strncat(&mtree->buf, " \\\n", 3);
Packit Service 1d0348
		for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
Packit Service 1d0348
			archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
		s = ++x;
Packit Service 1d0348
	}
Packit Service 1d0348
	archive_strcat(&mtree->buf, s);
Packit Service 1d0348
	archive_string_empty(&mtree->ebuf);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Write /set keyword.
Packit Service 1d0348
 * Set most used value of uid,gid,mode and fflags, which are
Packit Service 1d0348
 * collected by attr_counter_set_collect() function.
Packit Service 1d0348
 */
Packit Service 1d0348
static void
Packit Service 1d0348
write_global(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_string setstr;
Packit Service 1d0348
	struct archive_string unsetstr;
Packit Service 1d0348
	struct att_counter_set *acs;
Packit Service 1d0348
	int keys, oldkeys, effkeys;
Packit Service 1d0348
Packit Service 1d0348
	archive_string_init(&setstr);
Packit Service 1d0348
	archive_string_init(&unsetstr);
Packit Service 1d0348
	keys = mtree->keys & SET_KEYS;
Packit Service 1d0348
	oldkeys = mtree->set.keys;
Packit Service 1d0348
	effkeys = keys;
Packit Service 1d0348
	acs = &mtree->acs;
Packit Service 1d0348
	if (mtree->set.processing) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Check if the global data needs updating.
Packit Service 1d0348
		 */
Packit Service 1d0348
		effkeys &= ~F_TYPE;
Packit Service 1d0348
		if (acs->uid_list == NULL)
Packit Service 1d0348
			effkeys &= ~(F_UNAME | F_UID);
Packit Service 1d0348
		else if (oldkeys & (F_UNAME | F_UID)) {
Packit Service 1d0348
			if (acs->uid_list->count < 2 ||
Packit Service 1d0348
			    mtree->set.uid == acs->uid_list->m_entry->uid)
Packit Service 1d0348
				effkeys &= ~(F_UNAME | F_UID);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (acs->gid_list == NULL)
Packit Service 1d0348
			effkeys &= ~(F_GNAME | F_GID);
Packit Service 1d0348
		else if (oldkeys & (F_GNAME | F_GID)) {
Packit Service 1d0348
			if (acs->gid_list->count < 2 ||
Packit Service 1d0348
			    mtree->set.gid == acs->gid_list->m_entry->gid)
Packit Service 1d0348
				effkeys &= ~(F_GNAME | F_GID);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (acs->mode_list == NULL)
Packit Service 1d0348
			effkeys &= ~F_MODE;
Packit Service 1d0348
		else if (oldkeys & F_MODE) {
Packit Service 1d0348
			if (acs->mode_list->count < 2 ||
Packit Service 1d0348
			    mtree->set.mode == acs->mode_list->m_entry->mode)
Packit Service 1d0348
				effkeys &= ~F_MODE;
Packit Service 1d0348
		}
Packit Service 1d0348
		if (acs->flags_list == NULL)
Packit Service 1d0348
			effkeys &= ~F_FLAGS;
Packit Service 1d0348
		else if ((oldkeys & F_FLAGS) != 0) {
Packit Service 1d0348
			if (acs->flags_list->count < 2 ||
Packit Service 1d0348
			    (acs->flags_list->m_entry->fflags_set ==
Packit Service 1d0348
				mtree->set.fflags_set &&
Packit Service 1d0348
			     acs->flags_list->m_entry->fflags_clear ==
Packit Service 1d0348
				mtree->set.fflags_clear))
Packit Service 1d0348
				effkeys &= ~F_FLAGS;
Packit Service 1d0348
		}
Packit Service 1d0348
	} else {
Packit Service 1d0348
		if (acs->uid_list == NULL)
Packit Service 1d0348
			keys &= ~(F_UNAME | F_UID);
Packit Service 1d0348
		if (acs->gid_list == NULL)
Packit Service 1d0348
			keys &= ~(F_GNAME | F_GID);
Packit Service 1d0348
		if (acs->mode_list == NULL)
Packit Service 1d0348
			keys &= ~F_MODE;
Packit Service 1d0348
		if (acs->flags_list == NULL)
Packit Service 1d0348
			keys &= ~F_FLAGS;
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_TYPE) != 0) {
Packit Service 1d0348
		if (mtree->dironly) {
Packit Service 1d0348
			archive_strcat(&setstr, " type=dir");
Packit Service 1d0348
			mtree->set.type = AE_IFDIR;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			archive_strcat(&setstr, " type=file");
Packit Service 1d0348
			mtree->set.type = AE_IFREG;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_UNAME) != 0) {
Packit Service 1d0348
		if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) {
Packit Service 1d0348
			archive_strcat(&setstr, " uname=");
Packit Service 1d0348
			mtree_quote(&setstr, acs->uid_list->m_entry->uname.s);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			keys &= ~F_UNAME;
Packit Service 1d0348
			if ((oldkeys & F_UNAME) != 0)
Packit Service 1d0348
				archive_strcat(&unsetstr, " uname");
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_UID) != 0) {
Packit Service 1d0348
		mtree->set.uid = acs->uid_list->m_entry->uid;
Packit Service 1d0348
		archive_string_sprintf(&setstr, " uid=%jd",
Packit Service 1d0348
		    (intmax_t)mtree->set.uid);
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_GNAME) != 0) {
Packit Service 1d0348
		if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) {
Packit Service 1d0348
			archive_strcat(&setstr, " gname=");
Packit Service 1d0348
			mtree_quote(&setstr, acs->gid_list->m_entry->gname.s);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			keys &= ~F_GNAME;
Packit Service 1d0348
			if ((oldkeys & F_GNAME) != 0)
Packit Service 1d0348
				archive_strcat(&unsetstr, " gname");
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_GID) != 0) {
Packit Service 1d0348
		mtree->set.gid = acs->gid_list->m_entry->gid;
Packit Service 1d0348
		archive_string_sprintf(&setstr, " gid=%jd",
Packit Service 1d0348
		    (intmax_t)mtree->set.gid);
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_MODE) != 0) {
Packit Service 1d0348
		mtree->set.mode = acs->mode_list->m_entry->mode;
Packit Service 1d0348
		archive_string_sprintf(&setstr, " mode=%o",
Packit Service 1d0348
		    (unsigned int)mtree->set.mode);
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & effkeys & F_FLAGS) != 0) {
Packit Service 1d0348
		if (archive_strlen(
Packit Service 1d0348
		    &(acs->flags_list->m_entry->fflags_text)) > 0) {
Packit Service 1d0348
			archive_strcat(&setstr, " flags=");
Packit Service 1d0348
			mtree_quote(&setstr,
Packit Service 1d0348
			    acs->flags_list->m_entry->fflags_text.s);
Packit Service 1d0348
			mtree->set.fflags_set =
Packit Service 1d0348
			    acs->flags_list->m_entry->fflags_set;
Packit Service 1d0348
			mtree->set.fflags_clear =
Packit Service 1d0348
			    acs->flags_list->m_entry->fflags_clear;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			keys &= ~F_FLAGS;
Packit Service 1d0348
			if ((oldkeys & F_FLAGS) != 0)
Packit Service 1d0348
				archive_strcat(&unsetstr, " flags");
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (unsetstr.length > 0)
Packit Service 1d0348
		archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);
Packit Service 1d0348
	archive_string_free(&unsetstr);
Packit Service 1d0348
	if (setstr.length > 0)
Packit Service 1d0348
		archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
Packit Service 1d0348
	archive_string_free(&setstr);
Packit Service 1d0348
	mtree->set.keys = keys;
Packit Service 1d0348
	mtree->set.processing = 1;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static struct attr_counter *
Packit Service 1d0348
attr_counter_new(struct mtree_entry *me, struct attr_counter *prev)
Packit Service 1d0348
{
Packit Service 1d0348
	struct attr_counter *ac;
Packit Service 1d0348
Packit Service 1d0348
	ac = malloc(sizeof(*ac));
Packit Service 1d0348
	if (ac != NULL) {
Packit Service 1d0348
		ac->prev = prev;
Packit Service 1d0348
		ac->next = NULL;
Packit Service 1d0348
		ac->count = 1;
Packit Service 1d0348
		ac->m_entry = me;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (ac);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
attr_counter_free(struct attr_counter **top)
Packit Service 1d0348
{
Packit Service 1d0348
	struct attr_counter *ac, *tac;
Packit Service 1d0348
Packit Service 1d0348
	if (*top == NULL)
Packit Service 1d0348
		return;
Packit Service 1d0348
	ac = *top;
Packit Service 1d0348
        while (ac != NULL) {
Packit Service 1d0348
		tac = ac->next;
Packit Service 1d0348
		free(ac);
Packit Service 1d0348
		ac = tac;
Packit Service 1d0348
	}
Packit Service 1d0348
	*top = NULL;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
Packit Service 1d0348
    struct attr_counter *last, struct mtree_entry *me)
Packit Service 1d0348
{
Packit Service 1d0348
	struct attr_counter *pac;
Packit Service 1d0348
Packit Service 1d0348
	if (ac != NULL) {
Packit Service 1d0348
		ac->count++;
Packit Service 1d0348
		if (*top == ac || ac->prev->count >= ac->count)
Packit Service 1d0348
			return (0);
Packit Service 1d0348
		for (pac = ac->prev; pac; pac = pac->prev) {
Packit Service 1d0348
			if (pac->count >= ac->count)
Packit Service 1d0348
				break;
Packit Service 1d0348
		}
Packit Service 1d0348
		ac->prev->next = ac->next;
Packit Service 1d0348
		if (ac->next != NULL)
Packit Service 1d0348
			ac->next->prev = ac->prev;
Packit Service 1d0348
		if (pac != NULL) {
Packit Service 1d0348
			ac->prev = pac;
Packit Service 1d0348
			ac->next = pac->next;
Packit Service 1d0348
			pac->next = ac;
Packit Service 1d0348
			if (ac->next != NULL)
Packit Service 1d0348
				ac->next->prev = ac;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			ac->prev = NULL;
Packit Service 1d0348
			ac->next = *top;
Packit Service 1d0348
			*top = ac;
Packit Service 1d0348
			ac->next->prev = ac;
Packit Service 1d0348
		}
Packit Service 1d0348
	} else if (last != NULL) {
Packit Service 1d0348
		ac = attr_counter_new(me, last);
Packit Service 1d0348
		if (ac == NULL)
Packit Service 1d0348
			return (-1);
Packit Service 1d0348
		last->next = ac;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (0);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Tabulate uid,gid,mode and fflags of a entry in order to be used for /set.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)
Packit Service 1d0348
{
Packit Service 1d0348
	struct attr_counter *ac, *last;
Packit Service 1d0348
	struct att_counter_set *acs = &mtree->acs;
Packit Service 1d0348
	int keys = mtree->keys;
Packit Service 1d0348
Packit Service 1d0348
	if (keys & (F_UNAME | F_UID)) {
Packit Service 1d0348
		if (acs->uid_list == NULL) {
Packit Service 1d0348
			acs->uid_list = attr_counter_new(me, NULL);
Packit Service 1d0348
			if (acs->uid_list == NULL)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			last = NULL;
Packit Service 1d0348
			for (ac = acs->uid_list; ac; ac = ac->next) {
Packit Service 1d0348
				if (ac->m_entry->uid == me->uid)
Packit Service 1d0348
					break;
Packit Service 1d0348
				last = ac;
Packit Service 1d0348
			}
Packit Service 1d0348
			if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (keys & (F_GNAME | F_GID)) {
Packit Service 1d0348
		if (acs->gid_list == NULL) {
Packit Service 1d0348
			acs->gid_list = attr_counter_new(me, NULL);
Packit Service 1d0348
			if (acs->gid_list == NULL)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			last = NULL;
Packit Service 1d0348
			for (ac = acs->gid_list; ac; ac = ac->next) {
Packit Service 1d0348
				if (ac->m_entry->gid == me->gid)
Packit Service 1d0348
					break;
Packit Service 1d0348
				last = ac;
Packit Service 1d0348
			}
Packit Service 1d0348
			if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (keys & F_MODE) {
Packit Service 1d0348
		if (acs->mode_list == NULL) {
Packit Service 1d0348
			acs->mode_list = attr_counter_new(me, NULL);
Packit Service 1d0348
			if (acs->mode_list == NULL)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			last = NULL;
Packit Service 1d0348
			for (ac = acs->mode_list; ac; ac = ac->next) {
Packit Service 1d0348
				if (ac->m_entry->mode == me->mode)
Packit Service 1d0348
					break;
Packit Service 1d0348
				last = ac;
Packit Service 1d0348
			}
Packit Service 1d0348
			if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (keys & F_FLAGS) {
Packit Service 1d0348
		if (acs->flags_list == NULL) {
Packit Service 1d0348
			acs->flags_list = attr_counter_new(me, NULL);
Packit Service 1d0348
			if (acs->flags_list == NULL)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			last = NULL;
Packit Service 1d0348
			for (ac = acs->flags_list; ac; ac = ac->next) {
Packit Service 1d0348
				if (ac->m_entry->fflags_set == me->fflags_set &&
Packit Service 1d0348
				    ac->m_entry->fflags_clear ==
Packit Service 1d0348
							me->fflags_clear)
Packit Service 1d0348
					break;
Packit Service 1d0348
				last = ac;
Packit Service 1d0348
			}
Packit Service 1d0348
			if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0)
Packit Service 1d0348
				return (-1);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return (0);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
attr_counter_set_free(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
	struct att_counter_set *acs = &mtree->acs;
Packit Service 1d0348
Packit Service 1d0348
	attr_counter_free(&acs->uid_list);
Packit Service 1d0348
	attr_counter_free(&acs->gid_list);
Packit Service 1d0348
	attr_counter_free(&acs->mode_list);
Packit Service 1d0348
	attr_counter_free(&acs->flags_list);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)
Packit Service 1d0348
{
Packit Service 1d0348
	int keys;
Packit Service 1d0348
Packit Service 1d0348
	keys = mtree->keys;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * If a keyword has been set by /set, we do not need to
Packit Service 1d0348
	 * output it.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (mtree->set.keys == 0)
Packit Service 1d0348
		return (keys);/* /set is not used. */
Packit Service 1d0348
Packit Service 1d0348
	if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&
Packit Service 1d0348
	     mtree->set.gid == me->gid)
Packit Service 1d0348
		keys &= ~(F_GNAME | F_GID);
Packit Service 1d0348
	if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&
Packit Service 1d0348
	     mtree->set.uid == me->uid)
Packit Service 1d0348
		keys &= ~(F_UNAME | F_UID);
Packit Service 1d0348
	if (mtree->set.keys & F_FLAGS) {
Packit Service 1d0348
		if (mtree->set.fflags_set == me->fflags_set &&
Packit Service 1d0348
		    mtree->set.fflags_clear == me->fflags_clear)
Packit Service 1d0348
			keys &= ~F_FLAGS;
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode)
Packit Service 1d0348
		keys &= ~F_MODE;
Packit Service 1d0348
Packit Service 1d0348
	switch (me->filetype) {
Packit Service 1d0348
	case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
Packit Service 1d0348
	case AE_IFBLK: case AE_IFIFO:
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFDIR:
Packit Service 1d0348
		if ((mtree->set.keys & F_TYPE) != 0 &&
Packit Service 1d0348
		    mtree->set.type == AE_IFDIR)
Packit Service 1d0348
			keys &= ~F_TYPE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFREG:
Packit Service 1d0348
	default:	/* Handle unknown file types as regular files. */
Packit Service 1d0348
		if ((mtree->set.keys & F_TYPE) != 0 &&
Packit Service 1d0348
		    mtree->set.type == AE_IFREG)
Packit Service 1d0348
			keys &= ~F_TYPE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return (keys);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
Packit Service 1d0348
    struct mtree_entry **m_entry)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_entry *me;
Packit Service 1d0348
	const char *s;
Packit Service 1d0348
	int r;
Packit Service 1d0348
	static const struct archive_rb_tree_ops rb_ops = {
Packit Service 1d0348
		mtree_entry_cmp_node, mtree_entry_cmp_key
Packit Service 1d0348
	};
Packit Service 1d0348
Packit Service 1d0348
	me = calloc(1, sizeof(*me));
Packit Service 1d0348
	if (me == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate memory for a mtree entry");
Packit Service 1d0348
		*m_entry = NULL;
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	r = mtree_entry_setup_filenames(a, me, entry);
Packit Service 1d0348
	if (r < ARCHIVE_WARN) {
Packit Service 1d0348
		mtree_entry_free(me);
Packit Service 1d0348
		*m_entry = NULL;
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if ((s = archive_entry_symlink(entry)) != NULL)
Packit Service 1d0348
		archive_strcpy(&me->symlink, s);
Packit Service 1d0348
	me->nlink = archive_entry_nlink(entry);
Packit Service 1d0348
	me->filetype = archive_entry_filetype(entry);
Packit Service 1d0348
	me->mode = archive_entry_mode(entry) & 07777;
Packit Service 1d0348
	me->uid = archive_entry_uid(entry);
Packit Service 1d0348
	me->gid = archive_entry_gid(entry);
Packit Service 1d0348
	if ((s = archive_entry_uname(entry)) != NULL)
Packit Service 1d0348
		archive_strcpy(&me->uname, s);
Packit Service 1d0348
	if ((s = archive_entry_gname(entry)) != NULL)
Packit Service 1d0348
		archive_strcpy(&me->gname, s);
Packit Service 1d0348
	if ((s = archive_entry_fflags_text(entry)) != NULL)
Packit Service 1d0348
		archive_strcpy(&me->fflags_text, s);
Packit Service 1d0348
	archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
Packit Service 1d0348
	me->mtime = archive_entry_mtime(entry);
Packit Service 1d0348
	me->mtime_nsec = archive_entry_mtime_nsec(entry);
Packit Service 1d0348
	me->rdevmajor = archive_entry_rdevmajor(entry);
Packit Service 1d0348
	me->rdevminor = archive_entry_rdevminor(entry);
Packit Service 1d0348
	me->devmajor = archive_entry_devmajor(entry);
Packit Service 1d0348
	me->devminor = archive_entry_devminor(entry);
Packit Service 1d0348
	me->ino = archive_entry_ino(entry);
Packit Service 1d0348
	me->size = archive_entry_size(entry);
Packit Service 1d0348
	if (me->filetype == AE_IFDIR) {
Packit Service 1d0348
		me->dir_info = calloc(1, sizeof(*me->dir_info));
Packit Service 1d0348
		if (me->dir_info == NULL) {
Packit Service 1d0348
			mtree_entry_free(me);
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for a mtree entry");
Packit Service 1d0348
			*m_entry = NULL;
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		__archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops);
Packit Service 1d0348
		me->dir_info->children.first = NULL;
Packit Service 1d0348
		me->dir_info->children.last = &(me->dir_info->children.first);
Packit Service 1d0348
		me->dir_info->chnext = NULL;
Packit Service 1d0348
	} else if (me->filetype == AE_IFREG) {
Packit Service 1d0348
		me->reg_info = calloc(1, sizeof(*me->reg_info));
Packit Service 1d0348
		if (me->reg_info == NULL) {
Packit Service 1d0348
			mtree_entry_free(me);
Packit Service 1d0348
			archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
			    "Can't allocate memory for a mtree entry");
Packit Service 1d0348
			*m_entry = NULL;
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		me->reg_info->compute_sum = 0;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	*m_entry = me;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_entry_free(struct mtree_entry *me)
Packit Service 1d0348
{
Packit Service 1d0348
	archive_string_free(&me->parentdir);
Packit Service 1d0348
	archive_string_free(&me->basename);
Packit Service 1d0348
	archive_string_free(&me->pathname);
Packit Service 1d0348
	archive_string_free(&me->symlink);
Packit Service 1d0348
	archive_string_free(&me->uname);
Packit Service 1d0348
	archive_string_free(&me->gname);
Packit Service 1d0348
	archive_string_free(&me->fflags_text);
Packit Service 1d0348
	free(me->dir_info);
Packit Service 1d0348
	free(me->reg_info);
Packit Service 1d0348
	free(me);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_mtree_header(struct archive_write *a,
Packit Service 1d0348
    struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree= a->format_data;
Packit Service 1d0348
	struct mtree_entry *mtree_entry;
Packit Service 1d0348
	int r, r2;
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->first) {
Packit Service 1d0348
		mtree->first = 0;
Packit Service 1d0348
		archive_strcat(&mtree->buf, "#mtree\n");
Packit Service 1d0348
		if ((mtree->keys & SET_KEYS) == 0)
Packit Service 1d0348
			mtree->output_global_set = 0;/* Disabled. */
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	mtree->entry_bytes_remaining = archive_entry_size(entry);
Packit Service 1d0348
Packit Service 1d0348
	/* While directory only mode, we do not handle non directory files. */
Packit Service 1d0348
	if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	r2 = mtree_entry_new(a, entry, &mtree_entry);
Packit Service 1d0348
	if (r2 < ARCHIVE_WARN)
Packit Service 1d0348
		return (r2);
Packit Service 1d0348
	r = mtree_entry_tree_add(a, &mtree_entry);
Packit Service 1d0348
	if (r < ARCHIVE_WARN) {
Packit Service 1d0348
		mtree_entry_free(mtree_entry);
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	}
Packit Service 1d0348
	mtree->mtree_entry = mtree_entry;
Packit Service 1d0348
Packit Service 1d0348
	/* If the current file is a regular file, we have to
Packit Service 1d0348
	 * compute the sum of its content.
Packit Service 1d0348
	 * Initialize a bunch of sum check context. */
Packit Service 1d0348
	if (mtree_entry->reg_info)
Packit Service 1d0348
		sum_init(mtree);
Packit Service 1d0348
Packit Service 1d0348
	return (r2);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree = a->format_data;
Packit Service 1d0348
	struct archive_string *str;
Packit Service 1d0348
	int keys, ret;
Packit Service 1d0348
Packit Service 1d0348
	if (me->dir_info) {
Packit Service 1d0348
		if (mtree->classic) {
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * Output a comment line to describe the full
Packit Service 1d0348
			 * pathname of the entry as mtree utility does
Packit Service 1d0348
			 * while generating classic format.
Packit Service 1d0348
			 */
Packit Service 1d0348
			if (!mtree->dironly)
Packit Service 1d0348
				archive_strappend_char(&mtree->buf, '\n');
Packit Service 1d0348
			if (me->parentdir.s)
Packit Service 1d0348
				archive_string_sprintf(&mtree->buf,
Packit Service 1d0348
				    "# %s/%s\n",
Packit Service 1d0348
				    me->parentdir.s, me->basename.s);
Packit Service 1d0348
			else
Packit Service 1d0348
				archive_string_sprintf(&mtree->buf,
Packit Service 1d0348
				    "# %s\n",
Packit Service 1d0348
				    me->basename.s);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (mtree->output_global_set)
Packit Service 1d0348
			write_global(mtree);
Packit Service 1d0348
	}
Packit Service 1d0348
	archive_string_empty(&mtree->ebuf);
Packit Service 1d0348
	str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf;
Packit Service 1d0348
Packit Service 1d0348
	if (!mtree->classic && me->parentdir.s) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * If generating format is not classic one(v1), output
Packit Service 1d0348
		 * a full pathname.
Packit Service 1d0348
		 */
Packit Service 1d0348
		mtree_quote(str, me->parentdir.s);
Packit Service 1d0348
		archive_strappend_char(str, '/');
Packit Service 1d0348
	}
Packit Service 1d0348
	mtree_quote(str, me->basename.s);
Packit Service 1d0348
Packit Service 1d0348
	keys = get_global_set_keys(mtree, me);
Packit Service 1d0348
	if ((keys & F_NLINK) != 0 &&
Packit Service 1d0348
	    me->nlink != 1 && me->filetype != AE_IFDIR)
Packit Service 1d0348
		archive_string_sprintf(str, " nlink=%u", me->nlink);
Packit Service 1d0348
Packit Service 1d0348
	if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) {
Packit Service 1d0348
		archive_strcat(str, " gname=");
Packit Service 1d0348
		mtree_quote(str, me->gname.s);
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) {
Packit Service 1d0348
		archive_strcat(str, " uname=");
Packit Service 1d0348
		mtree_quote(str, me->uname.s);
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & F_FLAGS) != 0) {
Packit Service 1d0348
		if (archive_strlen(&me->fflags_text) > 0) {
Packit Service 1d0348
			archive_strcat(str, " flags=");
Packit Service 1d0348
			mtree_quote(str, me->fflags_text.s);
Packit Service 1d0348
		} else if (mtree->set.processing &&
Packit Service 1d0348
		    (mtree->set.keys & F_FLAGS) != 0)
Packit Service 1d0348
			/* Overwrite the global parameter. */
Packit Service 1d0348
			archive_strcat(str, " flags=none");
Packit Service 1d0348
	}
Packit Service 1d0348
	if ((keys & F_TIME) != 0)
Packit Service 1d0348
		archive_string_sprintf(str, " time=%jd.%jd",
Packit Service 1d0348
		    (intmax_t)me->mtime, (intmax_t)me->mtime_nsec);
Packit Service 1d0348
	if ((keys & F_MODE) != 0)
Packit Service 1d0348
		archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode);
Packit Service 1d0348
	if ((keys & F_GID) != 0)
Packit Service 1d0348
		archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid);
Packit Service 1d0348
	if ((keys & F_UID) != 0)
Packit Service 1d0348
		archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);
Packit Service 1d0348
Packit Service 1d0348
	if ((keys & F_INO) != 0)
Packit Service 1d0348
		archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino);
Packit Service 1d0348
	if ((keys & F_RESDEV) != 0) {
Packit Service 1d0348
		archive_string_sprintf(str,
Packit Service 1d0348
		    " resdevice=native,%ju,%ju",
Packit Service 1d0348
		    (uintmax_t)me->devmajor,
Packit Service 1d0348
		    (uintmax_t)me->devminor);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	switch (me->filetype) {
Packit Service 1d0348
	case AE_IFLNK:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=link");
Packit Service 1d0348
		if ((keys & F_SLINK) != 0) {
Packit Service 1d0348
			archive_strcat(str, " link=");
Packit Service 1d0348
			mtree_quote(str, me->symlink.s);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFSOCK:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=socket");
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFCHR:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=char");
Packit Service 1d0348
		if ((keys & F_DEV) != 0) {
Packit Service 1d0348
			archive_string_sprintf(str,
Packit Service 1d0348
			    " device=native,%ju,%ju",
Packit Service 1d0348
			    (uintmax_t)me->rdevmajor,
Packit Service 1d0348
			    (uintmax_t)me->rdevminor);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFBLK:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=block");
Packit Service 1d0348
		if ((keys & F_DEV) != 0) {
Packit Service 1d0348
			archive_string_sprintf(str,
Packit Service 1d0348
			    " device=native,%ju,%ju",
Packit Service 1d0348
			    (uintmax_t)me->rdevmajor,
Packit Service 1d0348
			    (uintmax_t)me->rdevminor);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFDIR:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=dir");
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFIFO:
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=fifo");
Packit Service 1d0348
		break;
Packit Service 1d0348
	case AE_IFREG:
Packit Service 1d0348
	default:	/* Handle unknown file types as regular files. */
Packit Service 1d0348
		if ((keys & F_TYPE) != 0)
Packit Service 1d0348
			archive_strcat(str, " type=file");
Packit Service 1d0348
		if ((keys & F_SIZE) != 0)
Packit Service 1d0348
			archive_string_sprintf(str, " size=%jd",
Packit Service 1d0348
			    (intmax_t)me->size);
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Write a bunch of sum. */
Packit Service 1d0348
	if (me->reg_info)
Packit Service 1d0348
		sum_write(str, me->reg_info);
Packit Service 1d0348
Packit Service 1d0348
	archive_strappend_char(str, '\n');
Packit Service 1d0348
	if (mtree->indent || mtree->classic)
Packit Service 1d0348
		mtree_indent(mtree);
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->buf.length > 32768) {
Packit Service 1d0348
		ret = __archive_write_output(
Packit Service 1d0348
			a, mtree->buf.s, mtree->buf.length);
Packit Service 1d0348
		archive_string_empty(&mtree->buf);
Packit Service 1d0348
	} else
Packit Service 1d0348
		ret = ARCHIVE_OK;
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree = a->format_data;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	if (n->parentdir.s) {
Packit Service 1d0348
		if (mtree->indent) {
Packit Service 1d0348
			int i, pd = mtree->depth * 4;
Packit Service 1d0348
			for (i = 0; i < pd; i++)
Packit Service 1d0348
				archive_strappend_char(&mtree->buf, ' ');
Packit Service 1d0348
		}
Packit Service 1d0348
		archive_string_sprintf(&mtree->buf, "# %s/%s\n",
Packit Service 1d0348
			n->parentdir.s, n->basename.s);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->indent) {
Packit Service 1d0348
		archive_string_empty(&mtree->ebuf);
Packit Service 1d0348
		archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4);
Packit Service 1d0348
		mtree_indent(mtree);
Packit Service 1d0348
	} else
Packit Service 1d0348
		archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4);
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->buf.length > 32768) {
Packit Service 1d0348
		ret = __archive_write_output(
Packit Service 1d0348
			a, mtree->buf.s, mtree->buf.length);
Packit Service 1d0348
		archive_string_empty(&mtree->buf);
Packit Service 1d0348
	} else
Packit Service 1d0348
		ret = ARCHIVE_OK;
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Write mtree entries saved at attr_counter_set_collect() function.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
write_mtree_entry_tree(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree = a->format_data;
Packit Service 1d0348
	struct mtree_entry *np = mtree->root;
Packit Service 1d0348
	struct archive_rb_node *n;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	do {
Packit Service 1d0348
		if (mtree->output_global_set) {
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * Collect attribute information to know which value
Packit Service 1d0348
			 * is frequently used among the children.
Packit Service 1d0348
			 */
Packit Service 1d0348
			attr_counter_set_reset(mtree);
Packit Service 1d0348
			ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
Packit Service 1d0348
				struct mtree_entry *e = (struct mtree_entry *)n;
Packit Service 1d0348
				if (attr_counter_set_collect(mtree, e) < 0) {
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
			}
Packit Service 1d0348
		}
Packit Service 1d0348
		if (!np->dir_info->virtual || mtree->classic) {
Packit Service 1d0348
			ret = write_mtree_entry(a, np);
Packit Service 1d0348
			if (ret != ARCHIVE_OK)
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
		} else {
Packit Service 1d0348
			/* Whenever output_global_set is enabled
Packit Service 1d0348
			 * output global value(/set keywords)
Packit Service 1d0348
			 * even if the directory entry is not allowed
Packit Service 1d0348
			 * to be written because the global values
Packit Service 1d0348
			 * can be used for the children. */
Packit Service 1d0348
			if (mtree->output_global_set)
Packit Service 1d0348
				write_global(mtree);
Packit Service 1d0348
		}
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Output the attribute of all files except directory files.
Packit Service 1d0348
		 */
Packit Service 1d0348
		mtree->depth++;
Packit Service 1d0348
		ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
Packit Service 1d0348
			struct mtree_entry *e = (struct mtree_entry *)n;
Packit Service 1d0348
Packit Service 1d0348
			if (e->dir_info)
Packit Service 1d0348
				mtree_entry_add_child_tail(np, e);
Packit Service 1d0348
			else {
Packit Service 1d0348
				ret = write_mtree_entry(a, e);
Packit Service 1d0348
				if (ret != ARCHIVE_OK)
Packit Service 1d0348
					return (ARCHIVE_FATAL);
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
		mtree->depth--;
Packit Service 1d0348
Packit Service 1d0348
		if (np->dir_info->children.first != NULL) {
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * Descend the tree.
Packit Service 1d0348
			 */
Packit Service 1d0348
			np = np->dir_info->children.first;
Packit Service 1d0348
			if (mtree->indent)
Packit Service 1d0348
				mtree->depth++;
Packit Service 1d0348
			continue;
Packit Service 1d0348
		} else if (mtree->classic) {
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * While printing mtree classic, if there are not
Packit Service 1d0348
			 * any directory files(except "." and "..") in the
Packit Service 1d0348
			 * directory, output two dots ".." as returning
Packit Service 1d0348
			 * the parent directory.
Packit Service 1d0348
			 */
Packit Service 1d0348
			ret = write_dot_dot_entry(a, np);
Packit Service 1d0348
			if (ret != ARCHIVE_OK)
Packit Service 1d0348
				return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		while (np != np->parent) {
Packit Service 1d0348
			if (np->dir_info->chnext == NULL) {
Packit Service 1d0348
				/*
Packit Service 1d0348
				 * Ascend the tree; go back to the parent.
Packit Service 1d0348
				 */
Packit Service 1d0348
				if (mtree->indent)
Packit Service 1d0348
					mtree->depth--;
Packit Service 1d0348
				if (mtree->classic) {
Packit Service 1d0348
					ret = write_dot_dot_entry(a,
Packit Service 1d0348
						np->parent);
Packit Service 1d0348
					if (ret != ARCHIVE_OK)
Packit Service 1d0348
						return (ARCHIVE_FATAL);
Packit Service 1d0348
				}
Packit Service 1d0348
				np = np->parent;
Packit Service 1d0348
			} else {
Packit Service 1d0348
				/*
Packit Service 1d0348
				 * Switch to next mtree entry in the directory.
Packit Service 1d0348
				 */
Packit Service 1d0348
				np = np->dir_info->chnext;
Packit Service 1d0348
				break;
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
	} while (np != np->parent); 
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_mtree_finish_entry(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree = a->format_data;
Packit Service 1d0348
	struct mtree_entry *me;
Packit Service 1d0348
Packit Service 1d0348
	if ((me = mtree->mtree_entry) == NULL)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	mtree->mtree_entry = NULL;
Packit Service 1d0348
Packit Service 1d0348
	if (me->reg_info)
Packit Service 1d0348
		sum_final(mtree, me->reg_info);
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_mtree_close(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree= a->format_data;
Packit Service 1d0348
	int ret;
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->root != NULL) {
Packit Service 1d0348
		ret = write_mtree_entry_tree(a);
Packit Service 1d0348
		if (ret != ARCHIVE_OK)
Packit Service 1d0348
			return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	archive_write_set_bytes_in_last_block(&a->archive, 1);
Packit Service 1d0348
Packit Service 1d0348
	return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static ssize_t
Packit Service 1d0348
archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree= a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	if (n > mtree->entry_bytes_remaining)
Packit Service 1d0348
		n = (size_t)mtree->entry_bytes_remaining;
Packit Service 1d0348
	mtree->entry_bytes_remaining -= n;
Packit Service 1d0348
Packit Service 1d0348
	/* We don't need to compute a regular file sum */
Packit Service 1d0348
	if (mtree->mtree_entry == NULL)
Packit Service 1d0348
		return (n);
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->mtree_entry->filetype == AE_IFREG)
Packit Service 1d0348
		sum_update(mtree, buff, n);
Packit Service 1d0348
Packit Service 1d0348
	return (n);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_mtree_free(struct archive_write *a)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree= a->format_data;
Packit Service 1d0348
Packit Service 1d0348
	if (mtree == NULL)
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
Packit Service 1d0348
	/* Make sure we dot not leave any entries. */
Packit Service 1d0348
	mtree_entry_register_free(mtree);
Packit Service 1d0348
	archive_string_free(&mtree->cur_dirstr);
Packit Service 1d0348
	archive_string_free(&mtree->ebuf);
Packit Service 1d0348
	archive_string_free(&mtree->buf);
Packit Service 1d0348
	attr_counter_set_free(mtree);
Packit Service 1d0348
	free(mtree);
Packit Service 1d0348
	a->format_data = NULL;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_mtree_options(struct archive_write *a, const char *key,
Packit Service 1d0348
    const char *value)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_writer *mtree= a->format_data;
Packit Service 1d0348
	int keybit = 0;
Packit Service 1d0348
Packit Service 1d0348
	switch (key[0]) {
Packit Service 1d0348
	case 'a':
Packit Service 1d0348
		if (strcmp(key, "all") == 0)
Packit Service 1d0348
			keybit = ~0;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'c':
Packit Service 1d0348
		if (strcmp(key, "cksum") == 0)
Packit Service 1d0348
			keybit = F_CKSUM;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'd':
Packit Service 1d0348
		if (strcmp(key, "device") == 0)
Packit Service 1d0348
			keybit = F_DEV;
Packit Service 1d0348
		else if (strcmp(key, "dironly") == 0) {
Packit Service 1d0348
			mtree->dironly = (value != NULL)? 1: 0;
Packit Service 1d0348
			return (ARCHIVE_OK);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'f':
Packit Service 1d0348
		if (strcmp(key, "flags") == 0)
Packit Service 1d0348
			keybit = F_FLAGS;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'g':
Packit Service 1d0348
		if (strcmp(key, "gid") == 0)
Packit Service 1d0348
			keybit = F_GID;
Packit Service 1d0348
		else if (strcmp(key, "gname") == 0)
Packit Service 1d0348
			keybit = F_GNAME;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'i':
Packit Service 1d0348
		if (strcmp(key, "indent") == 0) {
Packit Service 1d0348
			mtree->indent = (value != NULL)? 1: 0;
Packit Service 1d0348
			return (ARCHIVE_OK);
Packit Service 1d0348
		} else if (strcmp(key, "inode") == 0) {
Packit Service 1d0348
			keybit = F_INO;
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'l':
Packit Service 1d0348
		if (strcmp(key, "link") == 0)
Packit Service 1d0348
			keybit = F_SLINK;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'm':
Packit Service 1d0348
		if (strcmp(key, "md5") == 0 ||
Packit Service 1d0348
		    strcmp(key, "md5digest") == 0)
Packit Service 1d0348
			keybit = F_MD5;
Packit Service 1d0348
		if (strcmp(key, "mode") == 0)
Packit Service 1d0348
			keybit = F_MODE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'n':
Packit Service 1d0348
		if (strcmp(key, "nlink") == 0)
Packit Service 1d0348
			keybit = F_NLINK;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'r':
Packit Service 1d0348
		if (strcmp(key, "resdevice") == 0) {
Packit Service 1d0348
			keybit = F_RESDEV;
Packit Service 1d0348
		} else if (strcmp(key, "ripemd160digest") == 0 ||
Packit Service 1d0348
		    strcmp(key, "rmd160") == 0 ||
Packit Service 1d0348
		    strcmp(key, "rmd160digest") == 0)
Packit Service 1d0348
			keybit = F_RMD160;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 's':
Packit Service 1d0348
		if (strcmp(key, "sha1") == 0 ||
Packit Service 1d0348
		    strcmp(key, "sha1digest") == 0)
Packit Service 1d0348
			keybit = F_SHA1;
Packit Service 1d0348
		if (strcmp(key, "sha256") == 0 ||
Packit Service 1d0348
		    strcmp(key, "sha256digest") == 0)
Packit Service 1d0348
			keybit = F_SHA256;
Packit Service 1d0348
		if (strcmp(key, "sha384") == 0 ||
Packit Service 1d0348
		    strcmp(key, "sha384digest") == 0)
Packit Service 1d0348
			keybit = F_SHA384;
Packit Service 1d0348
		if (strcmp(key, "sha512") == 0 ||
Packit Service 1d0348
		    strcmp(key, "sha512digest") == 0)
Packit Service 1d0348
			keybit = F_SHA512;
Packit Service 1d0348
		if (strcmp(key, "size") == 0)
Packit Service 1d0348
			keybit = F_SIZE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 't':
Packit Service 1d0348
		if (strcmp(key, "time") == 0)
Packit Service 1d0348
			keybit = F_TIME;
Packit Service 1d0348
		else if (strcmp(key, "type") == 0)
Packit Service 1d0348
			keybit = F_TYPE;
Packit Service 1d0348
		break;
Packit Service 1d0348
	case 'u':
Packit Service 1d0348
		if (strcmp(key, "uid") == 0)
Packit Service 1d0348
			keybit = F_UID;
Packit Service 1d0348
		else if (strcmp(key, "uname") == 0)
Packit Service 1d0348
			keybit = F_UNAME;
Packit Service 1d0348
		else if (strcmp(key, "use-set") == 0) {
Packit Service 1d0348
			mtree->output_global_set = (value != NULL)? 1: 0;
Packit Service 1d0348
			return (ARCHIVE_OK);
Packit Service 1d0348
		}
Packit Service 1d0348
		break;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (keybit != 0) {
Packit Service 1d0348
		if (value != NULL)
Packit Service 1d0348
			mtree->keys |= keybit;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~keybit;
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Note: The "warn" return is just to inform the options
Packit Service 1d0348
	 * supervisor that we didn't handle it.  It will generate
Packit Service 1d0348
	 * a suitable error if no one used this option. */
Packit Service 1d0348
	return (ARCHIVE_WARN);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
archive_write_set_format_mtree_default(struct archive *_a, const char *fn)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
	struct mtree_writer *mtree;
Packit Service 1d0348
Packit Service 1d0348
	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);
Packit Service 1d0348
Packit Service 1d0348
	if (a->format_free != NULL)
Packit Service 1d0348
		(a->format_free)(a);
Packit Service 1d0348
Packit Service 1d0348
	if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
Packit Service 1d0348
		archive_set_error(&a->archive, ENOMEM,
Packit Service 1d0348
		    "Can't allocate mtree data");
Packit Service 1d0348
		return (ARCHIVE_FATAL);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	mtree->mtree_entry = NULL;
Packit Service 1d0348
	mtree->first = 1;
Packit Service 1d0348
	memset(&(mtree->set), 0, sizeof(mtree->set));
Packit Service 1d0348
	mtree->keys = DEFAULT_KEYS;
Packit Service 1d0348
	mtree->dironly = 0;
Packit Service 1d0348
	mtree->indent = 0;
Packit Service 1d0348
	archive_string_init(&mtree->ebuf);
Packit Service 1d0348
	archive_string_init(&mtree->buf);
Packit Service 1d0348
	mtree_entry_register_init(mtree);
Packit Service 1d0348
	a->format_data = mtree;
Packit Service 1d0348
	a->format_free = archive_write_mtree_free;
Packit Service 1d0348
	a->format_name = "mtree";
Packit Service 1d0348
	a->format_options = archive_write_mtree_options;
Packit Service 1d0348
	a->format_write_header = archive_write_mtree_header;
Packit Service 1d0348
	a->format_close = archive_write_mtree_close;
Packit Service 1d0348
	a->format_write_data = archive_write_mtree_data;
Packit Service 1d0348
	a->format_finish_entry = archive_write_mtree_finish_entry;
Packit Service 1d0348
	a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
Packit Service 1d0348
	a->archive.archive_format_name = "mtree";
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_mtree(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	return archive_write_set_format_mtree_default(_a,
Packit Service 1d0348
		"archive_write_set_format_mtree");
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
int
Packit Service 1d0348
archive_write_set_format_mtree_classic(struct archive *_a)
Packit Service 1d0348
{
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	r = archive_write_set_format_mtree_default(_a,
Packit Service 1d0348
		"archive_write_set_format_mtree_classic");
Packit Service 1d0348
	if (r == ARCHIVE_OK) {
Packit Service 1d0348
		struct archive_write *a = (struct archive_write *)_a;
Packit Service 1d0348
		struct mtree_writer *mtree;
Packit Service 1d0348
Packit Service 1d0348
		mtree = (struct mtree_writer *)a->format_data;
Packit Service 1d0348
Packit Service 1d0348
		/* Set to output a mtree archive in classic format. */
Packit Service 1d0348
		mtree->classic = 1;
Packit Service 1d0348
		/* Basically, mtree classic format uses '/set' global
Packit Service 1d0348
		 * value. */
Packit Service 1d0348
		mtree->output_global_set = 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	return (r);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
sum_init(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	mtree->compute_sum = 0;
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->keys & F_CKSUM) {
Packit Service 1d0348
		mtree->compute_sum |= F_CKSUM;
Packit Service 1d0348
		mtree->crc = 0;
Packit Service 1d0348
		mtree->crc_len = 0;
Packit Service 1d0348
	}
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	if (mtree->keys & F_MD5) {
Packit Service 1d0348
		if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_MD5;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_MD5;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	if (mtree->keys & F_RMD160) {
Packit Service 1d0348
		if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_RMD160;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_RMD160;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	if (mtree->keys & F_SHA1) {
Packit Service 1d0348
		if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_SHA1;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_SHA1;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	if (mtree->keys & F_SHA256) {
Packit Service 1d0348
		if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_SHA256;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_SHA256;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	if (mtree->keys & F_SHA384) {
Packit Service 1d0348
		if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_SHA384;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_SHA384;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	if (mtree->keys & F_SHA512) {
Packit Service 1d0348
		if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)
Packit Service 1d0348
			mtree->compute_sum |= F_SHA512;
Packit Service 1d0348
		else
Packit Service 1d0348
			mtree->keys &= ~F_SHA512;/* Not supported. */
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
Packit Service 1d0348
{
Packit Service 1d0348
	if (mtree->compute_sum & F_CKSUM) {
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Compute a POSIX 1003.2 checksum
Packit Service 1d0348
		 */
Packit Service 1d0348
		const unsigned char *p;
Packit Service 1d0348
		size_t nn;
Packit Service 1d0348
Packit Service 1d0348
		for (nn = n, p = buff; nn--; ++p)
Packit Service 1d0348
			COMPUTE_CRC(mtree->crc, *p);
Packit Service 1d0348
		mtree->crc_len += n;
Packit Service 1d0348
	}
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	if (mtree->compute_sum & F_MD5)
Packit Service 1d0348
		archive_md5_update(&mtree->md5ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	if (mtree->compute_sum & F_RMD160)
Packit Service 1d0348
		archive_rmd160_update(&mtree->rmd160ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA1)
Packit Service 1d0348
		archive_sha1_update(&mtree->sha1ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA256)
Packit Service 1d0348
		archive_sha256_update(&mtree->sha256ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA384)
Packit Service 1d0348
		archive_sha384_update(&mtree->sha384ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA512)
Packit Service 1d0348
		archive_sha512_update(&mtree->sha512ctx, buff, n);
Packit Service 1d0348
#endif
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
sum_final(struct mtree_writer *mtree, struct reg_info *reg)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	if (mtree->compute_sum & F_CKSUM) {
Packit Service 1d0348
		uint64_t len;
Packit Service 1d0348
		/* Include the length of the file. */
Packit Service 1d0348
		for (len = mtree->crc_len; len != 0; len >>= 8)
Packit Service 1d0348
			COMPUTE_CRC(mtree->crc, len & 0xff);
Packit Service 1d0348
		reg->crc = ~mtree->crc;
Packit Service 1d0348
	}
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	if (mtree->compute_sum & F_MD5)
Packit Service 1d0348
		archive_md5_final(&mtree->md5ctx, reg->buf_md5);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	if (mtree->compute_sum & F_RMD160)
Packit Service 1d0348
		archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA1)
Packit Service 1d0348
		archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA256)
Packit Service 1d0348
		archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA384)
Packit Service 1d0348
		archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384);
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	if (mtree->compute_sum & F_SHA512)
Packit Service 1d0348
		archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512);
Packit Service 1d0348
#endif
Packit Service 1d0348
	/* Save what types of sum are computed. */
Packit Service 1d0348
	reg->compute_sum = mtree->compute_sum;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
Packit Service 1d0348
    defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
Packit Service 1d0348
    defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
Packit Service 1d0348
static void
Packit Service 1d0348
strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
Packit Service 1d0348
{
Packit Service 1d0348
	static const char hex[] = "0123456789abcdef";
Packit Service 1d0348
	int i;
Packit Service 1d0348
Packit Service 1d0348
	for (i = 0; i < n; i++) {
Packit Service 1d0348
		archive_strappend_char(s, hex[bin[i] >> 4]);
Packit Service 1d0348
		archive_strappend_char(s, hex[bin[i] & 0x0f]);
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
sum_write(struct archive_string *str, struct reg_info *reg)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	if (reg->compute_sum & F_CKSUM) {
Packit Service 1d0348
		archive_string_sprintf(str, " cksum=%ju",
Packit Service 1d0348
		    (uintmax_t)reg->crc);
Packit Service 1d0348
	}
Packit Service 1d0348
#ifdef ARCHIVE_HAS_MD5
Packit Service 1d0348
	if (reg->compute_sum & F_MD5) {
Packit Service 1d0348
		archive_strcat(str, " md5digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_RMD160
Packit Service 1d0348
	if (reg->compute_sum & F_RMD160) {
Packit Service 1d0348
		archive_strcat(str, " rmd160digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA1
Packit Service 1d0348
	if (reg->compute_sum & F_SHA1) {
Packit Service 1d0348
		archive_strcat(str, " sha1digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA256
Packit Service 1d0348
	if (reg->compute_sum & F_SHA256) {
Packit Service 1d0348
		archive_strcat(str, " sha256digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA384
Packit Service 1d0348
	if (reg->compute_sum & F_SHA384) {
Packit Service 1d0348
		archive_strcat(str, " sha384digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
#ifdef ARCHIVE_HAS_SHA512
Packit Service 1d0348
	if (reg->compute_sum & F_SHA512) {
Packit Service 1d0348
		archive_strcat(str, " sha512digest=");
Packit Service 1d0348
		strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512));
Packit Service 1d0348
	}
Packit Service 1d0348
#endif
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_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 mtree_entry *e1 = (const struct mtree_entry *)n1;
Packit Service 1d0348
	const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp(e2->basename.s, e1->basename.s));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_cmp_key(const struct archive_rb_node *n, const void *key)
Packit Service 1d0348
{
Packit Service 1d0348
	const struct mtree_entry *e = (const struct mtree_entry *)n;
Packit Service 1d0348
Packit Service 1d0348
	return (strcmp((const char *)key, e->basename.s));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#if defined(_WIN32) || defined(__CYGWIN__)
Packit Service 1d0348
static int
Packit Service 1d0348
cleanup_backslash_1(char *p)
Packit Service 1d0348
{
Packit Service 1d0348
	int mb, dos;
Packit Service 1d0348
Packit Service 1d0348
	mb = dos = 0;
Packit Service 1d0348
	while (*p) {
Packit Service 1d0348
		if (*(unsigned char *)p > 127)
Packit Service 1d0348
			mb = 1;
Packit Service 1d0348
		if (*p == '\\') {
Packit Service 1d0348
			/* If we have not met any multi-byte characters,
Packit Service 1d0348
			 * we can replace '\' with '/'. */
Packit Service 1d0348
			if (!mb)
Packit Service 1d0348
				*p = '/';
Packit Service 1d0348
			dos = 1;
Packit Service 1d0348
		}
Packit Service 1d0348
		p++;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (!mb || !dos)
Packit Service 1d0348
		return (0);
Packit Service 1d0348
	return (-1);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
cleanup_backslash_2(wchar_t *p)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	/* Convert a path-separator from '\' to  '/' */
Packit Service 1d0348
	while (*p != L'\0') {
Packit Service 1d0348
		if (*p == L'\\')
Packit Service 1d0348
			*p = L'/';
Packit Service 1d0348
		p++;
Packit Service 1d0348
	}
Packit Service 1d0348
}
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
mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
Packit Service 1d0348
    struct archive_entry *entry)
Packit Service 1d0348
{
Packit Service 1d0348
	const char *pathname;
Packit Service 1d0348
	char *p, *dirname, *slash;
Packit Service 1d0348
	size_t len;
Packit Service 1d0348
	int ret = ARCHIVE_OK;
Packit Service 1d0348
Packit Service 1d0348
	archive_strcpy(&file->pathname, archive_entry_pathname(entry));
Packit Service 1d0348
#if defined(_WIN32) || defined(__CYGWIN__)
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Convert a path-separator from '\' to  '/'
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (cleanup_backslash_1(file->pathname.s) != 0) {
Packit Service 1d0348
		const wchar_t *wp = archive_entry_pathname_w(entry);
Packit Service 1d0348
		struct archive_wstring ws;
Packit Service 1d0348
Packit Service 1d0348
		if (wp != NULL) {
Packit Service 1d0348
			int r;
Packit Service 1d0348
			archive_string_init(&ws);
Packit Service 1d0348
			archive_wstrcpy(&ws, wp);
Packit Service 1d0348
			cleanup_backslash_2(ws.s);
Packit Service 1d0348
			archive_string_empty(&(file->pathname));
Packit Service 1d0348
			r = archive_string_append_from_wcs(&(file->pathname),
Packit Service 1d0348
			    ws.s, ws.length);
Packit Service 1d0348
			archive_wstring_free(&ws);
Packit Service 1d0348
			if (r < 0 && errno == ENOMEM) {
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
		}
Packit Service 1d0348
	}
Packit Service 1d0348
#else
Packit Service 1d0348
	(void)a; /* UNUSED */
Packit Service 1d0348
#endif
Packit Service 1d0348
	pathname =  file->pathname.s;
Packit Service 1d0348
	if (strcmp(pathname, ".") == 0) {
Packit Service 1d0348
		archive_strcpy(&file->basename, ".");
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	archive_strcpy(&(file->parentdir), pathname);
Packit Service 1d0348
Packit Service 1d0348
	len = file->parentdir.length;
Packit Service 1d0348
	p = dirname = file->parentdir.s;
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
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
	/*
Packit Service 1d0348
	 * Add "./" prefix.
Packit Service 1d0348
	 * NOTE: If the pathname does not have a path separator, we have
Packit Service 1d0348
	 * to add "./" to the head of the pathname because mtree reader
Packit Service 1d0348
	 * will suppose that it is v1(a.k.a classic) mtree format and
Packit Service 1d0348
	 * change the directory unexpectedly and so it will make a wrong
Packit Service 1d0348
	 * path.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) {
Packit Service 1d0348
		struct archive_string as;
Packit Service 1d0348
		archive_string_init(&as);
Packit Service 1d0348
		archive_strcpy(&as, "./");
Packit Service 1d0348
		archive_strncat(&as, p, len);
Packit Service 1d0348
		archive_string_empty(&file->parentdir);
Packit Service 1d0348
		archive_string_concat(&file->parentdir, &as);
Packit Service 1d0348
		archive_string_free(&as);
Packit Service 1d0348
		p = file->parentdir.s;
Packit Service 1d0348
		len = archive_strlen(&file->parentdir);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/*
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
	}
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 (ret);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Make a basename from file->parentdir.s and slash */
Packit Service 1d0348
	*slash  = '\0';
Packit Service 1d0348
	file->parentdir.length = slash - file->parentdir.s;
Packit Service 1d0348
	archive_strcpy(&(file->basename),  slash + 1);
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,
Packit Service 1d0348
    struct mtree_entry **m_entry)
Packit Service 1d0348
{
Packit Service 1d0348
	struct archive_entry *entry;
Packit Service 1d0348
	struct mtree_entry *file;
Packit Service 1d0348
	int r;
Packit Service 1d0348
Packit Service 1d0348
	entry = archive_entry_new();
Packit Service 1d0348
	if (entry == NULL) {
Packit Service 1d0348
		*m_entry = 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
	archive_entry_copy_pathname(entry, pathname);
Packit Service 1d0348
	archive_entry_set_mode(entry, AE_IFDIR | 0755);
Packit Service 1d0348
	archive_entry_set_mtime(entry, time(NULL), 0);
Packit Service 1d0348
Packit Service 1d0348
	r = mtree_entry_new(a, entry, &file;;
Packit Service 1d0348
	archive_entry_free(entry);
Packit Service 1d0348
	if (r < ARCHIVE_WARN) {
Packit Service 1d0348
		*m_entry = 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
Packit Service 1d0348
	file->dir_info->virtual = 1;
Packit Service 1d0348
Packit Service 1d0348
	*m_entry = file;
Packit Service 1d0348
	return (ARCHIVE_OK);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)
Packit Service 1d0348
{
Packit Service 1d0348
        file->next = NULL;
Packit Service 1d0348
        *mtree->file_list.last = file;
Packit Service 1d0348
        mtree->file_list.last = &(file->next);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_entry_register_init(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
	mtree->file_list.first = NULL;
Packit Service 1d0348
	mtree->file_list.last = &(mtree->file_list.first);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
mtree_entry_register_free(struct mtree_writer *mtree)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_entry *file, *file_next;
Packit Service 1d0348
Packit Service 1d0348
	file = mtree->file_list.first;
Packit Service 1d0348
	while (file != NULL) {
Packit Service 1d0348
		file_next = file->next;
Packit Service 1d0348
		mtree_entry_free(file);
Packit Service 1d0348
		file = file_next;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_add_child_tail(struct mtree_entry *parent,
Packit Service 1d0348
    struct mtree_entry *child)
Packit Service 1d0348
{
Packit Service 1d0348
	child->dir_info->chnext = NULL;
Packit Service 1d0348
	*parent->dir_info->children.last = child;
Packit Service 1d0348
	parent->dir_info->children.last = &(child->dir_info->chnext);
Packit Service 1d0348
	return (1);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Find a entry from a parent entry with the name.
Packit Service 1d0348
 */
Packit Service 1d0348
static struct mtree_entry *
Packit Service 1d0348
mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)
Packit Service 1d0348
{
Packit Service 1d0348
	struct mtree_entry *np;
Packit Service 1d0348
Packit Service 1d0348
	if (parent == NULL)
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	np = (struct mtree_entry *)__archive_rb_tree_find_node(
Packit Service 1d0348
	    &(parent->dir_info->rbtree), child_name);
Packit Service 1d0348
	return (np);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
get_path_component(char *name, size_t n, const char *fn)
Packit Service 1d0348
{
Packit Service 1d0348
	char *p;
Packit Service 1d0348
	size_t 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 ((int)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
mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
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 mtree_writer *mtree = (struct mtree_writer *)a->format_data;
Packit Service 1d0348
	struct mtree_entry *dent, *file, *np;
Packit Service 1d0348
	const char *fn, *p;
Packit Service 1d0348
	int l, r;
Packit Service 1d0348
Packit Service 1d0348
	file = *filep;
Packit Service 1d0348
	if (file->parentdir.length == 0 && file->basename.length == 1 &&
Packit Service 1d0348
	    file->basename.s[0] == '.') {
Packit Service 1d0348
		file->parent = file;
Packit Service 1d0348
		if (mtree->root != NULL) {
Packit Service 1d0348
			np = mtree->root;
Packit Service 1d0348
			goto same_entry;
Packit Service 1d0348
		}
Packit Service 1d0348
		mtree->root = file;
Packit Service 1d0348
		mtree_entry_register_add(mtree, file);
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (file->parentdir.length == 0) {
Packit Service 1d0348
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit Service 1d0348
		    "Internal programing error "
Packit Service 1d0348
		    "in generating canonical name for %s",
Packit Service 1d0348
		    file->pathname.s);
Packit Service 1d0348
		return (ARCHIVE_FAILED);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	fn = p = file->parentdir.s;
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 `file' entry to
Packit Service 1d0348
	 * `cur_dirent'.
Packit Service 1d0348
	 */
Packit Service 1d0348
	if (archive_strlen(&(mtree->cur_dirstr))
Packit Service 1d0348
	      == archive_strlen(&(file->parentdir)) &&
Packit Service 1d0348
	    strcmp(mtree->cur_dirstr.s, fn) == 0) {
Packit Service 1d0348
		if (!__archive_rb_tree_insert_node(
Packit Service 1d0348
		    &(mtree->cur_dirent->dir_info->rbtree),
Packit Service 1d0348
		    (struct archive_rb_node *)file)) {
Packit Service 1d0348
			/* There is the same name in the tree. */
Packit Service 1d0348
			np = (struct mtree_entry *)__archive_rb_tree_find_node(
Packit Service 1d0348
			    &(mtree->cur_dirent->dir_info->rbtree),
Packit Service 1d0348
			    file->basename.s);
Packit Service 1d0348
			goto same_entry;
Packit Service 1d0348
		}
Packit Service 1d0348
		file->parent = mtree->cur_dirent;
Packit Service 1d0348
		mtree_entry_register_add(mtree, file);
Packit Service 1d0348
		return (ARCHIVE_OK);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	dent = mtree->root;
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
			return (ARCHIVE_FATAL);
Packit Service 1d0348
		}
Packit Service 1d0348
		if (l == 1 && name[0] == '.' && dent != NULL &&
Packit Service 1d0348
		    dent == mtree->root) {
Packit Service 1d0348
			fn += l;
Packit Service 1d0348
			if (fn[0] == '/')
Packit Service 1d0348
				fn++;
Packit Service 1d0348
			continue;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		np = mtree_entry_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 sub directory. */
Packit Service 1d0348
		if (!np->dir_info) {
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
			    np->pathname.s, file->pathname.s);
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 mtree_entry *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
			r = mtree_entry_create_virtual_dir(a, as.s, &vp);
Packit Service 1d0348
			archive_string_free(&as);
Packit Service 1d0348
			if (r < ARCHIVE_WARN)
Packit Service 1d0348
				return (r);
Packit Service 1d0348
Packit Service 1d0348
			if (strcmp(vp->pathname.s, ".") == 0) {
Packit Service 1d0348
				vp->parent = vp;
Packit Service 1d0348
				mtree->root = vp;
Packit Service 1d0348
			} else {
Packit Service 1d0348
				__archive_rb_tree_insert_node(
Packit Service 1d0348
				    &(dent->dir_info->rbtree),
Packit Service 1d0348
				    (struct archive_rb_node *)vp);
Packit Service 1d0348
				vp->parent = dent;
Packit Service 1d0348
			}
Packit Service 1d0348
			mtree_entry_register_add(mtree, 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
				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 `file' can be
Packit Service 1d0348
		 * inserted. */
Packit Service 1d0348
		mtree->cur_dirent = dent;
Packit Service 1d0348
		archive_string_empty(&(mtree->cur_dirstr));
Packit Service 1d0348
		archive_string_ensure(&(mtree->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
			mtree->cur_dirstr.s[0] = 0;
Packit Service 1d0348
		else {
Packit Service 1d0348
			if (archive_strlen(&(dent->parentdir)) > 0) {
Packit Service 1d0348
				archive_string_copy(&(mtree->cur_dirstr),
Packit Service 1d0348
				    &(dent->parentdir));
Packit Service 1d0348
				archive_strappend_char(
Packit Service 1d0348
				    &(mtree->cur_dirstr), '/');
Packit Service 1d0348
			}
Packit Service 1d0348
			archive_string_concat(&(mtree->cur_dirstr),
Packit Service 1d0348
			    &(dent->basename));
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if (!__archive_rb_tree_insert_node(
Packit Service 1d0348
		    &(dent->dir_info->rbtree),
Packit Service 1d0348
		    (struct archive_rb_node *)file)) {
Packit Service 1d0348
			np = (struct mtree_entry *)__archive_rb_tree_find_node(
Packit Service 1d0348
			    &(dent->dir_info->rbtree), file->basename.s);
Packit Service 1d0348
			goto same_entry;
Packit Service 1d0348
		}
Packit Service 1d0348
		file->parent = dent;
Packit Service 1d0348
		mtree_entry_register_add(mtree, file);
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
	r = mtree_entry_exchange_same_entry(a, np, file);
Packit Service 1d0348
	if (r < ARCHIVE_WARN)
Packit Service 1d0348
		return (r);
Packit Service 1d0348
	if (np->dir_info)
Packit Service 1d0348
		np->dir_info->virtual = 0;
Packit Service 1d0348
	*filep = np;
Packit Service 1d0348
	mtree_entry_free(file);
Packit Service 1d0348
	return (ARCHIVE_WARN);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static int
Packit Service 1d0348
mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,
Packit Service 1d0348
    struct mtree_entry *file)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {
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
		    np->pathname.s);
Packit Service 1d0348
		return (ARCHIVE_FAILED);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Update the existent mtree entry's attributes by the new one's. */
Packit Service 1d0348
	archive_string_empty(&np->symlink);
Packit Service 1d0348
	archive_string_concat(&np->symlink, &file->symlink);
Packit Service 1d0348
	archive_string_empty(&np->uname);
Packit Service 1d0348
	archive_string_concat(&np->uname, &file->uname);
Packit Service 1d0348
	archive_string_empty(&np->gname);
Packit Service 1d0348
	archive_string_concat(&np->gname, &file->gname);
Packit Service 1d0348
	archive_string_empty(&np->fflags_text);
Packit Service 1d0348
	archive_string_concat(&np->fflags_text, &file->fflags_text);
Packit Service 1d0348
	np->nlink = file->nlink;
Packit Service 1d0348
	np->filetype = file->filetype;
Packit Service 1d0348
	np->mode = file->mode;
Packit Service 1d0348
	np->size = file->size;
Packit Service 1d0348
	np->uid = file->uid;
Packit Service 1d0348
	np->gid = file->gid;
Packit Service 1d0348
	np->fflags_set = file->fflags_set;
Packit Service 1d0348
	np->fflags_clear = file->fflags_clear;
Packit Service 1d0348
	np->mtime = file->mtime;
Packit Service 1d0348
	np->mtime_nsec = file->mtime_nsec;
Packit Service 1d0348
	np->rdevmajor = file->rdevmajor;
Packit Service 1d0348
	np->rdevminor = file->rdevminor;
Packit Service 1d0348
	np->devmajor = file->devmajor;
Packit Service 1d0348
	np->devminor = file->devminor;
Packit Service 1d0348
	np->ino = file->ino;
Packit Service 1d0348
Packit Service 1d0348
	return (ARCHIVE_WARN);
Packit Service 1d0348
}