archive_write_set_format_xar.c revision 232153
1231200Smm/*-
2232153Smm * Copyright (c) 2010-2012 Michihiro NAKAJIMA
3231200Smm * All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm *
14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24231200Smm */
25231200Smm
26231200Smm#include "archive_platform.h"
27231200Smm__FBSDID("$FreeBSD$");
28231200Smm
29231200Smm#ifdef HAVE_ERRNO_H
30231200Smm#include <errno.h>
31231200Smm#endif
32231200Smm#ifdef HAVE_LIMITS_H
33231200Smm#include <limits.h>
34231200Smm#endif
35231200Smm#include <stdlib.h>
36231200Smm#if HAVE_LIBXML_XMLWRITER_H
37231200Smm#include <libxml/xmlwriter.h>
38231200Smm#endif
39231200Smm#ifdef HAVE_BZLIB_H
40231200Smm#include <bzlib.h>
41231200Smm#endif
42231200Smm#if HAVE_LZMA_H
43231200Smm#include <lzma.h>
44231200Smm#endif
45231200Smm#ifdef HAVE_ZLIB_H
46231200Smm#include <zlib.h>
47231200Smm#endif
48231200Smm
49231200Smm#ifndef PATH_MAX
50231200Smm#define PATH_MAX 4096
51231200Smm#endif
52231200Smm
53231200Smm#include "archive.h"
54231200Smm#include "archive_crypto_private.h"
55231200Smm#include "archive_endian.h"
56231200Smm#include "archive_entry.h"
57231200Smm#include "archive_entry_locale.h"
58231200Smm#include "archive_private.h"
59231200Smm#include "archive_rb.h"
60231200Smm#include "archive_string.h"
61231200Smm#include "archive_write_private.h"
62231200Smm
63231200Smm/*
64231200Smm * Differences to xar utility.
65231200Smm * - Subdocument is not supported yet.
66231200Smm * - ACL is not supported yet.
67231200Smm * - When writing an XML element <link type="<file-type>">, <file-type>
68231200Smm *   which is a file type a symbolic link is referencing is always marked
69231200Smm *   as "broken". Xar utility uses stat(2) to get the file type, but, in
70231200Smm *   libarcive format writer, we should not use it; if it is needed, we
71231200Smm *   should get about it at archive_read_disk.c.
72231200Smm * - It is possible to appear both <flags> and <ext2> elements.
73231200Smm *   Xar utility generates <flags> on BSD platform and <ext2> on Linux
74231200Smm *   platform.
75231200Smm *
76231200Smm */
77231200Smm
78231200Smm#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
79231200Smm	LIBXML_VERSION >= 20703) ||\
80231200Smm	!defined(HAVE_ZLIB_H) || \
81231200Smm	!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
82231200Smm/*
83231200Smm * xar needs several external libraries.
84231200Smm *   o libxml2
85231200Smm *   o openssl or MD5/SHA1 hash function
86231200Smm *   o zlib
87231200Smm *   o bzlib2 (option)
88231200Smm *   o liblzma (option)
89231200Smm */
90231200Smmint
91231200Smmarchive_write_set_format_xar(struct archive *_a)
92231200Smm{
93231200Smm	struct archive_write *a = (struct archive_write *)_a;
94231200Smm
95231200Smm	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
96231200Smm	    "Xar not supported on this platform");
97231200Smm	return (ARCHIVE_WARN);
98231200Smm}
99231200Smm
100231200Smm#else	/* Support xar format */
101231200Smm
102231200Smm/*#define DEBUG_PRINT_TOC		1 */
103231200Smm
104232153Smm#define BAD_CAST_CONST (const xmlChar *)
105232153Smm
106231200Smm#define HEADER_MAGIC	0x78617221
107231200Smm#define HEADER_SIZE	28
108231200Smm#define HEADER_VERSION	1
109231200Smm
110231200Smmenum sumalg {
111231200Smm	CKSUM_NONE = 0,
112231200Smm	CKSUM_SHA1 = 1,
113231200Smm	CKSUM_MD5 = 2
114231200Smm};
115231200Smm
116231200Smm#define MD5_SIZE	16
117231200Smm#define SHA1_SIZE	20
118231200Smm#define MAX_SUM_SIZE	20
119231200Smm#define MD5_NAME	"md5"
120231200Smm#define SHA1_NAME	"sha1"
121231200Smm
122231200Smmenum enctype {
123231200Smm	NONE,
124231200Smm	GZIP,
125231200Smm	BZIP2,
126231200Smm	LZMA,
127231200Smm	XZ,
128231200Smm};
129231200Smm
130231200Smmstruct chksumwork {
131231200Smm	enum sumalg		 alg;
132231200Smm#ifdef ARCHIVE_HAS_MD5
133231200Smm	archive_md5_ctx		 md5ctx;
134231200Smm#endif
135231200Smm#ifdef ARCHIVE_HAS_SHA1
136231200Smm	archive_sha1_ctx	 sha1ctx;
137231200Smm#endif
138231200Smm};
139231200Smm
140231200Smmenum la_zaction {
141231200Smm	ARCHIVE_Z_FINISH,
142231200Smm	ARCHIVE_Z_RUN
143231200Smm};
144231200Smm
145231200Smm/*
146231200Smm * Universal zstream.
147231200Smm */
148231200Smmstruct la_zstream {
149231200Smm	const unsigned char	*next_in;
150231200Smm	size_t			 avail_in;
151231200Smm	uint64_t		 total_in;
152231200Smm
153231200Smm	unsigned char		*next_out;
154231200Smm	size_t			 avail_out;
155231200Smm	uint64_t		 total_out;
156231200Smm
157231200Smm	int			 valid;
158231200Smm	void			*real_stream;
159231200Smm	int			 (*code) (struct archive *a,
160231200Smm				    struct la_zstream *lastrm,
161231200Smm				    enum la_zaction action);
162231200Smm	int			 (*end)(struct archive *a,
163231200Smm				    struct la_zstream *lastrm);
164231200Smm};
165231200Smm
166231200Smmstruct chksumval {
167231200Smm	enum sumalg		 alg;
168231200Smm	size_t			 len;
169231200Smm	unsigned char		 val[MAX_SUM_SIZE];
170231200Smm};
171231200Smm
172231200Smmstruct heap_data {
173231200Smm	int			 id;
174231200Smm	struct heap_data	*next;
175231200Smm	uint64_t		 temp_offset;
176231200Smm	uint64_t		 length;	/* archived size.	*/
177231200Smm	uint64_t		 size;		/* extracted size.	*/
178231200Smm	enum enctype		 compression;
179231200Smm	struct chksumval	 a_sum;		/* archived checksum.	*/
180231200Smm	struct chksumval	 e_sum;		/* extracted checksum.	*/
181231200Smm};
182231200Smm
183231200Smmstruct file {
184231200Smm	struct archive_rb_node	 rbnode;
185231200Smm
186231200Smm	int			 id;
187231200Smm	struct archive_entry	*entry;
188231200Smm
189231200Smm	struct archive_rb_tree	 rbtree;
190231200Smm	struct file		*next;
191231200Smm	struct file		*chnext;
192231200Smm	struct file		*hlnext;
193231200Smm	/* For hardlinked files.
194231200Smm	 * Use only when archive_entry_nlink() > 1 */
195231200Smm	struct file		*hardlink_target;
196231200Smm	struct file		*parent;	/* parent directory entry */
197231200Smm	/*
198231200Smm	 * To manage sub directory files.
199231200Smm	 * We use 'chnext' a menber of struct file to chain.
200231200Smm	 */
201231200Smm	struct {
202231200Smm		struct file	*first;
203231200Smm		struct file	**last;
204231200Smm	}			 children;
205231200Smm
206231200Smm	/* For making a directory tree. */
207231200Smm        struct archive_string    parentdir;
208231200Smm        struct archive_string    basename;
209231200Smm        struct archive_string    symlink;
210231200Smm
211231200Smm	int			 ea_idx;
212231200Smm	struct {
213231200Smm		struct heap_data *first;
214231200Smm		struct heap_data **last;
215231200Smm	}			 xattr;
216231200Smm	struct heap_data	 data;
217231200Smm        struct archive_string    script;
218231200Smm
219231200Smm	int			 virtual:1;
220231200Smm	int			 dir:1;
221231200Smm};
222231200Smm
223231200Smmstruct hardlink {
224231200Smm	struct archive_rb_node	 rbnode;
225231200Smm	int			 nlink;
226231200Smm	struct {
227231200Smm		struct file	*first;
228231200Smm		struct file	**last;
229231200Smm	}			 file_list;
230231200Smm};
231231200Smm
232231200Smmstruct xar {
233231200Smm	int			 temp_fd;
234231200Smm	uint64_t		 temp_offset;
235231200Smm
236231200Smm	int			 file_idx;
237231200Smm	struct file		*root;
238231200Smm	struct file		*cur_dirent;
239231200Smm	struct archive_string	 cur_dirstr;
240231200Smm	struct file		*cur_file;
241231200Smm	uint64_t		 bytes_remaining;
242231200Smm	struct archive_string	 tstr;
243231200Smm	struct archive_string	 vstr;
244231200Smm
245231200Smm	enum sumalg		 opt_toc_sumalg;
246231200Smm	enum sumalg		 opt_sumalg;
247231200Smm	enum enctype		 opt_compression;
248231200Smm	int			 opt_compression_level;
249231200Smm
250231200Smm	struct chksumwork	 a_sumwrk;	/* archived checksum.	*/
251231200Smm	struct chksumwork	 e_sumwrk;	/* extracted checksum.	*/
252231200Smm	struct la_zstream	 stream;
253231200Smm	struct archive_string_conv *sconv;
254231200Smm	/*
255231200Smm	 * Compressed data buffer.
256231200Smm	 */
257231200Smm	unsigned char		 wbuff[1024 * 64];
258231200Smm	size_t			 wbuff_remaining;
259231200Smm
260231200Smm	struct heap_data	 toc;
261231200Smm	/*
262231200Smm	 * The list of all file entries is used to manage struct file
263231200Smm	 * objects.
264231200Smm	 * We use 'next' a menber of struct file to chain.
265231200Smm	 */
266231200Smm	struct {
267231200Smm		struct file	*first;
268231200Smm		struct file	**last;
269231200Smm	}			 file_list;
270231200Smm	/*
271231200Smm	 * The list of hard-linked file entries.
272231200Smm	 * We use 'hlnext' a menber of struct file to chain.
273231200Smm	 */
274231200Smm	struct archive_rb_tree	 hardlink_rbtree;
275231200Smm};
276231200Smm
277231200Smmstatic int	xar_options(struct archive_write *,
278231200Smm		    const char *, const char *);
279231200Smmstatic int	xar_write_header(struct archive_write *,
280231200Smm		    struct archive_entry *);
281231200Smmstatic ssize_t	xar_write_data(struct archive_write *,
282231200Smm		    const void *, size_t);
283231200Smmstatic int	xar_finish_entry(struct archive_write *);
284231200Smmstatic int	xar_close(struct archive_write *);
285231200Smmstatic int	xar_free(struct archive_write *);
286231200Smm
287231200Smmstatic struct file *file_new(struct archive_write *a, struct archive_entry *);
288231200Smmstatic void	file_free(struct file *);
289231200Smmstatic struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
290231200Smm		    const char *);
291231200Smmstatic int	file_add_child_tail(struct file *, struct file *);
292231200Smmstatic struct file *file_find_child(struct file *, const char *);
293231200Smmstatic int	file_gen_utility_names(struct archive_write *,
294231200Smm		    struct file *);
295231200Smmstatic int	get_path_component(char *, int, const char *);
296231200Smmstatic int	file_tree(struct archive_write *, struct file **);
297231200Smmstatic void	file_register(struct xar *, struct file *);
298231200Smmstatic void	file_init_register(struct xar *);
299231200Smmstatic void	file_free_register(struct xar *);
300231200Smmstatic int	file_register_hardlink(struct archive_write *,
301231200Smm		    struct file *);
302231200Smmstatic void	file_connect_hardlink_files(struct xar *);
303231200Smmstatic void	file_init_hardlinks(struct xar *);
304231200Smmstatic void	file_free_hardlinks(struct xar *);
305231200Smm
306231200Smmstatic void	checksum_init(struct chksumwork *, enum sumalg);
307231200Smmstatic void	checksum_update(struct chksumwork *, const void *, size_t);
308231200Smmstatic void	checksum_final(struct chksumwork *, struct chksumval *);
309231200Smmstatic int	compression_init_encoder_gzip(struct archive *,
310231200Smm		    struct la_zstream *, int, int);
311231200Smmstatic int	compression_code_gzip(struct archive *,
312231200Smm		    struct la_zstream *, enum la_zaction);
313231200Smmstatic int	compression_end_gzip(struct archive *, struct la_zstream *);
314231200Smmstatic int	compression_init_encoder_bzip2(struct archive *,
315231200Smm		    struct la_zstream *, int);
316231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
317231200Smmstatic int	compression_code_bzip2(struct archive *,
318231200Smm		    struct la_zstream *, enum la_zaction);
319231200Smmstatic int	compression_end_bzip2(struct archive *, struct la_zstream *);
320231200Smm#endif
321231200Smmstatic int	compression_init_encoder_lzma(struct archive *,
322231200Smm		    struct la_zstream *, int);
323231200Smmstatic int	compression_init_encoder_xz(struct archive *,
324231200Smm		    struct la_zstream *, int);
325231200Smm#if defined(HAVE_LZMA_H)
326231200Smmstatic int	compression_code_lzma(struct archive *,
327231200Smm		    struct la_zstream *, enum la_zaction);
328231200Smmstatic int	compression_end_lzma(struct archive *, struct la_zstream *);
329231200Smm#endif
330231200Smmstatic int	xar_compression_init_encoder(struct archive_write *);
331231200Smmstatic int	compression_code(struct archive *,
332231200Smm		    struct la_zstream *, enum la_zaction);
333231200Smmstatic int	compression_end(struct archive *,
334231200Smm		    struct la_zstream *);
335231200Smmstatic int	save_xattrs(struct archive_write *, struct file *);
336231200Smmstatic int	getalgsize(enum sumalg);
337231200Smmstatic const char *getalgname(enum sumalg);
338231200Smm
339231200Smmint
340231200Smmarchive_write_set_format_xar(struct archive *_a)
341231200Smm{
342231200Smm	struct archive_write *a = (struct archive_write *)_a;
343231200Smm	struct xar *xar;
344231200Smm
345231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
346231200Smm	    ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
347231200Smm
348231200Smm	/* If another format was already registered, unregister it. */
349231200Smm	if (a->format_free != NULL)
350231200Smm		(a->format_free)(a);
351231200Smm
352231200Smm	xar = calloc(1, sizeof(*xar));
353231200Smm	if (xar == NULL) {
354231200Smm		archive_set_error(&a->archive, ENOMEM,
355231200Smm		    "Can't allocate xar data");
356231200Smm		return (ARCHIVE_FATAL);
357231200Smm	}
358231200Smm	xar->temp_fd = -1;
359231200Smm	file_init_register(xar);
360231200Smm	file_init_hardlinks(xar);
361231200Smm	archive_string_init(&(xar->tstr));
362231200Smm	archive_string_init(&(xar->vstr));
363231200Smm
364231200Smm	/*
365231200Smm	 * Create the root directory.
366231200Smm	 */
367231200Smm	xar->root = file_create_virtual_dir(a, xar, "");
368231200Smm	if (xar->root == NULL) {
369231200Smm		free(xar);
370231200Smm		archive_set_error(&a->archive, ENOMEM,
371231200Smm		    "Can't allocate xar data");
372231200Smm		return (ARCHIVE_FATAL);
373231200Smm	}
374231200Smm	xar->root->parent = xar->root;
375231200Smm	file_register(xar, xar->root);
376231200Smm	xar->cur_dirent = xar->root;
377231200Smm	archive_string_init(&(xar->cur_dirstr));
378231200Smm	archive_string_ensure(&(xar->cur_dirstr), 1);
379231200Smm	xar->cur_dirstr.s[0] = 0;
380231200Smm
381231200Smm	/*
382231200Smm	 * Initialize option.
383231200Smm	 */
384231200Smm	/* Set default checksum type. */
385231200Smm	xar->opt_toc_sumalg = CKSUM_SHA1;
386231200Smm	xar->opt_sumalg = CKSUM_SHA1;
387231200Smm	/* Set default compression type and level. */
388231200Smm	xar->opt_compression = GZIP;
389231200Smm	xar->opt_compression_level = 6;
390231200Smm
391231200Smm	a->format_data = xar;
392231200Smm
393231200Smm	a->format_name = "xar";
394231200Smm	a->format_options = xar_options;
395231200Smm	a->format_write_header = xar_write_header;
396231200Smm	a->format_write_data = xar_write_data;
397231200Smm	a->format_finish_entry = xar_finish_entry;
398231200Smm	a->format_close = xar_close;
399231200Smm	a->format_free = xar_free;
400231200Smm	a->archive.archive_format = ARCHIVE_FORMAT_XAR;
401231200Smm	a->archive.archive_format_name = "xar";
402231200Smm
403231200Smm	return (ARCHIVE_OK);
404231200Smm}
405231200Smm
406231200Smmstatic int
407231200Smmxar_options(struct archive_write *a, const char *key, const char *value)
408231200Smm{
409231200Smm	struct xar *xar;
410231200Smm
411231200Smm	xar = (struct xar *)a->format_data;
412231200Smm
413231200Smm	if (strcmp(key, "checksum") == 0) {
414231200Smm		if (value == NULL)
415231200Smm			xar->opt_sumalg = CKSUM_NONE;
416231200Smm		else if (strcmp(value, "sha1") == 0)
417231200Smm			xar->opt_sumalg = CKSUM_SHA1;
418231200Smm		else if (strcmp(value, "md5") == 0)
419231200Smm			xar->opt_sumalg = CKSUM_MD5;
420231200Smm		else {
421231200Smm			archive_set_error(&(a->archive),
422231200Smm			    ARCHIVE_ERRNO_MISC,
423231200Smm			    "Unkonwn checksum name: `%s'",
424231200Smm			    value);
425231200Smm			return (ARCHIVE_FAILED);
426231200Smm		}
427231200Smm		return (ARCHIVE_OK);
428231200Smm	}
429231200Smm	if (strcmp(key, "compression") == 0) {
430231200Smm		const char *name = NULL;
431231200Smm
432231200Smm		if (value == NULL)
433231200Smm			xar->opt_compression = NONE;
434231200Smm		else if (strcmp(value, "gzip") == 0)
435231200Smm			xar->opt_compression = GZIP;
436231200Smm		else if (strcmp(value, "bzip2") == 0)
437231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
438231200Smm			xar->opt_compression = BZIP2;
439231200Smm#else
440231200Smm			name = "bzip2";
441231200Smm#endif
442231200Smm		else if (strcmp(value, "lzma") == 0)
443231200Smm#if HAVE_LZMA_H
444231200Smm			xar->opt_compression = LZMA;
445231200Smm#else
446231200Smm			name = "lzma";
447231200Smm#endif
448231200Smm		else if (strcmp(value, "xz") == 0)
449231200Smm#if HAVE_LZMA_H
450231200Smm			xar->opt_compression = XZ;
451231200Smm#else
452231200Smm			name = "xz";
453231200Smm#endif
454231200Smm		else {
455231200Smm			archive_set_error(&(a->archive),
456231200Smm			    ARCHIVE_ERRNO_MISC,
457231200Smm			    "Unkonwn compression name: `%s'",
458231200Smm			    value);
459231200Smm			return (ARCHIVE_FAILED);
460231200Smm		}
461231200Smm		if (name != NULL) {
462231200Smm			archive_set_error(&(a->archive),
463231200Smm			    ARCHIVE_ERRNO_MISC,
464231200Smm			    "`%s' compression not supported "
465231200Smm			    "on this platform",
466231200Smm			    name);
467231200Smm			return (ARCHIVE_FAILED);
468231200Smm		}
469231200Smm		return (ARCHIVE_OK);
470231200Smm	}
471231200Smm	if (strcmp(key, "compression-level") == 0) {
472231200Smm		if (value == NULL ||
473231200Smm		    !(value[0] >= '0' && value[0] <= '9') ||
474231200Smm		    value[1] != '\0') {
475231200Smm			archive_set_error(&(a->archive),
476231200Smm			    ARCHIVE_ERRNO_MISC,
477231200Smm			    "Illeagal value `%s'",
478231200Smm			    value);
479231200Smm			return (ARCHIVE_FAILED);
480231200Smm		}
481231200Smm		xar->opt_compression_level = value[0] - '0';
482231200Smm		return (ARCHIVE_OK);
483231200Smm	}
484231200Smm	if (strcmp(key, "toc-checksum") == 0) {
485231200Smm		if (value == NULL)
486231200Smm			xar->opt_toc_sumalg = CKSUM_NONE;
487231200Smm		else if (strcmp(value, "sha1") == 0)
488231200Smm			xar->opt_toc_sumalg = CKSUM_SHA1;
489231200Smm		else if (strcmp(value, "md5") == 0)
490231200Smm			xar->opt_toc_sumalg = CKSUM_MD5;
491231200Smm		else {
492231200Smm			archive_set_error(&(a->archive),
493231200Smm			    ARCHIVE_ERRNO_MISC,
494231200Smm			    "Unkonwn checksum name: `%s'",
495231200Smm			    value);
496231200Smm			return (ARCHIVE_FAILED);
497231200Smm		}
498231200Smm		return (ARCHIVE_OK);
499231200Smm	}
500231200Smm
501232153Smm	/* Note: The "warn" return is just to inform the options
502232153Smm	 * supervisor that we didn't handle it.  It will generate
503232153Smm	 * a suitable error if no one used this option. */
504232153Smm	return (ARCHIVE_WARN);
505231200Smm}
506231200Smm
507231200Smmstatic int
508231200Smmxar_write_header(struct archive_write *a, struct archive_entry *entry)
509231200Smm{
510231200Smm	struct xar *xar;
511231200Smm	struct file *file;
512231200Smm	struct archive_entry *file_entry;
513231200Smm	int r, r2;
514231200Smm
515231200Smm	xar = (struct xar *)a->format_data;
516231200Smm	xar->cur_file = NULL;
517231200Smm	xar->bytes_remaining = 0;
518231200Smm
519231200Smm	if (xar->sconv == NULL) {
520231200Smm		xar->sconv = archive_string_conversion_to_charset(
521231200Smm		    &a->archive, "UTF-8", 1);
522231200Smm		if (xar->sconv == NULL)
523231200Smm			return (ARCHIVE_FATAL);
524231200Smm	}
525231200Smm
526231200Smm	file = file_new(a, entry);
527231200Smm	if (file == NULL) {
528231200Smm		archive_set_error(&a->archive, ENOMEM,
529231200Smm		    "Can't allocate data");
530231200Smm		return (ARCHIVE_FATAL);
531231200Smm	}
532231200Smm	r2 = file_gen_utility_names(a, file);
533231200Smm	if (r2 < ARCHIVE_WARN)
534231200Smm		return (r2);
535231200Smm
536231200Smm	/*
537231200Smm	 * Ignore a path which looks like the top of directory name
538231200Smm	 * since we have already made the root directory of an Xar archive.
539231200Smm	 */
540231200Smm	if (archive_strlen(&(file->parentdir)) == 0 &&
541231200Smm	    archive_strlen(&(file->basename)) == 0) {
542231200Smm		file_free(file);
543231200Smm		return (r2);
544231200Smm	}
545231200Smm
546231200Smm	/* Add entry into tree */
547231200Smm	file_entry = file->entry;
548231200Smm	r = file_tree(a, &file);
549231200Smm	if (r != ARCHIVE_OK)
550231200Smm		return (r);
551231200Smm	/* There is the same file in tree and
552231200Smm	 * the current file is older than the file in tree.
553231200Smm	 * So we don't need the current file data anymore. */
554231200Smm	if (file->entry != file_entry)
555231200Smm		return (r2);
556231200Smm	if (file->id == 0)
557231200Smm		file_register(xar, file);
558231200Smm
559231200Smm	/* A virtual file, which is a directory, does not have
560231200Smm	 * any contents and we won't store it into a archive
561231200Smm	 * file other than its name. */
562231200Smm	if (file->virtual)
563231200Smm		return (r2);
564231200Smm
565231200Smm	/*
566231200Smm	 * Prepare to save the contents of the file.
567231200Smm	 */
568231200Smm	if (xar->temp_fd == -1) {
569231200Smm		int algsize;
570231200Smm		xar->temp_offset = 0;
571231200Smm		xar->temp_fd = __archive_mktemp(NULL);
572231200Smm		if (xar->temp_fd < 0) {
573231200Smm			archive_set_error(&a->archive, errno,
574231200Smm			    "Couldn't create temporary file");
575231200Smm			return (ARCHIVE_FATAL);
576231200Smm		}
577231200Smm		algsize = getalgsize(xar->opt_toc_sumalg);
578231200Smm		if (algsize > 0) {
579231200Smm			if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
580231200Smm				archive_set_error(&(a->archive), errno,
581231200Smm				    "lseek failed");
582231200Smm				return (ARCHIVE_FATAL);
583231200Smm			}
584231200Smm			xar->temp_offset = algsize;
585231200Smm		}
586231200Smm	}
587231200Smm
588231200Smm	if (archive_entry_hardlink(file->entry) == NULL) {
589231200Smm		r = save_xattrs(a, file);
590231200Smm		if (r != ARCHIVE_OK)
591231200Smm			return (ARCHIVE_FATAL);
592231200Smm	}
593231200Smm
594231200Smm	/* Non regular files contents are unneeded to be saved to
595231200Smm	 * a temporary file. */
596231200Smm	if (archive_entry_filetype(file->entry) != AE_IFREG)
597231200Smm		return (r2);
598231200Smm
599231200Smm	/*
600231200Smm	 * Set the current file to cur_file to read its contents.
601231200Smm	 */
602231200Smm	xar->cur_file = file;
603231200Smm
604231200Smm	if (archive_entry_nlink(file->entry) > 1) {
605231200Smm		r = file_register_hardlink(a, file);
606231200Smm		if (r != ARCHIVE_OK)
607231200Smm			return (r);
608231200Smm		if (archive_entry_hardlink(file->entry) != NULL) {
609231200Smm			archive_entry_unset_size(file->entry);
610231200Smm			return (r2);
611231200Smm		}
612231200Smm	}
613231200Smm
614231200Smm	/* Save a offset of current file in temporary file. */
615231200Smm	file->data.temp_offset = xar->temp_offset;
616231200Smm	file->data.size = archive_entry_size(file->entry);
617231200Smm	file->data.compression = xar->opt_compression;
618231200Smm	xar->bytes_remaining = archive_entry_size(file->entry);
619231200Smm	checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
620231200Smm	checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
621231200Smm	r = xar_compression_init_encoder(a);
622231200Smm
623231200Smm	if (r != ARCHIVE_OK)
624231200Smm		return (r);
625231200Smm	else
626231200Smm		return (r2);
627231200Smm}
628231200Smm
629231200Smmstatic int
630231200Smmwrite_to_temp(struct archive_write *a, const void *buff, size_t s)
631231200Smm{
632231200Smm	struct xar *xar;
633232153Smm	const unsigned char *p;
634231200Smm	ssize_t ws;
635231200Smm
636231200Smm	xar = (struct xar *)a->format_data;
637232153Smm	p = (const unsigned char *)buff;
638231200Smm	while (s) {
639231200Smm		ws = write(xar->temp_fd, p, s);
640231200Smm		if (ws < 0) {
641231200Smm			archive_set_error(&(a->archive), errno,
642231200Smm			    "fwrite function failed");
643231200Smm			return (ARCHIVE_FATAL);
644231200Smm		}
645231200Smm		s -= ws;
646231200Smm		p += ws;
647231200Smm		xar->temp_offset += ws;
648231200Smm	}
649231200Smm	return (ARCHIVE_OK);
650231200Smm}
651231200Smm
652231200Smmstatic ssize_t
653231200Smmxar_write_data(struct archive_write *a, const void *buff, size_t s)
654231200Smm{
655231200Smm	struct xar *xar;
656231200Smm	enum la_zaction run;
657231200Smm	size_t size, rsize;
658231200Smm	int r;
659231200Smm
660231200Smm	xar = (struct xar *)a->format_data;
661231200Smm
662231200Smm	if (s > xar->bytes_remaining)
663231200Smm		s = xar->bytes_remaining;
664231200Smm	if (s == 0 || xar->cur_file == NULL)
665231200Smm		return (0);
666231200Smm	if (xar->cur_file->data.compression == NONE) {
667231200Smm		checksum_update(&(xar->e_sumwrk), buff, s);
668231200Smm		checksum_update(&(xar->a_sumwrk), buff, s);
669231200Smm		size = rsize = s;
670231200Smm	} else {
671231200Smm		xar->stream.next_in = (const unsigned char *)buff;
672231200Smm		xar->stream.avail_in = s;
673231200Smm		if (xar->bytes_remaining > s)
674231200Smm			run = ARCHIVE_Z_RUN;
675231200Smm		else
676231200Smm			run = ARCHIVE_Z_FINISH;
677231200Smm		/* Compress file data. */
678231200Smm		r = compression_code(&(a->archive), &(xar->stream), run);
679231200Smm		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
680231200Smm			return (ARCHIVE_FATAL);
681231200Smm		rsize = s - xar->stream.avail_in;
682231200Smm		checksum_update(&(xar->e_sumwrk), buff, rsize);
683231200Smm		size = sizeof(xar->wbuff) - xar->stream.avail_out;
684231200Smm		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
685231200Smm	}
686231200Smm#if !defined(_WIN32) || defined(__CYGWIN__)
687231200Smm	if (xar->bytes_remaining ==
688232153Smm	    (uint64_t)archive_entry_size(xar->cur_file->entry)) {
689231200Smm		/*
690231200Smm		 * Get the path of a shell script if so.
691231200Smm		 */
692231200Smm		const unsigned char *b = (const unsigned char *)buff;
693231200Smm
694231200Smm		archive_string_empty(&(xar->cur_file->script));
695231200Smm		if (rsize > 2 && b[0] == '#' && b[1] == '!') {
696231200Smm			size_t i, end, off;
697231200Smm
698231200Smm			off = 2;
699231200Smm			if (b[off] == ' ')
700231200Smm				off++;
701231200Smm#ifdef PATH_MAX
702231200Smm			if ((rsize - off) > PATH_MAX)
703231200Smm				end = off + PATH_MAX;
704231200Smm			else
705231200Smm#endif
706231200Smm				end = rsize;
707231200Smm			/* Find the end of a script path. */
708231200Smm			for (i = off; i < end && b[i] != '\0' &&
709231200Smm			    b[i] != '\n' && b[i] != '\r' &&
710231200Smm			    b[i] != ' ' && b[i] != '\t'; i++)
711231200Smm				;
712231200Smm			archive_strncpy(&(xar->cur_file->script), b + off,
713231200Smm			    i - off);
714231200Smm		}
715231200Smm	}
716231200Smm#endif
717231200Smm
718231200Smm	if (xar->cur_file->data.compression == NONE) {
719231200Smm		if (write_to_temp(a, buff, size) != ARCHIVE_OK)
720231200Smm			return (ARCHIVE_FATAL);
721231200Smm	} else {
722231200Smm		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
723231200Smm			return (ARCHIVE_FATAL);
724231200Smm	}
725231200Smm	xar->bytes_remaining -= rsize;
726231200Smm	xar->cur_file->data.length += size;
727231200Smm
728231200Smm	return (rsize);
729231200Smm}
730231200Smm
731231200Smmstatic int
732231200Smmxar_finish_entry(struct archive_write *a)
733231200Smm{
734231200Smm	struct xar *xar;
735231200Smm	struct file *file;
736231200Smm	size_t s;
737231200Smm	ssize_t w;
738231200Smm
739231200Smm	xar = (struct xar *)a->format_data;
740231200Smm	if (xar->cur_file == NULL)
741231200Smm		return (ARCHIVE_OK);
742231200Smm
743231200Smm	while (xar->bytes_remaining > 0) {
744231200Smm		s = xar->bytes_remaining;
745231200Smm		if (s > a->null_length)
746231200Smm			s = a->null_length;
747231200Smm		w = xar_write_data(a, a->nulls, s);
748231200Smm		if (w > 0)
749231200Smm			xar->bytes_remaining -= w;
750231200Smm		else
751231200Smm			return (w);
752231200Smm	}
753231200Smm	file = xar->cur_file;
754231200Smm	checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
755231200Smm	checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
756231200Smm	xar->cur_file = NULL;
757231200Smm
758231200Smm	return (ARCHIVE_OK);
759231200Smm}
760231200Smm
761231200Smmstatic int
762231200Smmxmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
763231200Smm	const char *key, const char *value,
764231200Smm	const char *attrkey, const char *attrvalue)
765231200Smm{
766231200Smm	int r;
767231200Smm
768232153Smm	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
769231200Smm	if (r < 0) {
770231200Smm		archive_set_error(&a->archive,
771231200Smm		    ARCHIVE_ERRNO_MISC,
772231200Smm		    "xmlTextWriterStartElement() failed: %d", r);
773231200Smm		return (ARCHIVE_FATAL);
774231200Smm	}
775231200Smm	if (attrkey != NULL && attrvalue != NULL) {
776231200Smm		r = xmlTextWriterWriteAttribute(writer,
777232153Smm		    BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
778231200Smm		if (r < 0) {
779231200Smm			archive_set_error(&a->archive,
780231200Smm			    ARCHIVE_ERRNO_MISC,
781231200Smm			    "xmlTextWriterWriteAttribute() failed: %d", r);
782231200Smm			return (ARCHIVE_FATAL);
783231200Smm		}
784231200Smm	}
785231200Smm	if (value != NULL) {
786232153Smm		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
787231200Smm		if (r < 0) {
788231200Smm			archive_set_error(&a->archive,
789231200Smm			    ARCHIVE_ERRNO_MISC,
790231200Smm			    "xmlTextWriterWriteString() failed: %d", r);
791231200Smm			return (ARCHIVE_FATAL);
792231200Smm		}
793231200Smm	}
794231200Smm	r = xmlTextWriterEndElement(writer);
795231200Smm	if (r < 0) {
796231200Smm		archive_set_error(&a->archive,
797231200Smm		    ARCHIVE_ERRNO_MISC,
798231200Smm		    "xmlTextWriterEndElement() failed: %d", r);
799231200Smm		return (ARCHIVE_FATAL);
800231200Smm	}
801231200Smm	return (ARCHIVE_OK);
802231200Smm}
803231200Smm
804231200Smmstatic int
805231200Smmxmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
806231200Smm	const char *key, const char *value)
807231200Smm{
808231200Smm	int r;
809231200Smm
810231200Smm	if (value == NULL)
811231200Smm		return (ARCHIVE_OK);
812231200Smm
813232153Smm	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
814231200Smm	if (r < 0) {
815231200Smm		archive_set_error(&a->archive,
816231200Smm		    ARCHIVE_ERRNO_MISC,
817231200Smm		    "xmlTextWriterStartElement() failed: %d", r);
818231200Smm		return (ARCHIVE_FATAL);
819231200Smm	}
820231200Smm	if (value != NULL) {
821232153Smm		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
822231200Smm		if (r < 0) {
823231200Smm			archive_set_error(&a->archive,
824231200Smm			    ARCHIVE_ERRNO_MISC,
825231200Smm			    "xmlTextWriterWriteString() failed: %d", r);
826231200Smm			return (ARCHIVE_FATAL);
827231200Smm		}
828231200Smm	}
829231200Smm	r = xmlTextWriterEndElement(writer);
830231200Smm	if (r < 0) {
831231200Smm		archive_set_error(&a->archive,
832231200Smm		    ARCHIVE_ERRNO_MISC,
833231200Smm		    "xmlTextWriterEndElement() failed: %d", r);
834231200Smm		return (ARCHIVE_FATAL);
835231200Smm	}
836231200Smm	return (ARCHIVE_OK);
837231200Smm}
838231200Smm
839231200Smmstatic int
840231200Smmxmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
841231200Smm	const char *key, const char *fmt, ...)
842231200Smm{
843231200Smm	struct xar *xar;
844231200Smm	va_list ap;
845231200Smm
846231200Smm	xar = (struct xar *)a->format_data;
847231200Smm	va_start(ap, fmt);
848231200Smm	archive_string_empty(&xar->vstr);
849231200Smm	archive_string_vsprintf(&xar->vstr, fmt, ap);
850231200Smm	va_end(ap);
851231200Smm	return (xmlwrite_string(a, writer, key, xar->vstr.s));
852231200Smm}
853231200Smm
854231200Smmstatic int
855231200Smmxmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
856231200Smm	const char *key, time_t t, int z)
857231200Smm{
858231200Smm	char timestr[100];
859231200Smm	struct tm tm;
860231200Smm
861231200Smm#if defined(HAVE_GMTIME_R)
862231200Smm	gmtime_r(&t, &tm);
863231200Smm#elif defined(HAVE__GMTIME64_S)
864231200Smm	_gmtime64_s(&tm, &t);
865231200Smm#else
866231200Smm	memcpy(&tm, gmtime(&t), sizeof(tm));
867231200Smm#endif
868231200Smm	memset(&timestr, 0, sizeof(timestr));
869231200Smm	/* Do not use %F and %T for portability. */
870231200Smm	strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);
871231200Smm	if (z)
872231200Smm		strcat(timestr, "Z");
873231200Smm	return (xmlwrite_string(a, writer, key, timestr));
874231200Smm}
875231200Smm
876231200Smmstatic int
877231200Smmxmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
878231200Smm	const char *key, mode_t mode)
879231200Smm{
880231200Smm	char ms[5];
881231200Smm
882231200Smm	ms[0] = '0';
883231200Smm	ms[1] = '0' + ((mode >> 6) & 07);
884231200Smm	ms[2] = '0' + ((mode >> 3) & 07);
885231200Smm	ms[3] = '0' + (mode & 07);
886231200Smm	ms[4] = '\0';
887231200Smm
888231200Smm	return (xmlwrite_string(a, writer, key, ms));
889231200Smm}
890231200Smm
891231200Smmstatic int
892231200Smmxmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
893231200Smm	const char *key, struct chksumval *sum)
894231200Smm{
895231200Smm	const char *algname;
896231200Smm	int algsize;
897231200Smm	char buff[MAX_SUM_SIZE*2 + 1];
898231200Smm	char *p;
899231200Smm	unsigned char *s;
900231200Smm	int i, r;
901231200Smm
902231200Smm	if (sum->len > 0) {
903231200Smm		algname = getalgname(sum->alg);
904231200Smm		algsize = getalgsize(sum->alg);
905231200Smm		if (algname != NULL) {
906231200Smm			const char *hex = "0123456789abcdef";
907231200Smm			p = buff;
908231200Smm			s = sum->val;
909231200Smm			for (i = 0; i < algsize; i++) {
910231200Smm				*p++ = hex[(*s >> 4)];
911231200Smm				*p++ = hex[(*s & 0x0f)];
912231200Smm				s++;
913231200Smm			}
914231200Smm			*p = '\0';
915231200Smm			r = xmlwrite_string_attr(a, writer,
916231200Smm			    key, buff,
917231200Smm			    "style", algname);
918231200Smm			if (r < 0)
919231200Smm				return (ARCHIVE_FATAL);
920231200Smm		}
921231200Smm	}
922231200Smm	return (ARCHIVE_OK);
923231200Smm}
924231200Smm
925231200Smmstatic int
926231200Smmxmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
927231200Smm	struct heap_data *heap)
928231200Smm{
929231200Smm	const char *encname;
930231200Smm	int r;
931231200Smm
932231200Smm	r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
933231200Smm	if (r < 0)
934231200Smm		return (ARCHIVE_FATAL);
935231200Smm	r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
936231200Smm	if (r < 0)
937231200Smm		return (ARCHIVE_FATAL);
938231200Smm	r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
939231200Smm	if (r < 0)
940231200Smm		return (ARCHIVE_FATAL);
941231200Smm	switch (heap->compression) {
942231200Smm	case GZIP:
943231200Smm		encname = "application/x-gzip"; break;
944231200Smm	case BZIP2:
945231200Smm		encname = "application/x-bzip2"; break;
946231200Smm	case LZMA:
947231200Smm		encname = "application/x-lzma"; break;
948231200Smm	case XZ:
949231200Smm		encname = "application/x-xz"; break;
950231200Smm	default:
951231200Smm		encname = "application/octet-stream"; break;
952231200Smm	}
953231200Smm	r = xmlwrite_string_attr(a, writer, "encoding", NULL,
954231200Smm	    "style", encname);
955231200Smm	if (r < 0)
956231200Smm		return (ARCHIVE_FATAL);
957231200Smm	r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
958231200Smm	if (r < 0)
959231200Smm		return (ARCHIVE_FATAL);
960231200Smm	r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
961231200Smm	if (r < 0)
962231200Smm		return (ARCHIVE_FATAL);
963231200Smm	return (ARCHIVE_OK);
964231200Smm}
965231200Smm
966231200Smm/*
967231200Smm * xar utility records fflags as following xml elements:
968231200Smm *   <flags>
969231200Smm *     <UserNoDump/>
970231200Smm *     .....
971231200Smm *   </flags>
972231200Smm * or
973231200Smm *   <ext2>
974231200Smm *     <NoDump/>
975231200Smm *     .....
976231200Smm *   </ext2>
977231200Smm * If xar is running on BSD platform, records <flags>..</flags>;
978231200Smm * if xar is running on linux platform, records <ext2>..</ext2>;
979231200Smm * otherwise does not record.
980231200Smm *
981231200Smm * Our implements records both <flags> and <ext2> if it's necessary.
982231200Smm */
983231200Smmstatic int
984231200Smmmake_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
985231200Smm    const char *element, const char *fflags_text)
986231200Smm{
987231200Smm	static const struct flagentry {
988231200Smm		const char	*name;
989231200Smm		const char	*xarname;
990231200Smm	}
991231200Smm	flagbsd[] = {
992231200Smm		{ "sappnd",	"SystemAppend"},
993231200Smm		{ "sappend",	"SystemAppend"},
994231200Smm		{ "arch",	"SystemArchived"},
995231200Smm		{ "archived",	"SystemArchived"},
996231200Smm		{ "schg",	"SystemImmutable"},
997231200Smm		{ "schange",	"SystemImmutable"},
998231200Smm		{ "simmutable",	"SystemImmutable"},
999231200Smm		{ "nosunlnk",	"SystemNoUnlink"},
1000231200Smm		{ "nosunlink",	"SystemNoUnlink"},
1001231200Smm		{ "snapshot",	"SystemSnapshot"},
1002231200Smm		{ "uappnd",	"UserAppend"},
1003231200Smm		{ "uappend",	"UserAppend"},
1004231200Smm		{ "uchg",	"UserImmutable"},
1005231200Smm		{ "uchange",	"UserImmutable"},
1006231200Smm		{ "uimmutable",	"UserImmutable"},
1007231200Smm		{ "nodump",	"UserNoDump"},
1008231200Smm		{ "noopaque",	"UserOpaque"},
1009231200Smm		{ "nouunlnk",	"UserNoUnlink"},
1010231200Smm		{ "nouunlink",	"UserNoUnlink"},
1011231200Smm		{ NULL, NULL}
1012231200Smm	},
1013231200Smm	flagext2[] = {
1014231200Smm		{ "sappnd",	"AppendOnly"},
1015231200Smm		{ "sappend",	"AppendOnly"},
1016231200Smm		{ "schg",	"Immutable"},
1017231200Smm		{ "schange",	"Immutable"},
1018231200Smm		{ "simmutable",	"Immutable"},
1019231200Smm		{ "nodump",	"NoDump"},
1020231200Smm		{ "nouunlnk",	"Undelete"},
1021231200Smm		{ "nouunlink",	"Undelete"},
1022231200Smm		{ "btree",	"BTree"},
1023231200Smm		{ "comperr",	"CompError"},
1024231200Smm		{ "compress",	"Compress"},
1025231200Smm		{ "noatime",	"NoAtime"},
1026231200Smm		{ "compdirty",	"CompDirty"},
1027231200Smm		{ "comprblk",	"CompBlock"},
1028231200Smm		{ "dirsync",	"DirSync"},
1029231200Smm		{ "hashidx",	"HashIndexed"},
1030231200Smm		{ "imagic",	"iMagic"},
1031231200Smm		{ "journal",	"Journaled"},
1032231200Smm		{ "securedeletion",	"SecureDeletion"},
1033231200Smm		{ "sync",	"Synchronous"},
1034231200Smm		{ "notail",	"NoTail"},
1035231200Smm		{ "topdir",	"TopDir"},
1036231200Smm		{ "reserved",	"Reserved"},
1037231200Smm		{ NULL, NULL}
1038231200Smm	};
1039231200Smm	const struct flagentry *fe, *flagentry;
1040231200Smm#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
1041231200Smm	const struct flagentry *avail[FLAGENTRY_MAXSIZE];
1042231200Smm	const char *p;
1043231200Smm	int i, n, r;
1044231200Smm
1045231200Smm	if (strcmp(element, "ext2") == 0)
1046231200Smm		flagentry = flagext2;
1047231200Smm	else
1048231200Smm		flagentry = flagbsd;
1049231200Smm	n = 0;
1050231200Smm	p = fflags_text;
1051231200Smm	do {
1052231200Smm		const char *cp;
1053231200Smm
1054231200Smm		cp = strchr(p, ',');
1055231200Smm		if (cp == NULL)
1056231200Smm			cp = p + strlen(p);
1057231200Smm
1058231200Smm		for (fe = flagentry; fe->name != NULL; fe++) {
1059231200Smm			if (fe->name[cp - p] != '\0'
1060231200Smm			    || p[0] != fe->name[0])
1061231200Smm				continue;
1062231200Smm			if (strncmp(p, fe->name, cp - p) == 0) {
1063231200Smm				avail[n++] = fe;
1064231200Smm				break;
1065231200Smm			}
1066231200Smm		}
1067231200Smm		if (*cp == ',')
1068231200Smm			p = cp + 1;
1069231200Smm		else
1070231200Smm			p = NULL;
1071231200Smm	} while (p != NULL);
1072231200Smm
1073231200Smm	if (n > 0) {
1074232153Smm		r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
1075231200Smm		if (r < 0) {
1076231200Smm			archive_set_error(&a->archive,
1077231200Smm			    ARCHIVE_ERRNO_MISC,
1078231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1079231200Smm			return (ARCHIVE_FATAL);
1080231200Smm		}
1081231200Smm		for (i = 0; i < n; i++) {
1082231200Smm			r = xmlwrite_string(a, writer,
1083231200Smm			    avail[i]->xarname, NULL);
1084231200Smm			if (r != ARCHIVE_OK)
1085231200Smm				return (r);
1086231200Smm		}
1087231200Smm
1088231200Smm		r = xmlTextWriterEndElement(writer);
1089231200Smm		if (r < 0) {
1090231200Smm			archive_set_error(&a->archive,
1091231200Smm			    ARCHIVE_ERRNO_MISC,
1092231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1093231200Smm			return (ARCHIVE_FATAL);
1094231200Smm		}
1095231200Smm	}
1096231200Smm	return (ARCHIVE_OK);
1097231200Smm}
1098231200Smm
1099231200Smmstatic int
1100231200Smmmake_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
1101231200Smm    struct file *file)
1102231200Smm{
1103231200Smm	struct xar *xar;
1104231200Smm	const char *filetype, *filelink, *fflags;
1105231200Smm	struct archive_string linkto;
1106231200Smm	struct heap_data *heap;
1107231200Smm	unsigned char *tmp;
1108231200Smm	const char *p;
1109231200Smm	size_t len;
1110231200Smm	int r, r2, l, ll;
1111231200Smm
1112231200Smm	xar = (struct xar *)a->format_data;
1113231200Smm	r2 = ARCHIVE_OK;
1114231200Smm
1115231200Smm	/*
1116231200Smm	 * Make a file name entry, "<name>".
1117231200Smm	 */
1118231200Smm	l = ll = archive_strlen(&(file->basename));
1119231200Smm	tmp = malloc(l);
1120231200Smm	if (tmp == NULL) {
1121231200Smm		archive_set_error(&a->archive, ENOMEM,
1122231200Smm		    "Can't allocate memory");
1123231200Smm		return (ARCHIVE_FATAL);
1124231200Smm	}
1125231200Smm	r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
1126231200Smm	free(tmp);
1127231200Smm	if (r < 0) {
1128231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
1129231200Smm		if (r < 0) {
1130231200Smm			archive_set_error(&a->archive,
1131231200Smm			    ARCHIVE_ERRNO_MISC,
1132231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1133231200Smm			return (ARCHIVE_FATAL);
1134231200Smm		}
1135231200Smm		r = xmlTextWriterWriteAttribute(writer,
1136231200Smm		    BAD_CAST("enctype"), BAD_CAST("base64"));
1137231200Smm		if (r < 0) {
1138231200Smm			archive_set_error(&a->archive,
1139231200Smm			    ARCHIVE_ERRNO_MISC,
1140231200Smm			    "xmlTextWriterWriteAttribute() failed: %d", r);
1141231200Smm			return (ARCHIVE_FATAL);
1142231200Smm		}
1143231200Smm		r = xmlTextWriterWriteBase64(writer, file->basename.s,
1144231200Smm		    0, archive_strlen(&(file->basename)));
1145231200Smm		if (r < 0) {
1146231200Smm			archive_set_error(&a->archive,
1147231200Smm			    ARCHIVE_ERRNO_MISC,
1148231200Smm			    "xmlTextWriterWriteBase64() failed: %d", r);
1149231200Smm			return (ARCHIVE_FATAL);
1150231200Smm		}
1151231200Smm		r = xmlTextWriterEndElement(writer);
1152231200Smm		if (r < 0) {
1153231200Smm			archive_set_error(&a->archive,
1154231200Smm			    ARCHIVE_ERRNO_MISC,
1155231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1156231200Smm			return (ARCHIVE_FATAL);
1157231200Smm		}
1158231200Smm	} else {
1159231200Smm		r = xmlwrite_string(a, writer, "name", file->basename.s);
1160231200Smm		if (r < 0)
1161231200Smm			return (ARCHIVE_FATAL);
1162231200Smm	}
1163231200Smm
1164231200Smm	/*
1165231200Smm	 * Make a file type entry, "<type>".
1166231200Smm	 */
1167231200Smm	filelink = NULL;
1168231200Smm	archive_string_init(&linkto);
1169231200Smm	switch (archive_entry_filetype(file->entry)) {
1170231200Smm	case AE_IFDIR:
1171231200Smm		filetype = "directory"; break;
1172231200Smm	case AE_IFLNK:
1173231200Smm		filetype = "symlink"; break;
1174231200Smm	case AE_IFCHR:
1175231200Smm		filetype = "character special"; break;
1176231200Smm	case AE_IFBLK:
1177231200Smm		filetype = "block special"; break;
1178231200Smm	case AE_IFSOCK:
1179231200Smm		filetype = "socket"; break;
1180231200Smm	case AE_IFIFO:
1181231200Smm		filetype = "fifo"; break;
1182231200Smm	case AE_IFREG:
1183231200Smm	default:
1184231200Smm		if (file->hardlink_target != NULL) {
1185231200Smm			filetype = "hardlink";
1186231200Smm			filelink = "link";
1187231200Smm			if (file->hardlink_target == file)
1188231200Smm				archive_strcpy(&linkto, "original");
1189231200Smm			else
1190231200Smm				archive_string_sprintf(&linkto, "%d",
1191231200Smm				    file->hardlink_target->id);
1192231200Smm		} else
1193231200Smm			filetype = "file";
1194231200Smm		break;
1195231200Smm	}
1196231200Smm	r = xmlwrite_string_attr(a, writer, "type", filetype,
1197231200Smm	    filelink, linkto.s);
1198231200Smm	archive_string_free(&linkto);
1199231200Smm	if (r < 0)
1200231200Smm		return (ARCHIVE_FATAL);
1201231200Smm
1202231200Smm	/*
1203231200Smm	 * On a virtual directory, we record "name" and "type" only.
1204231200Smm	 */
1205231200Smm	if (file->virtual)
1206231200Smm		return (ARCHIVE_OK);
1207231200Smm
1208231200Smm	switch (archive_entry_filetype(file->entry)) {
1209231200Smm	case AE_IFLNK:
1210231200Smm		/*
1211231200Smm		 * xar utility has checked a file type, which
1212231200Smm		 * a symblic-link file has referenced.
1213231200Smm		 * For example:
1214231200Smm		 *   <link type="directory">../ref/</link>
1215231200Smm		 *   The symlink target file is "../ref/" and its
1216231200Smm		 *   file type is a directory.
1217231200Smm		 *
1218231200Smm		 *   <link type="file">../f</link>
1219231200Smm		 *   The symlink target file is "../f" and its
1220231200Smm		 *   file type is a regular file.
1221231200Smm		 *
1222231200Smm		 * But our implemention cannot do it, and then we
1223231200Smm		 * always record that a attribute "type" is "borken",
1224231200Smm		 * for example:
1225231200Smm		 *   <link type="broken">foo/bar</link>
1226231200Smm		 *   It means "foo/bar" is not reachable.
1227231200Smm		 */
1228231200Smm		r = xmlwrite_string_attr(a, writer, "link",
1229231200Smm		    file->symlink.s,
1230231200Smm		    "type", "broken");
1231231200Smm		if (r < 0)
1232231200Smm			return (ARCHIVE_FATAL);
1233231200Smm		break;
1234231200Smm	case AE_IFCHR:
1235231200Smm	case AE_IFBLK:
1236231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
1237231200Smm		if (r < 0) {
1238231200Smm			archive_set_error(&a->archive,
1239231200Smm			    ARCHIVE_ERRNO_MISC,
1240231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1241231200Smm			return (ARCHIVE_FATAL);
1242231200Smm		}
1243231200Smm		r = xmlwrite_fstring(a, writer, "major",
1244231200Smm		    "%d", archive_entry_rdevmajor(file->entry));
1245231200Smm		if (r < 0)
1246231200Smm			return (ARCHIVE_FATAL);
1247231200Smm		r = xmlwrite_fstring(a, writer, "minor",
1248231200Smm		    "%d", archive_entry_rdevminor(file->entry));
1249231200Smm		if (r < 0)
1250231200Smm			return (ARCHIVE_FATAL);
1251231200Smm		r = xmlTextWriterEndElement(writer);
1252231200Smm		if (r < 0) {
1253231200Smm			archive_set_error(&a->archive,
1254231200Smm			    ARCHIVE_ERRNO_MISC,
1255231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1256231200Smm			return (ARCHIVE_FATAL);
1257231200Smm		}
1258231200Smm		break;
1259231200Smm	default:
1260231200Smm		break;
1261231200Smm	}
1262231200Smm
1263231200Smm	/*
1264231200Smm	 * Make a inode entry, "<inode>".
1265231200Smm	 */
1266231200Smm	r = xmlwrite_fstring(a, writer, "inode",
1267231200Smm	    "%jd", archive_entry_ino64(file->entry));
1268231200Smm	if (r < 0)
1269231200Smm		return (ARCHIVE_FATAL);
1270231200Smm	if (archive_entry_dev(file->entry) != 0) {
1271231200Smm		r = xmlwrite_fstring(a, writer, "deviceno",
1272231200Smm		    "%d", archive_entry_dev(file->entry));
1273231200Smm		if (r < 0)
1274231200Smm			return (ARCHIVE_FATAL);
1275231200Smm	}
1276231200Smm
1277231200Smm	/*
1278231200Smm	 * Make a file mode entry, "<mode>".
1279231200Smm	 */
1280231200Smm	r = xmlwrite_mode(a, writer, "mode",
1281231200Smm	    archive_entry_mode(file->entry));
1282231200Smm	if (r < 0)
1283231200Smm		return (ARCHIVE_FATAL);
1284231200Smm
1285231200Smm	/*
1286231200Smm	 * Make a user entry, "<uid>" and "<user>.
1287231200Smm	 */
1288231200Smm	r = xmlwrite_fstring(a, writer, "uid",
1289231200Smm	    "%d", archive_entry_uid(file->entry));
1290231200Smm	if (r < 0)
1291231200Smm		return (ARCHIVE_FATAL);
1292231200Smm	r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
1293231200Smm	if (r != 0) {
1294231200Smm		if (errno == ENOMEM) {
1295231200Smm			archive_set_error(&a->archive, ENOMEM,
1296231200Smm			    "Can't allocate memory for Uname");
1297231200Smm			return (ARCHIVE_FATAL);
1298231200Smm		}
1299231200Smm		archive_set_error(&a->archive,
1300231200Smm		    ARCHIVE_ERRNO_FILE_FORMAT,
1301231200Smm		    "Can't translate uname '%s' to UTF-8",
1302231200Smm		    archive_entry_uname(file->entry));
1303231200Smm		r2 = ARCHIVE_WARN;
1304231200Smm	}
1305231200Smm	if (len > 0) {
1306231200Smm		r = xmlwrite_string(a, writer, "user", p);
1307231200Smm		if (r < 0)
1308231200Smm			return (ARCHIVE_FATAL);
1309231200Smm	}
1310231200Smm
1311231200Smm	/*
1312231200Smm	 * Make a group entry, "<gid>" and "<group>.
1313231200Smm	 */
1314231200Smm	r = xmlwrite_fstring(a, writer, "gid",
1315231200Smm	    "%d", archive_entry_gid(file->entry));
1316231200Smm	if (r < 0)
1317231200Smm		return (ARCHIVE_FATAL);
1318231200Smm	r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
1319231200Smm	if (r != 0) {
1320231200Smm		if (errno == ENOMEM) {
1321231200Smm			archive_set_error(&a->archive, ENOMEM,
1322231200Smm			    "Can't allocate memory for Gname");
1323231200Smm			return (ARCHIVE_FATAL);
1324231200Smm		}
1325231200Smm		archive_set_error(&a->archive,
1326231200Smm		    ARCHIVE_ERRNO_FILE_FORMAT,
1327231200Smm		    "Can't translate gname '%s' to UTF-8",
1328231200Smm		    archive_entry_gname(file->entry));
1329231200Smm		r2 = ARCHIVE_WARN;
1330231200Smm	}
1331231200Smm	if (len > 0) {
1332231200Smm		r = xmlwrite_string(a, writer, "group", p);
1333231200Smm		if (r < 0)
1334231200Smm			return (ARCHIVE_FATAL);
1335231200Smm	}
1336231200Smm
1337231200Smm	/*
1338231200Smm	 * Make a ctime entry, "<ctime>".
1339231200Smm	 */
1340231200Smm	if (archive_entry_ctime_is_set(file->entry)) {
1341231200Smm		r = xmlwrite_time(a, writer, "ctime",
1342231200Smm		    archive_entry_ctime(file->entry), 1);
1343231200Smm		if (r < 0)
1344231200Smm			return (ARCHIVE_FATAL);
1345231200Smm	}
1346231200Smm
1347231200Smm	/*
1348231200Smm	 * Make a mtime entry, "<mtime>".
1349231200Smm	 */
1350231200Smm	if (archive_entry_mtime_is_set(file->entry)) {
1351231200Smm		r = xmlwrite_time(a, writer, "mtime",
1352231200Smm		    archive_entry_mtime(file->entry), 1);
1353231200Smm		if (r < 0)
1354231200Smm			return (ARCHIVE_FATAL);
1355231200Smm	}
1356231200Smm
1357231200Smm	/*
1358231200Smm	 * Make a atime entry, "<atime>".
1359231200Smm	 */
1360231200Smm	if (archive_entry_atime_is_set(file->entry)) {
1361231200Smm		r = xmlwrite_time(a, writer, "atime",
1362231200Smm		    archive_entry_atime(file->entry), 1);
1363231200Smm		if (r < 0)
1364231200Smm			return (ARCHIVE_FATAL);
1365231200Smm	}
1366231200Smm
1367231200Smm	/*
1368231200Smm	 * Make fflags entries, "<flags>" and "<ext2>".
1369231200Smm	 */
1370231200Smm	fflags = archive_entry_fflags_text(file->entry);
1371231200Smm	if (fflags != NULL) {
1372231200Smm		r = make_fflags_entry(a, writer, "flags", fflags);
1373231200Smm		if (r < 0)
1374231200Smm			return (r);
1375231200Smm		r = make_fflags_entry(a, writer, "ext2", fflags);
1376231200Smm		if (r < 0)
1377231200Smm			return (r);
1378231200Smm	}
1379231200Smm
1380231200Smm	/*
1381231200Smm	 * Make extended attribute entries, "<ea>".
1382231200Smm	 */
1383231200Smm	archive_entry_xattr_reset(file->entry);
1384231200Smm	for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
1385231200Smm		const char *name;
1386231200Smm		const void *value;
1387231200Smm		size_t size;
1388231200Smm
1389231200Smm		archive_entry_xattr_next(file->entry,
1390231200Smm		    &name, &value, &size);
1391231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
1392231200Smm		if (r < 0) {
1393231200Smm			archive_set_error(&a->archive,
1394231200Smm			    ARCHIVE_ERRNO_MISC,
1395231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1396231200Smm			return (ARCHIVE_FATAL);
1397231200Smm		}
1398231200Smm		r = xmlTextWriterWriteFormatAttribute(writer,
1399231200Smm		    BAD_CAST("id"), "%d", heap->id);
1400231200Smm		if (r < 0) {
1401231200Smm			archive_set_error(&a->archive,
1402231200Smm			    ARCHIVE_ERRNO_MISC,
1403231200Smm			    "xmlTextWriterWriteAttribute() failed: %d", r);
1404231200Smm			return (ARCHIVE_FATAL);
1405231200Smm		}
1406231200Smm		r = xmlwrite_heap(a, writer, heap);
1407231200Smm		if (r < 0)
1408231200Smm			return (ARCHIVE_FATAL);
1409231200Smm		r = xmlwrite_string(a, writer, "name", name);
1410231200Smm		if (r < 0)
1411231200Smm			return (ARCHIVE_FATAL);
1412231200Smm
1413231200Smm		r = xmlTextWriterEndElement(writer);
1414231200Smm		if (r < 0) {
1415231200Smm			archive_set_error(&a->archive,
1416231200Smm			    ARCHIVE_ERRNO_MISC,
1417231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1418231200Smm			return (ARCHIVE_FATAL);
1419231200Smm		}
1420231200Smm	}
1421231200Smm
1422231200Smm	/*
1423231200Smm	 * Make a file data entry, "<data>".
1424231200Smm	 */
1425231200Smm	if (file->data.length > 0) {
1426231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
1427231200Smm		if (r < 0) {
1428231200Smm			archive_set_error(&a->archive,
1429231200Smm			    ARCHIVE_ERRNO_MISC,
1430231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1431231200Smm			return (ARCHIVE_FATAL);
1432231200Smm		}
1433231200Smm
1434231200Smm		r = xmlwrite_heap(a, writer, &(file->data));
1435231200Smm		if (r < 0)
1436231200Smm			return (ARCHIVE_FATAL);
1437231200Smm
1438231200Smm		r = xmlTextWriterEndElement(writer);
1439231200Smm		if (r < 0) {
1440231200Smm			archive_set_error(&a->archive,
1441231200Smm			    ARCHIVE_ERRNO_MISC,
1442231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1443231200Smm			return (ARCHIVE_FATAL);
1444231200Smm		}
1445231200Smm	}
1446231200Smm
1447231200Smm	if (archive_strlen(&file->script) > 0) {
1448231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
1449231200Smm		if (r < 0) {
1450231200Smm			archive_set_error(&a->archive,
1451231200Smm			    ARCHIVE_ERRNO_MISC,
1452231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1453231200Smm			return (ARCHIVE_FATAL);
1454231200Smm		}
1455231200Smm
1456231200Smm		r = xmlwrite_string(a, writer,
1457231200Smm		    "interpreter", file->script.s);
1458231200Smm		if (r < 0)
1459231200Smm			return (ARCHIVE_FATAL);
1460231200Smm
1461231200Smm		r = xmlwrite_string(a, writer, "type", "script");
1462231200Smm		if (r < 0)
1463231200Smm			return (ARCHIVE_FATAL);
1464231200Smm
1465231200Smm		r = xmlTextWriterEndElement(writer);
1466231200Smm		if (r < 0) {
1467231200Smm			archive_set_error(&a->archive,
1468231200Smm			    ARCHIVE_ERRNO_MISC,
1469231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1470231200Smm			return (ARCHIVE_FATAL);
1471231200Smm		}
1472231200Smm	}
1473231200Smm
1474231200Smm	return (r2);
1475231200Smm}
1476231200Smm
1477231200Smm/*
1478231200Smm * Make the TOC
1479231200Smm */
1480231200Smmstatic int
1481231200Smmmake_toc(struct archive_write *a)
1482231200Smm{
1483231200Smm	struct xar *xar;
1484231200Smm	struct file *np;
1485231200Smm	xmlBufferPtr bp;
1486231200Smm	xmlTextWriterPtr writer;
1487231200Smm	int algsize;
1488231200Smm	int r, ret;
1489231200Smm
1490231200Smm	xar = (struct xar *)a->format_data;
1491231200Smm
1492231200Smm	ret = ARCHIVE_FATAL;
1493231200Smm
1494231200Smm	/*
1495231200Smm	 * Initialize xml writer.
1496231200Smm	 */
1497231200Smm	writer = NULL;
1498231200Smm	bp = xmlBufferCreate();
1499231200Smm	if (bp == NULL) {
1500231200Smm		archive_set_error(&a->archive, ENOMEM,
1501231200Smm		    "xmlBufferCreate() "
1502231200Smm		    "couldn't create xml buffer");
1503231200Smm		goto exit_toc;
1504231200Smm	}
1505231200Smm	writer = xmlNewTextWriterMemory(bp, 0);
1506231200Smm	if (writer == NULL) {
1507231200Smm		archive_set_error(&a->archive,
1508231200Smm		    ARCHIVE_ERRNO_MISC,
1509231200Smm		    "xmlNewTextWriterMemory() "
1510231200Smm		    "couldn't create xml writer");
1511231200Smm		goto exit_toc;
1512231200Smm	}
1513231200Smm	r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
1514231200Smm	if (r < 0) {
1515231200Smm		archive_set_error(&a->archive,
1516231200Smm		    ARCHIVE_ERRNO_MISC,
1517231200Smm		    "xmlTextWriterStartDocument() failed: %d", r);
1518231200Smm		goto exit_toc;
1519231200Smm	}
1520231200Smm	r = xmlTextWriterSetIndent(writer, 4);
1521231200Smm	if (r < 0) {
1522231200Smm		archive_set_error(&a->archive,
1523231200Smm		    ARCHIVE_ERRNO_MISC,
1524231200Smm		    "xmlTextWriterSetIndent() failed: %d", r);
1525231200Smm		goto exit_toc;
1526231200Smm	}
1527231200Smm
1528231200Smm	/*
1529231200Smm	 * Start recoding TOC
1530231200Smm	 */
1531231200Smm	r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
1532231200Smm	if (r < 0) {
1533231200Smm		archive_set_error(&a->archive,
1534231200Smm		    ARCHIVE_ERRNO_MISC,
1535231200Smm		    "xmlTextWriterStartElement() failed: %d", r);
1536231200Smm		goto exit_toc;
1537231200Smm	}
1538231200Smm	r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
1539231200Smm	if (r < 0) {
1540231200Smm		archive_set_error(&a->archive,
1541231200Smm		    ARCHIVE_ERRNO_MISC,
1542231200Smm		    "xmlTextWriterStartDocument() failed: %d", r);
1543231200Smm		goto exit_toc;
1544231200Smm	}
1545231200Smm
1546231200Smm	/*
1547231200Smm	 * Record the creation time of the archive file.
1548231200Smm	 */
1549231200Smm	r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
1550231200Smm	if (r < 0)
1551231200Smm		goto exit_toc;
1552231200Smm
1553231200Smm	/*
1554231200Smm	 * Record the checksum value of TOC
1555231200Smm	 */
1556231200Smm	algsize = getalgsize(xar->opt_toc_sumalg);
1557231200Smm	if (algsize) {
1558231200Smm		/*
1559231200Smm		 * Record TOC checksum
1560231200Smm		 */
1561231200Smm		r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
1562231200Smm		if (r < 0) {
1563231200Smm			archive_set_error(&a->archive,
1564231200Smm			    ARCHIVE_ERRNO_MISC,
1565231200Smm			    "xmlTextWriterStartElement() failed: %d", r);
1566231200Smm			goto exit_toc;
1567231200Smm		}
1568231200Smm		r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
1569232153Smm		    BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
1570231200Smm		if (r < 0) {
1571231200Smm			archive_set_error(&a->archive,
1572231200Smm			    ARCHIVE_ERRNO_MISC,
1573231200Smm			    "xmlTextWriterWriteAttribute() failed: %d", r);
1574231200Smm			goto exit_toc;
1575231200Smm		}
1576231200Smm
1577231200Smm		/*
1578231200Smm		 * Record the offset of the value of checksum of TOC
1579231200Smm		 */
1580231200Smm		r = xmlwrite_string(a, writer, "offset", "0");
1581231200Smm		if (r < 0)
1582231200Smm			goto exit_toc;
1583231200Smm
1584231200Smm		/*
1585231200Smm		 * Record the size of the value of checksum of TOC
1586231200Smm		 */
1587231200Smm		r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
1588231200Smm		if (r < 0)
1589231200Smm			goto exit_toc;
1590231200Smm
1591231200Smm		r = xmlTextWriterEndElement(writer);
1592231200Smm		if (r < 0) {
1593231200Smm			archive_set_error(&a->archive,
1594231200Smm			    ARCHIVE_ERRNO_MISC,
1595231200Smm			    "xmlTextWriterEndElement() failed: %d", r);
1596231200Smm			goto exit_toc;
1597231200Smm		}
1598231200Smm	}
1599231200Smm
1600231200Smm	np = xar->root;
1601231200Smm	do {
1602231200Smm		if (np != np->parent) {
1603231200Smm			r = make_file_entry(a, writer, np);
1604231200Smm			if (r != ARCHIVE_OK)
1605231200Smm				goto exit_toc;
1606231200Smm		}
1607231200Smm
1608231200Smm		if (np->dir && np->children.first != NULL) {
1609231200Smm			/* Enter to sub directories. */
1610231200Smm			np = np->children.first;
1611231200Smm			r = xmlTextWriterStartElement(writer,
1612231200Smm			    BAD_CAST("file"));
1613231200Smm			if (r < 0) {
1614231200Smm				archive_set_error(&a->archive,
1615231200Smm				    ARCHIVE_ERRNO_MISC,
1616231200Smm				    "xmlTextWriterStartElement() "
1617231200Smm				    "failed: %d", r);
1618231200Smm				goto exit_toc;
1619231200Smm			}
1620231200Smm			r = xmlTextWriterWriteFormatAttribute(
1621231200Smm			    writer, BAD_CAST("id"), "%d", np->id);
1622231200Smm			if (r < 0) {
1623231200Smm				archive_set_error(&a->archive,
1624231200Smm				    ARCHIVE_ERRNO_MISC,
1625231200Smm				    "xmlTextWriterWriteAttribute() "
1626231200Smm				    "failed: %d", r);
1627231200Smm				goto exit_toc;
1628231200Smm			}
1629231200Smm			continue;
1630231200Smm		}
1631231200Smm		while (np != np->parent) {
1632231200Smm			r = xmlTextWriterEndElement(writer);
1633231200Smm			if (r < 0) {
1634231200Smm				archive_set_error(&a->archive,
1635231200Smm				    ARCHIVE_ERRNO_MISC,
1636231200Smm				    "xmlTextWriterEndElement() "
1637231200Smm				    "failed: %d", r);
1638231200Smm				goto exit_toc;
1639231200Smm			}
1640231200Smm			if (np->chnext == NULL) {
1641231200Smm				/* Return to the parent directory. */
1642231200Smm				np = np->parent;
1643231200Smm			} else {
1644231200Smm				np = np->chnext;
1645231200Smm				r = xmlTextWriterStartElement(writer,
1646231200Smm				    BAD_CAST("file"));
1647231200Smm				if (r < 0) {
1648231200Smm					archive_set_error(&a->archive,
1649231200Smm					    ARCHIVE_ERRNO_MISC,
1650231200Smm					    "xmlTextWriterStartElement() "
1651231200Smm					    "failed: %d", r);
1652231200Smm					goto exit_toc;
1653231200Smm				}
1654231200Smm				r = xmlTextWriterWriteFormatAttribute(
1655231200Smm				    writer, BAD_CAST("id"), "%d", np->id);
1656231200Smm				if (r < 0) {
1657231200Smm					archive_set_error(&a->archive,
1658231200Smm					    ARCHIVE_ERRNO_MISC,
1659231200Smm					    "xmlTextWriterWriteAttribute() "
1660231200Smm					    "failed: %d", r);
1661231200Smm					goto exit_toc;
1662231200Smm				}
1663231200Smm				break;
1664231200Smm			}
1665231200Smm		}
1666231200Smm	} while (np != np->parent);
1667231200Smm
1668231200Smm	r = xmlTextWriterEndDocument(writer);
1669231200Smm	if (r < 0) {
1670231200Smm		archive_set_error(&a->archive,
1671231200Smm		    ARCHIVE_ERRNO_MISC,
1672231200Smm		    "xmlTextWriterEndDocument() failed: %d", r);
1673231200Smm		goto exit_toc;
1674231200Smm	}
1675231200Smm#if DEBUG_PRINT_TOC
1676231200Smm	fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
1677231200Smm	    strlen((const char *)bp->content), bp->content);
1678231200Smm#endif
1679231200Smm
1680231200Smm	/*
1681231200Smm	 * Compress the TOC and calculate the sum of the TOC.
1682231200Smm	 */
1683231200Smm	xar->toc.temp_offset = xar->temp_offset;
1684231200Smm	xar->toc.size = bp->use;
1685231200Smm	checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
1686231200Smm
1687231200Smm	r = compression_init_encoder_gzip(&(a->archive),
1688231200Smm	    &(xar->stream), 6, 1);
1689231200Smm	if (r != ARCHIVE_OK)
1690231200Smm		goto exit_toc;
1691231200Smm	xar->stream.next_in = bp->content;
1692231200Smm	xar->stream.avail_in = bp->use;
1693231200Smm	xar->stream.total_in = 0;
1694231200Smm	xar->stream.next_out = xar->wbuff;
1695231200Smm	xar->stream.avail_out = sizeof(xar->wbuff);
1696231200Smm	xar->stream.total_out = 0;
1697231200Smm	for (;;) {
1698231200Smm		size_t size;
1699231200Smm
1700231200Smm		r = compression_code(&(a->archive),
1701231200Smm		    &(xar->stream), ARCHIVE_Z_FINISH);
1702231200Smm		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
1703231200Smm			goto exit_toc;
1704231200Smm		size = sizeof(xar->wbuff) - xar->stream.avail_out;
1705231200Smm		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
1706231200Smm		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
1707231200Smm			goto exit_toc;
1708231200Smm		if (r == ARCHIVE_EOF)
1709231200Smm			break;
1710231200Smm		xar->stream.next_out = xar->wbuff;
1711231200Smm		xar->stream.avail_out = sizeof(xar->wbuff);
1712231200Smm	}
1713231200Smm	r = compression_end(&(a->archive), &(xar->stream));
1714231200Smm	if (r != ARCHIVE_OK)
1715231200Smm		goto exit_toc;
1716231200Smm	xar->toc.length = xar->stream.total_out;
1717231200Smm	xar->toc.compression = GZIP;
1718231200Smm	checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
1719231200Smm
1720231200Smm	ret = ARCHIVE_OK;
1721231200Smmexit_toc:
1722231200Smm	if (writer)
1723231200Smm		xmlFreeTextWriter(writer);
1724231200Smm	if (bp)
1725231200Smm		xmlBufferFree(bp);
1726231200Smm
1727231200Smm	return (ret);
1728231200Smm}
1729231200Smm
1730231200Smmstatic int
1731231200Smmflush_wbuff(struct archive_write *a)
1732231200Smm{
1733231200Smm	struct xar *xar;
1734231200Smm	int r;
1735231200Smm	size_t s;
1736231200Smm
1737231200Smm	xar = (struct xar *)a->format_data;
1738231200Smm	s = sizeof(xar->wbuff) - xar->wbuff_remaining;
1739231200Smm	r = __archive_write_output(a, xar->wbuff, s);
1740231200Smm	if (r != ARCHIVE_OK)
1741231200Smm		return (r);
1742231200Smm	xar->wbuff_remaining = sizeof(xar->wbuff);
1743231200Smm	return (r);
1744231200Smm}
1745231200Smm
1746231200Smmstatic int
1747231200Smmcopy_out(struct archive_write *a, uint64_t offset, uint64_t length)
1748231200Smm{
1749231200Smm	struct xar *xar;
1750231200Smm	int r;
1751231200Smm
1752231200Smm	xar = (struct xar *)a->format_data;
1753231200Smm	if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
1754231200Smm		archive_set_error(&(a->archive), errno, "lseek failed");
1755231200Smm		return (ARCHIVE_FATAL);
1756231200Smm	}
1757231200Smm	while (length) {
1758231200Smm		size_t rsize;
1759231200Smm		ssize_t rs;
1760231200Smm		unsigned char *wb;
1761231200Smm
1762231200Smm		if (length > xar->wbuff_remaining)
1763231200Smm			rsize = xar->wbuff_remaining;
1764231200Smm		else
1765231200Smm			rsize = (size_t)length;
1766231200Smm		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
1767231200Smm		rs = read(xar->temp_fd, wb, rsize);
1768231200Smm		if (rs < 0) {
1769231200Smm			archive_set_error(&(a->archive), errno,
1770231200Smm			    "Can't read temporary file(%jd)",
1771231200Smm			    (intmax_t)rs);
1772231200Smm			return (ARCHIVE_FATAL);
1773231200Smm		}
1774231200Smm		if (rs == 0) {
1775231200Smm			archive_set_error(&(a->archive), 0,
1776231200Smm			    "Truncated xar archive");
1777231200Smm			return (ARCHIVE_FATAL);
1778231200Smm		}
1779231200Smm		xar->wbuff_remaining -= rs;
1780231200Smm		length -= rs;
1781231200Smm		if (xar->wbuff_remaining == 0) {
1782231200Smm			r = flush_wbuff(a);
1783231200Smm			if (r != ARCHIVE_OK)
1784231200Smm				return (r);
1785231200Smm		}
1786231200Smm	}
1787231200Smm	return (ARCHIVE_OK);
1788231200Smm}
1789231200Smm
1790231200Smmstatic int
1791231200Smmxar_close(struct archive_write *a)
1792231200Smm{
1793231200Smm	struct xar *xar;
1794231200Smm	unsigned char *wb;
1795231200Smm	uint64_t length;
1796231200Smm	int r;
1797231200Smm
1798231200Smm	xar = (struct xar *)a->format_data;
1799231200Smm
1800231200Smm	/* Empty! */
1801231200Smm	if (xar->root->children.first == NULL)
1802231200Smm		return (ARCHIVE_OK);
1803231200Smm
1804231200Smm	/* Save the length of all file extended attributes and contents. */
1805231200Smm	length = xar->temp_offset;
1806231200Smm
1807231200Smm	/* Connect hardlinked files */
1808231200Smm	file_connect_hardlink_files(xar);
1809231200Smm
1810231200Smm	/* Make the TOC */
1811231200Smm	r = make_toc(a);
1812231200Smm	if (r != ARCHIVE_OK)
1813231200Smm		return (r);
1814231200Smm	/*
1815231200Smm	 * Make the xar header on wbuff(write buffer).
1816231200Smm	 */
1817231200Smm	wb = xar->wbuff;
1818231200Smm	xar->wbuff_remaining = sizeof(xar->wbuff);
1819231200Smm	archive_be32enc(&wb[0], HEADER_MAGIC);
1820231200Smm	archive_be16enc(&wb[4], HEADER_SIZE);
1821231200Smm	archive_be16enc(&wb[6], HEADER_VERSION);
1822231200Smm	archive_be64enc(&wb[8], xar->toc.length);
1823231200Smm	archive_be64enc(&wb[16], xar->toc.size);
1824231200Smm	archive_be32enc(&wb[24], xar->toc.a_sum.alg);
1825231200Smm	xar->wbuff_remaining -= HEADER_SIZE;
1826231200Smm
1827231200Smm	/*
1828231200Smm	 * Write the TOC
1829231200Smm	 */
1830231200Smm	r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
1831231200Smm	if (r != ARCHIVE_OK)
1832231200Smm		return (r);
1833231200Smm
1834231200Smm	/* Write the checksum value of the TOC. */
1835231200Smm	if (xar->toc.a_sum.len) {
1836231200Smm		if (xar->wbuff_remaining < xar->toc.a_sum.len) {
1837231200Smm			r = flush_wbuff(a);
1838231200Smm			if (r != ARCHIVE_OK)
1839231200Smm				return (r);
1840231200Smm		}
1841231200Smm		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
1842231200Smm		memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
1843231200Smm		xar->wbuff_remaining -= xar->toc.a_sum.len;
1844231200Smm	}
1845231200Smm
1846231200Smm	/*
1847231200Smm	 * Write all file extended attributes and contents.
1848231200Smm	 */
1849231200Smm	r = copy_out(a, xar->toc.a_sum.len, length);
1850231200Smm	if (r != ARCHIVE_OK)
1851231200Smm		return (r);
1852231200Smm	r = flush_wbuff(a);
1853231200Smm	return (r);
1854231200Smm}
1855231200Smm
1856231200Smmstatic int
1857231200Smmxar_free(struct archive_write *a)
1858231200Smm{
1859231200Smm	struct xar *xar;
1860231200Smm
1861231200Smm	xar = (struct xar *)a->format_data;
1862231200Smm	archive_string_free(&(xar->cur_dirstr));
1863231200Smm	archive_string_free(&(xar->tstr));
1864231200Smm	archive_string_free(&(xar->vstr));
1865231200Smm	file_free_hardlinks(xar);
1866231200Smm	file_free_register(xar);
1867231200Smm	compression_end(&(a->archive), &(xar->stream));
1868231200Smm	free(xar);
1869231200Smm
1870231200Smm	return (ARCHIVE_OK);
1871231200Smm}
1872231200Smm
1873231200Smmstatic int
1874231200Smmfile_cmp_node(const struct archive_rb_node *n1,
1875231200Smm    const struct archive_rb_node *n2)
1876231200Smm{
1877232153Smm	const struct file *f1 = (const struct file *)n1;
1878232153Smm	const struct file *f2 = (const struct file *)n2;
1879231200Smm
1880231200Smm	return (strcmp(f1->basename.s, f2->basename.s));
1881231200Smm}
1882231200Smm
1883231200Smmstatic int
1884231200Smmfile_cmp_key(const struct archive_rb_node *n, const void *key)
1885231200Smm{
1886232153Smm	const struct file *f = (const struct file *)n;
1887231200Smm
1888231200Smm	return (strcmp(f->basename.s, (const char *)key));
1889231200Smm}
1890231200Smm
1891231200Smmstatic struct file *
1892231200Smmfile_new(struct archive_write *a, struct archive_entry *entry)
1893231200Smm{
1894231200Smm	struct file *file;
1895231200Smm	static const struct archive_rb_tree_ops rb_ops = {
1896231200Smm		file_cmp_node, file_cmp_key
1897231200Smm	};
1898231200Smm
1899231200Smm	file = calloc(1, sizeof(*file));
1900231200Smm	if (file == NULL)
1901231200Smm		return (NULL);
1902231200Smm
1903231200Smm	if (entry != NULL)
1904231200Smm		file->entry = archive_entry_clone(entry);
1905231200Smm	else
1906231200Smm		file->entry = archive_entry_new2(&a->archive);
1907231200Smm	if (file->entry == NULL) {
1908231200Smm		free(file);
1909231200Smm		return (NULL);
1910231200Smm	}
1911231200Smm	__archive_rb_tree_init(&(file->rbtree), &rb_ops);
1912231200Smm	file->children.first = NULL;
1913231200Smm	file->children.last = &(file->children.first);
1914231200Smm	file->xattr.first = NULL;
1915231200Smm	file->xattr.last = &(file->xattr.first);
1916231200Smm	archive_string_init(&(file->parentdir));
1917231200Smm	archive_string_init(&(file->basename));
1918231200Smm	archive_string_init(&(file->symlink));
1919231200Smm	archive_string_init(&(file->script));
1920231200Smm	if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
1921231200Smm		file->dir = 1;
1922231200Smm
1923231200Smm	return (file);
1924231200Smm}
1925231200Smm
1926231200Smmstatic void
1927231200Smmfile_free(struct file *file)
1928231200Smm{
1929231200Smm	struct heap_data *heap, *next_heap;
1930231200Smm
1931231200Smm	heap = file->xattr.first;
1932231200Smm	while (heap != NULL) {
1933231200Smm		next_heap = heap->next;
1934231200Smm		free(heap);
1935231200Smm		heap = next_heap;
1936231200Smm	}
1937231200Smm	archive_string_free(&(file->parentdir));
1938231200Smm	archive_string_free(&(file->basename));
1939231200Smm	archive_string_free(&(file->symlink));
1940231200Smm	archive_string_free(&(file->script));
1941231200Smm	free(file);
1942231200Smm}
1943231200Smm
1944231200Smmstatic struct file *
1945231200Smmfile_create_virtual_dir(struct archive_write *a, struct xar *xar,
1946231200Smm    const char *pathname)
1947231200Smm{
1948231200Smm	struct file *file;
1949231200Smm
1950232153Smm	(void)xar; /* UNUSED */
1951232153Smm
1952231200Smm	file = file_new(a, NULL);
1953231200Smm	if (file == NULL)
1954231200Smm		return (NULL);
1955231200Smm	archive_entry_set_pathname(file->entry, pathname);
1956231200Smm	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
1957231200Smm
1958231200Smm	file->dir = 1;
1959231200Smm	file->virtual = 1;
1960231200Smm
1961231200Smm	return (file);
1962231200Smm}
1963231200Smm
1964231200Smmstatic int
1965231200Smmfile_add_child_tail(struct file *parent, struct file *child)
1966231200Smm{
1967231200Smm	if (!__archive_rb_tree_insert_node(
1968231200Smm	    &(parent->rbtree), (struct archive_rb_node *)child))
1969231200Smm		return (0);
1970231200Smm	child->chnext = NULL;
1971231200Smm	*parent->children.last = child;
1972231200Smm	parent->children.last = &(child->chnext);
1973231200Smm	child->parent = parent;
1974231200Smm	return (1);
1975231200Smm}
1976231200Smm
1977231200Smm/*
1978231200Smm * Find a entry from `parent'
1979231200Smm */
1980231200Smmstatic struct file *
1981231200Smmfile_find_child(struct file *parent, const char *child_name)
1982231200Smm{
1983231200Smm	struct file *np;
1984231200Smm
1985231200Smm	np = (struct file *)__archive_rb_tree_find_node(
1986231200Smm	    &(parent->rbtree), child_name);
1987231200Smm	return (np);
1988231200Smm}
1989231200Smm
1990231200Smm#if defined(_WIN32) || defined(__CYGWIN__)
1991231200Smmstatic void
1992231200Smmcleanup_backslash(char *utf8, size_t len)
1993231200Smm{
1994231200Smm
1995231200Smm	/* Convert a path-separator from '\' to  '/' */
1996231200Smm	while (*utf8 != '\0' && len) {
1997231200Smm		if (*utf8 == '\\')
1998231200Smm			*utf8 = '/';
1999231200Smm		++utf8;
2000231200Smm		--len;
2001231200Smm	}
2002231200Smm}
2003231200Smm#else
2004231200Smm#define cleanup_backslash(p, len)	/* nop */
2005231200Smm#endif
2006231200Smm
2007231200Smm/*
2008231200Smm * Generate a parent directory name and a base name from a pathname.
2009231200Smm */
2010231200Smmstatic int
2011231200Smmfile_gen_utility_names(struct archive_write *a, struct file *file)
2012231200Smm{
2013231200Smm	struct xar *xar;
2014231200Smm	const char *pp;
2015231200Smm	char *p, *dirname, *slash;
2016231200Smm	size_t len;
2017231200Smm	int r = ARCHIVE_OK;
2018231200Smm
2019231200Smm	xar = (struct xar *)a->format_data;
2020231200Smm	archive_string_empty(&(file->parentdir));
2021231200Smm	archive_string_empty(&(file->basename));
2022231200Smm	archive_string_empty(&(file->symlink));
2023231200Smm
2024231200Smm	if (file->parent == file)/* virtual root */
2025231200Smm		return (ARCHIVE_OK);
2026231200Smm
2027231200Smm	if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)
2028231200Smm	    != 0) {
2029231200Smm		if (errno == ENOMEM) {
2030231200Smm			archive_set_error(&a->archive, ENOMEM,
2031231200Smm			    "Can't allocate memory for Pathname");
2032231200Smm			return (ARCHIVE_FATAL);
2033231200Smm		}
2034231200Smm		archive_set_error(&a->archive,
2035231200Smm		    ARCHIVE_ERRNO_FILE_FORMAT,
2036231200Smm		    "Can't translate pathname '%s' to UTF-8",
2037231200Smm		    archive_entry_pathname(file->entry));
2038231200Smm		r = ARCHIVE_WARN;
2039231200Smm	}
2040231200Smm	archive_strncpy(&(file->parentdir), pp, len);
2041231200Smm	len = file->parentdir.length;
2042231200Smm	p = dirname = file->parentdir.s;
2043231200Smm	/*
2044231200Smm	 * Convert a path-separator from '\' to  '/'
2045231200Smm	 */
2046231200Smm	cleanup_backslash(p, len);
2047231200Smm
2048231200Smm	/*
2049231200Smm	 * Remove leading '/', '../' and './' elements
2050231200Smm	 */
2051231200Smm	while (*p) {
2052231200Smm		if (p[0] == '/') {
2053231200Smm			p++;
2054231200Smm			len--;
2055231200Smm		} else if (p[0] != '.')
2056231200Smm			break;
2057231200Smm		else if (p[1] == '.' && p[2] == '/') {
2058231200Smm			p += 3;
2059231200Smm			len -= 3;
2060231200Smm		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
2061231200Smm			p += 2;
2062231200Smm			len -= 2;
2063231200Smm		} else if (p[1] == '\0') {
2064231200Smm			p++;
2065231200Smm			len--;
2066231200Smm		} else
2067231200Smm			break;
2068231200Smm	}
2069231200Smm	if (p != dirname) {
2070231200Smm		memmove(dirname, p, len+1);
2071231200Smm		p = dirname;
2072231200Smm	}
2073231200Smm	/*
2074231200Smm	 * Remove "/","/." and "/.." elements from tail.
2075231200Smm	 */
2076231200Smm	while (len > 0) {
2077231200Smm		size_t ll = len;
2078231200Smm
2079231200Smm		if (len > 0 && p[len-1] == '/') {
2080231200Smm			p[len-1] = '\0';
2081231200Smm			len--;
2082231200Smm		}
2083231200Smm		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
2084231200Smm			p[len-2] = '\0';
2085231200Smm			len -= 2;
2086231200Smm		}
2087231200Smm		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
2088231200Smm		    p[len-1] == '.') {
2089231200Smm			p[len-3] = '\0';
2090231200Smm			len -= 3;
2091231200Smm		}
2092231200Smm		if (ll == len)
2093231200Smm			break;
2094231200Smm	}
2095231200Smm	while (*p) {
2096231200Smm		if (p[0] == '/') {
2097231200Smm			if (p[1] == '/')
2098231200Smm				/* Convert '//' --> '/' */
2099231200Smm				strcpy(p, p+1);
2100231200Smm			else if (p[1] == '.' && p[2] == '/')
2101231200Smm				/* Convert '/./' --> '/' */
2102231200Smm				strcpy(p, p+2);
2103231200Smm			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
2104231200Smm				/* Convert 'dir/dir1/../dir2/'
2105231200Smm				 *     --> 'dir/dir2/'
2106231200Smm				 */
2107231200Smm				char *rp = p -1;
2108231200Smm				while (rp >= dirname) {
2109231200Smm					if (*rp == '/')
2110231200Smm						break;
2111231200Smm					--rp;
2112231200Smm				}
2113231200Smm				if (rp > dirname) {
2114231200Smm					strcpy(rp, p+3);
2115231200Smm					p = rp;
2116231200Smm				} else {
2117231200Smm					strcpy(dirname, p+4);
2118231200Smm					p = dirname;
2119231200Smm				}
2120231200Smm			} else
2121231200Smm				p++;
2122231200Smm		} else
2123231200Smm			p++;
2124231200Smm	}
2125231200Smm	p = dirname;
2126231200Smm	len = strlen(p);
2127231200Smm
2128231200Smm	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
2129231200Smm		size_t len2;
2130231200Smm		/* Convert symlink name too. */
2131231200Smm		if (archive_entry_symlink_l(file->entry, &pp, &len2,
2132231200Smm		    xar->sconv) != 0) {
2133231200Smm			if (errno == ENOMEM) {
2134231200Smm				archive_set_error(&a->archive, ENOMEM,
2135231200Smm				    "Can't allocate memory for Linkname");
2136231200Smm				return (ARCHIVE_FATAL);
2137231200Smm			}
2138231200Smm			archive_set_error(&a->archive,
2139231200Smm			    ARCHIVE_ERRNO_FILE_FORMAT,
2140231200Smm			    "Can't translate symlink '%s' to UTF-8",
2141231200Smm			    archive_entry_symlink(file->entry));
2142231200Smm			r = ARCHIVE_WARN;
2143231200Smm		}
2144231200Smm		archive_strncpy(&(file->symlink), pp, len2);
2145231200Smm		cleanup_backslash(file->symlink.s, file->symlink.length);
2146231200Smm	}
2147231200Smm	/*
2148231200Smm	 * - Count up directory elements.
2149231200Smm	 * - Find out the position which points the last position of
2150231200Smm	 *   path separator('/').
2151231200Smm	 */
2152231200Smm	slash = NULL;
2153231200Smm	for (; *p != '\0'; p++)
2154231200Smm		if (*p == '/')
2155231200Smm			slash = p;
2156231200Smm	if (slash == NULL) {
2157231200Smm		/* The pathname doesn't have a parent directory. */
2158231200Smm		file->parentdir.length = len;
2159231200Smm		archive_string_copy(&(file->basename), &(file->parentdir));
2160231200Smm		archive_string_empty(&(file->parentdir));
2161231200Smm		file->parentdir.s = '\0';
2162231200Smm		return (r);
2163231200Smm	}
2164231200Smm
2165231200Smm	/* Make a basename from dirname and slash */
2166231200Smm	*slash  = '\0';
2167231200Smm	file->parentdir.length = slash - dirname;
2168231200Smm	archive_strcpy(&(file->basename),  slash + 1);
2169231200Smm	return (r);
2170231200Smm}
2171231200Smm
2172231200Smmstatic int
2173231200Smmget_path_component(char *name, int n, const char *fn)
2174231200Smm{
2175231200Smm	char *p;
2176231200Smm	int l;
2177231200Smm
2178231200Smm	p = strchr(fn, '/');
2179231200Smm	if (p == NULL) {
2180231200Smm		if ((l = strlen(fn)) == 0)
2181231200Smm			return (0);
2182231200Smm	} else
2183231200Smm		l = p - fn;
2184231200Smm	if (l > n -1)
2185231200Smm		return (-1);
2186231200Smm	memcpy(name, fn, l);
2187231200Smm	name[l] = '\0';
2188231200Smm
2189231200Smm	return (l);
2190231200Smm}
2191231200Smm
2192231200Smm/*
2193231200Smm * Add a new entry into the tree.
2194231200Smm */
2195231200Smmstatic int
2196231200Smmfile_tree(struct archive_write *a, struct file **filepp)
2197231200Smm{
2198231200Smm#if defined(_WIN32) && !defined(__CYGWIN__)
2199231200Smm	char name[_MAX_FNAME];/* Included null terminator size. */
2200231200Smm#elif defined(NAME_MAX) && NAME_MAX >= 255
2201231200Smm	char name[NAME_MAX+1];
2202231200Smm#else
2203231200Smm	char name[256];
2204231200Smm#endif
2205231200Smm	struct xar *xar = (struct xar *)a->format_data;
2206231200Smm	struct file *dent, *file, *np;
2207231200Smm	struct archive_entry *ent;
2208231200Smm	const char *fn, *p;
2209231200Smm	int l;
2210231200Smm
2211231200Smm	file = *filepp;
2212231200Smm	dent = xar->root;
2213231200Smm	if (file->parentdir.length > 0)
2214231200Smm		fn = p = file->parentdir.s;
2215231200Smm	else
2216231200Smm		fn = p = "";
2217231200Smm
2218231200Smm	/*
2219231200Smm	 * If the path of the parent directory of `file' entry is
2220231200Smm	 * the same as the path of `cur_dirent', add isoent to
2221231200Smm	 * `cur_dirent'.
2222231200Smm	 */
2223231200Smm	if (archive_strlen(&(xar->cur_dirstr))
2224231200Smm	      == archive_strlen(&(file->parentdir)) &&
2225231200Smm	    strcmp(xar->cur_dirstr.s, fn) == 0) {
2226231200Smm		if (!file_add_child_tail(xar->cur_dirent, file)) {
2227231200Smm			np = (struct file *)__archive_rb_tree_find_node(
2228231200Smm			    &(xar->cur_dirent->rbtree),
2229231200Smm			    file->basename.s);
2230231200Smm			goto same_entry;
2231231200Smm		}
2232231200Smm		return (ARCHIVE_OK);
2233231200Smm	}
2234231200Smm
2235231200Smm	for (;;) {
2236231200Smm		l = get_path_component(name, sizeof(name), fn);
2237231200Smm		if (l == 0) {
2238231200Smm			np = NULL;
2239231200Smm			break;
2240231200Smm		}
2241231200Smm		if (l < 0) {
2242231200Smm			archive_set_error(&a->archive,
2243231200Smm			    ARCHIVE_ERRNO_MISC,
2244231200Smm			    "A name buffer is too small");
2245231200Smm			file_free(file);
2246231200Smm			*filepp = NULL;
2247231200Smm			return (ARCHIVE_FATAL);
2248231200Smm		}
2249231200Smm
2250231200Smm		np = file_find_child(dent, name);
2251231200Smm		if (np == NULL || fn[0] == '\0')
2252231200Smm			break;
2253231200Smm
2254231200Smm		/* Find next subdirectory. */
2255231200Smm		if (!np->dir) {
2256231200Smm			/* NOT Directory! */
2257231200Smm			archive_set_error(&a->archive,
2258231200Smm			    ARCHIVE_ERRNO_MISC,
2259231200Smm			    "`%s' is not directory, we cannot insert `%s' ",
2260231200Smm			    archive_entry_pathname(np->entry),
2261231200Smm			    archive_entry_pathname(file->entry));
2262231200Smm			file_free(file);
2263231200Smm			*filepp = NULL;
2264231200Smm			return (ARCHIVE_FAILED);
2265231200Smm		}
2266231200Smm		fn += l;
2267231200Smm		if (fn[0] == '/')
2268231200Smm			fn++;
2269231200Smm		dent = np;
2270231200Smm	}
2271231200Smm	if (np == NULL) {
2272231200Smm		/*
2273231200Smm		 * Create virtual parent directories.
2274231200Smm		 */
2275231200Smm		while (fn[0] != '\0') {
2276231200Smm			struct file *vp;
2277231200Smm			struct archive_string as;
2278231200Smm
2279231200Smm			archive_string_init(&as);
2280231200Smm			archive_strncat(&as, p, fn - p + l);
2281231200Smm			if (as.s[as.length-1] == '/') {
2282231200Smm				as.s[as.length-1] = '\0';
2283231200Smm				as.length--;
2284231200Smm			}
2285231200Smm			vp = file_create_virtual_dir(a, xar, as.s);
2286231200Smm			if (vp == NULL) {
2287231200Smm				archive_string_free(&as);
2288231200Smm				archive_set_error(&a->archive, ENOMEM,
2289231200Smm				    "Can't allocate memory");
2290231200Smm				file_free(file);
2291231200Smm				*filepp = NULL;
2292231200Smm				return (ARCHIVE_FATAL);
2293231200Smm			}
2294231200Smm			archive_string_free(&as);
2295231200Smm			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
2296231200Smm				return (ARCHIVE_FATAL);
2297231200Smm			file_add_child_tail(dent, vp);
2298231200Smm			file_register(xar, vp);
2299231200Smm			np = vp;
2300231200Smm
2301231200Smm			fn += l;
2302231200Smm			if (fn[0] == '/')
2303231200Smm				fn++;
2304231200Smm			l = get_path_component(name, sizeof(name), fn);
2305231200Smm			if (l < 0) {
2306231200Smm				archive_string_free(&as);
2307231200Smm				archive_set_error(&a->archive,
2308231200Smm				    ARCHIVE_ERRNO_MISC,
2309231200Smm				    "A name buffer is too small");
2310231200Smm				file_free(file);
2311231200Smm				*filepp = NULL;
2312231200Smm				return (ARCHIVE_FATAL);
2313231200Smm			}
2314231200Smm			dent = np;
2315231200Smm		}
2316231200Smm
2317231200Smm		/* Found out the parent directory where isoent can be
2318231200Smm		 * inserted. */
2319231200Smm		xar->cur_dirent = dent;
2320231200Smm		archive_string_empty(&(xar->cur_dirstr));
2321231200Smm		archive_string_ensure(&(xar->cur_dirstr),
2322231200Smm		    archive_strlen(&(dent->parentdir)) +
2323231200Smm		    archive_strlen(&(dent->basename)) + 2);
2324231200Smm		if (archive_strlen(&(dent->parentdir)) +
2325231200Smm		    archive_strlen(&(dent->basename)) == 0)
2326231200Smm			xar->cur_dirstr.s[0] = 0;
2327231200Smm		else {
2328231200Smm			if (archive_strlen(&(dent->parentdir)) > 0) {
2329231200Smm				archive_string_copy(&(xar->cur_dirstr),
2330231200Smm				    &(dent->parentdir));
2331231200Smm				archive_strappend_char(&(xar->cur_dirstr), '/');
2332231200Smm			}
2333231200Smm			archive_string_concat(&(xar->cur_dirstr),
2334231200Smm			    &(dent->basename));
2335231200Smm		}
2336231200Smm
2337231200Smm		if (!file_add_child_tail(dent, file)) {
2338231200Smm			np = (struct file *)__archive_rb_tree_find_node(
2339231200Smm			    &(dent->rbtree), file->basename.s);
2340231200Smm			goto same_entry;
2341231200Smm		}
2342231200Smm		return (ARCHIVE_OK);
2343231200Smm	}
2344231200Smm
2345231200Smmsame_entry:
2346231200Smm	/*
2347231200Smm	 * We have already has the entry the filename of which is
2348231200Smm	 * the same.
2349231200Smm	 */
2350231200Smm	if (archive_entry_filetype(np->entry) !=
2351231200Smm	    archive_entry_filetype(file->entry)) {
2352231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2353231200Smm		    "Found duplicate entries `%s' and its file type is "
2354231200Smm		    "different",
2355231200Smm		    archive_entry_pathname(np->entry));
2356231200Smm		file_free(file);
2357231200Smm		*filepp = NULL;
2358231200Smm		return (ARCHIVE_FAILED);
2359231200Smm	}
2360231200Smm
2361231200Smm	/* Swap files. */
2362231200Smm	ent = np->entry;
2363231200Smm	np->entry = file->entry;
2364231200Smm	file->entry = ent;
2365231200Smm	np->virtual = 0;
2366231200Smm
2367231200Smm	file_free(file);
2368231200Smm	*filepp = np;
2369231200Smm	return (ARCHIVE_OK);
2370231200Smm}
2371231200Smm
2372231200Smmstatic void
2373231200Smmfile_register(struct xar *xar, struct file *file)
2374231200Smm{
2375231200Smm	file->id = xar->file_idx++;
2376231200Smm        file->next = NULL;
2377231200Smm        *xar->file_list.last = file;
2378231200Smm        xar->file_list.last = &(file->next);
2379231200Smm}
2380231200Smm
2381231200Smmstatic void
2382231200Smmfile_init_register(struct xar *xar)
2383231200Smm{
2384231200Smm	xar->file_list.first = NULL;
2385231200Smm	xar->file_list.last = &(xar->file_list.first);
2386231200Smm}
2387231200Smm
2388231200Smmstatic void
2389231200Smmfile_free_register(struct xar *xar)
2390231200Smm{
2391231200Smm	struct file *file, *file_next;
2392231200Smm
2393231200Smm	file = xar->file_list.first;
2394231200Smm	while (file != NULL) {
2395231200Smm		file_next = file->next;
2396231200Smm		file_free(file);
2397231200Smm		file = file_next;
2398231200Smm	}
2399231200Smm}
2400231200Smm
2401231200Smm/*
2402231200Smm * Register entry to get a hardlink target.
2403231200Smm */
2404231200Smmstatic int
2405231200Smmfile_register_hardlink(struct archive_write *a, struct file *file)
2406231200Smm{
2407231200Smm	struct xar *xar = (struct xar *)a->format_data;
2408231200Smm	struct hardlink *hl;
2409231200Smm	const char *pathname;
2410231200Smm
2411231200Smm	archive_entry_set_nlink(file->entry, 1);
2412231200Smm	pathname = archive_entry_hardlink(file->entry);
2413231200Smm	if (pathname == NULL) {
2414231200Smm		/* This `file` is a hardlink target. */
2415231200Smm		hl = malloc(sizeof(*hl));
2416231200Smm		if (hl == NULL) {
2417231200Smm			archive_set_error(&a->archive, ENOMEM,
2418231200Smm			    "Can't allocate memory");
2419231200Smm			return (ARCHIVE_FATAL);
2420231200Smm		}
2421231200Smm		hl->nlink = 1;
2422231200Smm		/* A hardlink target must be the first position. */
2423231200Smm		file->hlnext = NULL;
2424231200Smm		hl->file_list.first = file;
2425231200Smm		hl->file_list.last = &(file->hlnext);
2426231200Smm		__archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
2427231200Smm		    (struct archive_rb_node *)hl);
2428231200Smm	} else {
2429231200Smm		hl = (struct hardlink *)__archive_rb_tree_find_node(
2430231200Smm		    &(xar->hardlink_rbtree), pathname);
2431231200Smm		if (hl != NULL) {
2432231200Smm			/* Insert `file` entry into the tail. */
2433231200Smm			file->hlnext = NULL;
2434231200Smm			*hl->file_list.last = file;
2435231200Smm			hl->file_list.last = &(file->hlnext);
2436231200Smm			hl->nlink++;
2437231200Smm		}
2438231200Smm		archive_entry_unset_size(file->entry);
2439231200Smm	}
2440231200Smm
2441231200Smm	return (ARCHIVE_OK);
2442231200Smm}
2443231200Smm
2444231200Smm/*
2445231200Smm * Hardlinked files have to have the same location of extent.
2446231200Smm * We have to find out hardlink target entries for entries which
2447231200Smm * have a hardlink target name.
2448231200Smm */
2449231200Smmstatic void
2450231200Smmfile_connect_hardlink_files(struct xar *xar)
2451231200Smm{
2452231200Smm	struct archive_rb_node *n;
2453231200Smm	struct hardlink *hl;
2454231200Smm	struct file *target, *nf;
2455231200Smm
2456231200Smm	ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
2457231200Smm		hl = (struct hardlink *)n;
2458231200Smm
2459231200Smm		/* The first entry must be a hardlink target. */
2460231200Smm		target = hl->file_list.first;
2461231200Smm		archive_entry_set_nlink(target->entry, hl->nlink);
2462231200Smm		if (hl->nlink > 1)
2463231200Smm			/* It means this file is a hardlink
2464231200Smm			 * targe itself. */
2465231200Smm			target->hardlink_target = target;
2466231200Smm		for (nf = target->hlnext;
2467231200Smm		    nf != NULL; nf = nf->hlnext) {
2468231200Smm			nf->hardlink_target = target;
2469231200Smm			archive_entry_set_nlink(nf->entry, hl->nlink);
2470231200Smm		}
2471231200Smm	}
2472231200Smm}
2473231200Smm
2474231200Smmstatic int
2475231200Smmfile_hd_cmp_node(const struct archive_rb_node *n1,
2476231200Smm    const struct archive_rb_node *n2)
2477231200Smm{
2478232153Smm	const struct hardlink *h1 = (const struct hardlink *)n1;
2479232153Smm	const struct hardlink *h2 = (const struct hardlink *)n2;
2480231200Smm
2481231200Smm	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
2482231200Smm		       archive_entry_pathname(h2->file_list.first->entry)));
2483231200Smm}
2484231200Smm
2485231200Smmstatic int
2486231200Smmfile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
2487231200Smm{
2488232153Smm	const struct hardlink *h = (const struct hardlink *)n;
2489231200Smm
2490231200Smm	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
2491231200Smm		       (const char *)key));
2492231200Smm}
2493231200Smm
2494231200Smm
2495231200Smmstatic void
2496231200Smmfile_init_hardlinks(struct xar *xar)
2497231200Smm{
2498231200Smm	static const struct archive_rb_tree_ops rb_ops = {
2499231200Smm		file_hd_cmp_node, file_hd_cmp_key,
2500231200Smm	};
2501231200Smm
2502231200Smm	__archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
2503231200Smm}
2504231200Smm
2505231200Smmstatic void
2506231200Smmfile_free_hardlinks(struct xar *xar)
2507231200Smm{
2508231200Smm	struct archive_rb_node *n, *next;
2509231200Smm
2510231200Smm	for (n = ARCHIVE_RB_TREE_MIN(&(xar->hardlink_rbtree)); n;) {
2511231200Smm		next = __archive_rb_tree_iterate(&(xar->hardlink_rbtree),
2512231200Smm		    n, ARCHIVE_RB_DIR_RIGHT);
2513231200Smm		free(n);
2514231200Smm		n = next;
2515231200Smm	}
2516231200Smm}
2517231200Smm
2518231200Smmstatic void
2519231200Smmchecksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
2520231200Smm{
2521231200Smm	sumwrk->alg = sum_alg;
2522231200Smm	switch (sum_alg) {
2523231200Smm	case CKSUM_NONE:
2524231200Smm		break;
2525231200Smm	case CKSUM_SHA1:
2526231200Smm		archive_sha1_init(&(sumwrk->sha1ctx));
2527231200Smm		break;
2528231200Smm	case CKSUM_MD5:
2529231200Smm		archive_md5_init(&(sumwrk->md5ctx));
2530231200Smm		break;
2531231200Smm	}
2532231200Smm}
2533231200Smm
2534231200Smmstatic void
2535231200Smmchecksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
2536231200Smm{
2537231200Smm
2538231200Smm	switch (sumwrk->alg) {
2539231200Smm	case CKSUM_NONE:
2540231200Smm		break;
2541231200Smm	case CKSUM_SHA1:
2542231200Smm		archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
2543231200Smm		break;
2544231200Smm	case CKSUM_MD5:
2545231200Smm		archive_md5_update(&(sumwrk->md5ctx), buff, size);
2546231200Smm		break;
2547231200Smm	}
2548231200Smm}
2549231200Smm
2550231200Smmstatic void
2551231200Smmchecksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
2552231200Smm{
2553231200Smm
2554231200Smm	switch (sumwrk->alg) {
2555231200Smm	case CKSUM_NONE:
2556231200Smm		sumval->len = 0;
2557231200Smm		break;
2558231200Smm	case CKSUM_SHA1:
2559231200Smm		archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
2560231200Smm		sumval->len = SHA1_SIZE;
2561231200Smm		break;
2562231200Smm	case CKSUM_MD5:
2563231200Smm		archive_md5_final(&(sumwrk->md5ctx), sumval->val);
2564231200Smm		sumval->len = MD5_SIZE;
2565231200Smm		break;
2566231200Smm	}
2567231200Smm	sumval->alg = sumwrk->alg;
2568231200Smm}
2569231200Smm
2570231200Smm#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
2571231200Smmstatic int
2572231200Smmcompression_unsupported_encoder(struct archive *a,
2573231200Smm    struct la_zstream *lastrm, const char *name)
2574231200Smm{
2575231200Smm
2576231200Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
2577231200Smm	    "%s compression not supported on this platform", name);
2578231200Smm	lastrm->valid = 0;
2579231200Smm	lastrm->real_stream = NULL;
2580231200Smm	return (ARCHIVE_FAILED);
2581231200Smm}
2582231200Smm#endif
2583231200Smm
2584231200Smmstatic int
2585231200Smmcompression_init_encoder_gzip(struct archive *a,
2586231200Smm    struct la_zstream *lastrm, int level, int withheader)
2587231200Smm{
2588231200Smm	z_stream *strm;
2589231200Smm
2590231200Smm	if (lastrm->valid)
2591231200Smm		compression_end(a, lastrm);
2592231200Smm	strm = calloc(1, sizeof(*strm));
2593231200Smm	if (strm == NULL) {
2594231200Smm		archive_set_error(a, ENOMEM,
2595231200Smm		    "Can't allocate memory for gzip stream");
2596231200Smm		return (ARCHIVE_FATAL);
2597231200Smm	}
2598231200Smm	/* zlib.h is not const-correct, so we need this one bit
2599231200Smm	 * of ugly hackery to convert a const * pointer to
2600231200Smm	 * a non-const pointer. */
2601231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
2602231200Smm	strm->avail_in = lastrm->avail_in;
2603231200Smm	strm->total_in = lastrm->total_in;
2604231200Smm	strm->next_out = lastrm->next_out;
2605231200Smm	strm->avail_out = lastrm->avail_out;
2606231200Smm	strm->total_out = lastrm->total_out;
2607231200Smm	if (deflateInit2(strm, level, Z_DEFLATED,
2608231200Smm	    (withheader)?15:-15,
2609231200Smm	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
2610231200Smm		free(strm);
2611231200Smm		lastrm->real_stream = NULL;
2612231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2613231200Smm		    "Internal error initializing compression library");
2614231200Smm		return (ARCHIVE_FATAL);
2615231200Smm	}
2616231200Smm	lastrm->real_stream = strm;
2617231200Smm	lastrm->valid = 1;
2618231200Smm	lastrm->code = compression_code_gzip;
2619231200Smm	lastrm->end = compression_end_gzip;
2620231200Smm	return (ARCHIVE_OK);
2621231200Smm}
2622231200Smm
2623231200Smmstatic int
2624231200Smmcompression_code_gzip(struct archive *a,
2625231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2626231200Smm{
2627231200Smm	z_stream *strm;
2628231200Smm	int r;
2629231200Smm
2630231200Smm	strm = (z_stream *)lastrm->real_stream;
2631231200Smm	/* zlib.h is not const-correct, so we need this one bit
2632231200Smm	 * of ugly hackery to convert a const * pointer to
2633231200Smm	 * a non-const pointer. */
2634231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
2635231200Smm	strm->avail_in = lastrm->avail_in;
2636231200Smm	strm->total_in = lastrm->total_in;
2637231200Smm	strm->next_out = lastrm->next_out;
2638231200Smm	strm->avail_out = lastrm->avail_out;
2639231200Smm	strm->total_out = lastrm->total_out;
2640231200Smm	r = deflate(strm,
2641231200Smm	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
2642231200Smm	lastrm->next_in = strm->next_in;
2643231200Smm	lastrm->avail_in = strm->avail_in;
2644231200Smm	lastrm->total_in = strm->total_in;
2645231200Smm	lastrm->next_out = strm->next_out;
2646231200Smm	lastrm->avail_out = strm->avail_out;
2647231200Smm	lastrm->total_out = strm->total_out;
2648231200Smm	switch (r) {
2649231200Smm	case Z_OK:
2650231200Smm		return (ARCHIVE_OK);
2651231200Smm	case Z_STREAM_END:
2652231200Smm		return (ARCHIVE_EOF);
2653231200Smm	default:
2654231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2655231200Smm		    "GZip compression failed:"
2656231200Smm		    " deflate() call returned status %d", r);
2657231200Smm		return (ARCHIVE_FATAL);
2658231200Smm	}
2659231200Smm}
2660231200Smm
2661231200Smmstatic int
2662231200Smmcompression_end_gzip(struct archive *a, struct la_zstream *lastrm)
2663231200Smm{
2664231200Smm	z_stream *strm;
2665231200Smm	int r;
2666231200Smm
2667231200Smm	strm = (z_stream *)lastrm->real_stream;
2668231200Smm	r = deflateEnd(strm);
2669231200Smm	free(strm);
2670231200Smm	lastrm->real_stream = NULL;
2671231200Smm	lastrm->valid = 0;
2672231200Smm	if (r != Z_OK) {
2673231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2674231200Smm		    "Failed to clean up compressor");
2675231200Smm		return (ARCHIVE_FATAL);
2676231200Smm	}
2677231200Smm	return (ARCHIVE_OK);
2678231200Smm}
2679231200Smm
2680231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
2681231200Smmstatic int
2682231200Smmcompression_init_encoder_bzip2(struct archive *a,
2683231200Smm    struct la_zstream *lastrm, int level)
2684231200Smm{
2685231200Smm	bz_stream *strm;
2686231200Smm
2687231200Smm	if (lastrm->valid)
2688231200Smm		compression_end(a, lastrm);
2689231200Smm	strm = calloc(1, sizeof(*strm));
2690231200Smm	if (strm == NULL) {
2691231200Smm		archive_set_error(a, ENOMEM,
2692231200Smm		    "Can't allocate memory for bzip2 stream");
2693231200Smm		return (ARCHIVE_FATAL);
2694231200Smm	}
2695231200Smm	/* bzlib.h is not const-correct, so we need this one bit
2696231200Smm	 * of ugly hackery to convert a const * pointer to
2697231200Smm	 * a non-const pointer. */
2698231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
2699231200Smm	strm->avail_in = lastrm->avail_in;
2700231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
2701231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
2702231200Smm	strm->next_out = (char *)lastrm->next_out;
2703231200Smm	strm->avail_out = lastrm->avail_out;
2704231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
2705231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
2706231200Smm	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
2707231200Smm		free(strm);
2708231200Smm		lastrm->real_stream = NULL;
2709231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2710231200Smm		    "Internal error initializing compression library");
2711231200Smm		return (ARCHIVE_FATAL);
2712231200Smm	}
2713231200Smm	lastrm->real_stream = strm;
2714231200Smm	lastrm->valid = 1;
2715231200Smm	lastrm->code = compression_code_bzip2;
2716231200Smm	lastrm->end = compression_end_bzip2;
2717231200Smm	return (ARCHIVE_OK);
2718231200Smm}
2719231200Smm
2720231200Smmstatic int
2721231200Smmcompression_code_bzip2(struct archive *a,
2722231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2723231200Smm{
2724231200Smm	bz_stream *strm;
2725231200Smm	int r;
2726231200Smm
2727231200Smm	strm = (bz_stream *)lastrm->real_stream;
2728231200Smm	/* bzlib.h is not const-correct, so we need this one bit
2729231200Smm	 * of ugly hackery to convert a const * pointer to
2730231200Smm	 * a non-const pointer. */
2731231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
2732231200Smm	strm->avail_in = lastrm->avail_in;
2733231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
2734231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
2735231200Smm	strm->next_out = (char *)lastrm->next_out;
2736231200Smm	strm->avail_out = lastrm->avail_out;
2737231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
2738231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
2739231200Smm	r = BZ2_bzCompress(strm,
2740231200Smm	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
2741231200Smm	lastrm->next_in = (const unsigned char *)strm->next_in;
2742231200Smm	lastrm->avail_in = strm->avail_in;
2743231200Smm	lastrm->total_in =
2744231200Smm	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
2745231200Smm	    + (uint64_t)(uint32_t)strm->total_in_lo32;
2746231200Smm	lastrm->next_out = (unsigned char *)strm->next_out;
2747231200Smm	lastrm->avail_out = strm->avail_out;
2748231200Smm	lastrm->total_out =
2749231200Smm	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
2750231200Smm	    + (uint64_t)(uint32_t)strm->total_out_lo32;
2751231200Smm	switch (r) {
2752231200Smm	case BZ_RUN_OK:     /* Non-finishing */
2753231200Smm	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
2754231200Smm		return (ARCHIVE_OK);
2755231200Smm	case BZ_STREAM_END: /* Finishing: all done */
2756231200Smm		/* Only occurs in finishing case */
2757231200Smm		return (ARCHIVE_EOF);
2758231200Smm	default:
2759231200Smm		/* Any other return value indicates an error */
2760231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2761231200Smm		    "Bzip2 compression failed:"
2762231200Smm		    " BZ2_bzCompress() call returned status %d", r);
2763231200Smm		return (ARCHIVE_FATAL);
2764231200Smm	}
2765231200Smm}
2766231200Smm
2767231200Smmstatic int
2768231200Smmcompression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
2769231200Smm{
2770231200Smm	bz_stream *strm;
2771231200Smm	int r;
2772231200Smm
2773231200Smm	strm = (bz_stream *)lastrm->real_stream;
2774231200Smm	r = BZ2_bzCompressEnd(strm);
2775231200Smm	free(strm);
2776231200Smm	lastrm->real_stream = NULL;
2777231200Smm	lastrm->valid = 0;
2778231200Smm	if (r != BZ_OK) {
2779231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2780231200Smm		    "Failed to clean up compressor");
2781231200Smm		return (ARCHIVE_FATAL);
2782231200Smm	}
2783231200Smm	return (ARCHIVE_OK);
2784231200Smm}
2785231200Smm
2786231200Smm#else
2787231200Smmstatic int
2788231200Smmcompression_init_encoder_bzip2(struct archive *a,
2789231200Smm    struct la_zstream *lastrm, int level)
2790231200Smm{
2791231200Smm
2792231200Smm	(void) level; /* UNUSED */
2793231200Smm	if (lastrm->valid)
2794231200Smm		compression_end(a, lastrm);
2795231200Smm	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
2796231200Smm}
2797231200Smm#endif
2798231200Smm
2799231200Smm#if defined(HAVE_LZMA_H)
2800231200Smmstatic int
2801231200Smmcompression_init_encoder_lzma(struct archive *a,
2802231200Smm    struct la_zstream *lastrm, int level)
2803231200Smm{
2804231200Smm	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
2805231200Smm	lzma_stream *strm;
2806231200Smm	lzma_options_lzma lzma_opt;
2807231200Smm	int r;
2808231200Smm
2809231200Smm	if (lastrm->valid)
2810231200Smm		compression_end(a, lastrm);
2811231200Smm	if (lzma_lzma_preset(&lzma_opt, level)) {
2812231200Smm		lastrm->real_stream = NULL;
2813231200Smm		archive_set_error(a, ENOMEM,
2814231200Smm		    "Internal error initializing compression library");
2815231200Smm		return (ARCHIVE_FATAL);
2816231200Smm	}
2817231200Smm	strm = calloc(1, sizeof(*strm));
2818231200Smm	if (strm == NULL) {
2819231200Smm		archive_set_error(a, ENOMEM,
2820231200Smm		    "Can't allocate memory for lzma stream");
2821231200Smm		return (ARCHIVE_FATAL);
2822231200Smm	}
2823231200Smm	*strm = lzma_init_data;
2824231200Smm	r = lzma_alone_encoder(strm, &lzma_opt);
2825231200Smm	switch (r) {
2826231200Smm	case LZMA_OK:
2827231200Smm		lastrm->real_stream = strm;
2828231200Smm		lastrm->valid = 1;
2829231200Smm		lastrm->code = compression_code_lzma;
2830231200Smm		lastrm->end = compression_end_lzma;
2831231200Smm		r = ARCHIVE_OK;
2832231200Smm		break;
2833231200Smm	case LZMA_MEM_ERROR:
2834231200Smm		free(strm);
2835231200Smm		lastrm->real_stream = NULL;
2836231200Smm		archive_set_error(a, ENOMEM,
2837231200Smm		    "Internal error initializing compression library: "
2838231200Smm		    "Cannot allocate memory");
2839231200Smm		r =  ARCHIVE_FATAL;
2840231200Smm		break;
2841231200Smm        default:
2842231200Smm		free(strm);
2843231200Smm		lastrm->real_stream = NULL;
2844231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2845231200Smm		    "Internal error initializing compression library: "
2846231200Smm		    "It's a bug in liblzma");
2847231200Smm		r =  ARCHIVE_FATAL;
2848231200Smm		break;
2849231200Smm	}
2850231200Smm	return (r);
2851231200Smm}
2852231200Smm
2853231200Smmstatic int
2854231200Smmcompression_init_encoder_xz(struct archive *a,
2855231200Smm    struct la_zstream *lastrm, int level)
2856231200Smm{
2857231200Smm	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
2858231200Smm	lzma_stream *strm;
2859231200Smm	lzma_filter *lzmafilters;
2860231200Smm	lzma_options_lzma lzma_opt;
2861231200Smm	int r;
2862231200Smm
2863231200Smm	if (lastrm->valid)
2864231200Smm		compression_end(a, lastrm);
2865231200Smm	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
2866231200Smm	if (strm == NULL) {
2867231200Smm		archive_set_error(a, ENOMEM,
2868231200Smm		    "Can't allocate memory for xz stream");
2869231200Smm		return (ARCHIVE_FATAL);
2870231200Smm	}
2871231200Smm	lzmafilters = (lzma_filter *)(strm+1);
2872231200Smm	if (level > 6)
2873231200Smm		level = 6;
2874231200Smm	if (lzma_lzma_preset(&lzma_opt, level)) {
2875231200Smm		lastrm->real_stream = NULL;
2876231200Smm		archive_set_error(a, ENOMEM,
2877231200Smm		    "Internal error initializing compression library");
2878231200Smm		return (ARCHIVE_FATAL);
2879231200Smm	}
2880231200Smm	lzmafilters[0].id = LZMA_FILTER_LZMA2;
2881231200Smm	lzmafilters[0].options = &lzma_opt;
2882231200Smm	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
2883231200Smm
2884231200Smm	*strm = lzma_init_data;
2885231200Smm	r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
2886231200Smm	switch (r) {
2887231200Smm	case LZMA_OK:
2888231200Smm		lastrm->real_stream = strm;
2889231200Smm		lastrm->valid = 1;
2890231200Smm		lastrm->code = compression_code_lzma;
2891231200Smm		lastrm->end = compression_end_lzma;
2892231200Smm		r = ARCHIVE_OK;
2893231200Smm		break;
2894231200Smm	case LZMA_MEM_ERROR:
2895231200Smm		free(strm);
2896231200Smm		lastrm->real_stream = NULL;
2897231200Smm		archive_set_error(a, ENOMEM,
2898231200Smm		    "Internal error initializing compression library: "
2899231200Smm		    "Cannot allocate memory");
2900231200Smm		r =  ARCHIVE_FATAL;
2901231200Smm		break;
2902231200Smm        default:
2903231200Smm		free(strm);
2904231200Smm		lastrm->real_stream = NULL;
2905231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2906231200Smm		    "Internal error initializing compression library: "
2907231200Smm		    "It's a bug in liblzma");
2908231200Smm		r =  ARCHIVE_FATAL;
2909231200Smm		break;
2910231200Smm	}
2911231200Smm	return (r);
2912231200Smm}
2913231200Smm
2914231200Smmstatic int
2915231200Smmcompression_code_lzma(struct archive *a,
2916231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2917231200Smm{
2918231200Smm	lzma_stream *strm;
2919231200Smm	int r;
2920231200Smm
2921231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2922231200Smm	strm->next_in = lastrm->next_in;
2923231200Smm	strm->avail_in = lastrm->avail_in;
2924231200Smm	strm->total_in = lastrm->total_in;
2925231200Smm	strm->next_out = lastrm->next_out;
2926231200Smm	strm->avail_out = lastrm->avail_out;
2927231200Smm	strm->total_out = lastrm->total_out;
2928231200Smm	r = lzma_code(strm,
2929231200Smm	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
2930231200Smm	lastrm->next_in = strm->next_in;
2931231200Smm	lastrm->avail_in = strm->avail_in;
2932231200Smm	lastrm->total_in = strm->total_in;
2933231200Smm	lastrm->next_out = strm->next_out;
2934231200Smm	lastrm->avail_out = strm->avail_out;
2935231200Smm	lastrm->total_out = strm->total_out;
2936231200Smm	switch (r) {
2937231200Smm	case LZMA_OK:
2938231200Smm		/* Non-finishing case */
2939231200Smm		return (ARCHIVE_OK);
2940231200Smm	case LZMA_STREAM_END:
2941231200Smm		/* This return can only occur in finishing case. */
2942231200Smm		return (ARCHIVE_EOF);
2943231200Smm	case LZMA_MEMLIMIT_ERROR:
2944231200Smm		archive_set_error(a, ENOMEM,
2945231200Smm		    "lzma compression error:"
2946231200Smm		    " %ju MiB would have been needed",
2947231200Smm		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
2948231200Smm			/ (1024 * 1024)));
2949231200Smm		return (ARCHIVE_FATAL);
2950231200Smm	default:
2951231200Smm		/* Any other return value indicates an error */
2952231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2953231200Smm		    "lzma compression failed:"
2954231200Smm		    " lzma_code() call returned status %d", r);
2955231200Smm		return (ARCHIVE_FATAL);
2956231200Smm	}
2957231200Smm}
2958231200Smm
2959231200Smmstatic int
2960231200Smmcompression_end_lzma(struct archive *a, struct la_zstream *lastrm)
2961231200Smm{
2962231200Smm	lzma_stream *strm;
2963231200Smm
2964231200Smm	(void)a; /* UNUSED */
2965231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2966231200Smm	lzma_end(strm);
2967231200Smm	free(strm);
2968231200Smm	lastrm->valid = 0;
2969231200Smm	lastrm->real_stream = NULL;
2970231200Smm	return (ARCHIVE_OK);
2971231200Smm}
2972231200Smm#else
2973231200Smmstatic int
2974231200Smmcompression_init_encoder_lzma(struct archive *a,
2975231200Smm    struct la_zstream *lastrm, int level)
2976231200Smm{
2977231200Smm
2978231200Smm	(void) level; /* UNUSED */
2979231200Smm	if (lastrm->valid)
2980231200Smm		compression_end(a, lastrm);
2981231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2982231200Smm}
2983231200Smmstatic int
2984231200Smmcompression_init_encoder_xz(struct archive *a,
2985231200Smm    struct la_zstream *lastrm, int level)
2986231200Smm{
2987231200Smm
2988231200Smm	(void) level; /* UNUSED */
2989231200Smm	if (lastrm->valid)
2990231200Smm		compression_end(a, lastrm);
2991231200Smm	return (compression_unsupported_encoder(a, lastrm, "xz"));
2992231200Smm}
2993231200Smm#endif
2994231200Smm
2995231200Smmstatic int
2996231200Smmxar_compression_init_encoder(struct archive_write *a)
2997231200Smm{
2998231200Smm	struct xar *xar;
2999231200Smm	int r;
3000231200Smm
3001231200Smm	xar = (struct xar *)a->format_data;
3002231200Smm	switch (xar->opt_compression) {
3003231200Smm	case GZIP:
3004231200Smm		r = compression_init_encoder_gzip(
3005231200Smm		    &(a->archive), &(xar->stream),
3006231200Smm		    xar->opt_compression_level, 1);
3007231200Smm		break;
3008231200Smm	case BZIP2:
3009231200Smm		r = compression_init_encoder_bzip2(
3010231200Smm		    &(a->archive), &(xar->stream),
3011231200Smm		    xar->opt_compression_level);
3012231200Smm		break;
3013231200Smm	case LZMA:
3014231200Smm		r = compression_init_encoder_lzma(
3015231200Smm		    &(a->archive), &(xar->stream),
3016231200Smm		    xar->opt_compression_level);
3017231200Smm		break;
3018231200Smm	case XZ:
3019231200Smm		r = compression_init_encoder_xz(
3020231200Smm		    &(a->archive), &(xar->stream),
3021231200Smm		    xar->opt_compression_level);
3022231200Smm		break;
3023231200Smm	default:
3024231200Smm		r = ARCHIVE_OK;
3025231200Smm		break;
3026231200Smm	}
3027231200Smm	if (r == ARCHIVE_OK) {
3028231200Smm		xar->stream.total_in = 0;
3029231200Smm		xar->stream.next_out = xar->wbuff;
3030231200Smm		xar->stream.avail_out = sizeof(xar->wbuff);
3031231200Smm		xar->stream.total_out = 0;
3032231200Smm	}
3033231200Smm
3034231200Smm	return (r);
3035231200Smm}
3036231200Smm
3037231200Smmstatic int
3038231200Smmcompression_code(struct archive *a, struct la_zstream *lastrm,
3039231200Smm    enum la_zaction action)
3040231200Smm{
3041231200Smm	if (lastrm->valid)
3042231200Smm		return (lastrm->code(a, lastrm, action));
3043231200Smm	return (ARCHIVE_OK);
3044231200Smm}
3045231200Smm
3046231200Smmstatic int
3047231200Smmcompression_end(struct archive *a, struct la_zstream *lastrm)
3048231200Smm{
3049231200Smm	if (lastrm->valid)
3050231200Smm		return (lastrm->end(a, lastrm));
3051231200Smm	return (ARCHIVE_OK);
3052231200Smm}
3053231200Smm
3054231200Smm
3055231200Smmstatic int
3056231200Smmsave_xattrs(struct archive_write *a, struct file *file)
3057231200Smm{
3058231200Smm	struct xar *xar;
3059231200Smm	const char *name;
3060231200Smm	const void *value;
3061231200Smm	struct heap_data *heap;
3062231200Smm	size_t size;
3063231200Smm	int count, r;
3064231200Smm
3065231200Smm	xar = (struct xar *)a->format_data;
3066231200Smm	count = archive_entry_xattr_reset(file->entry);
3067231200Smm	if (count == 0)
3068231200Smm		return (ARCHIVE_OK);
3069231200Smm	while (count--) {
3070231200Smm		archive_entry_xattr_next(file->entry,
3071231200Smm		    &name, &value, &size);
3072231200Smm		checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
3073231200Smm		checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
3074231200Smm
3075231200Smm		heap = calloc(1, sizeof(*heap));
3076231200Smm		if (heap == NULL) {
3077231200Smm			archive_set_error(&a->archive, ENOMEM,
3078231200Smm			    "Can't allocate memory for xattr");
3079231200Smm			return (ARCHIVE_FATAL);
3080231200Smm		}
3081231200Smm		heap->id = file->ea_idx++;
3082231200Smm		heap->temp_offset = xar->temp_offset;
3083231200Smm		heap->size = size;/* save a extracted size */
3084231200Smm		heap->compression = xar->opt_compression;
3085231200Smm		/* Get a extracted sumcheck value. */
3086231200Smm		checksum_update(&(xar->e_sumwrk), value, size);
3087231200Smm		checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
3088231200Smm
3089231200Smm		/*
3090231200Smm		 * Not compression to xattr is simple way.
3091231200Smm		 */
3092231200Smm		if (heap->compression == NONE) {
3093231200Smm			checksum_update(&(xar->a_sumwrk), value, size);
3094231200Smm			checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
3095231200Smm			if (write_to_temp(a, value, size)
3096231200Smm			    != ARCHIVE_OK)
3097231200Smm				return (ARCHIVE_FATAL);
3098231200Smm			heap->length = size;
3099231200Smm			/* Add heap to the tail of file->xattr. */
3100231200Smm			heap->next = NULL;
3101231200Smm			*file->xattr.last = heap;
3102231200Smm			file->xattr.last = &(heap->next);
3103231200Smm			/* Next xattr */
3104231200Smm			continue;
3105231200Smm		}
3106231200Smm
3107231200Smm		/*
3108231200Smm		 * Init compression library.
3109231200Smm		 */
3110231200Smm		r = xar_compression_init_encoder(a);
3111231200Smm		if (r != ARCHIVE_OK) {
3112231200Smm			free(heap);
3113231200Smm			return (ARCHIVE_FATAL);
3114231200Smm		}
3115231200Smm
3116231200Smm		xar->stream.next_in = (const unsigned char *)value;
3117231200Smm		xar->stream.avail_in = size;
3118231200Smm		for (;;) {
3119231200Smm			r = compression_code(&(a->archive),
3120231200Smm			    &(xar->stream), ARCHIVE_Z_FINISH);
3121231200Smm			if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
3122231200Smm				free(heap);
3123231200Smm				return (ARCHIVE_FATAL);
3124231200Smm			}
3125231200Smm			size = sizeof(xar->wbuff) - xar->stream.avail_out;
3126231200Smm			checksum_update(&(xar->a_sumwrk),
3127231200Smm			    xar->wbuff, size);
3128231200Smm			if (write_to_temp(a, xar->wbuff, size)
3129231200Smm			    != ARCHIVE_OK)
3130231200Smm				return (ARCHIVE_FATAL);
3131231200Smm			if (r == ARCHIVE_OK) {
3132231200Smm				xar->stream.next_out = xar->wbuff;
3133231200Smm				xar->stream.avail_out = sizeof(xar->wbuff);
3134231200Smm			} else {
3135231200Smm				checksum_final(&(xar->a_sumwrk),
3136231200Smm				    &(heap->a_sum));
3137231200Smm				heap->length = xar->stream.total_out;
3138231200Smm				/* Add heap to the tail of file->xattr. */
3139231200Smm				heap->next = NULL;
3140231200Smm				*file->xattr.last = heap;
3141231200Smm				file->xattr.last = &(heap->next);
3142231200Smm				break;
3143231200Smm			}
3144231200Smm		}
3145231200Smm		/* Clean up compression library. */
3146231200Smm		r = compression_end(&(a->archive), &(xar->stream));
3147231200Smm		if (r != ARCHIVE_OK)
3148231200Smm			return (ARCHIVE_FATAL);
3149231200Smm	}
3150231200Smm	return (ARCHIVE_OK);
3151231200Smm}
3152231200Smm
3153231200Smmstatic int
3154231200Smmgetalgsize(enum sumalg sumalg)
3155231200Smm{
3156231200Smm	switch (sumalg) {
3157231200Smm	default:
3158231200Smm	case CKSUM_NONE:
3159231200Smm		return (0);
3160231200Smm	case CKSUM_SHA1:
3161231200Smm		return (SHA1_SIZE);
3162231200Smm	case CKSUM_MD5:
3163231200Smm		return (MD5_SIZE);
3164231200Smm	}
3165231200Smm}
3166231200Smm
3167231200Smmstatic const char *
3168231200Smmgetalgname(enum sumalg sumalg)
3169231200Smm{
3170231200Smm	switch (sumalg) {
3171231200Smm	default:
3172231200Smm	case CKSUM_NONE:
3173231200Smm		return (NULL);
3174231200Smm	case CKSUM_SHA1:
3175231200Smm		return (SHA1_NAME);
3176231200Smm	case CKSUM_MD5:
3177231200Smm		return (MD5_NAME);
3178231200Smm	}
3179231200Smm}
3180231200Smm
3181231200Smm#endif /* Support xar format */
3182231200Smm
3183