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