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