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