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