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