1c09f92d2SPeter Avalos /*-
259bf7050SPeter Avalos * Copyright (c) 2010-2012 Michihiro NAKAJIMA
3c09f92d2SPeter Avalos * All rights reserved.
4c09f92d2SPeter Avalos *
5c09f92d2SPeter Avalos * Redistribution and use in source and binary forms, with or without
6c09f92d2SPeter Avalos * modification, are permitted provided that the following conditions
7c09f92d2SPeter Avalos * are met:
8c09f92d2SPeter Avalos * 1. Redistributions of source code must retain the above copyright
9c09f92d2SPeter Avalos * notice, this list of conditions and the following disclaimer.
10c09f92d2SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
11c09f92d2SPeter Avalos * notice, this list of conditions and the following disclaimer in the
12c09f92d2SPeter Avalos * documentation and/or other materials provided with the distribution.
13c09f92d2SPeter Avalos *
14c09f92d2SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15c09f92d2SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16c09f92d2SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c09f92d2SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18c09f92d2SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19c09f92d2SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20c09f92d2SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21c09f92d2SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22c09f92d2SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23c09f92d2SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24c09f92d2SPeter Avalos */
25c09f92d2SPeter Avalos
26c09f92d2SPeter Avalos #include "archive_platform.h"
27c09f92d2SPeter Avalos __FBSDID("$FreeBSD$");
28c09f92d2SPeter Avalos
29c09f92d2SPeter Avalos #ifdef HAVE_ERRNO_H
30c09f92d2SPeter Avalos #include <errno.h>
31c09f92d2SPeter Avalos #endif
32c09f92d2SPeter Avalos #ifdef HAVE_LIMITS_H
33c09f92d2SPeter Avalos #include <limits.h>
34c09f92d2SPeter Avalos #endif
35c09f92d2SPeter Avalos #include <stdlib.h>
36c09f92d2SPeter Avalos #if HAVE_LIBXML_XMLWRITER_H
37c09f92d2SPeter Avalos #include <libxml/xmlwriter.h>
38c09f92d2SPeter Avalos #endif
39c09f92d2SPeter Avalos #ifdef HAVE_BZLIB_H
40c09f92d2SPeter Avalos #include <bzlib.h>
41c09f92d2SPeter Avalos #endif
42c09f92d2SPeter Avalos #if HAVE_LZMA_H
43c09f92d2SPeter Avalos #include <lzma.h>
44c09f92d2SPeter Avalos #endif
45c09f92d2SPeter Avalos #ifdef HAVE_ZLIB_H
46c09f92d2SPeter Avalos #include <zlib.h>
47c09f92d2SPeter Avalos #endif
48c09f92d2SPeter Avalos
49c09f92d2SPeter Avalos #include "archive.h"
506b384f39SPeter Avalos #include "archive_digest_private.h"
51c09f92d2SPeter Avalos #include "archive_endian.h"
52c09f92d2SPeter Avalos #include "archive_entry.h"
53c09f92d2SPeter Avalos #include "archive_entry_locale.h"
54c09f92d2SPeter Avalos #include "archive_private.h"
55c09f92d2SPeter Avalos #include "archive_rb.h"
56c09f92d2SPeter Avalos #include "archive_string.h"
57c09f92d2SPeter Avalos #include "archive_write_private.h"
58c09f92d2SPeter Avalos
59c09f92d2SPeter Avalos /*
60c09f92d2SPeter Avalos * Differences to xar utility.
61c09f92d2SPeter Avalos * - Subdocument is not supported yet.
62c09f92d2SPeter Avalos * - ACL is not supported yet.
63c09f92d2SPeter Avalos * - When writing an XML element <link type="<file-type>">, <file-type>
64c09f92d2SPeter Avalos * which is a file type a symbolic link is referencing is always marked
65c09f92d2SPeter Avalos * as "broken". Xar utility uses stat(2) to get the file type, but, in
66e95abc47Szrj * libarchive format writer, we should not use it; if it is needed, we
67c09f92d2SPeter Avalos * should get about it at archive_read_disk.c.
68c09f92d2SPeter Avalos * - It is possible to appear both <flags> and <ext2> elements.
69c09f92d2SPeter Avalos * Xar utility generates <flags> on BSD platform and <ext2> on Linux
70c09f92d2SPeter Avalos * platform.
71c09f92d2SPeter Avalos *
72c09f92d2SPeter Avalos */
73c09f92d2SPeter Avalos
74c09f92d2SPeter Avalos #if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
75c09f92d2SPeter Avalos LIBXML_VERSION >= 20703) ||\
76c09f92d2SPeter Avalos !defined(HAVE_ZLIB_H) || \
77c09f92d2SPeter Avalos !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
78c09f92d2SPeter Avalos /*
79c09f92d2SPeter Avalos * xar needs several external libraries.
80c09f92d2SPeter Avalos * o libxml2
81c09f92d2SPeter Avalos * o openssl or MD5/SHA1 hash function
82c09f92d2SPeter Avalos * o zlib
83c09f92d2SPeter Avalos * o bzlib2 (option)
84c09f92d2SPeter Avalos * o liblzma (option)
85c09f92d2SPeter Avalos */
86c09f92d2SPeter Avalos int
archive_write_set_format_xar(struct archive * _a)87c09f92d2SPeter Avalos archive_write_set_format_xar(struct archive *_a)
88c09f92d2SPeter Avalos {
89c09f92d2SPeter Avalos struct archive_write *a = (struct archive_write *)_a;
90c09f92d2SPeter Avalos
91c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
92c09f92d2SPeter Avalos "Xar not supported on this platform");
93c09f92d2SPeter Avalos return (ARCHIVE_WARN);
94c09f92d2SPeter Avalos }
95c09f92d2SPeter Avalos
96c09f92d2SPeter Avalos #else /* Support xar format */
97c09f92d2SPeter Avalos
98c09f92d2SPeter Avalos /*#define DEBUG_PRINT_TOC 1 */
99c09f92d2SPeter Avalos
10059bf7050SPeter Avalos #define BAD_CAST_CONST (const xmlChar *)
10159bf7050SPeter Avalos
102c09f92d2SPeter Avalos #define HEADER_MAGIC 0x78617221
103c09f92d2SPeter Avalos #define HEADER_SIZE 28
104c09f92d2SPeter Avalos #define HEADER_VERSION 1
105c09f92d2SPeter Avalos
106c09f92d2SPeter Avalos enum sumalg {
107c09f92d2SPeter Avalos CKSUM_NONE = 0,
108c09f92d2SPeter Avalos CKSUM_SHA1 = 1,
109c09f92d2SPeter Avalos CKSUM_MD5 = 2
110c09f92d2SPeter Avalos };
111c09f92d2SPeter Avalos
112c09f92d2SPeter Avalos #define MD5_SIZE 16
113c09f92d2SPeter Avalos #define SHA1_SIZE 20
114c09f92d2SPeter Avalos #define MAX_SUM_SIZE 20
115c09f92d2SPeter Avalos #define MD5_NAME "md5"
116c09f92d2SPeter Avalos #define SHA1_NAME "sha1"
117c09f92d2SPeter Avalos
118c09f92d2SPeter Avalos enum enctype {
119c09f92d2SPeter Avalos NONE,
120c09f92d2SPeter Avalos GZIP,
121c09f92d2SPeter Avalos BZIP2,
122c09f92d2SPeter Avalos LZMA,
123c09f92d2SPeter Avalos XZ,
124c09f92d2SPeter Avalos };
125c09f92d2SPeter Avalos
126c09f92d2SPeter Avalos struct chksumwork {
127c09f92d2SPeter Avalos enum sumalg alg;
128c09f92d2SPeter Avalos #ifdef ARCHIVE_HAS_MD5
129c09f92d2SPeter Avalos archive_md5_ctx md5ctx;
130c09f92d2SPeter Avalos #endif
131c09f92d2SPeter Avalos #ifdef ARCHIVE_HAS_SHA1
132c09f92d2SPeter Avalos archive_sha1_ctx sha1ctx;
133c09f92d2SPeter Avalos #endif
134c09f92d2SPeter Avalos };
135c09f92d2SPeter Avalos
136c09f92d2SPeter Avalos enum la_zaction {
137c09f92d2SPeter Avalos ARCHIVE_Z_FINISH,
138c09f92d2SPeter Avalos ARCHIVE_Z_RUN
139c09f92d2SPeter Avalos };
140c09f92d2SPeter Avalos
141c09f92d2SPeter Avalos /*
142c09f92d2SPeter Avalos * Universal zstream.
143c09f92d2SPeter Avalos */
144c09f92d2SPeter Avalos struct la_zstream {
145c09f92d2SPeter Avalos const unsigned char *next_in;
146c09f92d2SPeter Avalos size_t avail_in;
147c09f92d2SPeter Avalos uint64_t total_in;
148c09f92d2SPeter Avalos
149c09f92d2SPeter Avalos unsigned char *next_out;
150c09f92d2SPeter Avalos size_t avail_out;
151c09f92d2SPeter Avalos uint64_t total_out;
152c09f92d2SPeter Avalos
153c09f92d2SPeter Avalos int valid;
154c09f92d2SPeter Avalos void *real_stream;
155c09f92d2SPeter Avalos int (*code) (struct archive *a,
156c09f92d2SPeter Avalos struct la_zstream *lastrm,
157c09f92d2SPeter Avalos enum la_zaction action);
158c09f92d2SPeter Avalos int (*end)(struct archive *a,
159c09f92d2SPeter Avalos struct la_zstream *lastrm);
160c09f92d2SPeter Avalos };
161c09f92d2SPeter Avalos
162c09f92d2SPeter Avalos struct chksumval {
163c09f92d2SPeter Avalos enum sumalg alg;
164c09f92d2SPeter Avalos size_t len;
165c09f92d2SPeter Avalos unsigned char val[MAX_SUM_SIZE];
166c09f92d2SPeter Avalos };
167c09f92d2SPeter Avalos
168c09f92d2SPeter Avalos struct heap_data {
169c09f92d2SPeter Avalos int id;
170c09f92d2SPeter Avalos struct heap_data *next;
171c09f92d2SPeter Avalos uint64_t temp_offset;
172c09f92d2SPeter Avalos uint64_t length; /* archived size. */
173c09f92d2SPeter Avalos uint64_t size; /* extracted size. */
174c09f92d2SPeter Avalos enum enctype compression;
175c09f92d2SPeter Avalos struct chksumval a_sum; /* archived checksum. */
176c09f92d2SPeter Avalos struct chksumval e_sum; /* extracted checksum. */
177c09f92d2SPeter Avalos };
178c09f92d2SPeter Avalos
179c09f92d2SPeter Avalos struct file {
180c09f92d2SPeter Avalos struct archive_rb_node rbnode;
181c09f92d2SPeter Avalos
182c09f92d2SPeter Avalos int id;
183c09f92d2SPeter Avalos struct archive_entry *entry;
184c09f92d2SPeter Avalos
185c09f92d2SPeter Avalos struct archive_rb_tree rbtree;
186c09f92d2SPeter Avalos struct file *next;
187c09f92d2SPeter Avalos struct file *chnext;
188c09f92d2SPeter Avalos struct file *hlnext;
189c09f92d2SPeter Avalos /* For hardlinked files.
190c09f92d2SPeter Avalos * Use only when archive_entry_nlink() > 1 */
191c09f92d2SPeter Avalos struct file *hardlink_target;
192c09f92d2SPeter Avalos struct file *parent; /* parent directory entry */
193c09f92d2SPeter Avalos /*
194c09f92d2SPeter Avalos * To manage sub directory files.
195e95abc47Szrj * We use 'chnext' (a member of struct file) to chain.
196c09f92d2SPeter Avalos */
197c09f92d2SPeter Avalos struct {
198c09f92d2SPeter Avalos struct file *first;
199c09f92d2SPeter Avalos struct file **last;
200c09f92d2SPeter Avalos } children;
201c09f92d2SPeter Avalos
202c09f92d2SPeter Avalos /* For making a directory tree. */
203c09f92d2SPeter Avalos struct archive_string parentdir;
204c09f92d2SPeter Avalos struct archive_string basename;
205c09f92d2SPeter Avalos struct archive_string symlink;
206c09f92d2SPeter Avalos
207c09f92d2SPeter Avalos int ea_idx;
208c09f92d2SPeter Avalos struct {
209c09f92d2SPeter Avalos struct heap_data *first;
210c09f92d2SPeter Avalos struct heap_data **last;
211c09f92d2SPeter Avalos } xattr;
212c09f92d2SPeter Avalos struct heap_data data;
213c09f92d2SPeter Avalos struct archive_string script;
214c09f92d2SPeter Avalos
215085658deSDaniel Fojt signed int virtual:1;
216085658deSDaniel Fojt signed int dir:1;
217c09f92d2SPeter Avalos };
218c09f92d2SPeter Avalos
219c09f92d2SPeter Avalos struct hardlink {
220c09f92d2SPeter Avalos struct archive_rb_node rbnode;
221c09f92d2SPeter Avalos int nlink;
222c09f92d2SPeter Avalos struct {
223c09f92d2SPeter Avalos struct file *first;
224c09f92d2SPeter Avalos struct file **last;
225c09f92d2SPeter Avalos } file_list;
226c09f92d2SPeter Avalos };
227c09f92d2SPeter Avalos
228c09f92d2SPeter Avalos struct xar {
229c09f92d2SPeter Avalos int temp_fd;
230c09f92d2SPeter Avalos uint64_t temp_offset;
231c09f92d2SPeter Avalos
232c09f92d2SPeter Avalos int file_idx;
233c09f92d2SPeter Avalos struct file *root;
234c09f92d2SPeter Avalos struct file *cur_dirent;
235c09f92d2SPeter Avalos struct archive_string cur_dirstr;
236c09f92d2SPeter Avalos struct file *cur_file;
237c09f92d2SPeter Avalos uint64_t bytes_remaining;
238c09f92d2SPeter Avalos struct archive_string tstr;
239c09f92d2SPeter Avalos struct archive_string vstr;
240c09f92d2SPeter Avalos
241c09f92d2SPeter Avalos enum sumalg opt_toc_sumalg;
242c09f92d2SPeter Avalos enum sumalg opt_sumalg;
243c09f92d2SPeter Avalos enum enctype opt_compression;
244c09f92d2SPeter Avalos int opt_compression_level;
2456b384f39SPeter Avalos uint32_t opt_threads;
246c09f92d2SPeter Avalos
247c09f92d2SPeter Avalos struct chksumwork a_sumwrk; /* archived checksum. */
248c09f92d2SPeter Avalos struct chksumwork e_sumwrk; /* extracted checksum. */
249c09f92d2SPeter Avalos struct la_zstream stream;
250c09f92d2SPeter Avalos struct archive_string_conv *sconv;
251c09f92d2SPeter Avalos /*
252c09f92d2SPeter Avalos * Compressed data buffer.
253c09f92d2SPeter Avalos */
254c09f92d2SPeter Avalos unsigned char wbuff[1024 * 64];
255c09f92d2SPeter Avalos size_t wbuff_remaining;
256c09f92d2SPeter Avalos
257c09f92d2SPeter Avalos struct heap_data toc;
258c09f92d2SPeter Avalos /*
259c09f92d2SPeter Avalos * The list of all file entries is used to manage struct file
260c09f92d2SPeter Avalos * objects.
261e95abc47Szrj * We use 'next' (a member of struct file) to chain.
262c09f92d2SPeter Avalos */
263c09f92d2SPeter Avalos struct {
264c09f92d2SPeter Avalos struct file *first;
265c09f92d2SPeter Avalos struct file **last;
266c09f92d2SPeter Avalos } file_list;
267c09f92d2SPeter Avalos /*
268c09f92d2SPeter Avalos * The list of hard-linked file entries.
269e95abc47Szrj * We use 'hlnext' (a member of struct file) to chain.
270c09f92d2SPeter Avalos */
271c09f92d2SPeter Avalos struct archive_rb_tree hardlink_rbtree;
272c09f92d2SPeter Avalos };
273c09f92d2SPeter Avalos
274c09f92d2SPeter Avalos static int xar_options(struct archive_write *,
275c09f92d2SPeter Avalos const char *, const char *);
276c09f92d2SPeter Avalos static int xar_write_header(struct archive_write *,
277c09f92d2SPeter Avalos struct archive_entry *);
278c09f92d2SPeter Avalos static ssize_t xar_write_data(struct archive_write *,
279c09f92d2SPeter Avalos const void *, size_t);
280c09f92d2SPeter Avalos static int xar_finish_entry(struct archive_write *);
281c09f92d2SPeter Avalos static int xar_close(struct archive_write *);
282c09f92d2SPeter Avalos static int xar_free(struct archive_write *);
283c09f92d2SPeter Avalos
284c09f92d2SPeter Avalos static struct file *file_new(struct archive_write *a, struct archive_entry *);
285c09f92d2SPeter Avalos static void file_free(struct file *);
286c09f92d2SPeter Avalos static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
287c09f92d2SPeter Avalos const char *);
288c09f92d2SPeter Avalos static int file_add_child_tail(struct file *, struct file *);
289c09f92d2SPeter Avalos static struct file *file_find_child(struct file *, const char *);
290c09f92d2SPeter Avalos static int file_gen_utility_names(struct archive_write *,
291c09f92d2SPeter Avalos struct file *);
292c09f92d2SPeter Avalos static int get_path_component(char *, int, const char *);
293c09f92d2SPeter Avalos static int file_tree(struct archive_write *, struct file **);
294c09f92d2SPeter Avalos static void file_register(struct xar *, struct file *);
295c09f92d2SPeter Avalos static void file_init_register(struct xar *);
296c09f92d2SPeter Avalos static void file_free_register(struct xar *);
297c09f92d2SPeter Avalos static int file_register_hardlink(struct archive_write *,
298c09f92d2SPeter Avalos struct file *);
299c09f92d2SPeter Avalos static void file_connect_hardlink_files(struct xar *);
300c09f92d2SPeter Avalos static void file_init_hardlinks(struct xar *);
301c09f92d2SPeter Avalos static void file_free_hardlinks(struct xar *);
302c09f92d2SPeter Avalos
303c09f92d2SPeter Avalos static void checksum_init(struct chksumwork *, enum sumalg);
304c09f92d2SPeter Avalos static void checksum_update(struct chksumwork *, const void *, size_t);
305c09f92d2SPeter Avalos static void checksum_final(struct chksumwork *, struct chksumval *);
306c09f92d2SPeter Avalos static int compression_init_encoder_gzip(struct archive *,
307c09f92d2SPeter Avalos struct la_zstream *, int, int);
308c09f92d2SPeter Avalos static int compression_code_gzip(struct archive *,
309c09f92d2SPeter Avalos struct la_zstream *, enum la_zaction);
310c09f92d2SPeter Avalos static int compression_end_gzip(struct archive *, struct la_zstream *);
311c09f92d2SPeter Avalos static int compression_init_encoder_bzip2(struct archive *,
312c09f92d2SPeter Avalos struct la_zstream *, int);
313c09f92d2SPeter Avalos #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
314c09f92d2SPeter Avalos static int compression_code_bzip2(struct archive *,
315c09f92d2SPeter Avalos struct la_zstream *, enum la_zaction);
316c09f92d2SPeter Avalos static int compression_end_bzip2(struct archive *, struct la_zstream *);
317c09f92d2SPeter Avalos #endif
318c09f92d2SPeter Avalos static int compression_init_encoder_lzma(struct archive *,
319c09f92d2SPeter Avalos struct la_zstream *, int);
320c09f92d2SPeter Avalos static int compression_init_encoder_xz(struct archive *,
3216b384f39SPeter Avalos struct la_zstream *, int, int);
322c09f92d2SPeter Avalos #if defined(HAVE_LZMA_H)
323c09f92d2SPeter Avalos static int compression_code_lzma(struct archive *,
324c09f92d2SPeter Avalos struct la_zstream *, enum la_zaction);
325c09f92d2SPeter Avalos static int compression_end_lzma(struct archive *, struct la_zstream *);
326c09f92d2SPeter Avalos #endif
327c09f92d2SPeter Avalos static int xar_compression_init_encoder(struct archive_write *);
328c09f92d2SPeter Avalos static int compression_code(struct archive *,
329c09f92d2SPeter Avalos struct la_zstream *, enum la_zaction);
330c09f92d2SPeter Avalos static int compression_end(struct archive *,
331c09f92d2SPeter Avalos struct la_zstream *);
332c09f92d2SPeter Avalos static int save_xattrs(struct archive_write *, struct file *);
333c09f92d2SPeter Avalos static int getalgsize(enum sumalg);
334c09f92d2SPeter Avalos static const char *getalgname(enum sumalg);
335c09f92d2SPeter Avalos
336c09f92d2SPeter Avalos int
archive_write_set_format_xar(struct archive * _a)337c09f92d2SPeter Avalos archive_write_set_format_xar(struct archive *_a)
338c09f92d2SPeter Avalos {
339c09f92d2SPeter Avalos struct archive_write *a = (struct archive_write *)_a;
340c09f92d2SPeter Avalos struct xar *xar;
341c09f92d2SPeter Avalos
342c09f92d2SPeter Avalos archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
343c09f92d2SPeter Avalos ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
344c09f92d2SPeter Avalos
345c09f92d2SPeter Avalos /* If another format was already registered, unregister it. */
346c09f92d2SPeter Avalos if (a->format_free != NULL)
347c09f92d2SPeter Avalos (a->format_free)(a);
348c09f92d2SPeter Avalos
349c09f92d2SPeter Avalos xar = calloc(1, sizeof(*xar));
350c09f92d2SPeter Avalos if (xar == NULL) {
351c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
352c09f92d2SPeter Avalos "Can't allocate xar data");
353c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
354c09f92d2SPeter Avalos }
355c09f92d2SPeter Avalos xar->temp_fd = -1;
356c09f92d2SPeter Avalos file_init_register(xar);
357c09f92d2SPeter Avalos file_init_hardlinks(xar);
358c09f92d2SPeter Avalos archive_string_init(&(xar->tstr));
359c09f92d2SPeter Avalos archive_string_init(&(xar->vstr));
360c09f92d2SPeter Avalos
361c09f92d2SPeter Avalos /*
362c09f92d2SPeter Avalos * Create the root directory.
363c09f92d2SPeter Avalos */
364c09f92d2SPeter Avalos xar->root = file_create_virtual_dir(a, xar, "");
365c09f92d2SPeter Avalos if (xar->root == NULL) {
366c09f92d2SPeter Avalos free(xar);
367c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
368c09f92d2SPeter Avalos "Can't allocate xar data");
369c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
370c09f92d2SPeter Avalos }
371c09f92d2SPeter Avalos xar->root->parent = xar->root;
372c09f92d2SPeter Avalos file_register(xar, xar->root);
373c09f92d2SPeter Avalos xar->cur_dirent = xar->root;
374c09f92d2SPeter Avalos archive_string_init(&(xar->cur_dirstr));
375c09f92d2SPeter Avalos archive_string_ensure(&(xar->cur_dirstr), 1);
376c09f92d2SPeter Avalos xar->cur_dirstr.s[0] = 0;
377c09f92d2SPeter Avalos
378c09f92d2SPeter Avalos /*
379c09f92d2SPeter Avalos * Initialize option.
380c09f92d2SPeter Avalos */
381c09f92d2SPeter Avalos /* Set default checksum type. */
382c09f92d2SPeter Avalos xar->opt_toc_sumalg = CKSUM_SHA1;
383c09f92d2SPeter Avalos xar->opt_sumalg = CKSUM_SHA1;
3846b384f39SPeter Avalos /* Set default compression type, level, and number of threads. */
385c09f92d2SPeter Avalos xar->opt_compression = GZIP;
386c09f92d2SPeter Avalos xar->opt_compression_level = 6;
3876b384f39SPeter Avalos xar->opt_threads = 1;
388c09f92d2SPeter Avalos
389c09f92d2SPeter Avalos a->format_data = xar;
390c09f92d2SPeter Avalos
391c09f92d2SPeter Avalos a->format_name = "xar";
392c09f92d2SPeter Avalos a->format_options = xar_options;
393c09f92d2SPeter Avalos a->format_write_header = xar_write_header;
394c09f92d2SPeter Avalos a->format_write_data = xar_write_data;
395c09f92d2SPeter Avalos a->format_finish_entry = xar_finish_entry;
396c09f92d2SPeter Avalos a->format_close = xar_close;
397c09f92d2SPeter Avalos a->format_free = xar_free;
398c09f92d2SPeter Avalos a->archive.archive_format = ARCHIVE_FORMAT_XAR;
399c09f92d2SPeter Avalos a->archive.archive_format_name = "xar";
400c09f92d2SPeter Avalos
401c09f92d2SPeter Avalos return (ARCHIVE_OK);
402c09f92d2SPeter Avalos }
403c09f92d2SPeter Avalos
404c09f92d2SPeter Avalos static int
xar_options(struct archive_write * a,const char * key,const char * value)405c09f92d2SPeter Avalos xar_options(struct archive_write *a, const char *key, const char *value)
406c09f92d2SPeter Avalos {
407c09f92d2SPeter Avalos struct xar *xar;
408c09f92d2SPeter Avalos
409c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
410c09f92d2SPeter Avalos
411c09f92d2SPeter Avalos if (strcmp(key, "checksum") == 0) {
412c09f92d2SPeter Avalos if (value == NULL)
413c09f92d2SPeter Avalos xar->opt_sumalg = CKSUM_NONE;
414085658deSDaniel Fojt else if (strcmp(value, "none") == 0)
415085658deSDaniel Fojt xar->opt_sumalg = CKSUM_NONE;
416c09f92d2SPeter Avalos else if (strcmp(value, "sha1") == 0)
417c09f92d2SPeter Avalos xar->opt_sumalg = CKSUM_SHA1;
418c09f92d2SPeter Avalos else if (strcmp(value, "md5") == 0)
419c09f92d2SPeter Avalos xar->opt_sumalg = CKSUM_MD5;
420c09f92d2SPeter Avalos else {
421c09f92d2SPeter Avalos archive_set_error(&(a->archive),
422c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
423d4d8193eSPeter Avalos "Unknown checksum name: `%s'",
424c09f92d2SPeter Avalos value);
425c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
426c09f92d2SPeter Avalos }
427c09f92d2SPeter Avalos return (ARCHIVE_OK);
428c09f92d2SPeter Avalos }
429c09f92d2SPeter Avalos if (strcmp(key, "compression") == 0) {
430c09f92d2SPeter Avalos const char *name = NULL;
431c09f92d2SPeter Avalos
432c09f92d2SPeter Avalos if (value == NULL)
433c09f92d2SPeter Avalos xar->opt_compression = NONE;
434085658deSDaniel Fojt else if (strcmp(value, "none") == 0)
435085658deSDaniel Fojt xar->opt_compression = NONE;
436c09f92d2SPeter Avalos else if (strcmp(value, "gzip") == 0)
437c09f92d2SPeter Avalos xar->opt_compression = GZIP;
438c09f92d2SPeter Avalos else if (strcmp(value, "bzip2") == 0)
439c09f92d2SPeter Avalos #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
440c09f92d2SPeter Avalos xar->opt_compression = BZIP2;
441c09f92d2SPeter Avalos #else
442c09f92d2SPeter Avalos name = "bzip2";
443c09f92d2SPeter Avalos #endif
444c09f92d2SPeter Avalos else if (strcmp(value, "lzma") == 0)
445c09f92d2SPeter Avalos #if HAVE_LZMA_H
446c09f92d2SPeter Avalos xar->opt_compression = LZMA;
447c09f92d2SPeter Avalos #else
448c09f92d2SPeter Avalos name = "lzma";
449c09f92d2SPeter Avalos #endif
450c09f92d2SPeter Avalos else if (strcmp(value, "xz") == 0)
451c09f92d2SPeter Avalos #if HAVE_LZMA_H
452c09f92d2SPeter Avalos xar->opt_compression = XZ;
453c09f92d2SPeter Avalos #else
454c09f92d2SPeter Avalos name = "xz";
455c09f92d2SPeter Avalos #endif
456c09f92d2SPeter Avalos else {
457c09f92d2SPeter Avalos archive_set_error(&(a->archive),
458c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
459d4d8193eSPeter Avalos "Unknown compression name: `%s'",
460c09f92d2SPeter Avalos value);
461c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
462c09f92d2SPeter Avalos }
463c09f92d2SPeter Avalos if (name != NULL) {
464c09f92d2SPeter Avalos archive_set_error(&(a->archive),
465c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
466c09f92d2SPeter Avalos "`%s' compression not supported "
467c09f92d2SPeter Avalos "on this platform",
468c09f92d2SPeter Avalos name);
469c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
470c09f92d2SPeter Avalos }
471c09f92d2SPeter Avalos return (ARCHIVE_OK);
472c09f92d2SPeter Avalos }
473c09f92d2SPeter Avalos if (strcmp(key, "compression-level") == 0) {
474c09f92d2SPeter Avalos if (value == NULL ||
475c09f92d2SPeter Avalos !(value[0] >= '0' && value[0] <= '9') ||
476c09f92d2SPeter Avalos value[1] != '\0') {
477c09f92d2SPeter Avalos archive_set_error(&(a->archive),
478c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
479d4d8193eSPeter Avalos "Illegal value `%s'",
480c09f92d2SPeter Avalos value);
481c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
482c09f92d2SPeter Avalos }
483c09f92d2SPeter Avalos xar->opt_compression_level = value[0] - '0';
484c09f92d2SPeter Avalos return (ARCHIVE_OK);
485c09f92d2SPeter Avalos }
486c09f92d2SPeter Avalos if (strcmp(key, "toc-checksum") == 0) {
487c09f92d2SPeter Avalos if (value == NULL)
488c09f92d2SPeter Avalos xar->opt_toc_sumalg = CKSUM_NONE;
489085658deSDaniel Fojt else if (strcmp(value, "none") == 0)
490085658deSDaniel Fojt xar->opt_toc_sumalg = CKSUM_NONE;
491c09f92d2SPeter Avalos else if (strcmp(value, "sha1") == 0)
492c09f92d2SPeter Avalos xar->opt_toc_sumalg = CKSUM_SHA1;
493c09f92d2SPeter Avalos else if (strcmp(value, "md5") == 0)
494c09f92d2SPeter Avalos xar->opt_toc_sumalg = CKSUM_MD5;
495c09f92d2SPeter Avalos else {
496c09f92d2SPeter Avalos archive_set_error(&(a->archive),
497c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
498d4d8193eSPeter Avalos "Unknown checksum name: `%s'",
499c09f92d2SPeter Avalos value);
500c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
501c09f92d2SPeter Avalos }
502c09f92d2SPeter Avalos return (ARCHIVE_OK);
503c09f92d2SPeter Avalos }
5046b384f39SPeter Avalos if (strcmp(key, "threads") == 0) {
505085658deSDaniel Fojt char *endptr;
506085658deSDaniel Fojt
5076b384f39SPeter Avalos if (value == NULL)
5086b384f39SPeter Avalos return (ARCHIVE_FAILED);
509085658deSDaniel Fojt errno = 0;
510085658deSDaniel Fojt xar->opt_threads = (int)strtoul(value, &endptr, 10);
511085658deSDaniel Fojt if (errno != 0 || *endptr != '\0') {
5126b384f39SPeter Avalos xar->opt_threads = 1;
5136b384f39SPeter Avalos archive_set_error(&(a->archive),
5146b384f39SPeter Avalos ARCHIVE_ERRNO_MISC,
5156b384f39SPeter Avalos "Illegal value `%s'",
5166b384f39SPeter Avalos value);
5176b384f39SPeter Avalos return (ARCHIVE_FAILED);
5186b384f39SPeter Avalos }
5196b384f39SPeter Avalos if (xar->opt_threads == 0) {
5206b384f39SPeter Avalos #ifdef HAVE_LZMA_STREAM_ENCODER_MT
5216b384f39SPeter Avalos xar->opt_threads = lzma_cputhreads();
5226b384f39SPeter Avalos #else
5236b384f39SPeter Avalos xar->opt_threads = 1;
5246b384f39SPeter Avalos #endif
5256b384f39SPeter Avalos }
5266b384f39SPeter Avalos }
527c09f92d2SPeter Avalos
52859bf7050SPeter Avalos /* Note: The "warn" return is just to inform the options
52959bf7050SPeter Avalos * supervisor that we didn't handle it. It will generate
53059bf7050SPeter Avalos * a suitable error if no one used this option. */
53159bf7050SPeter Avalos return (ARCHIVE_WARN);
532c09f92d2SPeter Avalos }
533c09f92d2SPeter Avalos
534c09f92d2SPeter Avalos static int
xar_write_header(struct archive_write * a,struct archive_entry * entry)535c09f92d2SPeter Avalos xar_write_header(struct archive_write *a, struct archive_entry *entry)
536c09f92d2SPeter Avalos {
537c09f92d2SPeter Avalos struct xar *xar;
538c09f92d2SPeter Avalos struct file *file;
539c09f92d2SPeter Avalos struct archive_entry *file_entry;
540c09f92d2SPeter Avalos int r, r2;
541c09f92d2SPeter Avalos
542c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
543c09f92d2SPeter Avalos xar->cur_file = NULL;
544c09f92d2SPeter Avalos xar->bytes_remaining = 0;
545c09f92d2SPeter Avalos
546c09f92d2SPeter Avalos if (xar->sconv == NULL) {
547c09f92d2SPeter Avalos xar->sconv = archive_string_conversion_to_charset(
548c09f92d2SPeter Avalos &a->archive, "UTF-8", 1);
549c09f92d2SPeter Avalos if (xar->sconv == NULL)
550c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
551c09f92d2SPeter Avalos }
552c09f92d2SPeter Avalos
553c09f92d2SPeter Avalos file = file_new(a, entry);
554c09f92d2SPeter Avalos if (file == NULL) {
555c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
556c09f92d2SPeter Avalos "Can't allocate data");
557c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
558c09f92d2SPeter Avalos }
559c09f92d2SPeter Avalos r2 = file_gen_utility_names(a, file);
560c09f92d2SPeter Avalos if (r2 < ARCHIVE_WARN)
561c09f92d2SPeter Avalos return (r2);
562c09f92d2SPeter Avalos
563c09f92d2SPeter Avalos /*
564c09f92d2SPeter Avalos * Ignore a path which looks like the top of directory name
565c09f92d2SPeter Avalos * since we have already made the root directory of an Xar archive.
566c09f92d2SPeter Avalos */
567c09f92d2SPeter Avalos if (archive_strlen(&(file->parentdir)) == 0 &&
568c09f92d2SPeter Avalos archive_strlen(&(file->basename)) == 0) {
569c09f92d2SPeter Avalos file_free(file);
570c09f92d2SPeter Avalos return (r2);
571c09f92d2SPeter Avalos }
572c09f92d2SPeter Avalos
573c09f92d2SPeter Avalos /* Add entry into tree */
574c09f92d2SPeter Avalos file_entry = file->entry;
575c09f92d2SPeter Avalos r = file_tree(a, &file);
576c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
577c09f92d2SPeter Avalos return (r);
578c09f92d2SPeter Avalos /* There is the same file in tree and
579c09f92d2SPeter Avalos * the current file is older than the file in tree.
580c09f92d2SPeter Avalos * So we don't need the current file data anymore. */
581c09f92d2SPeter Avalos if (file->entry != file_entry)
582c09f92d2SPeter Avalos return (r2);
583c09f92d2SPeter Avalos if (file->id == 0)
584c09f92d2SPeter Avalos file_register(xar, file);
585c09f92d2SPeter Avalos
586c09f92d2SPeter Avalos /* A virtual file, which is a directory, does not have
587c09f92d2SPeter Avalos * any contents and we won't store it into a archive
588c09f92d2SPeter Avalos * file other than its name. */
589c09f92d2SPeter Avalos if (file->virtual)
590c09f92d2SPeter Avalos return (r2);
591c09f92d2SPeter Avalos
592c09f92d2SPeter Avalos /*
593c09f92d2SPeter Avalos * Prepare to save the contents of the file.
594c09f92d2SPeter Avalos */
595c09f92d2SPeter Avalos if (xar->temp_fd == -1) {
596c09f92d2SPeter Avalos int algsize;
597c09f92d2SPeter Avalos xar->temp_offset = 0;
598c09f92d2SPeter Avalos xar->temp_fd = __archive_mktemp(NULL);
599c09f92d2SPeter Avalos if (xar->temp_fd < 0) {
600c09f92d2SPeter Avalos archive_set_error(&a->archive, errno,
601c09f92d2SPeter Avalos "Couldn't create temporary file");
602c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
603c09f92d2SPeter Avalos }
604c09f92d2SPeter Avalos algsize = getalgsize(xar->opt_toc_sumalg);
605c09f92d2SPeter Avalos if (algsize > 0) {
606c09f92d2SPeter Avalos if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
607c09f92d2SPeter Avalos archive_set_error(&(a->archive), errno,
608c09f92d2SPeter Avalos "lseek failed");
609c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
610c09f92d2SPeter Avalos }
611c09f92d2SPeter Avalos xar->temp_offset = algsize;
612c09f92d2SPeter Avalos }
613c09f92d2SPeter Avalos }
614c09f92d2SPeter Avalos
615c09f92d2SPeter Avalos if (archive_entry_hardlink(file->entry) == NULL) {
616c09f92d2SPeter Avalos r = save_xattrs(a, file);
617c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
618c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
619c09f92d2SPeter Avalos }
620c09f92d2SPeter Avalos
621c09f92d2SPeter Avalos /* Non regular files contents are unneeded to be saved to
622c09f92d2SPeter Avalos * a temporary file. */
623c09f92d2SPeter Avalos if (archive_entry_filetype(file->entry) != AE_IFREG)
624c09f92d2SPeter Avalos return (r2);
625c09f92d2SPeter Avalos
626c09f92d2SPeter Avalos /*
627c09f92d2SPeter Avalos * Set the current file to cur_file to read its contents.
628c09f92d2SPeter Avalos */
629c09f92d2SPeter Avalos xar->cur_file = file;
630c09f92d2SPeter Avalos
631c09f92d2SPeter Avalos if (archive_entry_nlink(file->entry) > 1) {
632c09f92d2SPeter Avalos r = file_register_hardlink(a, file);
633c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
634c09f92d2SPeter Avalos return (r);
635c09f92d2SPeter Avalos if (archive_entry_hardlink(file->entry) != NULL) {
636c09f92d2SPeter Avalos archive_entry_unset_size(file->entry);
637c09f92d2SPeter Avalos return (r2);
638c09f92d2SPeter Avalos }
639c09f92d2SPeter Avalos }
640c09f92d2SPeter Avalos
641c09f92d2SPeter Avalos /* Save a offset of current file in temporary file. */
642c09f92d2SPeter Avalos file->data.temp_offset = xar->temp_offset;
643c09f92d2SPeter Avalos file->data.size = archive_entry_size(file->entry);
644c09f92d2SPeter Avalos file->data.compression = xar->opt_compression;
645c09f92d2SPeter Avalos xar->bytes_remaining = archive_entry_size(file->entry);
646c09f92d2SPeter Avalos checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
647c09f92d2SPeter Avalos checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
648c09f92d2SPeter Avalos r = xar_compression_init_encoder(a);
649c09f92d2SPeter Avalos
650c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
651c09f92d2SPeter Avalos return (r);
652c09f92d2SPeter Avalos else
653c09f92d2SPeter Avalos return (r2);
654c09f92d2SPeter Avalos }
655c09f92d2SPeter Avalos
656c09f92d2SPeter Avalos static int
write_to_temp(struct archive_write * a,const void * buff,size_t s)657c09f92d2SPeter Avalos write_to_temp(struct archive_write *a, const void *buff, size_t s)
658c09f92d2SPeter Avalos {
659c09f92d2SPeter Avalos struct xar *xar;
66059bf7050SPeter Avalos const unsigned char *p;
661c09f92d2SPeter Avalos ssize_t ws;
662c09f92d2SPeter Avalos
663c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
66459bf7050SPeter Avalos p = (const unsigned char *)buff;
665c09f92d2SPeter Avalos while (s) {
666c09f92d2SPeter Avalos ws = write(xar->temp_fd, p, s);
667c09f92d2SPeter Avalos if (ws < 0) {
668c09f92d2SPeter Avalos archive_set_error(&(a->archive), errno,
669c09f92d2SPeter Avalos "fwrite function failed");
670c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
671c09f92d2SPeter Avalos }
672c09f92d2SPeter Avalos s -= ws;
673c09f92d2SPeter Avalos p += ws;
674c09f92d2SPeter Avalos xar->temp_offset += ws;
675c09f92d2SPeter Avalos }
676c09f92d2SPeter Avalos return (ARCHIVE_OK);
677c09f92d2SPeter Avalos }
678c09f92d2SPeter Avalos
679c09f92d2SPeter Avalos static ssize_t
xar_write_data(struct archive_write * a,const void * buff,size_t s)680c09f92d2SPeter Avalos xar_write_data(struct archive_write *a, const void *buff, size_t s)
681c09f92d2SPeter Avalos {
682c09f92d2SPeter Avalos struct xar *xar;
683c09f92d2SPeter Avalos enum la_zaction run;
684085658deSDaniel Fojt size_t size = 0;
685085658deSDaniel Fojt size_t rsize;
686c09f92d2SPeter Avalos int r;
687c09f92d2SPeter Avalos
688c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
689c09f92d2SPeter Avalos
690c09f92d2SPeter Avalos if (s > xar->bytes_remaining)
69159bf7050SPeter Avalos s = (size_t)xar->bytes_remaining;
692c09f92d2SPeter Avalos if (s == 0 || xar->cur_file == NULL)
693c09f92d2SPeter Avalos return (0);
694c09f92d2SPeter Avalos if (xar->cur_file->data.compression == NONE) {
695c09f92d2SPeter Avalos checksum_update(&(xar->e_sumwrk), buff, s);
696c09f92d2SPeter Avalos checksum_update(&(xar->a_sumwrk), buff, s);
697c09f92d2SPeter Avalos size = rsize = s;
698c09f92d2SPeter Avalos } else {
699c09f92d2SPeter Avalos xar->stream.next_in = (const unsigned char *)buff;
700c09f92d2SPeter Avalos xar->stream.avail_in = s;
701c09f92d2SPeter Avalos if (xar->bytes_remaining > s)
702c09f92d2SPeter Avalos run = ARCHIVE_Z_RUN;
703c09f92d2SPeter Avalos else
704c09f92d2SPeter Avalos run = ARCHIVE_Z_FINISH;
705c09f92d2SPeter Avalos /* Compress file data. */
706085658deSDaniel Fojt for (;;) {
707085658deSDaniel Fojt r = compression_code(&(a->archive), &(xar->stream),
708085658deSDaniel Fojt run);
709c09f92d2SPeter Avalos if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
710c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
711085658deSDaniel Fojt if (xar->stream.avail_out == 0 ||
712085658deSDaniel Fojt run == ARCHIVE_Z_FINISH) {
713085658deSDaniel Fojt size = sizeof(xar->wbuff) -
714085658deSDaniel Fojt xar->stream.avail_out;
715085658deSDaniel Fojt checksum_update(&(xar->a_sumwrk), xar->wbuff,
716085658deSDaniel Fojt size);
717085658deSDaniel Fojt xar->cur_file->data.length += size;
718085658deSDaniel Fojt if (write_to_temp(a, xar->wbuff,
719085658deSDaniel Fojt size) != ARCHIVE_OK)
720085658deSDaniel Fojt return (ARCHIVE_FATAL);
721085658deSDaniel Fojt if (r == ARCHIVE_OK) {
722085658deSDaniel Fojt /* Output buffer was full */
723085658deSDaniel Fojt xar->stream.next_out = xar->wbuff;
724085658deSDaniel Fojt xar->stream.avail_out =
725085658deSDaniel Fojt sizeof(xar->wbuff);
726085658deSDaniel Fojt } else {
727085658deSDaniel Fojt /* ARCHIVE_EOF - We are done */
728085658deSDaniel Fojt break;
729085658deSDaniel Fojt }
730085658deSDaniel Fojt } else {
731085658deSDaniel Fojt /* Compressor wants more input */
732085658deSDaniel Fojt break;
733085658deSDaniel Fojt }
734085658deSDaniel Fojt }
735c09f92d2SPeter Avalos rsize = s - xar->stream.avail_in;
736c09f92d2SPeter Avalos checksum_update(&(xar->e_sumwrk), buff, rsize);
737c09f92d2SPeter Avalos }
738c09f92d2SPeter Avalos #if !defined(_WIN32) || defined(__CYGWIN__)
739c09f92d2SPeter Avalos if (xar->bytes_remaining ==
74059bf7050SPeter Avalos (uint64_t)archive_entry_size(xar->cur_file->entry)) {
741c09f92d2SPeter Avalos /*
742c09f92d2SPeter Avalos * Get the path of a shell script if so.
743c09f92d2SPeter Avalos */
744c09f92d2SPeter Avalos const unsigned char *b = (const unsigned char *)buff;
745c09f92d2SPeter Avalos
746c09f92d2SPeter Avalos archive_string_empty(&(xar->cur_file->script));
747c09f92d2SPeter Avalos if (rsize > 2 && b[0] == '#' && b[1] == '!') {
748c09f92d2SPeter Avalos size_t i, end, off;
749c09f92d2SPeter Avalos
750c09f92d2SPeter Avalos off = 2;
751c09f92d2SPeter Avalos if (b[off] == ' ')
752c09f92d2SPeter Avalos off++;
75355c601bbSPeter Avalos #ifdef PATH_MAX
75455c601bbSPeter Avalos if ((rsize - off) > PATH_MAX)
75555c601bbSPeter Avalos end = off + PATH_MAX;
75655c601bbSPeter Avalos else
75755c601bbSPeter Avalos #endif
75855c601bbSPeter Avalos end = rsize;
75955c601bbSPeter Avalos /* Find the end of a script path. */
760c09f92d2SPeter Avalos for (i = off; i < end && b[i] != '\0' &&
761c09f92d2SPeter Avalos b[i] != '\n' && b[i] != '\r' &&
762c09f92d2SPeter Avalos b[i] != ' ' && b[i] != '\t'; i++)
76355c601bbSPeter Avalos ;
76455c601bbSPeter Avalos archive_strncpy(&(xar->cur_file->script), b + off,
76555c601bbSPeter Avalos i - off);
766c09f92d2SPeter Avalos }
767c09f92d2SPeter Avalos }
768c09f92d2SPeter Avalos #endif
769c09f92d2SPeter Avalos
770c09f92d2SPeter Avalos if (xar->cur_file->data.compression == NONE) {
771c09f92d2SPeter Avalos if (write_to_temp(a, buff, size) != ARCHIVE_OK)
772c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
773085658deSDaniel Fojt xar->cur_file->data.length += size;
774c09f92d2SPeter Avalos }
775c09f92d2SPeter Avalos xar->bytes_remaining -= rsize;
776c09f92d2SPeter Avalos
777c09f92d2SPeter Avalos return (rsize);
778c09f92d2SPeter Avalos }
779c09f92d2SPeter Avalos
780c09f92d2SPeter Avalos static int
xar_finish_entry(struct archive_write * a)781c09f92d2SPeter Avalos xar_finish_entry(struct archive_write *a)
782c09f92d2SPeter Avalos {
783c09f92d2SPeter Avalos struct xar *xar;
784c09f92d2SPeter Avalos struct file *file;
785c09f92d2SPeter Avalos size_t s;
786c09f92d2SPeter Avalos ssize_t w;
787c09f92d2SPeter Avalos
788c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
789c09f92d2SPeter Avalos if (xar->cur_file == NULL)
790c09f92d2SPeter Avalos return (ARCHIVE_OK);
791c09f92d2SPeter Avalos
792c09f92d2SPeter Avalos while (xar->bytes_remaining > 0) {
79359bf7050SPeter Avalos s = (size_t)xar->bytes_remaining;
794c09f92d2SPeter Avalos if (s > a->null_length)
795c09f92d2SPeter Avalos s = a->null_length;
796c09f92d2SPeter Avalos w = xar_write_data(a, a->nulls, s);
797c09f92d2SPeter Avalos if (w > 0)
798c09f92d2SPeter Avalos xar->bytes_remaining -= w;
799c09f92d2SPeter Avalos else
800c09f92d2SPeter Avalos return (w);
801c09f92d2SPeter Avalos }
802c09f92d2SPeter Avalos file = xar->cur_file;
803c09f92d2SPeter Avalos checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
804c09f92d2SPeter Avalos checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
805c09f92d2SPeter Avalos xar->cur_file = NULL;
806c09f92d2SPeter Avalos
807c09f92d2SPeter Avalos return (ARCHIVE_OK);
808c09f92d2SPeter Avalos }
809c09f92d2SPeter Avalos
810c09f92d2SPeter Avalos static int
xmlwrite_string_attr(struct archive_write * a,xmlTextWriterPtr writer,const char * key,const char * value,const char * attrkey,const char * attrvalue)811c09f92d2SPeter Avalos xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
812c09f92d2SPeter Avalos const char *key, const char *value,
813c09f92d2SPeter Avalos const char *attrkey, const char *attrvalue)
814c09f92d2SPeter Avalos {
815c09f92d2SPeter Avalos int r;
816c09f92d2SPeter Avalos
81759bf7050SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
818c09f92d2SPeter Avalos if (r < 0) {
819c09f92d2SPeter Avalos archive_set_error(&a->archive,
820c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
821c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
822c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
823c09f92d2SPeter Avalos }
824c09f92d2SPeter Avalos if (attrkey != NULL && attrvalue != NULL) {
825c09f92d2SPeter Avalos r = xmlTextWriterWriteAttribute(writer,
82659bf7050SPeter Avalos BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
827c09f92d2SPeter Avalos if (r < 0) {
828c09f92d2SPeter Avalos archive_set_error(&a->archive,
829c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
830c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() failed: %d", r);
831c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
832c09f92d2SPeter Avalos }
833c09f92d2SPeter Avalos }
834c09f92d2SPeter Avalos if (value != NULL) {
83559bf7050SPeter Avalos r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
836c09f92d2SPeter Avalos if (r < 0) {
837c09f92d2SPeter Avalos archive_set_error(&a->archive,
838c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
839c09f92d2SPeter Avalos "xmlTextWriterWriteString() failed: %d", r);
840c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
841c09f92d2SPeter Avalos }
842c09f92d2SPeter Avalos }
843c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
844c09f92d2SPeter Avalos if (r < 0) {
845c09f92d2SPeter Avalos archive_set_error(&a->archive,
846c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
847c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
848c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
849c09f92d2SPeter Avalos }
850c09f92d2SPeter Avalos return (ARCHIVE_OK);
851c09f92d2SPeter Avalos }
852c09f92d2SPeter Avalos
853c09f92d2SPeter Avalos static int
xmlwrite_string(struct archive_write * a,xmlTextWriterPtr writer,const char * key,const char * value)854c09f92d2SPeter Avalos xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
855c09f92d2SPeter Avalos const char *key, const char *value)
856c09f92d2SPeter Avalos {
857c09f92d2SPeter Avalos int r;
858c09f92d2SPeter Avalos
859c09f92d2SPeter Avalos if (value == NULL)
860c09f92d2SPeter Avalos return (ARCHIVE_OK);
861c09f92d2SPeter Avalos
86259bf7050SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
863c09f92d2SPeter Avalos if (r < 0) {
864c09f92d2SPeter Avalos archive_set_error(&a->archive,
865c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
866c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
867c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
868c09f92d2SPeter Avalos }
869c09f92d2SPeter Avalos if (value != NULL) {
87059bf7050SPeter Avalos r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
871c09f92d2SPeter Avalos if (r < 0) {
872c09f92d2SPeter Avalos archive_set_error(&a->archive,
873c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
874c09f92d2SPeter Avalos "xmlTextWriterWriteString() failed: %d", r);
875c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
876c09f92d2SPeter Avalos }
877c09f92d2SPeter Avalos }
878c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
879c09f92d2SPeter Avalos if (r < 0) {
880c09f92d2SPeter Avalos archive_set_error(&a->archive,
881c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
882c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
883c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
884c09f92d2SPeter Avalos }
885c09f92d2SPeter Avalos return (ARCHIVE_OK);
886c09f92d2SPeter Avalos }
887c09f92d2SPeter Avalos
888c09f92d2SPeter Avalos static int
xmlwrite_fstring(struct archive_write * a,xmlTextWriterPtr writer,const char * key,const char * fmt,...)889c09f92d2SPeter Avalos xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
890c09f92d2SPeter Avalos const char *key, const char *fmt, ...)
891c09f92d2SPeter Avalos {
892c09f92d2SPeter Avalos struct xar *xar;
893c09f92d2SPeter Avalos va_list ap;
894c09f92d2SPeter Avalos
895c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
896c09f92d2SPeter Avalos va_start(ap, fmt);
897c09f92d2SPeter Avalos archive_string_empty(&xar->vstr);
898c09f92d2SPeter Avalos archive_string_vsprintf(&xar->vstr, fmt, ap);
899c09f92d2SPeter Avalos va_end(ap);
900c09f92d2SPeter Avalos return (xmlwrite_string(a, writer, key, xar->vstr.s));
901c09f92d2SPeter Avalos }
902c09f92d2SPeter Avalos
903c09f92d2SPeter Avalos static int
xmlwrite_time(struct archive_write * a,xmlTextWriterPtr writer,const char * key,time_t t,int z)904c09f92d2SPeter Avalos xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
905c09f92d2SPeter Avalos const char *key, time_t t, int z)
906c09f92d2SPeter Avalos {
907c09f92d2SPeter Avalos char timestr[100];
908c09f92d2SPeter Avalos struct tm tm;
909085658deSDaniel Fojt #if defined(HAVE__GMTIME64_S)
910085658deSDaniel Fojt __time64_t tmptime;
911085658deSDaniel Fojt #endif
912c09f92d2SPeter Avalos
913c09f92d2SPeter Avalos #if defined(HAVE_GMTIME_R)
914c09f92d2SPeter Avalos gmtime_r(&t, &tm);
915c09f92d2SPeter Avalos #elif defined(HAVE__GMTIME64_S)
916085658deSDaniel Fojt tmptime = t;
917085658deSDaniel Fojt _gmtime64_s(&tm, &tmptime);
918c09f92d2SPeter Avalos #else
919c09f92d2SPeter Avalos memcpy(&tm, gmtime(&t), sizeof(tm));
920c09f92d2SPeter Avalos #endif
921c09f92d2SPeter Avalos memset(×tr, 0, sizeof(timestr));
922c09f92d2SPeter Avalos /* Do not use %F and %T for portability. */
923c09f92d2SPeter Avalos strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);
924c09f92d2SPeter Avalos if (z)
925c09f92d2SPeter Avalos strcat(timestr, "Z");
926c09f92d2SPeter Avalos return (xmlwrite_string(a, writer, key, timestr));
927c09f92d2SPeter Avalos }
928c09f92d2SPeter Avalos
929c09f92d2SPeter Avalos static int
xmlwrite_mode(struct archive_write * a,xmlTextWriterPtr writer,const char * key,mode_t mode)930c09f92d2SPeter Avalos xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
931c09f92d2SPeter Avalos const char *key, mode_t mode)
932c09f92d2SPeter Avalos {
933c09f92d2SPeter Avalos char ms[5];
934c09f92d2SPeter Avalos
935c09f92d2SPeter Avalos ms[0] = '0';
936c09f92d2SPeter Avalos ms[1] = '0' + ((mode >> 6) & 07);
937c09f92d2SPeter Avalos ms[2] = '0' + ((mode >> 3) & 07);
938c09f92d2SPeter Avalos ms[3] = '0' + (mode & 07);
939c09f92d2SPeter Avalos ms[4] = '\0';
940c09f92d2SPeter Avalos
941c09f92d2SPeter Avalos return (xmlwrite_string(a, writer, key, ms));
942c09f92d2SPeter Avalos }
943c09f92d2SPeter Avalos
944c09f92d2SPeter Avalos static int
xmlwrite_sum(struct archive_write * a,xmlTextWriterPtr writer,const char * key,struct chksumval * sum)945c09f92d2SPeter Avalos xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
946c09f92d2SPeter Avalos const char *key, struct chksumval *sum)
947c09f92d2SPeter Avalos {
948c09f92d2SPeter Avalos const char *algname;
949c09f92d2SPeter Avalos int algsize;
950c09f92d2SPeter Avalos char buff[MAX_SUM_SIZE*2 + 1];
951c09f92d2SPeter Avalos char *p;
952c09f92d2SPeter Avalos unsigned char *s;
953c09f92d2SPeter Avalos int i, r;
954c09f92d2SPeter Avalos
955c09f92d2SPeter Avalos if (sum->len > 0) {
956c09f92d2SPeter Avalos algname = getalgname(sum->alg);
957c09f92d2SPeter Avalos algsize = getalgsize(sum->alg);
958c09f92d2SPeter Avalos if (algname != NULL) {
959c09f92d2SPeter Avalos const char *hex = "0123456789abcdef";
960c09f92d2SPeter Avalos p = buff;
961c09f92d2SPeter Avalos s = sum->val;
962c09f92d2SPeter Avalos for (i = 0; i < algsize; i++) {
963c09f92d2SPeter Avalos *p++ = hex[(*s >> 4)];
964c09f92d2SPeter Avalos *p++ = hex[(*s & 0x0f)];
965c09f92d2SPeter Avalos s++;
966c09f92d2SPeter Avalos }
967c09f92d2SPeter Avalos *p = '\0';
968c09f92d2SPeter Avalos r = xmlwrite_string_attr(a, writer,
969c09f92d2SPeter Avalos key, buff,
970c09f92d2SPeter Avalos "style", algname);
971c09f92d2SPeter Avalos if (r < 0)
972c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
973c09f92d2SPeter Avalos }
974c09f92d2SPeter Avalos }
975c09f92d2SPeter Avalos return (ARCHIVE_OK);
976c09f92d2SPeter Avalos }
977c09f92d2SPeter Avalos
978c09f92d2SPeter Avalos static int
xmlwrite_heap(struct archive_write * a,xmlTextWriterPtr writer,struct heap_data * heap)979c09f92d2SPeter Avalos xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
980c09f92d2SPeter Avalos struct heap_data *heap)
981c09f92d2SPeter Avalos {
982c09f92d2SPeter Avalos const char *encname;
983c09f92d2SPeter Avalos int r;
984c09f92d2SPeter Avalos
985c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
986c09f92d2SPeter Avalos if (r < 0)
987c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
988c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
989c09f92d2SPeter Avalos if (r < 0)
990c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
991c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
992c09f92d2SPeter Avalos if (r < 0)
993c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
994c09f92d2SPeter Avalos switch (heap->compression) {
995c09f92d2SPeter Avalos case GZIP:
996c09f92d2SPeter Avalos encname = "application/x-gzip"; break;
997c09f92d2SPeter Avalos case BZIP2:
998c09f92d2SPeter Avalos encname = "application/x-bzip2"; break;
999c09f92d2SPeter Avalos case LZMA:
1000c09f92d2SPeter Avalos encname = "application/x-lzma"; break;
1001c09f92d2SPeter Avalos case XZ:
1002c09f92d2SPeter Avalos encname = "application/x-xz"; break;
1003c09f92d2SPeter Avalos default:
1004c09f92d2SPeter Avalos encname = "application/octet-stream"; break;
1005c09f92d2SPeter Avalos }
1006c09f92d2SPeter Avalos r = xmlwrite_string_attr(a, writer, "encoding", NULL,
1007c09f92d2SPeter Avalos "style", encname);
1008c09f92d2SPeter Avalos if (r < 0)
1009c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1010c09f92d2SPeter Avalos r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
1011c09f92d2SPeter Avalos if (r < 0)
1012c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1013c09f92d2SPeter Avalos r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
1014c09f92d2SPeter Avalos if (r < 0)
1015c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1016c09f92d2SPeter Avalos return (ARCHIVE_OK);
1017c09f92d2SPeter Avalos }
1018c09f92d2SPeter Avalos
1019c09f92d2SPeter Avalos /*
1020c09f92d2SPeter Avalos * xar utility records fflags as following xml elements:
1021c09f92d2SPeter Avalos * <flags>
1022c09f92d2SPeter Avalos * <UserNoDump/>
1023c09f92d2SPeter Avalos * .....
1024c09f92d2SPeter Avalos * </flags>
1025c09f92d2SPeter Avalos * or
1026c09f92d2SPeter Avalos * <ext2>
1027c09f92d2SPeter Avalos * <NoDump/>
1028c09f92d2SPeter Avalos * .....
1029c09f92d2SPeter Avalos * </ext2>
1030c09f92d2SPeter Avalos * If xar is running on BSD platform, records <flags>..</flags>;
1031c09f92d2SPeter Avalos * if xar is running on linux platform, records <ext2>..</ext2>;
1032c09f92d2SPeter Avalos * otherwise does not record.
1033c09f92d2SPeter Avalos *
1034c09f92d2SPeter Avalos * Our implements records both <flags> and <ext2> if it's necessary.
1035c09f92d2SPeter Avalos */
1036c09f92d2SPeter Avalos static int
make_fflags_entry(struct archive_write * a,xmlTextWriterPtr writer,const char * element,const char * fflags_text)1037c09f92d2SPeter Avalos make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
1038c09f92d2SPeter Avalos const char *element, const char *fflags_text)
1039c09f92d2SPeter Avalos {
1040c09f92d2SPeter Avalos static const struct flagentry {
1041c09f92d2SPeter Avalos const char *name;
1042c09f92d2SPeter Avalos const char *xarname;
1043c09f92d2SPeter Avalos }
1044c09f92d2SPeter Avalos flagbsd[] = {
1045c09f92d2SPeter Avalos { "sappnd", "SystemAppend"},
1046c09f92d2SPeter Avalos { "sappend", "SystemAppend"},
1047c09f92d2SPeter Avalos { "arch", "SystemArchived"},
1048c09f92d2SPeter Avalos { "archived", "SystemArchived"},
1049c09f92d2SPeter Avalos { "schg", "SystemImmutable"},
1050c09f92d2SPeter Avalos { "schange", "SystemImmutable"},
1051c09f92d2SPeter Avalos { "simmutable", "SystemImmutable"},
1052c09f92d2SPeter Avalos { "nosunlnk", "SystemNoUnlink"},
1053c09f92d2SPeter Avalos { "nosunlink", "SystemNoUnlink"},
1054c09f92d2SPeter Avalos { "snapshot", "SystemSnapshot"},
1055c09f92d2SPeter Avalos { "uappnd", "UserAppend"},
1056c09f92d2SPeter Avalos { "uappend", "UserAppend"},
1057c09f92d2SPeter Avalos { "uchg", "UserImmutable"},
1058c09f92d2SPeter Avalos { "uchange", "UserImmutable"},
1059c09f92d2SPeter Avalos { "uimmutable", "UserImmutable"},
1060c09f92d2SPeter Avalos { "nodump", "UserNoDump"},
1061c09f92d2SPeter Avalos { "noopaque", "UserOpaque"},
1062c09f92d2SPeter Avalos { "nouunlnk", "UserNoUnlink"},
1063c09f92d2SPeter Avalos { "nouunlink", "UserNoUnlink"},
1064c09f92d2SPeter Avalos { NULL, NULL}
1065c09f92d2SPeter Avalos },
1066c09f92d2SPeter Avalos flagext2[] = {
1067c09f92d2SPeter Avalos { "sappnd", "AppendOnly"},
1068c09f92d2SPeter Avalos { "sappend", "AppendOnly"},
1069c09f92d2SPeter Avalos { "schg", "Immutable"},
1070c09f92d2SPeter Avalos { "schange", "Immutable"},
1071c09f92d2SPeter Avalos { "simmutable", "Immutable"},
1072c09f92d2SPeter Avalos { "nodump", "NoDump"},
1073c09f92d2SPeter Avalos { "nouunlnk", "Undelete"},
1074c09f92d2SPeter Avalos { "nouunlink", "Undelete"},
1075c09f92d2SPeter Avalos { "btree", "BTree"},
1076c09f92d2SPeter Avalos { "comperr", "CompError"},
1077c09f92d2SPeter Avalos { "compress", "Compress"},
1078c09f92d2SPeter Avalos { "noatime", "NoAtime"},
1079c09f92d2SPeter Avalos { "compdirty", "CompDirty"},
1080c09f92d2SPeter Avalos { "comprblk", "CompBlock"},
1081c09f92d2SPeter Avalos { "dirsync", "DirSync"},
1082c09f92d2SPeter Avalos { "hashidx", "HashIndexed"},
1083c09f92d2SPeter Avalos { "imagic", "iMagic"},
1084c09f92d2SPeter Avalos { "journal", "Journaled"},
1085c09f92d2SPeter Avalos { "securedeletion", "SecureDeletion"},
1086c09f92d2SPeter Avalos { "sync", "Synchronous"},
1087c09f92d2SPeter Avalos { "notail", "NoTail"},
1088c09f92d2SPeter Avalos { "topdir", "TopDir"},
1089c09f92d2SPeter Avalos { "reserved", "Reserved"},
1090c09f92d2SPeter Avalos { NULL, NULL}
1091c09f92d2SPeter Avalos };
1092c09f92d2SPeter Avalos const struct flagentry *fe, *flagentry;
1093c09f92d2SPeter Avalos #define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
1094c09f92d2SPeter Avalos const struct flagentry *avail[FLAGENTRY_MAXSIZE];
1095c09f92d2SPeter Avalos const char *p;
1096c09f92d2SPeter Avalos int i, n, r;
1097c09f92d2SPeter Avalos
1098c09f92d2SPeter Avalos if (strcmp(element, "ext2") == 0)
1099c09f92d2SPeter Avalos flagentry = flagext2;
1100c09f92d2SPeter Avalos else
1101c09f92d2SPeter Avalos flagentry = flagbsd;
1102c09f92d2SPeter Avalos n = 0;
1103c09f92d2SPeter Avalos p = fflags_text;
1104c09f92d2SPeter Avalos do {
1105c09f92d2SPeter Avalos const char *cp;
1106c09f92d2SPeter Avalos
1107c09f92d2SPeter Avalos cp = strchr(p, ',');
1108c09f92d2SPeter Avalos if (cp == NULL)
1109c09f92d2SPeter Avalos cp = p + strlen(p);
1110c09f92d2SPeter Avalos
1111c09f92d2SPeter Avalos for (fe = flagentry; fe->name != NULL; fe++) {
1112c09f92d2SPeter Avalos if (fe->name[cp - p] != '\0'
1113c09f92d2SPeter Avalos || p[0] != fe->name[0])
1114c09f92d2SPeter Avalos continue;
1115c09f92d2SPeter Avalos if (strncmp(p, fe->name, cp - p) == 0) {
1116c09f92d2SPeter Avalos avail[n++] = fe;
1117c09f92d2SPeter Avalos break;
1118c09f92d2SPeter Avalos }
1119c09f92d2SPeter Avalos }
1120c09f92d2SPeter Avalos if (*cp == ',')
1121c09f92d2SPeter Avalos p = cp + 1;
1122c09f92d2SPeter Avalos else
1123c09f92d2SPeter Avalos p = NULL;
1124c09f92d2SPeter Avalos } while (p != NULL);
1125c09f92d2SPeter Avalos
1126c09f92d2SPeter Avalos if (n > 0) {
112759bf7050SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
1128c09f92d2SPeter Avalos if (r < 0) {
1129c09f92d2SPeter Avalos archive_set_error(&a->archive,
1130c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1131c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1132c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1133c09f92d2SPeter Avalos }
1134c09f92d2SPeter Avalos for (i = 0; i < n; i++) {
1135c09f92d2SPeter Avalos r = xmlwrite_string(a, writer,
1136c09f92d2SPeter Avalos avail[i]->xarname, NULL);
1137c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1138c09f92d2SPeter Avalos return (r);
1139c09f92d2SPeter Avalos }
1140c09f92d2SPeter Avalos
1141c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1142c09f92d2SPeter Avalos if (r < 0) {
1143c09f92d2SPeter Avalos archive_set_error(&a->archive,
1144c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1145c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1146c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1147c09f92d2SPeter Avalos }
1148c09f92d2SPeter Avalos }
1149c09f92d2SPeter Avalos return (ARCHIVE_OK);
1150c09f92d2SPeter Avalos }
1151c09f92d2SPeter Avalos
1152c09f92d2SPeter Avalos static int
make_file_entry(struct archive_write * a,xmlTextWriterPtr writer,struct file * file)1153c09f92d2SPeter Avalos make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
1154c09f92d2SPeter Avalos struct file *file)
1155c09f92d2SPeter Avalos {
1156c09f92d2SPeter Avalos struct xar *xar;
1157c09f92d2SPeter Avalos const char *filetype, *filelink, *fflags;
1158c09f92d2SPeter Avalos struct archive_string linkto;
1159c09f92d2SPeter Avalos struct heap_data *heap;
1160c09f92d2SPeter Avalos unsigned char *tmp;
1161c09f92d2SPeter Avalos const char *p;
1162c09f92d2SPeter Avalos size_t len;
1163c09f92d2SPeter Avalos int r, r2, l, ll;
1164c09f92d2SPeter Avalos
1165c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
1166c09f92d2SPeter Avalos r2 = ARCHIVE_OK;
1167c09f92d2SPeter Avalos
1168c09f92d2SPeter Avalos /*
1169c09f92d2SPeter Avalos * Make a file name entry, "<name>".
1170c09f92d2SPeter Avalos */
1171c09f92d2SPeter Avalos l = ll = archive_strlen(&(file->basename));
1172c09f92d2SPeter Avalos tmp = malloc(l);
1173c09f92d2SPeter Avalos if (tmp == NULL) {
1174c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1175c09f92d2SPeter Avalos "Can't allocate memory");
1176c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1177c09f92d2SPeter Avalos }
1178c09f92d2SPeter Avalos r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
1179c09f92d2SPeter Avalos free(tmp);
1180c09f92d2SPeter Avalos if (r < 0) {
1181c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
1182c09f92d2SPeter Avalos if (r < 0) {
1183c09f92d2SPeter Avalos archive_set_error(&a->archive,
1184c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1185c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1186c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1187c09f92d2SPeter Avalos }
1188c09f92d2SPeter Avalos r = xmlTextWriterWriteAttribute(writer,
1189c09f92d2SPeter Avalos BAD_CAST("enctype"), BAD_CAST("base64"));
1190c09f92d2SPeter Avalos if (r < 0) {
1191c09f92d2SPeter Avalos archive_set_error(&a->archive,
1192c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1193c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() failed: %d", r);
1194c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1195c09f92d2SPeter Avalos }
1196c09f92d2SPeter Avalos r = xmlTextWriterWriteBase64(writer, file->basename.s,
1197c09f92d2SPeter Avalos 0, archive_strlen(&(file->basename)));
1198c09f92d2SPeter Avalos if (r < 0) {
1199c09f92d2SPeter Avalos archive_set_error(&a->archive,
1200c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1201c09f92d2SPeter Avalos "xmlTextWriterWriteBase64() failed: %d", r);
1202c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1203c09f92d2SPeter Avalos }
1204c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1205c09f92d2SPeter Avalos if (r < 0) {
1206c09f92d2SPeter Avalos archive_set_error(&a->archive,
1207c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1208c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1209c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1210c09f92d2SPeter Avalos }
1211c09f92d2SPeter Avalos } else {
1212c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "name", file->basename.s);
1213c09f92d2SPeter Avalos if (r < 0)
1214c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1215c09f92d2SPeter Avalos }
1216c09f92d2SPeter Avalos
1217c09f92d2SPeter Avalos /*
1218c09f92d2SPeter Avalos * Make a file type entry, "<type>".
1219c09f92d2SPeter Avalos */
1220c09f92d2SPeter Avalos filelink = NULL;
1221c09f92d2SPeter Avalos archive_string_init(&linkto);
1222c09f92d2SPeter Avalos switch (archive_entry_filetype(file->entry)) {
1223c09f92d2SPeter Avalos case AE_IFDIR:
1224c09f92d2SPeter Avalos filetype = "directory"; break;
1225c09f92d2SPeter Avalos case AE_IFLNK:
1226c09f92d2SPeter Avalos filetype = "symlink"; break;
1227c09f92d2SPeter Avalos case AE_IFCHR:
1228c09f92d2SPeter Avalos filetype = "character special"; break;
1229c09f92d2SPeter Avalos case AE_IFBLK:
1230c09f92d2SPeter Avalos filetype = "block special"; break;
1231c09f92d2SPeter Avalos case AE_IFSOCK:
1232c09f92d2SPeter Avalos filetype = "socket"; break;
1233c09f92d2SPeter Avalos case AE_IFIFO:
1234c09f92d2SPeter Avalos filetype = "fifo"; break;
1235c09f92d2SPeter Avalos case AE_IFREG:
1236c09f92d2SPeter Avalos default:
1237c09f92d2SPeter Avalos if (file->hardlink_target != NULL) {
1238c09f92d2SPeter Avalos filetype = "hardlink";
1239c09f92d2SPeter Avalos filelink = "link";
1240c09f92d2SPeter Avalos if (file->hardlink_target == file)
1241c09f92d2SPeter Avalos archive_strcpy(&linkto, "original");
1242c09f92d2SPeter Avalos else
1243c09f92d2SPeter Avalos archive_string_sprintf(&linkto, "%d",
1244c09f92d2SPeter Avalos file->hardlink_target->id);
1245c09f92d2SPeter Avalos } else
1246c09f92d2SPeter Avalos filetype = "file";
1247c09f92d2SPeter Avalos break;
1248c09f92d2SPeter Avalos }
1249c09f92d2SPeter Avalos r = xmlwrite_string_attr(a, writer, "type", filetype,
1250c09f92d2SPeter Avalos filelink, linkto.s);
1251c09f92d2SPeter Avalos archive_string_free(&linkto);
1252c09f92d2SPeter Avalos if (r < 0)
1253c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1254c09f92d2SPeter Avalos
1255c09f92d2SPeter Avalos /*
1256c09f92d2SPeter Avalos * On a virtual directory, we record "name" and "type" only.
1257c09f92d2SPeter Avalos */
1258c09f92d2SPeter Avalos if (file->virtual)
1259c09f92d2SPeter Avalos return (ARCHIVE_OK);
1260c09f92d2SPeter Avalos
1261c09f92d2SPeter Avalos switch (archive_entry_filetype(file->entry)) {
1262c09f92d2SPeter Avalos case AE_IFLNK:
1263c09f92d2SPeter Avalos /*
1264c09f92d2SPeter Avalos * xar utility has checked a file type, which
1265e95abc47Szrj * a symbolic-link file has referenced.
1266c09f92d2SPeter Avalos * For example:
1267c09f92d2SPeter Avalos * <link type="directory">../ref/</link>
1268c09f92d2SPeter Avalos * The symlink target file is "../ref/" and its
1269c09f92d2SPeter Avalos * file type is a directory.
1270c09f92d2SPeter Avalos *
1271c09f92d2SPeter Avalos * <link type="file">../f</link>
1272c09f92d2SPeter Avalos * The symlink target file is "../f" and its
1273c09f92d2SPeter Avalos * file type is a regular file.
1274c09f92d2SPeter Avalos *
1275e95abc47Szrj * But our implementation cannot do it, and then we
1276e95abc47Szrj * always record that a attribute "type" is "broken",
1277c09f92d2SPeter Avalos * for example:
1278c09f92d2SPeter Avalos * <link type="broken">foo/bar</link>
1279c09f92d2SPeter Avalos * It means "foo/bar" is not reachable.
1280c09f92d2SPeter Avalos */
1281c09f92d2SPeter Avalos r = xmlwrite_string_attr(a, writer, "link",
1282c09f92d2SPeter Avalos file->symlink.s,
1283c09f92d2SPeter Avalos "type", "broken");
1284c09f92d2SPeter Avalos if (r < 0)
1285c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1286c09f92d2SPeter Avalos break;
1287c09f92d2SPeter Avalos case AE_IFCHR:
1288c09f92d2SPeter Avalos case AE_IFBLK:
1289c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
1290c09f92d2SPeter Avalos if (r < 0) {
1291c09f92d2SPeter Avalos archive_set_error(&a->archive,
1292c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1293c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1294c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1295c09f92d2SPeter Avalos }
1296c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "major",
1297c09f92d2SPeter Avalos "%d", archive_entry_rdevmajor(file->entry));
1298c09f92d2SPeter Avalos if (r < 0)
1299c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1300c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "minor",
1301c09f92d2SPeter Avalos "%d", archive_entry_rdevminor(file->entry));
1302c09f92d2SPeter Avalos if (r < 0)
1303c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1304c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1305c09f92d2SPeter Avalos if (r < 0) {
1306c09f92d2SPeter Avalos archive_set_error(&a->archive,
1307c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1308c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1309c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1310c09f92d2SPeter Avalos }
1311c09f92d2SPeter Avalos break;
1312c09f92d2SPeter Avalos default:
1313c09f92d2SPeter Avalos break;
1314c09f92d2SPeter Avalos }
1315c09f92d2SPeter Avalos
1316c09f92d2SPeter Avalos /*
1317c09f92d2SPeter Avalos * Make a inode entry, "<inode>".
1318c09f92d2SPeter Avalos */
1319c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "inode",
1320c09f92d2SPeter Avalos "%jd", archive_entry_ino64(file->entry));
1321c09f92d2SPeter Avalos if (r < 0)
1322c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1323c09f92d2SPeter Avalos if (archive_entry_dev(file->entry) != 0) {
1324c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "deviceno",
1325c09f92d2SPeter Avalos "%d", archive_entry_dev(file->entry));
1326c09f92d2SPeter Avalos if (r < 0)
1327c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1328c09f92d2SPeter Avalos }
1329c09f92d2SPeter Avalos
1330c09f92d2SPeter Avalos /*
1331c09f92d2SPeter Avalos * Make a file mode entry, "<mode>".
1332c09f92d2SPeter Avalos */
1333c09f92d2SPeter Avalos r = xmlwrite_mode(a, writer, "mode",
1334c09f92d2SPeter Avalos archive_entry_mode(file->entry));
1335c09f92d2SPeter Avalos if (r < 0)
1336c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1337c09f92d2SPeter Avalos
1338c09f92d2SPeter Avalos /*
1339c09f92d2SPeter Avalos * Make a user entry, "<uid>" and "<user>.
1340c09f92d2SPeter Avalos */
1341c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "uid",
1342c09f92d2SPeter Avalos "%d", archive_entry_uid(file->entry));
1343c09f92d2SPeter Avalos if (r < 0)
1344c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1345c09f92d2SPeter Avalos r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
1346c09f92d2SPeter Avalos if (r != 0) {
1347c09f92d2SPeter Avalos if (errno == ENOMEM) {
1348c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1349c09f92d2SPeter Avalos "Can't allocate memory for Uname");
1350c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1351c09f92d2SPeter Avalos }
1352c09f92d2SPeter Avalos archive_set_error(&a->archive,
1353c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
1354c09f92d2SPeter Avalos "Can't translate uname '%s' to UTF-8",
1355c09f92d2SPeter Avalos archive_entry_uname(file->entry));
1356c09f92d2SPeter Avalos r2 = ARCHIVE_WARN;
1357c09f92d2SPeter Avalos }
1358c09f92d2SPeter Avalos if (len > 0) {
1359c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "user", p);
1360c09f92d2SPeter Avalos if (r < 0)
1361c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1362c09f92d2SPeter Avalos }
1363c09f92d2SPeter Avalos
1364c09f92d2SPeter Avalos /*
1365c09f92d2SPeter Avalos * Make a group entry, "<gid>" and "<group>.
1366c09f92d2SPeter Avalos */
1367c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "gid",
1368c09f92d2SPeter Avalos "%d", archive_entry_gid(file->entry));
1369c09f92d2SPeter Avalos if (r < 0)
1370c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1371c09f92d2SPeter Avalos r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
1372c09f92d2SPeter Avalos if (r != 0) {
1373c09f92d2SPeter Avalos if (errno == ENOMEM) {
1374c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1375c09f92d2SPeter Avalos "Can't allocate memory for Gname");
1376c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1377c09f92d2SPeter Avalos }
1378c09f92d2SPeter Avalos archive_set_error(&a->archive,
1379c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
1380c09f92d2SPeter Avalos "Can't translate gname '%s' to UTF-8",
1381c09f92d2SPeter Avalos archive_entry_gname(file->entry));
1382c09f92d2SPeter Avalos r2 = ARCHIVE_WARN;
1383c09f92d2SPeter Avalos }
1384c09f92d2SPeter Avalos if (len > 0) {
1385c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "group", p);
1386c09f92d2SPeter Avalos if (r < 0)
1387c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1388c09f92d2SPeter Avalos }
1389c09f92d2SPeter Avalos
1390c09f92d2SPeter Avalos /*
1391c09f92d2SPeter Avalos * Make a ctime entry, "<ctime>".
1392c09f92d2SPeter Avalos */
1393c09f92d2SPeter Avalos if (archive_entry_ctime_is_set(file->entry)) {
1394c09f92d2SPeter Avalos r = xmlwrite_time(a, writer, "ctime",
1395c09f92d2SPeter Avalos archive_entry_ctime(file->entry), 1);
1396c09f92d2SPeter Avalos if (r < 0)
1397c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1398c09f92d2SPeter Avalos }
1399c09f92d2SPeter Avalos
1400c09f92d2SPeter Avalos /*
1401c09f92d2SPeter Avalos * Make a mtime entry, "<mtime>".
1402c09f92d2SPeter Avalos */
1403c09f92d2SPeter Avalos if (archive_entry_mtime_is_set(file->entry)) {
1404c09f92d2SPeter Avalos r = xmlwrite_time(a, writer, "mtime",
1405c09f92d2SPeter Avalos archive_entry_mtime(file->entry), 1);
1406c09f92d2SPeter Avalos if (r < 0)
1407c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1408c09f92d2SPeter Avalos }
1409c09f92d2SPeter Avalos
1410c09f92d2SPeter Avalos /*
1411c09f92d2SPeter Avalos * Make a atime entry, "<atime>".
1412c09f92d2SPeter Avalos */
1413c09f92d2SPeter Avalos if (archive_entry_atime_is_set(file->entry)) {
1414c09f92d2SPeter Avalos r = xmlwrite_time(a, writer, "atime",
1415c09f92d2SPeter Avalos archive_entry_atime(file->entry), 1);
1416c09f92d2SPeter Avalos if (r < 0)
1417c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1418c09f92d2SPeter Avalos }
1419c09f92d2SPeter Avalos
1420c09f92d2SPeter Avalos /*
1421c09f92d2SPeter Avalos * Make fflags entries, "<flags>" and "<ext2>".
1422c09f92d2SPeter Avalos */
1423c09f92d2SPeter Avalos fflags = archive_entry_fflags_text(file->entry);
1424c09f92d2SPeter Avalos if (fflags != NULL) {
1425c09f92d2SPeter Avalos r = make_fflags_entry(a, writer, "flags", fflags);
1426c09f92d2SPeter Avalos if (r < 0)
1427c09f92d2SPeter Avalos return (r);
1428c09f92d2SPeter Avalos r = make_fflags_entry(a, writer, "ext2", fflags);
1429c09f92d2SPeter Avalos if (r < 0)
1430c09f92d2SPeter Avalos return (r);
1431c09f92d2SPeter Avalos }
1432c09f92d2SPeter Avalos
1433c09f92d2SPeter Avalos /*
1434c09f92d2SPeter Avalos * Make extended attribute entries, "<ea>".
1435c09f92d2SPeter Avalos */
1436c09f92d2SPeter Avalos archive_entry_xattr_reset(file->entry);
1437c09f92d2SPeter Avalos for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
1438c09f92d2SPeter Avalos const char *name;
1439c09f92d2SPeter Avalos const void *value;
1440c09f92d2SPeter Avalos size_t size;
1441c09f92d2SPeter Avalos
1442c09f92d2SPeter Avalos archive_entry_xattr_next(file->entry,
1443c09f92d2SPeter Avalos &name, &value, &size);
1444c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
1445c09f92d2SPeter Avalos if (r < 0) {
1446c09f92d2SPeter Avalos archive_set_error(&a->archive,
1447c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1448c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1449c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1450c09f92d2SPeter Avalos }
1451c09f92d2SPeter Avalos r = xmlTextWriterWriteFormatAttribute(writer,
1452c09f92d2SPeter Avalos BAD_CAST("id"), "%d", heap->id);
1453c09f92d2SPeter Avalos if (r < 0) {
1454c09f92d2SPeter Avalos archive_set_error(&a->archive,
1455c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1456c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() failed: %d", r);
1457c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1458c09f92d2SPeter Avalos }
1459c09f92d2SPeter Avalos r = xmlwrite_heap(a, writer, heap);
1460c09f92d2SPeter Avalos if (r < 0)
1461c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1462c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "name", name);
1463c09f92d2SPeter Avalos if (r < 0)
1464c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1465c09f92d2SPeter Avalos
1466c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1467c09f92d2SPeter Avalos if (r < 0) {
1468c09f92d2SPeter Avalos archive_set_error(&a->archive,
1469c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1470c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1471c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1472c09f92d2SPeter Avalos }
1473c09f92d2SPeter Avalos }
1474c09f92d2SPeter Avalos
1475c09f92d2SPeter Avalos /*
1476c09f92d2SPeter Avalos * Make a file data entry, "<data>".
1477c09f92d2SPeter Avalos */
1478c09f92d2SPeter Avalos if (file->data.length > 0) {
1479c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
1480c09f92d2SPeter Avalos if (r < 0) {
1481c09f92d2SPeter Avalos archive_set_error(&a->archive,
1482c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1483c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1484c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1485c09f92d2SPeter Avalos }
1486c09f92d2SPeter Avalos
1487c09f92d2SPeter Avalos r = xmlwrite_heap(a, writer, &(file->data));
1488c09f92d2SPeter Avalos if (r < 0)
1489c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1490c09f92d2SPeter Avalos
1491c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1492c09f92d2SPeter Avalos if (r < 0) {
1493c09f92d2SPeter Avalos archive_set_error(&a->archive,
1494c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1495c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1496c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1497c09f92d2SPeter Avalos }
1498c09f92d2SPeter Avalos }
1499c09f92d2SPeter Avalos
1500c09f92d2SPeter Avalos if (archive_strlen(&file->script) > 0) {
1501c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
1502c09f92d2SPeter Avalos if (r < 0) {
1503c09f92d2SPeter Avalos archive_set_error(&a->archive,
1504c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1505c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1506c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1507c09f92d2SPeter Avalos }
1508c09f92d2SPeter Avalos
1509c09f92d2SPeter Avalos r = xmlwrite_string(a, writer,
1510c09f92d2SPeter Avalos "interpreter", file->script.s);
1511c09f92d2SPeter Avalos if (r < 0)
1512c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1513c09f92d2SPeter Avalos
1514c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "type", "script");
1515c09f92d2SPeter Avalos if (r < 0)
1516c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1517c09f92d2SPeter Avalos
1518c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1519c09f92d2SPeter Avalos if (r < 0) {
1520c09f92d2SPeter Avalos archive_set_error(&a->archive,
1521c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1522c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1523c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1524c09f92d2SPeter Avalos }
1525c09f92d2SPeter Avalos }
1526c09f92d2SPeter Avalos
1527c09f92d2SPeter Avalos return (r2);
1528c09f92d2SPeter Avalos }
1529c09f92d2SPeter Avalos
1530c09f92d2SPeter Avalos /*
1531c09f92d2SPeter Avalos * Make the TOC
1532c09f92d2SPeter Avalos */
1533c09f92d2SPeter Avalos static int
make_toc(struct archive_write * a)1534c09f92d2SPeter Avalos make_toc(struct archive_write *a)
1535c09f92d2SPeter Avalos {
1536c09f92d2SPeter Avalos struct xar *xar;
1537c09f92d2SPeter Avalos struct file *np;
1538c09f92d2SPeter Avalos xmlBufferPtr bp;
1539c09f92d2SPeter Avalos xmlTextWriterPtr writer;
1540c09f92d2SPeter Avalos int algsize;
1541c09f92d2SPeter Avalos int r, ret;
1542c09f92d2SPeter Avalos
1543c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
1544c09f92d2SPeter Avalos
1545c09f92d2SPeter Avalos ret = ARCHIVE_FATAL;
1546c09f92d2SPeter Avalos
1547c09f92d2SPeter Avalos /*
1548c09f92d2SPeter Avalos * Initialize xml writer.
1549c09f92d2SPeter Avalos */
1550c09f92d2SPeter Avalos writer = NULL;
1551c09f92d2SPeter Avalos bp = xmlBufferCreate();
1552c09f92d2SPeter Avalos if (bp == NULL) {
1553c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
1554c09f92d2SPeter Avalos "xmlBufferCreate() "
1555c09f92d2SPeter Avalos "couldn't create xml buffer");
1556c09f92d2SPeter Avalos goto exit_toc;
1557c09f92d2SPeter Avalos }
1558c09f92d2SPeter Avalos writer = xmlNewTextWriterMemory(bp, 0);
1559c09f92d2SPeter Avalos if (writer == NULL) {
1560c09f92d2SPeter Avalos archive_set_error(&a->archive,
1561c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1562c09f92d2SPeter Avalos "xmlNewTextWriterMemory() "
1563c09f92d2SPeter Avalos "couldn't create xml writer");
1564c09f92d2SPeter Avalos goto exit_toc;
1565c09f92d2SPeter Avalos }
1566c09f92d2SPeter Avalos r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
1567c09f92d2SPeter Avalos if (r < 0) {
1568c09f92d2SPeter Avalos archive_set_error(&a->archive,
1569c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1570c09f92d2SPeter Avalos "xmlTextWriterStartDocument() failed: %d", r);
1571c09f92d2SPeter Avalos goto exit_toc;
1572c09f92d2SPeter Avalos }
1573c09f92d2SPeter Avalos r = xmlTextWriterSetIndent(writer, 4);
1574c09f92d2SPeter Avalos if (r < 0) {
1575c09f92d2SPeter Avalos archive_set_error(&a->archive,
1576c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1577c09f92d2SPeter Avalos "xmlTextWriterSetIndent() failed: %d", r);
1578c09f92d2SPeter Avalos goto exit_toc;
1579c09f92d2SPeter Avalos }
1580c09f92d2SPeter Avalos
1581c09f92d2SPeter Avalos /*
1582e95abc47Szrj * Start recording TOC
1583c09f92d2SPeter Avalos */
1584c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
1585c09f92d2SPeter Avalos if (r < 0) {
1586c09f92d2SPeter Avalos archive_set_error(&a->archive,
1587c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1588c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1589c09f92d2SPeter Avalos goto exit_toc;
1590c09f92d2SPeter Avalos }
1591c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
1592c09f92d2SPeter Avalos if (r < 0) {
1593c09f92d2SPeter Avalos archive_set_error(&a->archive,
1594c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1595c09f92d2SPeter Avalos "xmlTextWriterStartDocument() failed: %d", r);
1596c09f92d2SPeter Avalos goto exit_toc;
1597c09f92d2SPeter Avalos }
1598c09f92d2SPeter Avalos
1599c09f92d2SPeter Avalos /*
1600c09f92d2SPeter Avalos * Record the creation time of the archive file.
1601c09f92d2SPeter Avalos */
1602c09f92d2SPeter Avalos r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
1603c09f92d2SPeter Avalos if (r < 0)
1604c09f92d2SPeter Avalos goto exit_toc;
1605c09f92d2SPeter Avalos
1606c09f92d2SPeter Avalos /*
1607c09f92d2SPeter Avalos * Record the checksum value of TOC
1608c09f92d2SPeter Avalos */
1609c09f92d2SPeter Avalos algsize = getalgsize(xar->opt_toc_sumalg);
1610c09f92d2SPeter Avalos if (algsize) {
1611c09f92d2SPeter Avalos /*
1612c09f92d2SPeter Avalos * Record TOC checksum
1613c09f92d2SPeter Avalos */
1614c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
1615c09f92d2SPeter Avalos if (r < 0) {
1616c09f92d2SPeter Avalos archive_set_error(&a->archive,
1617c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1618c09f92d2SPeter Avalos "xmlTextWriterStartElement() failed: %d", r);
1619c09f92d2SPeter Avalos goto exit_toc;
1620c09f92d2SPeter Avalos }
1621c09f92d2SPeter Avalos r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
162259bf7050SPeter Avalos BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
1623c09f92d2SPeter Avalos if (r < 0) {
1624c09f92d2SPeter Avalos archive_set_error(&a->archive,
1625c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1626c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() failed: %d", r);
1627c09f92d2SPeter Avalos goto exit_toc;
1628c09f92d2SPeter Avalos }
1629c09f92d2SPeter Avalos
1630c09f92d2SPeter Avalos /*
1631c09f92d2SPeter Avalos * Record the offset of the value of checksum of TOC
1632c09f92d2SPeter Avalos */
1633c09f92d2SPeter Avalos r = xmlwrite_string(a, writer, "offset", "0");
1634c09f92d2SPeter Avalos if (r < 0)
1635c09f92d2SPeter Avalos goto exit_toc;
1636c09f92d2SPeter Avalos
1637c09f92d2SPeter Avalos /*
1638c09f92d2SPeter Avalos * Record the size of the value of checksum of TOC
1639c09f92d2SPeter Avalos */
1640c09f92d2SPeter Avalos r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
1641c09f92d2SPeter Avalos if (r < 0)
1642c09f92d2SPeter Avalos goto exit_toc;
1643c09f92d2SPeter Avalos
1644c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1645c09f92d2SPeter Avalos if (r < 0) {
1646c09f92d2SPeter Avalos archive_set_error(&a->archive,
1647c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1648c09f92d2SPeter Avalos "xmlTextWriterEndElement() failed: %d", r);
1649c09f92d2SPeter Avalos goto exit_toc;
1650c09f92d2SPeter Avalos }
1651c09f92d2SPeter Avalos }
1652c09f92d2SPeter Avalos
1653c09f92d2SPeter Avalos np = xar->root;
1654c09f92d2SPeter Avalos do {
1655c09f92d2SPeter Avalos if (np != np->parent) {
1656c09f92d2SPeter Avalos r = make_file_entry(a, writer, np);
1657c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1658c09f92d2SPeter Avalos goto exit_toc;
1659c09f92d2SPeter Avalos }
1660c09f92d2SPeter Avalos
1661c09f92d2SPeter Avalos if (np->dir && np->children.first != NULL) {
1662c09f92d2SPeter Avalos /* Enter to sub directories. */
1663c09f92d2SPeter Avalos np = np->children.first;
1664c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer,
1665c09f92d2SPeter Avalos BAD_CAST("file"));
1666c09f92d2SPeter Avalos if (r < 0) {
1667c09f92d2SPeter Avalos archive_set_error(&a->archive,
1668c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1669c09f92d2SPeter Avalos "xmlTextWriterStartElement() "
1670c09f92d2SPeter Avalos "failed: %d", r);
1671c09f92d2SPeter Avalos goto exit_toc;
1672c09f92d2SPeter Avalos }
1673c09f92d2SPeter Avalos r = xmlTextWriterWriteFormatAttribute(
1674c09f92d2SPeter Avalos writer, BAD_CAST("id"), "%d", np->id);
1675c09f92d2SPeter Avalos if (r < 0) {
1676c09f92d2SPeter Avalos archive_set_error(&a->archive,
1677c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1678c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() "
1679c09f92d2SPeter Avalos "failed: %d", r);
1680c09f92d2SPeter Avalos goto exit_toc;
1681c09f92d2SPeter Avalos }
1682c09f92d2SPeter Avalos continue;
1683c09f92d2SPeter Avalos }
1684c09f92d2SPeter Avalos while (np != np->parent) {
1685c09f92d2SPeter Avalos r = xmlTextWriterEndElement(writer);
1686c09f92d2SPeter Avalos if (r < 0) {
1687c09f92d2SPeter Avalos archive_set_error(&a->archive,
1688c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1689c09f92d2SPeter Avalos "xmlTextWriterEndElement() "
1690c09f92d2SPeter Avalos "failed: %d", r);
1691c09f92d2SPeter Avalos goto exit_toc;
1692c09f92d2SPeter Avalos }
1693c09f92d2SPeter Avalos if (np->chnext == NULL) {
1694c09f92d2SPeter Avalos /* Return to the parent directory. */
1695c09f92d2SPeter Avalos np = np->parent;
1696c09f92d2SPeter Avalos } else {
1697c09f92d2SPeter Avalos np = np->chnext;
1698c09f92d2SPeter Avalos r = xmlTextWriterStartElement(writer,
1699c09f92d2SPeter Avalos BAD_CAST("file"));
1700c09f92d2SPeter Avalos if (r < 0) {
1701c09f92d2SPeter Avalos archive_set_error(&a->archive,
1702c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1703c09f92d2SPeter Avalos "xmlTextWriterStartElement() "
1704c09f92d2SPeter Avalos "failed: %d", r);
1705c09f92d2SPeter Avalos goto exit_toc;
1706c09f92d2SPeter Avalos }
1707c09f92d2SPeter Avalos r = xmlTextWriterWriteFormatAttribute(
1708c09f92d2SPeter Avalos writer, BAD_CAST("id"), "%d", np->id);
1709c09f92d2SPeter Avalos if (r < 0) {
1710c09f92d2SPeter Avalos archive_set_error(&a->archive,
1711c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1712c09f92d2SPeter Avalos "xmlTextWriterWriteAttribute() "
1713c09f92d2SPeter Avalos "failed: %d", r);
1714c09f92d2SPeter Avalos goto exit_toc;
1715c09f92d2SPeter Avalos }
1716c09f92d2SPeter Avalos break;
1717c09f92d2SPeter Avalos }
1718c09f92d2SPeter Avalos }
1719c09f92d2SPeter Avalos } while (np != np->parent);
1720c09f92d2SPeter Avalos
1721c09f92d2SPeter Avalos r = xmlTextWriterEndDocument(writer);
1722c09f92d2SPeter Avalos if (r < 0) {
1723c09f92d2SPeter Avalos archive_set_error(&a->archive,
1724c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
1725c09f92d2SPeter Avalos "xmlTextWriterEndDocument() failed: %d", r);
1726c09f92d2SPeter Avalos goto exit_toc;
1727c09f92d2SPeter Avalos }
1728c09f92d2SPeter Avalos #if DEBUG_PRINT_TOC
1729c09f92d2SPeter Avalos fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
1730c09f92d2SPeter Avalos strlen((const char *)bp->content), bp->content);
1731c09f92d2SPeter Avalos #endif
1732c09f92d2SPeter Avalos
1733c09f92d2SPeter Avalos /*
1734c09f92d2SPeter Avalos * Compress the TOC and calculate the sum of the TOC.
1735c09f92d2SPeter Avalos */
1736c09f92d2SPeter Avalos xar->toc.temp_offset = xar->temp_offset;
1737c09f92d2SPeter Avalos xar->toc.size = bp->use;
1738c09f92d2SPeter Avalos checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
1739c09f92d2SPeter Avalos
1740c09f92d2SPeter Avalos r = compression_init_encoder_gzip(&(a->archive),
1741c09f92d2SPeter Avalos &(xar->stream), 6, 1);
1742c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1743c09f92d2SPeter Avalos goto exit_toc;
1744c09f92d2SPeter Avalos xar->stream.next_in = bp->content;
1745c09f92d2SPeter Avalos xar->stream.avail_in = bp->use;
1746c09f92d2SPeter Avalos xar->stream.total_in = 0;
1747c09f92d2SPeter Avalos xar->stream.next_out = xar->wbuff;
1748c09f92d2SPeter Avalos xar->stream.avail_out = sizeof(xar->wbuff);
1749c09f92d2SPeter Avalos xar->stream.total_out = 0;
1750c09f92d2SPeter Avalos for (;;) {
1751c09f92d2SPeter Avalos size_t size;
1752c09f92d2SPeter Avalos
1753c09f92d2SPeter Avalos r = compression_code(&(a->archive),
1754c09f92d2SPeter Avalos &(xar->stream), ARCHIVE_Z_FINISH);
1755c09f92d2SPeter Avalos if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
1756c09f92d2SPeter Avalos goto exit_toc;
1757c09f92d2SPeter Avalos size = sizeof(xar->wbuff) - xar->stream.avail_out;
1758c09f92d2SPeter Avalos checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
1759c09f92d2SPeter Avalos if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
1760c09f92d2SPeter Avalos goto exit_toc;
1761c09f92d2SPeter Avalos if (r == ARCHIVE_EOF)
1762c09f92d2SPeter Avalos break;
1763c09f92d2SPeter Avalos xar->stream.next_out = xar->wbuff;
1764c09f92d2SPeter Avalos xar->stream.avail_out = sizeof(xar->wbuff);
1765c09f92d2SPeter Avalos }
1766c09f92d2SPeter Avalos r = compression_end(&(a->archive), &(xar->stream));
1767c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1768c09f92d2SPeter Avalos goto exit_toc;
1769c09f92d2SPeter Avalos xar->toc.length = xar->stream.total_out;
1770c09f92d2SPeter Avalos xar->toc.compression = GZIP;
1771c09f92d2SPeter Avalos checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
1772c09f92d2SPeter Avalos
1773c09f92d2SPeter Avalos ret = ARCHIVE_OK;
1774c09f92d2SPeter Avalos exit_toc:
1775c09f92d2SPeter Avalos if (writer)
1776c09f92d2SPeter Avalos xmlFreeTextWriter(writer);
1777c09f92d2SPeter Avalos if (bp)
1778c09f92d2SPeter Avalos xmlBufferFree(bp);
1779c09f92d2SPeter Avalos
1780c09f92d2SPeter Avalos return (ret);
1781c09f92d2SPeter Avalos }
1782c09f92d2SPeter Avalos
1783c09f92d2SPeter Avalos static int
flush_wbuff(struct archive_write * a)1784c09f92d2SPeter Avalos flush_wbuff(struct archive_write *a)
1785c09f92d2SPeter Avalos {
1786c09f92d2SPeter Avalos struct xar *xar;
1787c09f92d2SPeter Avalos int r;
1788c09f92d2SPeter Avalos size_t s;
1789c09f92d2SPeter Avalos
1790c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
1791c09f92d2SPeter Avalos s = sizeof(xar->wbuff) - xar->wbuff_remaining;
1792c09f92d2SPeter Avalos r = __archive_write_output(a, xar->wbuff, s);
1793c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1794c09f92d2SPeter Avalos return (r);
1795c09f92d2SPeter Avalos xar->wbuff_remaining = sizeof(xar->wbuff);
1796c09f92d2SPeter Avalos return (r);
1797c09f92d2SPeter Avalos }
1798c09f92d2SPeter Avalos
1799c09f92d2SPeter Avalos static int
copy_out(struct archive_write * a,uint64_t offset,uint64_t length)1800c09f92d2SPeter Avalos copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
1801c09f92d2SPeter Avalos {
1802c09f92d2SPeter Avalos struct xar *xar;
1803c09f92d2SPeter Avalos int r;
1804c09f92d2SPeter Avalos
1805c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
1806c09f92d2SPeter Avalos if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
1807c09f92d2SPeter Avalos archive_set_error(&(a->archive), errno, "lseek failed");
1808c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1809c09f92d2SPeter Avalos }
1810c09f92d2SPeter Avalos while (length) {
1811c09f92d2SPeter Avalos size_t rsize;
1812c09f92d2SPeter Avalos ssize_t rs;
1813c09f92d2SPeter Avalos unsigned char *wb;
1814c09f92d2SPeter Avalos
1815c09f92d2SPeter Avalos if (length > xar->wbuff_remaining)
1816c09f92d2SPeter Avalos rsize = xar->wbuff_remaining;
1817c09f92d2SPeter Avalos else
1818c09f92d2SPeter Avalos rsize = (size_t)length;
1819c09f92d2SPeter Avalos wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
1820c09f92d2SPeter Avalos rs = read(xar->temp_fd, wb, rsize);
1821c09f92d2SPeter Avalos if (rs < 0) {
1822c09f92d2SPeter Avalos archive_set_error(&(a->archive), errno,
1823c09f92d2SPeter Avalos "Can't read temporary file(%jd)",
1824c09f92d2SPeter Avalos (intmax_t)rs);
1825c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1826c09f92d2SPeter Avalos }
1827c09f92d2SPeter Avalos if (rs == 0) {
1828c09f92d2SPeter Avalos archive_set_error(&(a->archive), 0,
1829c09f92d2SPeter Avalos "Truncated xar archive");
1830c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
1831c09f92d2SPeter Avalos }
1832c09f92d2SPeter Avalos xar->wbuff_remaining -= rs;
1833c09f92d2SPeter Avalos length -= rs;
1834c09f92d2SPeter Avalos if (xar->wbuff_remaining == 0) {
1835c09f92d2SPeter Avalos r = flush_wbuff(a);
1836c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1837c09f92d2SPeter Avalos return (r);
1838c09f92d2SPeter Avalos }
1839c09f92d2SPeter Avalos }
1840c09f92d2SPeter Avalos return (ARCHIVE_OK);
1841c09f92d2SPeter Avalos }
1842c09f92d2SPeter Avalos
1843c09f92d2SPeter Avalos static int
xar_close(struct archive_write * a)1844c09f92d2SPeter Avalos xar_close(struct archive_write *a)
1845c09f92d2SPeter Avalos {
1846c09f92d2SPeter Avalos struct xar *xar;
1847c09f92d2SPeter Avalos unsigned char *wb;
1848c09f92d2SPeter Avalos uint64_t length;
1849c09f92d2SPeter Avalos int r;
1850c09f92d2SPeter Avalos
1851c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
1852c09f92d2SPeter Avalos
1853c09f92d2SPeter Avalos /* Empty! */
1854c09f92d2SPeter Avalos if (xar->root->children.first == NULL)
1855c09f92d2SPeter Avalos return (ARCHIVE_OK);
1856c09f92d2SPeter Avalos
1857c09f92d2SPeter Avalos /* Save the length of all file extended attributes and contents. */
1858c09f92d2SPeter Avalos length = xar->temp_offset;
1859c09f92d2SPeter Avalos
1860c09f92d2SPeter Avalos /* Connect hardlinked files */
1861c09f92d2SPeter Avalos file_connect_hardlink_files(xar);
1862c09f92d2SPeter Avalos
1863c09f92d2SPeter Avalos /* Make the TOC */
1864c09f92d2SPeter Avalos r = make_toc(a);
1865c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1866c09f92d2SPeter Avalos return (r);
1867c09f92d2SPeter Avalos /*
1868c09f92d2SPeter Avalos * Make the xar header on wbuff(write buffer).
1869c09f92d2SPeter Avalos */
1870c09f92d2SPeter Avalos wb = xar->wbuff;
1871c09f92d2SPeter Avalos xar->wbuff_remaining = sizeof(xar->wbuff);
1872c09f92d2SPeter Avalos archive_be32enc(&wb[0], HEADER_MAGIC);
1873c09f92d2SPeter Avalos archive_be16enc(&wb[4], HEADER_SIZE);
1874c09f92d2SPeter Avalos archive_be16enc(&wb[6], HEADER_VERSION);
1875c09f92d2SPeter Avalos archive_be64enc(&wb[8], xar->toc.length);
1876c09f92d2SPeter Avalos archive_be64enc(&wb[16], xar->toc.size);
1877c09f92d2SPeter Avalos archive_be32enc(&wb[24], xar->toc.a_sum.alg);
1878c09f92d2SPeter Avalos xar->wbuff_remaining -= HEADER_SIZE;
1879c09f92d2SPeter Avalos
1880c09f92d2SPeter Avalos /*
1881c09f92d2SPeter Avalos * Write the TOC
1882c09f92d2SPeter Avalos */
1883c09f92d2SPeter Avalos r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
1884c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1885c09f92d2SPeter Avalos return (r);
1886c09f92d2SPeter Avalos
1887c09f92d2SPeter Avalos /* Write the checksum value of the TOC. */
1888c09f92d2SPeter Avalos if (xar->toc.a_sum.len) {
1889c09f92d2SPeter Avalos if (xar->wbuff_remaining < xar->toc.a_sum.len) {
1890c09f92d2SPeter Avalos r = flush_wbuff(a);
1891c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1892c09f92d2SPeter Avalos return (r);
1893c09f92d2SPeter Avalos }
1894c09f92d2SPeter Avalos wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
1895c09f92d2SPeter Avalos memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
1896c09f92d2SPeter Avalos xar->wbuff_remaining -= xar->toc.a_sum.len;
1897c09f92d2SPeter Avalos }
1898c09f92d2SPeter Avalos
1899c09f92d2SPeter Avalos /*
1900c09f92d2SPeter Avalos * Write all file extended attributes and contents.
1901c09f92d2SPeter Avalos */
1902c09f92d2SPeter Avalos r = copy_out(a, xar->toc.a_sum.len, length);
1903c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
1904c09f92d2SPeter Avalos return (r);
1905c09f92d2SPeter Avalos r = flush_wbuff(a);
1906c09f92d2SPeter Avalos return (r);
1907c09f92d2SPeter Avalos }
1908c09f92d2SPeter Avalos
1909c09f92d2SPeter Avalos static int
xar_free(struct archive_write * a)1910c09f92d2SPeter Avalos xar_free(struct archive_write *a)
1911c09f92d2SPeter Avalos {
1912c09f92d2SPeter Avalos struct xar *xar;
1913c09f92d2SPeter Avalos
1914c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
19156b384f39SPeter Avalos
19166b384f39SPeter Avalos /* Close the temporary file. */
19176b384f39SPeter Avalos if (xar->temp_fd >= 0)
19186b384f39SPeter Avalos close(xar->temp_fd);
19196b384f39SPeter Avalos
1920c09f92d2SPeter Avalos archive_string_free(&(xar->cur_dirstr));
1921c09f92d2SPeter Avalos archive_string_free(&(xar->tstr));
1922c09f92d2SPeter Avalos archive_string_free(&(xar->vstr));
1923c09f92d2SPeter Avalos file_free_hardlinks(xar);
1924c09f92d2SPeter Avalos file_free_register(xar);
1925c09f92d2SPeter Avalos compression_end(&(a->archive), &(xar->stream));
1926c09f92d2SPeter Avalos free(xar);
1927c09f92d2SPeter Avalos
1928c09f92d2SPeter Avalos return (ARCHIVE_OK);
1929c09f92d2SPeter Avalos }
1930c09f92d2SPeter Avalos
1931c09f92d2SPeter Avalos static int
file_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)1932c09f92d2SPeter Avalos file_cmp_node(const struct archive_rb_node *n1,
1933c09f92d2SPeter Avalos const struct archive_rb_node *n2)
1934c09f92d2SPeter Avalos {
193559bf7050SPeter Avalos const struct file *f1 = (const struct file *)n1;
193659bf7050SPeter Avalos const struct file *f2 = (const struct file *)n2;
1937c09f92d2SPeter Avalos
1938c09f92d2SPeter Avalos return (strcmp(f1->basename.s, f2->basename.s));
1939c09f92d2SPeter Avalos }
1940c09f92d2SPeter Avalos
1941c09f92d2SPeter Avalos static int
file_cmp_key(const struct archive_rb_node * n,const void * key)1942c09f92d2SPeter Avalos file_cmp_key(const struct archive_rb_node *n, const void *key)
1943c09f92d2SPeter Avalos {
194459bf7050SPeter Avalos const struct file *f = (const struct file *)n;
1945c09f92d2SPeter Avalos
1946c09f92d2SPeter Avalos return (strcmp(f->basename.s, (const char *)key));
1947c09f92d2SPeter Avalos }
1948c09f92d2SPeter Avalos
1949c09f92d2SPeter Avalos static struct file *
file_new(struct archive_write * a,struct archive_entry * entry)1950c09f92d2SPeter Avalos file_new(struct archive_write *a, struct archive_entry *entry)
1951c09f92d2SPeter Avalos {
1952c09f92d2SPeter Avalos struct file *file;
1953c09f92d2SPeter Avalos static const struct archive_rb_tree_ops rb_ops = {
1954c09f92d2SPeter Avalos file_cmp_node, file_cmp_key
1955c09f92d2SPeter Avalos };
1956c09f92d2SPeter Avalos
1957c09f92d2SPeter Avalos file = calloc(1, sizeof(*file));
1958c09f92d2SPeter Avalos if (file == NULL)
1959c09f92d2SPeter Avalos return (NULL);
1960c09f92d2SPeter Avalos
1961c09f92d2SPeter Avalos if (entry != NULL)
1962c09f92d2SPeter Avalos file->entry = archive_entry_clone(entry);
1963c09f92d2SPeter Avalos else
1964c09f92d2SPeter Avalos file->entry = archive_entry_new2(&a->archive);
1965c09f92d2SPeter Avalos if (file->entry == NULL) {
1966c09f92d2SPeter Avalos free(file);
1967c09f92d2SPeter Avalos return (NULL);
1968c09f92d2SPeter Avalos }
1969c09f92d2SPeter Avalos __archive_rb_tree_init(&(file->rbtree), &rb_ops);
1970c09f92d2SPeter Avalos file->children.first = NULL;
1971c09f92d2SPeter Avalos file->children.last = &(file->children.first);
1972c09f92d2SPeter Avalos file->xattr.first = NULL;
1973c09f92d2SPeter Avalos file->xattr.last = &(file->xattr.first);
1974c09f92d2SPeter Avalos archive_string_init(&(file->parentdir));
1975c09f92d2SPeter Avalos archive_string_init(&(file->basename));
1976c09f92d2SPeter Avalos archive_string_init(&(file->symlink));
1977c09f92d2SPeter Avalos archive_string_init(&(file->script));
1978c09f92d2SPeter Avalos if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
1979c09f92d2SPeter Avalos file->dir = 1;
1980c09f92d2SPeter Avalos
1981c09f92d2SPeter Avalos return (file);
1982c09f92d2SPeter Avalos }
1983c09f92d2SPeter Avalos
1984c09f92d2SPeter Avalos static void
file_free(struct file * file)1985c09f92d2SPeter Avalos file_free(struct file *file)
1986c09f92d2SPeter Avalos {
1987c09f92d2SPeter Avalos struct heap_data *heap, *next_heap;
1988c09f92d2SPeter Avalos
1989c09f92d2SPeter Avalos heap = file->xattr.first;
1990c09f92d2SPeter Avalos while (heap != NULL) {
1991c09f92d2SPeter Avalos next_heap = heap->next;
1992c09f92d2SPeter Avalos free(heap);
1993c09f92d2SPeter Avalos heap = next_heap;
1994c09f92d2SPeter Avalos }
1995c09f92d2SPeter Avalos archive_string_free(&(file->parentdir));
1996c09f92d2SPeter Avalos archive_string_free(&(file->basename));
1997c09f92d2SPeter Avalos archive_string_free(&(file->symlink));
1998c09f92d2SPeter Avalos archive_string_free(&(file->script));
1999e95abc47Szrj archive_entry_free(file->entry);
2000c09f92d2SPeter Avalos free(file);
2001c09f92d2SPeter Avalos }
2002c09f92d2SPeter Avalos
2003c09f92d2SPeter Avalos static struct file *
file_create_virtual_dir(struct archive_write * a,struct xar * xar,const char * pathname)2004c09f92d2SPeter Avalos file_create_virtual_dir(struct archive_write *a, struct xar *xar,
2005c09f92d2SPeter Avalos const char *pathname)
2006c09f92d2SPeter Avalos {
2007c09f92d2SPeter Avalos struct file *file;
2008c09f92d2SPeter Avalos
200959bf7050SPeter Avalos (void)xar; /* UNUSED */
201059bf7050SPeter Avalos
2011c09f92d2SPeter Avalos file = file_new(a, NULL);
2012c09f92d2SPeter Avalos if (file == NULL)
2013c09f92d2SPeter Avalos return (NULL);
2014c09f92d2SPeter Avalos archive_entry_set_pathname(file->entry, pathname);
2015c09f92d2SPeter Avalos archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
2016c09f92d2SPeter Avalos
2017c09f92d2SPeter Avalos file->dir = 1;
2018c09f92d2SPeter Avalos file->virtual = 1;
2019c09f92d2SPeter Avalos
2020c09f92d2SPeter Avalos return (file);
2021c09f92d2SPeter Avalos }
2022c09f92d2SPeter Avalos
2023c09f92d2SPeter Avalos static int
file_add_child_tail(struct file * parent,struct file * child)2024c09f92d2SPeter Avalos file_add_child_tail(struct file *parent, struct file *child)
2025c09f92d2SPeter Avalos {
2026c09f92d2SPeter Avalos if (!__archive_rb_tree_insert_node(
2027c09f92d2SPeter Avalos &(parent->rbtree), (struct archive_rb_node *)child))
2028c09f92d2SPeter Avalos return (0);
2029c09f92d2SPeter Avalos child->chnext = NULL;
2030c09f92d2SPeter Avalos *parent->children.last = child;
2031c09f92d2SPeter Avalos parent->children.last = &(child->chnext);
2032c09f92d2SPeter Avalos child->parent = parent;
2033c09f92d2SPeter Avalos return (1);
2034c09f92d2SPeter Avalos }
2035c09f92d2SPeter Avalos
2036c09f92d2SPeter Avalos /*
2037c09f92d2SPeter Avalos * Find a entry from `parent'
2038c09f92d2SPeter Avalos */
2039c09f92d2SPeter Avalos static struct file *
file_find_child(struct file * parent,const char * child_name)2040c09f92d2SPeter Avalos file_find_child(struct file *parent, const char *child_name)
2041c09f92d2SPeter Avalos {
2042c09f92d2SPeter Avalos struct file *np;
2043c09f92d2SPeter Avalos
2044c09f92d2SPeter Avalos np = (struct file *)__archive_rb_tree_find_node(
2045c09f92d2SPeter Avalos &(parent->rbtree), child_name);
2046c09f92d2SPeter Avalos return (np);
2047c09f92d2SPeter Avalos }
2048c09f92d2SPeter Avalos
2049c09f92d2SPeter Avalos #if defined(_WIN32) || defined(__CYGWIN__)
2050c09f92d2SPeter Avalos static void
cleanup_backslash(char * utf8,size_t len)2051c09f92d2SPeter Avalos cleanup_backslash(char *utf8, size_t len)
2052c09f92d2SPeter Avalos {
2053c09f92d2SPeter Avalos
2054c09f92d2SPeter Avalos /* Convert a path-separator from '\' to '/' */
2055c09f92d2SPeter Avalos while (*utf8 != '\0' && len) {
2056c09f92d2SPeter Avalos if (*utf8 == '\\')
2057c09f92d2SPeter Avalos *utf8 = '/';
2058c09f92d2SPeter Avalos ++utf8;
2059c09f92d2SPeter Avalos --len;
2060c09f92d2SPeter Avalos }
2061c09f92d2SPeter Avalos }
2062c09f92d2SPeter Avalos #else
2063c09f92d2SPeter Avalos #define cleanup_backslash(p, len) /* nop */
2064c09f92d2SPeter Avalos #endif
2065c09f92d2SPeter Avalos
2066c09f92d2SPeter Avalos /*
2067c09f92d2SPeter Avalos * Generate a parent directory name and a base name from a pathname.
2068c09f92d2SPeter Avalos */
2069c09f92d2SPeter Avalos static int
file_gen_utility_names(struct archive_write * a,struct file * file)2070c09f92d2SPeter Avalos file_gen_utility_names(struct archive_write *a, struct file *file)
2071c09f92d2SPeter Avalos {
2072c09f92d2SPeter Avalos struct xar *xar;
2073c09f92d2SPeter Avalos const char *pp;
2074c09f92d2SPeter Avalos char *p, *dirname, *slash;
2075c09f92d2SPeter Avalos size_t len;
2076c09f92d2SPeter Avalos int r = ARCHIVE_OK;
2077c09f92d2SPeter Avalos
2078c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
2079c09f92d2SPeter Avalos archive_string_empty(&(file->parentdir));
2080c09f92d2SPeter Avalos archive_string_empty(&(file->basename));
2081c09f92d2SPeter Avalos archive_string_empty(&(file->symlink));
2082c09f92d2SPeter Avalos
2083c09f92d2SPeter Avalos if (file->parent == file)/* virtual root */
2084c09f92d2SPeter Avalos return (ARCHIVE_OK);
2085c09f92d2SPeter Avalos
2086c09f92d2SPeter Avalos if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)
2087c09f92d2SPeter Avalos != 0) {
2088c09f92d2SPeter Avalos if (errno == ENOMEM) {
2089c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
2090c09f92d2SPeter Avalos "Can't allocate memory for Pathname");
2091c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2092c09f92d2SPeter Avalos }
2093c09f92d2SPeter Avalos archive_set_error(&a->archive,
2094c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
2095c09f92d2SPeter Avalos "Can't translate pathname '%s' to UTF-8",
2096c09f92d2SPeter Avalos archive_entry_pathname(file->entry));
2097c09f92d2SPeter Avalos r = ARCHIVE_WARN;
2098c09f92d2SPeter Avalos }
2099c09f92d2SPeter Avalos archive_strncpy(&(file->parentdir), pp, len);
2100c09f92d2SPeter Avalos len = file->parentdir.length;
2101c09f92d2SPeter Avalos p = dirname = file->parentdir.s;
2102c09f92d2SPeter Avalos /*
2103c09f92d2SPeter Avalos * Convert a path-separator from '\' to '/'
2104c09f92d2SPeter Avalos */
2105c09f92d2SPeter Avalos cleanup_backslash(p, len);
2106c09f92d2SPeter Avalos
2107c09f92d2SPeter Avalos /*
2108c09f92d2SPeter Avalos * Remove leading '/', '../' and './' elements
2109c09f92d2SPeter Avalos */
2110c09f92d2SPeter Avalos while (*p) {
2111c09f92d2SPeter Avalos if (p[0] == '/') {
2112c09f92d2SPeter Avalos p++;
2113c09f92d2SPeter Avalos len--;
2114c09f92d2SPeter Avalos } else if (p[0] != '.')
2115c09f92d2SPeter Avalos break;
2116c09f92d2SPeter Avalos else if (p[1] == '.' && p[2] == '/') {
2117c09f92d2SPeter Avalos p += 3;
2118c09f92d2SPeter Avalos len -= 3;
2119c09f92d2SPeter Avalos } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
2120c09f92d2SPeter Avalos p += 2;
2121c09f92d2SPeter Avalos len -= 2;
2122c09f92d2SPeter Avalos } else if (p[1] == '\0') {
2123c09f92d2SPeter Avalos p++;
2124c09f92d2SPeter Avalos len--;
2125c09f92d2SPeter Avalos } else
2126c09f92d2SPeter Avalos break;
2127c09f92d2SPeter Avalos }
2128c09f92d2SPeter Avalos if (p != dirname) {
2129c09f92d2SPeter Avalos memmove(dirname, p, len+1);
2130c09f92d2SPeter Avalos p = dirname;
2131c09f92d2SPeter Avalos }
2132c09f92d2SPeter Avalos /*
2133c09f92d2SPeter Avalos * Remove "/","/." and "/.." elements from tail.
2134c09f92d2SPeter Avalos */
2135c09f92d2SPeter Avalos while (len > 0) {
2136c09f92d2SPeter Avalos size_t ll = len;
2137c09f92d2SPeter Avalos
2138085658deSDaniel Fojt if (p[len-1] == '/') {
2139c09f92d2SPeter Avalos p[len-1] = '\0';
2140c09f92d2SPeter Avalos len--;
2141c09f92d2SPeter Avalos }
2142c09f92d2SPeter Avalos if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
2143c09f92d2SPeter Avalos p[len-2] = '\0';
2144c09f92d2SPeter Avalos len -= 2;
2145c09f92d2SPeter Avalos }
2146c09f92d2SPeter Avalos if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
2147c09f92d2SPeter Avalos p[len-1] == '.') {
2148c09f92d2SPeter Avalos p[len-3] = '\0';
2149c09f92d2SPeter Avalos len -= 3;
2150c09f92d2SPeter Avalos }
2151c09f92d2SPeter Avalos if (ll == len)
2152c09f92d2SPeter Avalos break;
2153c09f92d2SPeter Avalos }
2154c09f92d2SPeter Avalos while (*p) {
2155c09f92d2SPeter Avalos if (p[0] == '/') {
2156c09f92d2SPeter Avalos if (p[1] == '/')
2157c09f92d2SPeter Avalos /* Convert '//' --> '/' */
2158085658deSDaniel Fojt memmove(p, p+1, strlen(p+1) + 1);
2159c09f92d2SPeter Avalos else if (p[1] == '.' && p[2] == '/')
2160c09f92d2SPeter Avalos /* Convert '/./' --> '/' */
2161085658deSDaniel Fojt memmove(p, p+2, strlen(p+2) + 1);
2162c09f92d2SPeter Avalos else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
2163c09f92d2SPeter Avalos /* Convert 'dir/dir1/../dir2/'
2164c09f92d2SPeter Avalos * --> 'dir/dir2/'
2165c09f92d2SPeter Avalos */
2166c09f92d2SPeter Avalos char *rp = p -1;
2167c09f92d2SPeter Avalos while (rp >= dirname) {
2168c09f92d2SPeter Avalos if (*rp == '/')
2169c09f92d2SPeter Avalos break;
2170c09f92d2SPeter Avalos --rp;
2171c09f92d2SPeter Avalos }
2172c09f92d2SPeter Avalos if (rp > dirname) {
2173c09f92d2SPeter Avalos strcpy(rp, p+3);
2174c09f92d2SPeter Avalos p = rp;
2175c09f92d2SPeter Avalos } else {
2176c09f92d2SPeter Avalos strcpy(dirname, p+4);
2177c09f92d2SPeter Avalos p = dirname;
2178c09f92d2SPeter Avalos }
2179c09f92d2SPeter Avalos } else
2180c09f92d2SPeter Avalos p++;
2181c09f92d2SPeter Avalos } else
2182c09f92d2SPeter Avalos p++;
2183c09f92d2SPeter Avalos }
2184c09f92d2SPeter Avalos p = dirname;
2185c09f92d2SPeter Avalos len = strlen(p);
2186c09f92d2SPeter Avalos
2187c09f92d2SPeter Avalos if (archive_entry_filetype(file->entry) == AE_IFLNK) {
2188c09f92d2SPeter Avalos size_t len2;
2189c09f92d2SPeter Avalos /* Convert symlink name too. */
2190c09f92d2SPeter Avalos if (archive_entry_symlink_l(file->entry, &pp, &len2,
2191c09f92d2SPeter Avalos xar->sconv) != 0) {
2192c09f92d2SPeter Avalos if (errno == ENOMEM) {
2193c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
2194c09f92d2SPeter Avalos "Can't allocate memory for Linkname");
2195c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2196c09f92d2SPeter Avalos }
2197c09f92d2SPeter Avalos archive_set_error(&a->archive,
2198c09f92d2SPeter Avalos ARCHIVE_ERRNO_FILE_FORMAT,
2199c09f92d2SPeter Avalos "Can't translate symlink '%s' to UTF-8",
2200c09f92d2SPeter Avalos archive_entry_symlink(file->entry));
2201c09f92d2SPeter Avalos r = ARCHIVE_WARN;
2202c09f92d2SPeter Avalos }
2203c09f92d2SPeter Avalos archive_strncpy(&(file->symlink), pp, len2);
2204c09f92d2SPeter Avalos cleanup_backslash(file->symlink.s, file->symlink.length);
2205c09f92d2SPeter Avalos }
2206c09f92d2SPeter Avalos /*
2207c09f92d2SPeter Avalos * - Count up directory elements.
2208c09f92d2SPeter Avalos * - Find out the position which points the last position of
2209c09f92d2SPeter Avalos * path separator('/').
2210c09f92d2SPeter Avalos */
2211c09f92d2SPeter Avalos slash = NULL;
2212c09f92d2SPeter Avalos for (; *p != '\0'; p++)
2213c09f92d2SPeter Avalos if (*p == '/')
2214c09f92d2SPeter Avalos slash = p;
2215c09f92d2SPeter Avalos if (slash == NULL) {
2216c09f92d2SPeter Avalos /* The pathname doesn't have a parent directory. */
2217c09f92d2SPeter Avalos file->parentdir.length = len;
2218c09f92d2SPeter Avalos archive_string_copy(&(file->basename), &(file->parentdir));
2219c09f92d2SPeter Avalos archive_string_empty(&(file->parentdir));
22206b384f39SPeter Avalos *file->parentdir.s = '\0';
2221c09f92d2SPeter Avalos return (r);
2222c09f92d2SPeter Avalos }
2223c09f92d2SPeter Avalos
2224c09f92d2SPeter Avalos /* Make a basename from dirname and slash */
2225c09f92d2SPeter Avalos *slash = '\0';
2226c09f92d2SPeter Avalos file->parentdir.length = slash - dirname;
2227c09f92d2SPeter Avalos archive_strcpy(&(file->basename), slash + 1);
2228c09f92d2SPeter Avalos return (r);
2229c09f92d2SPeter Avalos }
2230c09f92d2SPeter Avalos
2231c09f92d2SPeter Avalos static int
get_path_component(char * name,int n,const char * fn)2232c09f92d2SPeter Avalos get_path_component(char *name, int n, const char *fn)
2233c09f92d2SPeter Avalos {
2234c09f92d2SPeter Avalos char *p;
2235c09f92d2SPeter Avalos int l;
2236c09f92d2SPeter Avalos
2237c09f92d2SPeter Avalos p = strchr(fn, '/');
2238c09f92d2SPeter Avalos if (p == NULL) {
2239c09f92d2SPeter Avalos if ((l = strlen(fn)) == 0)
2240c09f92d2SPeter Avalos return (0);
2241c09f92d2SPeter Avalos } else
2242c09f92d2SPeter Avalos l = p - fn;
2243c09f92d2SPeter Avalos if (l > n -1)
2244c09f92d2SPeter Avalos return (-1);
2245c09f92d2SPeter Avalos memcpy(name, fn, l);
2246c09f92d2SPeter Avalos name[l] = '\0';
2247c09f92d2SPeter Avalos
2248c09f92d2SPeter Avalos return (l);
2249c09f92d2SPeter Avalos }
2250c09f92d2SPeter Avalos
2251c09f92d2SPeter Avalos /*
2252c09f92d2SPeter Avalos * Add a new entry into the tree.
2253c09f92d2SPeter Avalos */
2254c09f92d2SPeter Avalos static int
file_tree(struct archive_write * a,struct file ** filepp)2255c09f92d2SPeter Avalos file_tree(struct archive_write *a, struct file **filepp)
2256c09f92d2SPeter Avalos {
2257c09f92d2SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__)
2258c09f92d2SPeter Avalos char name[_MAX_FNAME];/* Included null terminator size. */
2259c09f92d2SPeter Avalos #elif defined(NAME_MAX) && NAME_MAX >= 255
2260c09f92d2SPeter Avalos char name[NAME_MAX+1];
2261c09f92d2SPeter Avalos #else
2262c09f92d2SPeter Avalos char name[256];
2263c09f92d2SPeter Avalos #endif
2264c09f92d2SPeter Avalos struct xar *xar = (struct xar *)a->format_data;
2265c09f92d2SPeter Avalos struct file *dent, *file, *np;
2266c09f92d2SPeter Avalos struct archive_entry *ent;
2267c09f92d2SPeter Avalos const char *fn, *p;
2268c09f92d2SPeter Avalos int l;
2269c09f92d2SPeter Avalos
2270c09f92d2SPeter Avalos file = *filepp;
2271c09f92d2SPeter Avalos dent = xar->root;
2272c09f92d2SPeter Avalos if (file->parentdir.length > 0)
2273c09f92d2SPeter Avalos fn = p = file->parentdir.s;
2274c09f92d2SPeter Avalos else
2275c09f92d2SPeter Avalos fn = p = "";
2276c09f92d2SPeter Avalos
2277c09f92d2SPeter Avalos /*
2278c09f92d2SPeter Avalos * If the path of the parent directory of `file' entry is
2279c09f92d2SPeter Avalos * the same as the path of `cur_dirent', add isoent to
2280c09f92d2SPeter Avalos * `cur_dirent'.
2281c09f92d2SPeter Avalos */
2282c09f92d2SPeter Avalos if (archive_strlen(&(xar->cur_dirstr))
2283c09f92d2SPeter Avalos == archive_strlen(&(file->parentdir)) &&
2284c09f92d2SPeter Avalos strcmp(xar->cur_dirstr.s, fn) == 0) {
2285c09f92d2SPeter Avalos if (!file_add_child_tail(xar->cur_dirent, file)) {
2286c09f92d2SPeter Avalos np = (struct file *)__archive_rb_tree_find_node(
2287c09f92d2SPeter Avalos &(xar->cur_dirent->rbtree),
2288c09f92d2SPeter Avalos file->basename.s);
2289c09f92d2SPeter Avalos goto same_entry;
2290c09f92d2SPeter Avalos }
2291c09f92d2SPeter Avalos return (ARCHIVE_OK);
2292c09f92d2SPeter Avalos }
2293c09f92d2SPeter Avalos
2294c09f92d2SPeter Avalos for (;;) {
2295c09f92d2SPeter Avalos l = get_path_component(name, sizeof(name), fn);
2296c09f92d2SPeter Avalos if (l == 0) {
2297c09f92d2SPeter Avalos np = NULL;
2298c09f92d2SPeter Avalos break;
2299c09f92d2SPeter Avalos }
2300c09f92d2SPeter Avalos if (l < 0) {
2301c09f92d2SPeter Avalos archive_set_error(&a->archive,
2302c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
2303c09f92d2SPeter Avalos "A name buffer is too small");
2304c09f92d2SPeter Avalos file_free(file);
2305c09f92d2SPeter Avalos *filepp = NULL;
2306c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2307c09f92d2SPeter Avalos }
2308c09f92d2SPeter Avalos
2309c09f92d2SPeter Avalos np = file_find_child(dent, name);
2310c09f92d2SPeter Avalos if (np == NULL || fn[0] == '\0')
2311c09f92d2SPeter Avalos break;
2312c09f92d2SPeter Avalos
2313c09f92d2SPeter Avalos /* Find next subdirectory. */
2314c09f92d2SPeter Avalos if (!np->dir) {
2315c09f92d2SPeter Avalos /* NOT Directory! */
2316c09f92d2SPeter Avalos archive_set_error(&a->archive,
2317c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
2318c09f92d2SPeter Avalos "`%s' is not directory, we cannot insert `%s' ",
2319c09f92d2SPeter Avalos archive_entry_pathname(np->entry),
2320c09f92d2SPeter Avalos archive_entry_pathname(file->entry));
2321c09f92d2SPeter Avalos file_free(file);
2322c09f92d2SPeter Avalos *filepp = NULL;
2323c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
2324c09f92d2SPeter Avalos }
2325c09f92d2SPeter Avalos fn += l;
2326c09f92d2SPeter Avalos if (fn[0] == '/')
2327c09f92d2SPeter Avalos fn++;
2328c09f92d2SPeter Avalos dent = np;
2329c09f92d2SPeter Avalos }
2330c09f92d2SPeter Avalos if (np == NULL) {
2331c09f92d2SPeter Avalos /*
2332c09f92d2SPeter Avalos * Create virtual parent directories.
2333c09f92d2SPeter Avalos */
2334c09f92d2SPeter Avalos while (fn[0] != '\0') {
2335c09f92d2SPeter Avalos struct file *vp;
2336c09f92d2SPeter Avalos struct archive_string as;
2337c09f92d2SPeter Avalos
2338c09f92d2SPeter Avalos archive_string_init(&as);
2339c09f92d2SPeter Avalos archive_strncat(&as, p, fn - p + l);
2340c09f92d2SPeter Avalos if (as.s[as.length-1] == '/') {
2341c09f92d2SPeter Avalos as.s[as.length-1] = '\0';
2342c09f92d2SPeter Avalos as.length--;
2343c09f92d2SPeter Avalos }
2344c09f92d2SPeter Avalos vp = file_create_virtual_dir(a, xar, as.s);
2345c09f92d2SPeter Avalos if (vp == NULL) {
2346c09f92d2SPeter Avalos archive_string_free(&as);
2347c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
2348c09f92d2SPeter Avalos "Can't allocate memory");
2349c09f92d2SPeter Avalos file_free(file);
2350c09f92d2SPeter Avalos *filepp = NULL;
2351c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2352c09f92d2SPeter Avalos }
2353c09f92d2SPeter Avalos archive_string_free(&as);
2354c09f92d2SPeter Avalos if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
2355c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2356c09f92d2SPeter Avalos file_add_child_tail(dent, vp);
2357c09f92d2SPeter Avalos file_register(xar, vp);
2358c09f92d2SPeter Avalos np = vp;
2359c09f92d2SPeter Avalos
2360c09f92d2SPeter Avalos fn += l;
2361c09f92d2SPeter Avalos if (fn[0] == '/')
2362c09f92d2SPeter Avalos fn++;
2363c09f92d2SPeter Avalos l = get_path_component(name, sizeof(name), fn);
2364c09f92d2SPeter Avalos if (l < 0) {
2365c09f92d2SPeter Avalos archive_string_free(&as);
2366c09f92d2SPeter Avalos archive_set_error(&a->archive,
2367c09f92d2SPeter Avalos ARCHIVE_ERRNO_MISC,
2368c09f92d2SPeter Avalos "A name buffer is too small");
2369c09f92d2SPeter Avalos file_free(file);
2370c09f92d2SPeter Avalos *filepp = NULL;
2371c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2372c09f92d2SPeter Avalos }
2373c09f92d2SPeter Avalos dent = np;
2374c09f92d2SPeter Avalos }
2375c09f92d2SPeter Avalos
2376c09f92d2SPeter Avalos /* Found out the parent directory where isoent can be
2377c09f92d2SPeter Avalos * inserted. */
2378c09f92d2SPeter Avalos xar->cur_dirent = dent;
2379c09f92d2SPeter Avalos archive_string_empty(&(xar->cur_dirstr));
2380c09f92d2SPeter Avalos archive_string_ensure(&(xar->cur_dirstr),
2381c09f92d2SPeter Avalos archive_strlen(&(dent->parentdir)) +
2382c09f92d2SPeter Avalos archive_strlen(&(dent->basename)) + 2);
2383c09f92d2SPeter Avalos if (archive_strlen(&(dent->parentdir)) +
2384c09f92d2SPeter Avalos archive_strlen(&(dent->basename)) == 0)
2385c09f92d2SPeter Avalos xar->cur_dirstr.s[0] = 0;
2386c09f92d2SPeter Avalos else {
2387c09f92d2SPeter Avalos if (archive_strlen(&(dent->parentdir)) > 0) {
2388c09f92d2SPeter Avalos archive_string_copy(&(xar->cur_dirstr),
2389c09f92d2SPeter Avalos &(dent->parentdir));
2390c09f92d2SPeter Avalos archive_strappend_char(&(xar->cur_dirstr), '/');
2391c09f92d2SPeter Avalos }
2392c09f92d2SPeter Avalos archive_string_concat(&(xar->cur_dirstr),
2393c09f92d2SPeter Avalos &(dent->basename));
2394c09f92d2SPeter Avalos }
2395c09f92d2SPeter Avalos
2396c09f92d2SPeter Avalos if (!file_add_child_tail(dent, file)) {
2397c09f92d2SPeter Avalos np = (struct file *)__archive_rb_tree_find_node(
2398c09f92d2SPeter Avalos &(dent->rbtree), file->basename.s);
2399c09f92d2SPeter Avalos goto same_entry;
2400c09f92d2SPeter Avalos }
2401c09f92d2SPeter Avalos return (ARCHIVE_OK);
2402c09f92d2SPeter Avalos }
2403c09f92d2SPeter Avalos
2404c09f92d2SPeter Avalos same_entry:
2405c09f92d2SPeter Avalos /*
2406c09f92d2SPeter Avalos * We have already has the entry the filename of which is
2407c09f92d2SPeter Avalos * the same.
2408c09f92d2SPeter Avalos */
2409c09f92d2SPeter Avalos if (archive_entry_filetype(np->entry) !=
2410c09f92d2SPeter Avalos archive_entry_filetype(file->entry)) {
2411c09f92d2SPeter Avalos archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2412c09f92d2SPeter Avalos "Found duplicate entries `%s' and its file type is "
2413c09f92d2SPeter Avalos "different",
2414c09f92d2SPeter Avalos archive_entry_pathname(np->entry));
2415c09f92d2SPeter Avalos file_free(file);
2416c09f92d2SPeter Avalos *filepp = NULL;
2417c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
2418c09f92d2SPeter Avalos }
2419c09f92d2SPeter Avalos
2420c09f92d2SPeter Avalos /* Swap files. */
2421c09f92d2SPeter Avalos ent = np->entry;
2422c09f92d2SPeter Avalos np->entry = file->entry;
2423c09f92d2SPeter Avalos file->entry = ent;
2424c09f92d2SPeter Avalos np->virtual = 0;
2425c09f92d2SPeter Avalos
2426c09f92d2SPeter Avalos file_free(file);
2427c09f92d2SPeter Avalos *filepp = np;
2428c09f92d2SPeter Avalos return (ARCHIVE_OK);
2429c09f92d2SPeter Avalos }
2430c09f92d2SPeter Avalos
2431c09f92d2SPeter Avalos static void
file_register(struct xar * xar,struct file * file)2432c09f92d2SPeter Avalos file_register(struct xar *xar, struct file *file)
2433c09f92d2SPeter Avalos {
2434c09f92d2SPeter Avalos file->id = xar->file_idx++;
2435c09f92d2SPeter Avalos file->next = NULL;
2436c09f92d2SPeter Avalos *xar->file_list.last = file;
2437c09f92d2SPeter Avalos xar->file_list.last = &(file->next);
2438c09f92d2SPeter Avalos }
2439c09f92d2SPeter Avalos
2440c09f92d2SPeter Avalos static void
file_init_register(struct xar * xar)2441c09f92d2SPeter Avalos file_init_register(struct xar *xar)
2442c09f92d2SPeter Avalos {
2443c09f92d2SPeter Avalos xar->file_list.first = NULL;
2444c09f92d2SPeter Avalos xar->file_list.last = &(xar->file_list.first);
2445c09f92d2SPeter Avalos }
2446c09f92d2SPeter Avalos
2447c09f92d2SPeter Avalos static void
file_free_register(struct xar * xar)2448c09f92d2SPeter Avalos file_free_register(struct xar *xar)
2449c09f92d2SPeter Avalos {
2450c09f92d2SPeter Avalos struct file *file, *file_next;
2451c09f92d2SPeter Avalos
2452c09f92d2SPeter Avalos file = xar->file_list.first;
2453c09f92d2SPeter Avalos while (file != NULL) {
2454c09f92d2SPeter Avalos file_next = file->next;
2455c09f92d2SPeter Avalos file_free(file);
2456c09f92d2SPeter Avalos file = file_next;
2457c09f92d2SPeter Avalos }
2458c09f92d2SPeter Avalos }
2459c09f92d2SPeter Avalos
2460c09f92d2SPeter Avalos /*
2461c09f92d2SPeter Avalos * Register entry to get a hardlink target.
2462c09f92d2SPeter Avalos */
2463c09f92d2SPeter Avalos static int
file_register_hardlink(struct archive_write * a,struct file * file)2464c09f92d2SPeter Avalos file_register_hardlink(struct archive_write *a, struct file *file)
2465c09f92d2SPeter Avalos {
2466c09f92d2SPeter Avalos struct xar *xar = (struct xar *)a->format_data;
2467c09f92d2SPeter Avalos struct hardlink *hl;
2468c09f92d2SPeter Avalos const char *pathname;
2469c09f92d2SPeter Avalos
2470c09f92d2SPeter Avalos archive_entry_set_nlink(file->entry, 1);
2471c09f92d2SPeter Avalos pathname = archive_entry_hardlink(file->entry);
2472c09f92d2SPeter Avalos if (pathname == NULL) {
2473c09f92d2SPeter Avalos /* This `file` is a hardlink target. */
2474c09f92d2SPeter Avalos hl = malloc(sizeof(*hl));
2475c09f92d2SPeter Avalos if (hl == NULL) {
2476c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
2477c09f92d2SPeter Avalos "Can't allocate memory");
2478c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2479c09f92d2SPeter Avalos }
2480c09f92d2SPeter Avalos hl->nlink = 1;
2481c09f92d2SPeter Avalos /* A hardlink target must be the first position. */
2482c09f92d2SPeter Avalos file->hlnext = NULL;
2483c09f92d2SPeter Avalos hl->file_list.first = file;
2484c09f92d2SPeter Avalos hl->file_list.last = &(file->hlnext);
2485c09f92d2SPeter Avalos __archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
2486c09f92d2SPeter Avalos (struct archive_rb_node *)hl);
2487c09f92d2SPeter Avalos } else {
2488c09f92d2SPeter Avalos hl = (struct hardlink *)__archive_rb_tree_find_node(
2489c09f92d2SPeter Avalos &(xar->hardlink_rbtree), pathname);
2490c09f92d2SPeter Avalos if (hl != NULL) {
2491c09f92d2SPeter Avalos /* Insert `file` entry into the tail. */
2492c09f92d2SPeter Avalos file->hlnext = NULL;
2493c09f92d2SPeter Avalos *hl->file_list.last = file;
2494c09f92d2SPeter Avalos hl->file_list.last = &(file->hlnext);
2495c09f92d2SPeter Avalos hl->nlink++;
2496c09f92d2SPeter Avalos }
2497c09f92d2SPeter Avalos archive_entry_unset_size(file->entry);
2498c09f92d2SPeter Avalos }
2499c09f92d2SPeter Avalos
2500c09f92d2SPeter Avalos return (ARCHIVE_OK);
2501c09f92d2SPeter Avalos }
2502c09f92d2SPeter Avalos
2503c09f92d2SPeter Avalos /*
2504c09f92d2SPeter Avalos * Hardlinked files have to have the same location of extent.
2505c09f92d2SPeter Avalos * We have to find out hardlink target entries for entries which
2506c09f92d2SPeter Avalos * have a hardlink target name.
2507c09f92d2SPeter Avalos */
2508c09f92d2SPeter Avalos static void
file_connect_hardlink_files(struct xar * xar)2509c09f92d2SPeter Avalos file_connect_hardlink_files(struct xar *xar)
2510c09f92d2SPeter Avalos {
2511c09f92d2SPeter Avalos struct archive_rb_node *n;
2512c09f92d2SPeter Avalos struct hardlink *hl;
2513c09f92d2SPeter Avalos struct file *target, *nf;
2514c09f92d2SPeter Avalos
2515c09f92d2SPeter Avalos ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
2516c09f92d2SPeter Avalos hl = (struct hardlink *)n;
2517c09f92d2SPeter Avalos
2518c09f92d2SPeter Avalos /* The first entry must be a hardlink target. */
2519c09f92d2SPeter Avalos target = hl->file_list.first;
2520c09f92d2SPeter Avalos archive_entry_set_nlink(target->entry, hl->nlink);
2521c09f92d2SPeter Avalos if (hl->nlink > 1)
2522c09f92d2SPeter Avalos /* It means this file is a hardlink
2523e95abc47Szrj * target itself. */
2524c09f92d2SPeter Avalos target->hardlink_target = target;
2525c09f92d2SPeter Avalos for (nf = target->hlnext;
2526c09f92d2SPeter Avalos nf != NULL; nf = nf->hlnext) {
2527c09f92d2SPeter Avalos nf->hardlink_target = target;
2528c09f92d2SPeter Avalos archive_entry_set_nlink(nf->entry, hl->nlink);
2529c09f92d2SPeter Avalos }
2530c09f92d2SPeter Avalos }
2531c09f92d2SPeter Avalos }
2532c09f92d2SPeter Avalos
2533c09f92d2SPeter Avalos static int
file_hd_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)2534c09f92d2SPeter Avalos file_hd_cmp_node(const struct archive_rb_node *n1,
2535c09f92d2SPeter Avalos const struct archive_rb_node *n2)
2536c09f92d2SPeter Avalos {
253759bf7050SPeter Avalos const struct hardlink *h1 = (const struct hardlink *)n1;
253859bf7050SPeter Avalos const struct hardlink *h2 = (const struct hardlink *)n2;
2539c09f92d2SPeter Avalos
2540c09f92d2SPeter Avalos return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
2541c09f92d2SPeter Avalos archive_entry_pathname(h2->file_list.first->entry)));
2542c09f92d2SPeter Avalos }
2543c09f92d2SPeter Avalos
2544c09f92d2SPeter Avalos static int
file_hd_cmp_key(const struct archive_rb_node * n,const void * key)2545c09f92d2SPeter Avalos file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
2546c09f92d2SPeter Avalos {
254759bf7050SPeter Avalos const struct hardlink *h = (const struct hardlink *)n;
2548c09f92d2SPeter Avalos
2549c09f92d2SPeter Avalos return (strcmp(archive_entry_pathname(h->file_list.first->entry),
2550c09f92d2SPeter Avalos (const char *)key));
2551c09f92d2SPeter Avalos }
2552c09f92d2SPeter Avalos
2553c09f92d2SPeter Avalos
2554c09f92d2SPeter Avalos static void
file_init_hardlinks(struct xar * xar)2555c09f92d2SPeter Avalos file_init_hardlinks(struct xar *xar)
2556c09f92d2SPeter Avalos {
2557c09f92d2SPeter Avalos static const struct archive_rb_tree_ops rb_ops = {
2558c09f92d2SPeter Avalos file_hd_cmp_node, file_hd_cmp_key,
2559c09f92d2SPeter Avalos };
2560c09f92d2SPeter Avalos
2561c09f92d2SPeter Avalos __archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
2562c09f92d2SPeter Avalos }
2563c09f92d2SPeter Avalos
2564c09f92d2SPeter Avalos static void
file_free_hardlinks(struct xar * xar)2565c09f92d2SPeter Avalos file_free_hardlinks(struct xar *xar)
2566c09f92d2SPeter Avalos {
2567085658deSDaniel Fojt struct archive_rb_node *n, *tmp;
2568c09f92d2SPeter Avalos
2569085658deSDaniel Fojt ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(xar->hardlink_rbtree), tmp) {
2570085658deSDaniel Fojt __archive_rb_tree_remove_node(&(xar->hardlink_rbtree), n);
2571c09f92d2SPeter Avalos free(n);
2572c09f92d2SPeter Avalos }
2573c09f92d2SPeter Avalos }
2574c09f92d2SPeter Avalos
2575c09f92d2SPeter Avalos static void
checksum_init(struct chksumwork * sumwrk,enum sumalg sum_alg)2576c09f92d2SPeter Avalos checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
2577c09f92d2SPeter Avalos {
2578c09f92d2SPeter Avalos sumwrk->alg = sum_alg;
2579c09f92d2SPeter Avalos switch (sum_alg) {
2580c09f92d2SPeter Avalos case CKSUM_NONE:
2581c09f92d2SPeter Avalos break;
2582c09f92d2SPeter Avalos case CKSUM_SHA1:
2583c09f92d2SPeter Avalos archive_sha1_init(&(sumwrk->sha1ctx));
2584c09f92d2SPeter Avalos break;
2585c09f92d2SPeter Avalos case CKSUM_MD5:
2586c09f92d2SPeter Avalos archive_md5_init(&(sumwrk->md5ctx));
2587c09f92d2SPeter Avalos break;
2588c09f92d2SPeter Avalos }
2589c09f92d2SPeter Avalos }
2590c09f92d2SPeter Avalos
2591c09f92d2SPeter Avalos static void
checksum_update(struct chksumwork * sumwrk,const void * buff,size_t size)2592c09f92d2SPeter Avalos checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
2593c09f92d2SPeter Avalos {
2594c09f92d2SPeter Avalos
2595c09f92d2SPeter Avalos switch (sumwrk->alg) {
2596c09f92d2SPeter Avalos case CKSUM_NONE:
2597c09f92d2SPeter Avalos break;
2598c09f92d2SPeter Avalos case CKSUM_SHA1:
2599c09f92d2SPeter Avalos archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
2600c09f92d2SPeter Avalos break;
2601c09f92d2SPeter Avalos case CKSUM_MD5:
2602c09f92d2SPeter Avalos archive_md5_update(&(sumwrk->md5ctx), buff, size);
2603c09f92d2SPeter Avalos break;
2604c09f92d2SPeter Avalos }
2605c09f92d2SPeter Avalos }
2606c09f92d2SPeter Avalos
2607c09f92d2SPeter Avalos static void
checksum_final(struct chksumwork * sumwrk,struct chksumval * sumval)2608c09f92d2SPeter Avalos checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
2609c09f92d2SPeter Avalos {
2610c09f92d2SPeter Avalos
2611c09f92d2SPeter Avalos switch (sumwrk->alg) {
2612c09f92d2SPeter Avalos case CKSUM_NONE:
2613c09f92d2SPeter Avalos sumval->len = 0;
2614c09f92d2SPeter Avalos break;
2615c09f92d2SPeter Avalos case CKSUM_SHA1:
2616c09f92d2SPeter Avalos archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
2617c09f92d2SPeter Avalos sumval->len = SHA1_SIZE;
2618c09f92d2SPeter Avalos break;
2619c09f92d2SPeter Avalos case CKSUM_MD5:
2620c09f92d2SPeter Avalos archive_md5_final(&(sumwrk->md5ctx), sumval->val);
2621c09f92d2SPeter Avalos sumval->len = MD5_SIZE;
2622c09f92d2SPeter Avalos break;
2623c09f92d2SPeter Avalos }
2624c09f92d2SPeter Avalos sumval->alg = sumwrk->alg;
2625c09f92d2SPeter Avalos }
2626c09f92d2SPeter Avalos
2627c09f92d2SPeter Avalos #if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
2628c09f92d2SPeter Avalos static int
compression_unsupported_encoder(struct archive * a,struct la_zstream * lastrm,const char * name)2629c09f92d2SPeter Avalos compression_unsupported_encoder(struct archive *a,
2630c09f92d2SPeter Avalos struct la_zstream *lastrm, const char *name)
2631c09f92d2SPeter Avalos {
2632c09f92d2SPeter Avalos
2633c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2634c09f92d2SPeter Avalos "%s compression not supported on this platform", name);
2635c09f92d2SPeter Avalos lastrm->valid = 0;
2636c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2637c09f92d2SPeter Avalos return (ARCHIVE_FAILED);
2638c09f92d2SPeter Avalos }
2639c09f92d2SPeter Avalos #endif
2640c09f92d2SPeter Avalos
2641c09f92d2SPeter Avalos static int
compression_init_encoder_gzip(struct archive * a,struct la_zstream * lastrm,int level,int withheader)2642c09f92d2SPeter Avalos compression_init_encoder_gzip(struct archive *a,
2643c09f92d2SPeter Avalos struct la_zstream *lastrm, int level, int withheader)
2644c09f92d2SPeter Avalos {
2645c09f92d2SPeter Avalos z_stream *strm;
2646c09f92d2SPeter Avalos
2647c09f92d2SPeter Avalos if (lastrm->valid)
2648c09f92d2SPeter Avalos compression_end(a, lastrm);
2649c09f92d2SPeter Avalos strm = calloc(1, sizeof(*strm));
2650c09f92d2SPeter Avalos if (strm == NULL) {
2651c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2652c09f92d2SPeter Avalos "Can't allocate memory for gzip stream");
2653c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2654c09f92d2SPeter Avalos }
2655c09f92d2SPeter Avalos /* zlib.h is not const-correct, so we need this one bit
2656c09f92d2SPeter Avalos * of ugly hackery to convert a const * pointer to
2657c09f92d2SPeter Avalos * a non-const pointer. */
2658c09f92d2SPeter Avalos strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
2659c09f92d2SPeter Avalos strm->avail_in = lastrm->avail_in;
266059bf7050SPeter Avalos strm->total_in = (uLong)lastrm->total_in;
2661c09f92d2SPeter Avalos strm->next_out = lastrm->next_out;
2662c09f92d2SPeter Avalos strm->avail_out = lastrm->avail_out;
266359bf7050SPeter Avalos strm->total_out = (uLong)lastrm->total_out;
2664c09f92d2SPeter Avalos if (deflateInit2(strm, level, Z_DEFLATED,
2665c09f92d2SPeter Avalos (withheader)?15:-15,
2666c09f92d2SPeter Avalos 8, Z_DEFAULT_STRATEGY) != Z_OK) {
2667c09f92d2SPeter Avalos free(strm);
2668c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2669c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2670c09f92d2SPeter Avalos "Internal error initializing compression library");
2671c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2672c09f92d2SPeter Avalos }
2673c09f92d2SPeter Avalos lastrm->real_stream = strm;
2674c09f92d2SPeter Avalos lastrm->valid = 1;
2675c09f92d2SPeter Avalos lastrm->code = compression_code_gzip;
2676c09f92d2SPeter Avalos lastrm->end = compression_end_gzip;
2677c09f92d2SPeter Avalos return (ARCHIVE_OK);
2678c09f92d2SPeter Avalos }
2679c09f92d2SPeter Avalos
2680c09f92d2SPeter Avalos static int
compression_code_gzip(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2681c09f92d2SPeter Avalos compression_code_gzip(struct archive *a,
2682c09f92d2SPeter Avalos struct la_zstream *lastrm, enum la_zaction action)
2683c09f92d2SPeter Avalos {
2684c09f92d2SPeter Avalos z_stream *strm;
2685c09f92d2SPeter Avalos int r;
2686c09f92d2SPeter Avalos
2687c09f92d2SPeter Avalos strm = (z_stream *)lastrm->real_stream;
2688c09f92d2SPeter Avalos /* zlib.h is not const-correct, so we need this one bit
2689c09f92d2SPeter Avalos * of ugly hackery to convert a const * pointer to
2690c09f92d2SPeter Avalos * a non-const pointer. */
2691c09f92d2SPeter Avalos strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
2692c09f92d2SPeter Avalos strm->avail_in = lastrm->avail_in;
269359bf7050SPeter Avalos strm->total_in = (uLong)lastrm->total_in;
2694c09f92d2SPeter Avalos strm->next_out = lastrm->next_out;
2695c09f92d2SPeter Avalos strm->avail_out = lastrm->avail_out;
269659bf7050SPeter Avalos strm->total_out = (uLong)lastrm->total_out;
2697c09f92d2SPeter Avalos r = deflate(strm,
2698c09f92d2SPeter Avalos (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
2699c09f92d2SPeter Avalos lastrm->next_in = strm->next_in;
2700c09f92d2SPeter Avalos lastrm->avail_in = strm->avail_in;
2701c09f92d2SPeter Avalos lastrm->total_in = strm->total_in;
2702c09f92d2SPeter Avalos lastrm->next_out = strm->next_out;
2703c09f92d2SPeter Avalos lastrm->avail_out = strm->avail_out;
2704c09f92d2SPeter Avalos lastrm->total_out = strm->total_out;
2705c09f92d2SPeter Avalos switch (r) {
2706c09f92d2SPeter Avalos case Z_OK:
2707c09f92d2SPeter Avalos return (ARCHIVE_OK);
2708c09f92d2SPeter Avalos case Z_STREAM_END:
2709c09f92d2SPeter Avalos return (ARCHIVE_EOF);
2710c09f92d2SPeter Avalos default:
2711c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2712c09f92d2SPeter Avalos "GZip compression failed:"
2713c09f92d2SPeter Avalos " deflate() call returned status %d", r);
2714c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2715c09f92d2SPeter Avalos }
2716c09f92d2SPeter Avalos }
2717c09f92d2SPeter Avalos
2718c09f92d2SPeter Avalos static int
compression_end_gzip(struct archive * a,struct la_zstream * lastrm)2719c09f92d2SPeter Avalos compression_end_gzip(struct archive *a, struct la_zstream *lastrm)
2720c09f92d2SPeter Avalos {
2721c09f92d2SPeter Avalos z_stream *strm;
2722c09f92d2SPeter Avalos int r;
2723c09f92d2SPeter Avalos
2724c09f92d2SPeter Avalos strm = (z_stream *)lastrm->real_stream;
2725c09f92d2SPeter Avalos r = deflateEnd(strm);
2726c09f92d2SPeter Avalos free(strm);
2727c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2728c09f92d2SPeter Avalos lastrm->valid = 0;
2729c09f92d2SPeter Avalos if (r != Z_OK) {
2730c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2731c09f92d2SPeter Avalos "Failed to clean up compressor");
2732c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2733c09f92d2SPeter Avalos }
2734c09f92d2SPeter Avalos return (ARCHIVE_OK);
2735c09f92d2SPeter Avalos }
2736c09f92d2SPeter Avalos
2737c09f92d2SPeter Avalos #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
2738c09f92d2SPeter Avalos static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)2739c09f92d2SPeter Avalos compression_init_encoder_bzip2(struct archive *a,
2740c09f92d2SPeter Avalos struct la_zstream *lastrm, int level)
2741c09f92d2SPeter Avalos {
2742c09f92d2SPeter Avalos bz_stream *strm;
2743c09f92d2SPeter Avalos
2744c09f92d2SPeter Avalos if (lastrm->valid)
2745c09f92d2SPeter Avalos compression_end(a, lastrm);
2746c09f92d2SPeter Avalos strm = calloc(1, sizeof(*strm));
2747c09f92d2SPeter Avalos if (strm == NULL) {
2748c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2749c09f92d2SPeter Avalos "Can't allocate memory for bzip2 stream");
2750c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2751c09f92d2SPeter Avalos }
2752c09f92d2SPeter Avalos /* bzlib.h is not const-correct, so we need this one bit
2753c09f92d2SPeter Avalos * of ugly hackery to convert a const * pointer to
2754c09f92d2SPeter Avalos * a non-const pointer. */
2755c09f92d2SPeter Avalos strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
2756c09f92d2SPeter Avalos strm->avail_in = lastrm->avail_in;
2757c09f92d2SPeter Avalos strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
2758c09f92d2SPeter Avalos strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
2759c09f92d2SPeter Avalos strm->next_out = (char *)lastrm->next_out;
2760c09f92d2SPeter Avalos strm->avail_out = lastrm->avail_out;
2761c09f92d2SPeter Avalos strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
2762c09f92d2SPeter Avalos strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
2763c09f92d2SPeter Avalos if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
2764c09f92d2SPeter Avalos free(strm);
2765c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2766c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2767c09f92d2SPeter Avalos "Internal error initializing compression library");
2768c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2769c09f92d2SPeter Avalos }
2770c09f92d2SPeter Avalos lastrm->real_stream = strm;
2771c09f92d2SPeter Avalos lastrm->valid = 1;
2772c09f92d2SPeter Avalos lastrm->code = compression_code_bzip2;
2773c09f92d2SPeter Avalos lastrm->end = compression_end_bzip2;
2774c09f92d2SPeter Avalos return (ARCHIVE_OK);
2775c09f92d2SPeter Avalos }
2776c09f92d2SPeter Avalos
2777c09f92d2SPeter Avalos static int
compression_code_bzip2(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2778c09f92d2SPeter Avalos compression_code_bzip2(struct archive *a,
2779c09f92d2SPeter Avalos struct la_zstream *lastrm, enum la_zaction action)
2780c09f92d2SPeter Avalos {
2781c09f92d2SPeter Avalos bz_stream *strm;
2782c09f92d2SPeter Avalos int r;
2783c09f92d2SPeter Avalos
2784c09f92d2SPeter Avalos strm = (bz_stream *)lastrm->real_stream;
2785c09f92d2SPeter Avalos /* bzlib.h is not const-correct, so we need this one bit
2786c09f92d2SPeter Avalos * of ugly hackery to convert a const * pointer to
2787c09f92d2SPeter Avalos * a non-const pointer. */
2788c09f92d2SPeter Avalos strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
2789c09f92d2SPeter Avalos strm->avail_in = lastrm->avail_in;
2790c09f92d2SPeter Avalos strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
2791c09f92d2SPeter Avalos strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
2792c09f92d2SPeter Avalos strm->next_out = (char *)lastrm->next_out;
2793c09f92d2SPeter Avalos strm->avail_out = lastrm->avail_out;
2794c09f92d2SPeter Avalos strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
2795c09f92d2SPeter Avalos strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
2796c09f92d2SPeter Avalos r = BZ2_bzCompress(strm,
2797c09f92d2SPeter Avalos (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
2798c09f92d2SPeter Avalos lastrm->next_in = (const unsigned char *)strm->next_in;
2799c09f92d2SPeter Avalos lastrm->avail_in = strm->avail_in;
2800c09f92d2SPeter Avalos lastrm->total_in =
2801c09f92d2SPeter Avalos (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
2802c09f92d2SPeter Avalos + (uint64_t)(uint32_t)strm->total_in_lo32;
2803c09f92d2SPeter Avalos lastrm->next_out = (unsigned char *)strm->next_out;
2804c09f92d2SPeter Avalos lastrm->avail_out = strm->avail_out;
2805c09f92d2SPeter Avalos lastrm->total_out =
2806c09f92d2SPeter Avalos (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
2807c09f92d2SPeter Avalos + (uint64_t)(uint32_t)strm->total_out_lo32;
2808c09f92d2SPeter Avalos switch (r) {
2809c09f92d2SPeter Avalos case BZ_RUN_OK: /* Non-finishing */
2810c09f92d2SPeter Avalos case BZ_FINISH_OK: /* Finishing: There's more work to do */
2811c09f92d2SPeter Avalos return (ARCHIVE_OK);
2812c09f92d2SPeter Avalos case BZ_STREAM_END: /* Finishing: all done */
2813c09f92d2SPeter Avalos /* Only occurs in finishing case */
2814c09f92d2SPeter Avalos return (ARCHIVE_EOF);
2815c09f92d2SPeter Avalos default:
2816c09f92d2SPeter Avalos /* Any other return value indicates an error */
2817c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2818c09f92d2SPeter Avalos "Bzip2 compression failed:"
2819c09f92d2SPeter Avalos " BZ2_bzCompress() call returned status %d", r);
2820c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2821c09f92d2SPeter Avalos }
2822c09f92d2SPeter Avalos }
2823c09f92d2SPeter Avalos
2824c09f92d2SPeter Avalos static int
compression_end_bzip2(struct archive * a,struct la_zstream * lastrm)2825c09f92d2SPeter Avalos compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
2826c09f92d2SPeter Avalos {
2827c09f92d2SPeter Avalos bz_stream *strm;
2828c09f92d2SPeter Avalos int r;
2829c09f92d2SPeter Avalos
2830c09f92d2SPeter Avalos strm = (bz_stream *)lastrm->real_stream;
2831c09f92d2SPeter Avalos r = BZ2_bzCompressEnd(strm);
2832c09f92d2SPeter Avalos free(strm);
2833c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2834c09f92d2SPeter Avalos lastrm->valid = 0;
2835c09f92d2SPeter Avalos if (r != BZ_OK) {
2836c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2837c09f92d2SPeter Avalos "Failed to clean up compressor");
2838c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2839c09f92d2SPeter Avalos }
2840c09f92d2SPeter Avalos return (ARCHIVE_OK);
2841c09f92d2SPeter Avalos }
2842c09f92d2SPeter Avalos
2843c09f92d2SPeter Avalos #else
2844c09f92d2SPeter Avalos static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)2845c09f92d2SPeter Avalos compression_init_encoder_bzip2(struct archive *a,
2846c09f92d2SPeter Avalos struct la_zstream *lastrm, int level)
2847c09f92d2SPeter Avalos {
2848c09f92d2SPeter Avalos
2849c09f92d2SPeter Avalos (void) level; /* UNUSED */
2850c09f92d2SPeter Avalos if (lastrm->valid)
2851c09f92d2SPeter Avalos compression_end(a, lastrm);
2852c09f92d2SPeter Avalos return (compression_unsupported_encoder(a, lastrm, "bzip2"));
2853c09f92d2SPeter Avalos }
2854c09f92d2SPeter Avalos #endif
2855c09f92d2SPeter Avalos
2856c09f92d2SPeter Avalos #if defined(HAVE_LZMA_H)
2857c09f92d2SPeter Avalos static int
compression_init_encoder_lzma(struct archive * a,struct la_zstream * lastrm,int level)2858c09f92d2SPeter Avalos compression_init_encoder_lzma(struct archive *a,
2859c09f92d2SPeter Avalos struct la_zstream *lastrm, int level)
2860c09f92d2SPeter Avalos {
2861c09f92d2SPeter Avalos static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
2862c09f92d2SPeter Avalos lzma_stream *strm;
2863c09f92d2SPeter Avalos lzma_options_lzma lzma_opt;
2864c09f92d2SPeter Avalos int r;
2865c09f92d2SPeter Avalos
2866c09f92d2SPeter Avalos if (lastrm->valid)
2867c09f92d2SPeter Avalos compression_end(a, lastrm);
2868c09f92d2SPeter Avalos if (lzma_lzma_preset(&lzma_opt, level)) {
2869c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2870c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2871c09f92d2SPeter Avalos "Internal error initializing compression library");
2872c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2873c09f92d2SPeter Avalos }
2874c09f92d2SPeter Avalos strm = calloc(1, sizeof(*strm));
2875c09f92d2SPeter Avalos if (strm == NULL) {
2876c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2877c09f92d2SPeter Avalos "Can't allocate memory for lzma stream");
2878c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2879c09f92d2SPeter Avalos }
2880c09f92d2SPeter Avalos *strm = lzma_init_data;
2881c09f92d2SPeter Avalos r = lzma_alone_encoder(strm, &lzma_opt);
2882c09f92d2SPeter Avalos switch (r) {
2883c09f92d2SPeter Avalos case LZMA_OK:
2884c09f92d2SPeter Avalos lastrm->real_stream = strm;
2885c09f92d2SPeter Avalos lastrm->valid = 1;
2886c09f92d2SPeter Avalos lastrm->code = compression_code_lzma;
2887c09f92d2SPeter Avalos lastrm->end = compression_end_lzma;
2888c09f92d2SPeter Avalos r = ARCHIVE_OK;
2889c09f92d2SPeter Avalos break;
2890c09f92d2SPeter Avalos case LZMA_MEM_ERROR:
2891c09f92d2SPeter Avalos free(strm);
2892c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2893c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2894c09f92d2SPeter Avalos "Internal error initializing compression library: "
2895c09f92d2SPeter Avalos "Cannot allocate memory");
2896c09f92d2SPeter Avalos r = ARCHIVE_FATAL;
2897c09f92d2SPeter Avalos break;
2898c09f92d2SPeter Avalos default:
2899c09f92d2SPeter Avalos free(strm);
2900c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2901c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2902c09f92d2SPeter Avalos "Internal error initializing compression library: "
2903c09f92d2SPeter Avalos "It's a bug in liblzma");
2904c09f92d2SPeter Avalos r = ARCHIVE_FATAL;
2905c09f92d2SPeter Avalos break;
2906c09f92d2SPeter Avalos }
2907c09f92d2SPeter Avalos return (r);
2908c09f92d2SPeter Avalos }
2909c09f92d2SPeter Avalos
2910c09f92d2SPeter Avalos static int
compression_init_encoder_xz(struct archive * a,struct la_zstream * lastrm,int level,int threads)2911c09f92d2SPeter Avalos compression_init_encoder_xz(struct archive *a,
29126b384f39SPeter Avalos struct la_zstream *lastrm, int level, int threads)
2913c09f92d2SPeter Avalos {
2914c09f92d2SPeter Avalos static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
2915c09f92d2SPeter Avalos lzma_stream *strm;
2916c09f92d2SPeter Avalos lzma_filter *lzmafilters;
2917c09f92d2SPeter Avalos lzma_options_lzma lzma_opt;
2918c09f92d2SPeter Avalos int r;
29196b384f39SPeter Avalos #ifdef HAVE_LZMA_STREAM_ENCODER_MT
29206b384f39SPeter Avalos lzma_mt mt_options;
29216b384f39SPeter Avalos #endif
29226b384f39SPeter Avalos
29236b384f39SPeter Avalos (void)threads; /* UNUSED (if multi-threaded LZMA library not avail) */
2924c09f92d2SPeter Avalos
2925c09f92d2SPeter Avalos if (lastrm->valid)
2926c09f92d2SPeter Avalos compression_end(a, lastrm);
2927c09f92d2SPeter Avalos strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
2928c09f92d2SPeter Avalos if (strm == NULL) {
2929c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2930c09f92d2SPeter Avalos "Can't allocate memory for xz stream");
2931c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2932c09f92d2SPeter Avalos }
2933c09f92d2SPeter Avalos lzmafilters = (lzma_filter *)(strm+1);
2934*50f8aa9cSAntonio Huete Jimenez if (level > 9)
2935*50f8aa9cSAntonio Huete Jimenez level = 9;
2936c09f92d2SPeter Avalos if (lzma_lzma_preset(&lzma_opt, level)) {
293759bf7050SPeter Avalos free(strm);
2938c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2939c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2940c09f92d2SPeter Avalos "Internal error initializing compression library");
2941c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
2942c09f92d2SPeter Avalos }
2943c09f92d2SPeter Avalos lzmafilters[0].id = LZMA_FILTER_LZMA2;
2944c09f92d2SPeter Avalos lzmafilters[0].options = &lzma_opt;
2945c09f92d2SPeter Avalos lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
2946c09f92d2SPeter Avalos
2947c09f92d2SPeter Avalos *strm = lzma_init_data;
29486b384f39SPeter Avalos #ifdef HAVE_LZMA_STREAM_ENCODER_MT
29496b384f39SPeter Avalos if (threads > 1) {
2950e95abc47Szrj memset(&mt_options, 0, sizeof(mt_options));
29516b384f39SPeter Avalos mt_options.threads = threads;
29526b384f39SPeter Avalos mt_options.timeout = 300;
29536b384f39SPeter Avalos mt_options.filters = lzmafilters;
29546b384f39SPeter Avalos mt_options.check = LZMA_CHECK_CRC64;
29556b384f39SPeter Avalos r = lzma_stream_encoder_mt(strm, &mt_options);
29566b384f39SPeter Avalos } else
29576b384f39SPeter Avalos #endif
2958c09f92d2SPeter Avalos r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
2959c09f92d2SPeter Avalos switch (r) {
2960c09f92d2SPeter Avalos case LZMA_OK:
2961c09f92d2SPeter Avalos lastrm->real_stream = strm;
2962c09f92d2SPeter Avalos lastrm->valid = 1;
2963c09f92d2SPeter Avalos lastrm->code = compression_code_lzma;
2964c09f92d2SPeter Avalos lastrm->end = compression_end_lzma;
2965c09f92d2SPeter Avalos r = ARCHIVE_OK;
2966c09f92d2SPeter Avalos break;
2967c09f92d2SPeter Avalos case LZMA_MEM_ERROR:
2968c09f92d2SPeter Avalos free(strm);
2969c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2970c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
2971c09f92d2SPeter Avalos "Internal error initializing compression library: "
2972c09f92d2SPeter Avalos "Cannot allocate memory");
2973c09f92d2SPeter Avalos r = ARCHIVE_FATAL;
2974c09f92d2SPeter Avalos break;
2975c09f92d2SPeter Avalos default:
2976c09f92d2SPeter Avalos free(strm);
2977c09f92d2SPeter Avalos lastrm->real_stream = NULL;
2978c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
2979c09f92d2SPeter Avalos "Internal error initializing compression library: "
2980c09f92d2SPeter Avalos "It's a bug in liblzma");
2981c09f92d2SPeter Avalos r = ARCHIVE_FATAL;
2982c09f92d2SPeter Avalos break;
2983c09f92d2SPeter Avalos }
2984c09f92d2SPeter Avalos return (r);
2985c09f92d2SPeter Avalos }
2986c09f92d2SPeter Avalos
2987c09f92d2SPeter Avalos static int
compression_code_lzma(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2988c09f92d2SPeter Avalos compression_code_lzma(struct archive *a,
2989c09f92d2SPeter Avalos struct la_zstream *lastrm, enum la_zaction action)
2990c09f92d2SPeter Avalos {
2991c09f92d2SPeter Avalos lzma_stream *strm;
2992c09f92d2SPeter Avalos int r;
2993c09f92d2SPeter Avalos
2994c09f92d2SPeter Avalos strm = (lzma_stream *)lastrm->real_stream;
2995c09f92d2SPeter Avalos strm->next_in = lastrm->next_in;
2996c09f92d2SPeter Avalos strm->avail_in = lastrm->avail_in;
2997c09f92d2SPeter Avalos strm->total_in = lastrm->total_in;
2998c09f92d2SPeter Avalos strm->next_out = lastrm->next_out;
2999c09f92d2SPeter Avalos strm->avail_out = lastrm->avail_out;
3000c09f92d2SPeter Avalos strm->total_out = lastrm->total_out;
3001c09f92d2SPeter Avalos r = lzma_code(strm,
3002c09f92d2SPeter Avalos (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
3003c09f92d2SPeter Avalos lastrm->next_in = strm->next_in;
3004c09f92d2SPeter Avalos lastrm->avail_in = strm->avail_in;
3005c09f92d2SPeter Avalos lastrm->total_in = strm->total_in;
3006c09f92d2SPeter Avalos lastrm->next_out = strm->next_out;
3007c09f92d2SPeter Avalos lastrm->avail_out = strm->avail_out;
3008c09f92d2SPeter Avalos lastrm->total_out = strm->total_out;
3009c09f92d2SPeter Avalos switch (r) {
3010c09f92d2SPeter Avalos case LZMA_OK:
3011c09f92d2SPeter Avalos /* Non-finishing case */
3012c09f92d2SPeter Avalos return (ARCHIVE_OK);
3013c09f92d2SPeter Avalos case LZMA_STREAM_END:
3014c09f92d2SPeter Avalos /* This return can only occur in finishing case. */
3015c09f92d2SPeter Avalos return (ARCHIVE_EOF);
3016c09f92d2SPeter Avalos case LZMA_MEMLIMIT_ERROR:
3017c09f92d2SPeter Avalos archive_set_error(a, ENOMEM,
3018c09f92d2SPeter Avalos "lzma compression error:"
3019c09f92d2SPeter Avalos " %ju MiB would have been needed",
3020c09f92d2SPeter Avalos (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
3021c09f92d2SPeter Avalos / (1024 * 1024)));
3022c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3023c09f92d2SPeter Avalos default:
3024c09f92d2SPeter Avalos /* Any other return value indicates an error */
3025c09f92d2SPeter Avalos archive_set_error(a, ARCHIVE_ERRNO_MISC,
3026c09f92d2SPeter Avalos "lzma compression failed:"
3027c09f92d2SPeter Avalos " lzma_code() call returned status %d", r);
3028c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3029c09f92d2SPeter Avalos }
3030c09f92d2SPeter Avalos }
3031c09f92d2SPeter Avalos
3032c09f92d2SPeter Avalos static int
compression_end_lzma(struct archive * a,struct la_zstream * lastrm)3033c09f92d2SPeter Avalos compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
3034c09f92d2SPeter Avalos {
3035c09f92d2SPeter Avalos lzma_stream *strm;
3036c09f92d2SPeter Avalos
3037c09f92d2SPeter Avalos (void)a; /* UNUSED */
3038c09f92d2SPeter Avalos strm = (lzma_stream *)lastrm->real_stream;
3039c09f92d2SPeter Avalos lzma_end(strm);
3040c09f92d2SPeter Avalos free(strm);
3041c09f92d2SPeter Avalos lastrm->valid = 0;
3042c09f92d2SPeter Avalos lastrm->real_stream = NULL;
3043c09f92d2SPeter Avalos return (ARCHIVE_OK);
3044c09f92d2SPeter Avalos }
3045c09f92d2SPeter Avalos #else
3046c09f92d2SPeter Avalos static int
compression_init_encoder_lzma(struct archive * a,struct la_zstream * lastrm,int level)3047c09f92d2SPeter Avalos compression_init_encoder_lzma(struct archive *a,
3048c09f92d2SPeter Avalos struct la_zstream *lastrm, int level)
3049c09f92d2SPeter Avalos {
3050c09f92d2SPeter Avalos
3051c09f92d2SPeter Avalos (void) level; /* UNUSED */
3052c09f92d2SPeter Avalos if (lastrm->valid)
3053c09f92d2SPeter Avalos compression_end(a, lastrm);
3054c09f92d2SPeter Avalos return (compression_unsupported_encoder(a, lastrm, "lzma"));
3055c09f92d2SPeter Avalos }
3056c09f92d2SPeter Avalos static int
compression_init_encoder_xz(struct archive * a,struct la_zstream * lastrm,int level,int threads)3057c09f92d2SPeter Avalos compression_init_encoder_xz(struct archive *a,
30586b384f39SPeter Avalos struct la_zstream *lastrm, int level, int threads)
3059c09f92d2SPeter Avalos {
3060c09f92d2SPeter Avalos
3061c09f92d2SPeter Avalos (void) level; /* UNUSED */
30626b384f39SPeter Avalos (void) threads; /* UNUSED */
3063c09f92d2SPeter Avalos if (lastrm->valid)
3064c09f92d2SPeter Avalos compression_end(a, lastrm);
3065c09f92d2SPeter Avalos return (compression_unsupported_encoder(a, lastrm, "xz"));
3066c09f92d2SPeter Avalos }
3067c09f92d2SPeter Avalos #endif
3068c09f92d2SPeter Avalos
3069c09f92d2SPeter Avalos static int
xar_compression_init_encoder(struct archive_write * a)3070c09f92d2SPeter Avalos xar_compression_init_encoder(struct archive_write *a)
3071c09f92d2SPeter Avalos {
3072c09f92d2SPeter Avalos struct xar *xar;
3073c09f92d2SPeter Avalos int r;
3074c09f92d2SPeter Avalos
3075c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
3076c09f92d2SPeter Avalos switch (xar->opt_compression) {
3077c09f92d2SPeter Avalos case GZIP:
3078c09f92d2SPeter Avalos r = compression_init_encoder_gzip(
3079c09f92d2SPeter Avalos &(a->archive), &(xar->stream),
3080c09f92d2SPeter Avalos xar->opt_compression_level, 1);
3081c09f92d2SPeter Avalos break;
3082c09f92d2SPeter Avalos case BZIP2:
3083c09f92d2SPeter Avalos r = compression_init_encoder_bzip2(
3084c09f92d2SPeter Avalos &(a->archive), &(xar->stream),
3085c09f92d2SPeter Avalos xar->opt_compression_level);
3086c09f92d2SPeter Avalos break;
3087c09f92d2SPeter Avalos case LZMA:
3088c09f92d2SPeter Avalos r = compression_init_encoder_lzma(
3089c09f92d2SPeter Avalos &(a->archive), &(xar->stream),
3090c09f92d2SPeter Avalos xar->opt_compression_level);
3091c09f92d2SPeter Avalos break;
3092c09f92d2SPeter Avalos case XZ:
3093c09f92d2SPeter Avalos r = compression_init_encoder_xz(
3094c09f92d2SPeter Avalos &(a->archive), &(xar->stream),
30956b384f39SPeter Avalos xar->opt_compression_level, xar->opt_threads);
3096c09f92d2SPeter Avalos break;
3097c09f92d2SPeter Avalos default:
3098c09f92d2SPeter Avalos r = ARCHIVE_OK;
3099c09f92d2SPeter Avalos break;
3100c09f92d2SPeter Avalos }
3101c09f92d2SPeter Avalos if (r == ARCHIVE_OK) {
3102c09f92d2SPeter Avalos xar->stream.total_in = 0;
3103c09f92d2SPeter Avalos xar->stream.next_out = xar->wbuff;
3104c09f92d2SPeter Avalos xar->stream.avail_out = sizeof(xar->wbuff);
3105c09f92d2SPeter Avalos xar->stream.total_out = 0;
3106c09f92d2SPeter Avalos }
3107c09f92d2SPeter Avalos
3108c09f92d2SPeter Avalos return (r);
3109c09f92d2SPeter Avalos }
3110c09f92d2SPeter Avalos
3111c09f92d2SPeter Avalos static int
compression_code(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)3112c09f92d2SPeter Avalos compression_code(struct archive *a, struct la_zstream *lastrm,
3113c09f92d2SPeter Avalos enum la_zaction action)
3114c09f92d2SPeter Avalos {
3115c09f92d2SPeter Avalos if (lastrm->valid)
3116c09f92d2SPeter Avalos return (lastrm->code(a, lastrm, action));
3117c09f92d2SPeter Avalos return (ARCHIVE_OK);
3118c09f92d2SPeter Avalos }
3119c09f92d2SPeter Avalos
3120c09f92d2SPeter Avalos static int
compression_end(struct archive * a,struct la_zstream * lastrm)3121c09f92d2SPeter Avalos compression_end(struct archive *a, struct la_zstream *lastrm)
3122c09f92d2SPeter Avalos {
3123c09f92d2SPeter Avalos if (lastrm->valid)
3124c09f92d2SPeter Avalos return (lastrm->end(a, lastrm));
3125c09f92d2SPeter Avalos return (ARCHIVE_OK);
3126c09f92d2SPeter Avalos }
3127c09f92d2SPeter Avalos
3128c09f92d2SPeter Avalos
3129c09f92d2SPeter Avalos static int
save_xattrs(struct archive_write * a,struct file * file)3130c09f92d2SPeter Avalos save_xattrs(struct archive_write *a, struct file *file)
3131c09f92d2SPeter Avalos {
3132c09f92d2SPeter Avalos struct xar *xar;
3133c09f92d2SPeter Avalos const char *name;
3134c09f92d2SPeter Avalos const void *value;
3135c09f92d2SPeter Avalos struct heap_data *heap;
3136c09f92d2SPeter Avalos size_t size;
3137c09f92d2SPeter Avalos int count, r;
3138c09f92d2SPeter Avalos
3139c09f92d2SPeter Avalos xar = (struct xar *)a->format_data;
3140c09f92d2SPeter Avalos count = archive_entry_xattr_reset(file->entry);
3141c09f92d2SPeter Avalos if (count == 0)
3142c09f92d2SPeter Avalos return (ARCHIVE_OK);
3143c09f92d2SPeter Avalos while (count--) {
3144c09f92d2SPeter Avalos archive_entry_xattr_next(file->entry,
3145c09f92d2SPeter Avalos &name, &value, &size);
3146c09f92d2SPeter Avalos checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
3147c09f92d2SPeter Avalos checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
3148c09f92d2SPeter Avalos
3149c09f92d2SPeter Avalos heap = calloc(1, sizeof(*heap));
3150c09f92d2SPeter Avalos if (heap == NULL) {
3151c09f92d2SPeter Avalos archive_set_error(&a->archive, ENOMEM,
3152c09f92d2SPeter Avalos "Can't allocate memory for xattr");
3153c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3154c09f92d2SPeter Avalos }
3155c09f92d2SPeter Avalos heap->id = file->ea_idx++;
3156c09f92d2SPeter Avalos heap->temp_offset = xar->temp_offset;
3157c09f92d2SPeter Avalos heap->size = size;/* save a extracted size */
3158c09f92d2SPeter Avalos heap->compression = xar->opt_compression;
3159c09f92d2SPeter Avalos /* Get a extracted sumcheck value. */
3160c09f92d2SPeter Avalos checksum_update(&(xar->e_sumwrk), value, size);
3161c09f92d2SPeter Avalos checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
3162c09f92d2SPeter Avalos
3163c09f92d2SPeter Avalos /*
3164c09f92d2SPeter Avalos * Not compression to xattr is simple way.
3165c09f92d2SPeter Avalos */
3166c09f92d2SPeter Avalos if (heap->compression == NONE) {
3167c09f92d2SPeter Avalos checksum_update(&(xar->a_sumwrk), value, size);
3168c09f92d2SPeter Avalos checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
3169c09f92d2SPeter Avalos if (write_to_temp(a, value, size)
3170d4d8193eSPeter Avalos != ARCHIVE_OK) {
3171d4d8193eSPeter Avalos free(heap);
3172c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3173d4d8193eSPeter Avalos }
3174c09f92d2SPeter Avalos heap->length = size;
3175c09f92d2SPeter Avalos /* Add heap to the tail of file->xattr. */
3176c09f92d2SPeter Avalos heap->next = NULL;
3177c09f92d2SPeter Avalos *file->xattr.last = heap;
3178c09f92d2SPeter Avalos file->xattr.last = &(heap->next);
3179c09f92d2SPeter Avalos /* Next xattr */
3180c09f92d2SPeter Avalos continue;
3181c09f92d2SPeter Avalos }
3182c09f92d2SPeter Avalos
3183c09f92d2SPeter Avalos /*
3184c09f92d2SPeter Avalos * Init compression library.
3185c09f92d2SPeter Avalos */
3186c09f92d2SPeter Avalos r = xar_compression_init_encoder(a);
3187c09f92d2SPeter Avalos if (r != ARCHIVE_OK) {
3188c09f92d2SPeter Avalos free(heap);
3189c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3190c09f92d2SPeter Avalos }
3191c09f92d2SPeter Avalos
3192c09f92d2SPeter Avalos xar->stream.next_in = (const unsigned char *)value;
3193c09f92d2SPeter Avalos xar->stream.avail_in = size;
3194c09f92d2SPeter Avalos for (;;) {
3195c09f92d2SPeter Avalos r = compression_code(&(a->archive),
3196c09f92d2SPeter Avalos &(xar->stream), ARCHIVE_Z_FINISH);
3197c09f92d2SPeter Avalos if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
3198c09f92d2SPeter Avalos free(heap);
3199c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3200c09f92d2SPeter Avalos }
3201c09f92d2SPeter Avalos size = sizeof(xar->wbuff) - xar->stream.avail_out;
3202c09f92d2SPeter Avalos checksum_update(&(xar->a_sumwrk),
3203c09f92d2SPeter Avalos xar->wbuff, size);
3204c09f92d2SPeter Avalos if (write_to_temp(a, xar->wbuff, size)
3205085658deSDaniel Fojt != ARCHIVE_OK) {
3206085658deSDaniel Fojt free(heap);
3207c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3208085658deSDaniel Fojt }
3209c09f92d2SPeter Avalos if (r == ARCHIVE_OK) {
3210c09f92d2SPeter Avalos xar->stream.next_out = xar->wbuff;
3211c09f92d2SPeter Avalos xar->stream.avail_out = sizeof(xar->wbuff);
3212c09f92d2SPeter Avalos } else {
3213c09f92d2SPeter Avalos checksum_final(&(xar->a_sumwrk),
3214c09f92d2SPeter Avalos &(heap->a_sum));
3215c09f92d2SPeter Avalos heap->length = xar->stream.total_out;
3216c09f92d2SPeter Avalos /* Add heap to the tail of file->xattr. */
3217c09f92d2SPeter Avalos heap->next = NULL;
3218c09f92d2SPeter Avalos *file->xattr.last = heap;
3219c09f92d2SPeter Avalos file->xattr.last = &(heap->next);
3220c09f92d2SPeter Avalos break;
3221c09f92d2SPeter Avalos }
3222c09f92d2SPeter Avalos }
3223c09f92d2SPeter Avalos /* Clean up compression library. */
3224c09f92d2SPeter Avalos r = compression_end(&(a->archive), &(xar->stream));
3225c09f92d2SPeter Avalos if (r != ARCHIVE_OK)
3226c09f92d2SPeter Avalos return (ARCHIVE_FATAL);
3227c09f92d2SPeter Avalos }
3228c09f92d2SPeter Avalos return (ARCHIVE_OK);
3229c09f92d2SPeter Avalos }
3230c09f92d2SPeter Avalos
3231c09f92d2SPeter Avalos static int
getalgsize(enum sumalg sumalg)3232c09f92d2SPeter Avalos getalgsize(enum sumalg sumalg)
3233c09f92d2SPeter Avalos {
3234c09f92d2SPeter Avalos switch (sumalg) {
3235c09f92d2SPeter Avalos default:
3236c09f92d2SPeter Avalos case CKSUM_NONE:
3237c09f92d2SPeter Avalos return (0);
3238c09f92d2SPeter Avalos case CKSUM_SHA1:
3239c09f92d2SPeter Avalos return (SHA1_SIZE);
3240c09f92d2SPeter Avalos case CKSUM_MD5:
3241c09f92d2SPeter Avalos return (MD5_SIZE);
3242c09f92d2SPeter Avalos }
3243c09f92d2SPeter Avalos }
3244c09f92d2SPeter Avalos
3245c09f92d2SPeter Avalos static const char *
getalgname(enum sumalg sumalg)3246c09f92d2SPeter Avalos getalgname(enum sumalg sumalg)
3247c09f92d2SPeter Avalos {
3248c09f92d2SPeter Avalos switch (sumalg) {
3249c09f92d2SPeter Avalos default:
3250c09f92d2SPeter Avalos case CKSUM_NONE:
3251c09f92d2SPeter Avalos return (NULL);
3252c09f92d2SPeter Avalos case CKSUM_SHA1:
3253c09f92d2SPeter Avalos return (SHA1_NAME);
3254c09f92d2SPeter Avalos case CKSUM_MD5:
3255c09f92d2SPeter Avalos return (MD5_NAME);
3256c09f92d2SPeter Avalos }
3257c09f92d2SPeter Avalos }
3258c09f92d2SPeter Avalos
3259c09f92d2SPeter Avalos #endif /* Support xar format */
3260