xref: /freebsd/contrib/libarchive/libarchive/archive_write_set_format_7zip.c (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
1 /*-
2  * Copyright (c) 2011-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 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #ifdef HAVE_BZLIB_H
41 #include <bzlib.h>
42 #endif
43 #if HAVE_LZMA_H
44 #include <lzma.h>
45 #endif
46 #ifdef HAVE_ZLIB_H
47 #include <zlib.h>
48 #endif
49 #ifdef HAVE_ZSTD_H
50 #include <zstd.h>
51 #endif
52 
53 #include "archive.h"
54 #ifndef HAVE_ZLIB_H
55 #include "archive_crc32.h"
56 #endif
57 #include "archive_endian.h"
58 #include "archive_entry.h"
59 #include "archive_entry_locale.h"
60 #include "archive_ppmd7_private.h"
61 #include "archive_private.h"
62 #include "archive_rb.h"
63 #include "archive_string.h"
64 #include "archive_time_private.h"
65 #include "archive_write_private.h"
66 #include "archive_write_set_format_private.h"
67 
68 /*
69  * Codec ID
70  */
71 #define _7Z_COPY	0
72 #define _7Z_LZMA1	0x030101
73 #define _7Z_LZMA2	0x21
74 #define _7Z_DEFLATE	0x040108
75 #define _7Z_BZIP2	0x040202
76 #define _7Z_PPMD	0x030401
77 
78 #define _7Z_ZSTD	0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */
79 
80 /*
81  * 7-Zip header property IDs.
82  */
83 #define kEnd			0x00
84 #define kHeader			0x01
85 #define kArchiveProperties	0x02
86 #define kAdditionalStreamsInfo	0x03
87 #define kMainStreamsInfo	0x04
88 #define kFilesInfo		0x05
89 #define kPackInfo		0x06
90 #define kUnPackInfo		0x07
91 #define kSubStreamsInfo		0x08
92 #define kSize			0x09
93 #define kCRC			0x0A
94 #define kFolder			0x0B
95 #define kCodersUnPackSize	0x0C
96 #define kNumUnPackStream	0x0D
97 #define kEmptyStream		0x0E
98 #define kEmptyFile		0x0F
99 #define kAnti			0x10
100 #define kName			0x11
101 #define kCTime			0x12
102 #define kATime			0x13
103 #define kMTime			0x14
104 #define kAttributes		0x15
105 #define kEncodedHeader		0x17
106 
107 // Check that some windows file attribute constants are defined.
108 // Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
109 #ifndef FILE_ATTRIBUTE_READONLY
110 #define FILE_ATTRIBUTE_READONLY 0x00000001
111 #endif
112 
113 #ifndef FILE_ATTRIBUTE_DIRECTORY
114 #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
115 #endif
116 
117 #ifndef FILE_ATTRIBUTE_ARCHIVE
118 #define FILE_ATTRIBUTE_ARCHIVE 0x00000020
119 #endif
120 
121 // This value is defined in 7zip with the comment "trick for Unix".
122 //
123 // 7z archives created on unix have this bit set in the high 16 bits of
124 // the attr field along with the unix permissions.
125 #define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000
126 
127 // Many systems define min or MIN, but not all.
128 #define sevenzipmin(a,b) ((a) < (b) ? (a) : (b))
129 
130 enum la_zaction {
131 	ARCHIVE_Z_FINISH,
132 	ARCHIVE_Z_RUN
133 };
134 
135 /*
136  * A stream object of universal compressor.
137  */
138 struct la_zstream {
139 	const uint8_t		*next_in;
140 	size_t			 avail_in;
141 	uint64_t		 total_in;
142 
143 	uint8_t			*next_out;
144 	size_t			 avail_out;
145 	uint64_t		 total_out;
146 
147 	uint32_t		 prop_size;
148 	uint8_t			*props;
149 
150 	int			 valid;
151 	void			*real_stream;
152 	int			 (*code) (struct archive *a,
153 				    struct la_zstream *lastrm,
154 				    enum la_zaction action);
155 	int			 (*end)(struct archive *a,
156 				    struct la_zstream *lastrm);
157 };
158 
159 #define PPMD7_DEFAULT_ORDER	6
160 #define PPMD7_DEFAULT_MEM_SIZE	(1 << 24)
161 
162 struct ppmd_stream {
163 	int			 stat;
164 	CPpmd7			 ppmd7_context;
165 	CPpmd7z_RangeEnc	 range_enc;
166 	IByteOut		 byteout;
167 	uint8_t			*buff;
168 	uint8_t			*buff_ptr;
169 	uint8_t			*buff_end;
170 	size_t			 buff_bytes;
171 };
172 
173 struct coder {
174 	unsigned		 codec;
175 	size_t			 prop_size;
176 	uint8_t			*props;
177 };
178 
179 struct file {
180 	struct archive_rb_node	 rbnode;
181 
182 	struct file		*next;
183 	unsigned		 name_len;
184 	uint8_t			*utf16name;/* UTF16-LE name. */
185 	uint64_t		 size;
186 	unsigned		 flg;
187 #define MTIME_IS_SET	(1<<0)
188 #define ATIME_IS_SET	(1<<1)
189 #define CTIME_IS_SET	(1<<2)
190 #define CRC32_IS_SET	(1<<3)
191 #define HAS_STREAM	(1<<4)
192 
193 	struct {
194 		time_t		 time;
195 		long		 time_ns;
196 	}			 times[3];
197 #define MTIME 0
198 #define ATIME 1
199 #define CTIME 2
200 
201 	mode_t			 mode;
202 	uint32_t		 crc32;
203 
204 	unsigned int		 dir:1;
205 };
206 
207 struct _7zip {
208 	int			 temp_fd;
209 	uint64_t		 temp_offset;
210 
211 	struct file		*cur_file;
212 	size_t			 total_number_entry;
213 	size_t			 total_number_nonempty_entry;
214 	size_t			 total_number_empty_entry;
215 	size_t			 total_number_dir_entry;
216 	size_t			 total_bytes_entry_name;
217 	size_t			 total_number_time_defined[3];
218 	uint64_t		 entry_bytes_remaining;
219 	uint32_t		 entry_crc32;
220 	uint32_t		 precode_crc32;
221 	uint32_t		 encoded_crc32;
222 	int			 crc32flg;
223 #define	PRECODE_CRC32	1
224 #define	ENCODED_CRC32	2
225 
226 	unsigned		 opt_compression;
227 
228 	int			 opt_compression_level;
229 	int			 opt_zstd_compression_level; // This requires a different default value.
230 
231 	int			 opt_threads;
232 
233 	struct la_zstream	 stream;
234 	struct coder		 coder;
235 
236 	struct archive_string_conv *sconv;
237 
238 	/*
239 	 * Compressed data buffer.
240 	 */
241 	unsigned char		 wbuff[512 * 20 * 6];
242 	size_t			 wbuff_remaining;
243 
244 	/*
245 	 * The list of the file entries which has its contents is used to
246 	 * manage struct file objects.
247 	 * We use 'next' (a member of struct file) to chain.
248 	 */
249 	struct {
250 		struct file	*first;
251 		struct file	**last;
252 	}			 file_list, empty_list;
253 	struct archive_rb_tree	 rbtree;/* for empty files */
254 };
255 
256 static int	_7z_options(struct archive_write *,
257 		    const char *, const char *);
258 static int	_7z_write_header(struct archive_write *,
259 		    struct archive_entry *);
260 static ssize_t	_7z_write_data(struct archive_write *,
261 		    const void *, size_t);
262 static int	_7z_finish_entry(struct archive_write *);
263 static int	_7z_close(struct archive_write *);
264 static int	_7z_free(struct archive_write *);
265 static int	file_cmp_node(const struct archive_rb_node *,
266 		    const struct archive_rb_node *);
267 static int	file_cmp_key(const struct archive_rb_node *, const void *);
268 static int	file_new(struct archive_write *a, struct archive_entry *,
269 		    struct file **);
270 static void	file_free(struct file *);
271 static void	file_register(struct _7zip *, struct file *);
272 static void	file_register_empty(struct _7zip *, struct file *);
273 static void	file_init_register(struct _7zip *);
274 static void	file_init_register_empty(struct _7zip *);
275 static void	file_free_register(struct _7zip *);
276 static ssize_t	compress_out(struct archive_write *, const void *, size_t ,
277 		    enum la_zaction);
278 static int	compression_init_encoder_copy(struct archive *,
279 		    struct la_zstream *);
280 static int	compression_code_copy(struct archive *,
281 		    struct la_zstream *, enum la_zaction);
282 static int	compression_end_copy(struct archive *, struct la_zstream *);
283 static int	compression_init_encoder_deflate(struct archive *,
284 		    struct la_zstream *, int, int);
285 #ifdef HAVE_ZLIB_H
286 static int	compression_code_deflate(struct archive *,
287 		    struct la_zstream *, enum la_zaction);
288 static int	compression_end_deflate(struct archive *, struct la_zstream *);
289 #endif
290 static int	compression_init_encoder_bzip2(struct archive *,
291 		    struct la_zstream *, int);
292 #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
293 static int	compression_code_bzip2(struct archive *,
294 		    struct la_zstream *, enum la_zaction);
295 static int	compression_end_bzip2(struct archive *, struct la_zstream *);
296 #endif
297 static int	compression_init_encoder_lzma1(struct archive *,
298 		    struct la_zstream *, int);
299 static int	compression_init_encoder_lzma2(struct archive *,
300 		    struct la_zstream *, int);
301 #if defined(HAVE_LZMA_H)
302 static int	compression_code_lzma(struct archive *,
303 		    struct la_zstream *, enum la_zaction);
304 static int	compression_end_lzma(struct archive *, struct la_zstream *);
305 #endif
306 static int	compression_init_encoder_ppmd(struct archive *,
307 		    struct la_zstream *, uint8_t, uint32_t);
308 static int	compression_code_ppmd(struct archive *,
309 		    struct la_zstream *, enum la_zaction);
310 static int	compression_end_ppmd(struct archive *, struct la_zstream *);
311 static int	_7z_compression_init_encoder(struct archive_write *, unsigned,
312 		    int);
313 static int	compression_init_encoder_zstd(struct archive *,
314 		    struct la_zstream *, int, int);
315 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
316 static int	compression_code_zstd(struct archive *,
317 		    struct la_zstream *, enum la_zaction);
318 static int	compression_end_zstd(struct archive *, struct la_zstream *);
319 #endif
320 static int	compression_code(struct archive *,
321 		    struct la_zstream *, enum la_zaction);
322 static int	compression_end(struct archive *,
323 		    struct la_zstream *);
324 static int	enc_uint64(struct archive_write *, uint64_t);
325 static int	make_header(struct archive_write *, uint64_t, uint64_t,
326 		    uint64_t, int, struct coder *);
327 static int	make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
328 		    	uint64_t, int, struct coder *, int, uint32_t);
329 
330 static int
string_to_number(const char * string,intmax_t * numberp)331 string_to_number(const char *string, intmax_t *numberp)
332 {
333 	char *end;
334 
335 	if (string == NULL || *string == '\0')
336 		return (ARCHIVE_WARN);
337 	errno = 0;
338 	*numberp = strtoimax(string, &end, 10);
339 	if (end == string || *end != '\0' || errno == EOVERFLOW) {
340 		*numberp = 0;
341 		return (ARCHIVE_WARN);
342 	}
343 	return (ARCHIVE_OK);
344 }
345 
346 int
archive_write_set_format_7zip(struct archive * _a)347 archive_write_set_format_7zip(struct archive *_a)
348 {
349 	static const struct archive_rb_tree_ops rb_ops = {
350 		file_cmp_node, file_cmp_key
351 	};
352 	struct archive_write *a = (struct archive_write *)_a;
353 	struct _7zip *zip;
354 
355 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
356 	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
357 
358 	/* If another format was already registered, unregister it. */
359 	(void)__archive_write_unregister_format(a);
360 
361 	zip = calloc(1, sizeof(*zip));
362 	if (zip == NULL) {
363 		archive_set_error(&a->archive, ENOMEM,
364 		    "Can't allocate 7-Zip data");
365 		return (ARCHIVE_FATAL);
366 	}
367 	zip->temp_fd = -1;
368 	__archive_rb_tree_init(&(zip->rbtree), &rb_ops);
369 	file_init_register(zip);
370 	file_init_register_empty(zip);
371 
372 	/* Set default compression type and its level. */
373 #if HAVE_LZMA_H
374 	zip->opt_compression = _7Z_LZMA1;
375 #elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
376 	zip->opt_compression = _7Z_BZIP2;
377 #elif defined(HAVE_ZLIB_H)
378 	zip->opt_compression = _7Z_DEFLATE;
379 #elif HAVE_ZSTD_H && HAVE_ZSTD_compressStream
380 	zip->opt_compression = _7Z_ZSTD;
381 #else
382 	zip->opt_compression = _7Z_COPY;
383 #endif
384 
385 	zip->opt_compression_level = 6;
386 
387 #ifdef ZSTD_CLEVEL_DEFAULT
388 	// Zstandard compression needs a different default
389 	// value than other encoders.
390 	zip->opt_zstd_compression_level = ZSTD_CLEVEL_DEFAULT;
391 #else
392 	zip->opt_zstd_compression_level = 3;
393 #endif
394 
395 	zip->opt_threads = 1;
396 
397 	a->format_data = zip;
398 
399 	a->format_name = "7zip";
400 	a->format_options = _7z_options;
401 	a->format_write_header = _7z_write_header;
402 	a->format_write_data = _7z_write_data;
403 	a->format_finish_entry = _7z_finish_entry;
404 	a->format_close = _7z_close;
405 	a->format_free = _7z_free;
406 	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
407 	a->archive.archive_format_name = "7zip";
408 
409 	return (ARCHIVE_OK);
410 }
411 
412 static int
_7z_options(struct archive_write * a,const char * key,const char * value)413 _7z_options(struct archive_write *a, const char *key, const char *value)
414 {
415 	struct _7zip *zip = a->format_data;
416 
417 	if (strcmp(key, "compression") == 0) {
418 		const char *name = NULL;
419 
420 		if (value == NULL || strcmp(value, "copy") == 0 ||
421 		    strcmp(value, "COPY") == 0 ||
422 		    strcmp(value, "store") == 0 ||
423 		    strcmp(value, "STORE") == 0)
424 			zip->opt_compression = _7Z_COPY;
425 		else if (strcmp(value, "deflate") == 0 ||
426 		    strcmp(value, "DEFLATE") == 0)
427 #if HAVE_ZLIB_H
428 			zip->opt_compression = _7Z_DEFLATE;
429 #else
430 			name = "deflate";
431 #endif
432 		else if (strcmp(value, "bzip2") == 0 ||
433 		    strcmp(value, "BZIP2") == 0)
434 #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
435 			zip->opt_compression = _7Z_BZIP2;
436 #else
437 			name = "bzip2";
438 #endif
439 		else if (strcmp(value, "lzma1") == 0 ||
440 		    strcmp(value, "LZMA1") == 0)
441 #if HAVE_LZMA_H
442 			zip->opt_compression = _7Z_LZMA1;
443 #else
444 			name = "lzma1";
445 #endif
446 		else if (strcmp(value, "lzma2") == 0 ||
447 		    strcmp(value, "LZMA2") == 0)
448 #if HAVE_LZMA_H
449 			zip->opt_compression = _7Z_LZMA2;
450 #else
451 			name = "lzma2";
452 #endif
453 		else if (strcmp(value, "zstd") == 0 ||
454 		    strcmp(value, "ZSTD") == 0)
455 #if HAVE_ZSTD_H
456 			zip->opt_compression = _7Z_ZSTD;
457 #else
458 			name = "zstd";
459 #endif
460 		else if (strcmp(value, "ppmd") == 0 ||
461 		    strcmp(value, "PPMD") == 0 ||
462 		    strcmp(value, "PPMd") == 0)
463 			zip->opt_compression = _7Z_PPMD;
464 		else {
465 			archive_set_error(&(a->archive),
466 			    ARCHIVE_ERRNO_MISC,
467 			    "Unknown compression name: `%s'",
468 			    value);
469 			return (ARCHIVE_FAILED);
470 		}
471 		if (name != NULL) {
472 			archive_set_error(&(a->archive),
473 			    ARCHIVE_ERRNO_MISC,
474 			    "`%s' compression not supported "
475 			    "on this platform",
476 			    name);
477 			return (ARCHIVE_FAILED);
478 		}
479 		return (ARCHIVE_OK);
480 	}
481 	if (strcmp(key, "compression-level") == 0) {
482 		if (value == NULL || *value == '\0') {
483 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
484 				"Invalid compression-level option value `%s'", value);
485 			return (ARCHIVE_FAILED);
486 		}
487 
488 		char *end = NULL;
489 		errno = 0;
490 		long lvl = strtol(value, &end, 10);
491 		if (errno != 0 || end == NULL || *end != '\0') {
492 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
493 				"parsing compression-level option value failed `%s'", value);
494 			return (ARCHIVE_FAILED);
495 		}
496 
497 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream && HAVE_ZSTD_minCLevel
498 		int min_level = sevenzipmin(0, ZSTD_minCLevel());
499 #else
500 		const int min_level = 0;
501 #endif
502 
503 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
504 		int max_level = ZSTD_maxCLevel();
505 #else
506 		const int max_level = 9;
507 #endif
508 
509 		if (lvl < min_level || lvl > max_level) {
510 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
511 				"compression-level option value `%ld' out of range", lvl);
512 			return (ARCHIVE_FAILED);
513 		}
514 
515 		// Note: we don't know here if this value is for zstd (negative to ~22),
516 		// or zlib-style 0-9. If zstd is enabled but not in use, we will need to
517 		// validate opt_compression_level before use.
518 		zip->opt_compression_level = (int)lvl;
519 
520 		zip->opt_zstd_compression_level = (int)lvl;
521 		return (ARCHIVE_OK);
522 	}
523 	if (strcmp(key, "threads") == 0) {
524 		intmax_t threads;
525 		if (string_to_number(value, &threads) != ARCHIVE_OK) {
526 			return (ARCHIVE_WARN);
527 		}
528 		if (threads < 0 || threads > INT_MAX) {
529 			return (ARCHIVE_WARN);
530 		}
531 		if (threads == 0) {
532 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
533 			threads = sysconf(_SC_NPROCESSORS_ONLN);
534 #elif !defined(__CYGWIN__) && defined(_WIN32_WINNT) && \
535 	_WIN32_WINNT >= 0x0601 /* _WIN32_WINNT_WIN7 */
536 			DWORD winCores = GetActiveProcessorCount(
537 				ALL_PROCESSOR_GROUPS);
538 			threads = (intmax_t)winCores;
539 #else
540 			threads = 1;
541 #endif
542 		}
543 
544 		zip->opt_threads = (int)threads;
545 		return (ARCHIVE_OK);
546 	}
547 
548 	/* Note: The "warn" return is just to inform the options
549 	 * supervisor that we didn't handle it.  It will generate
550 	 * a suitable error if no one used this option. */
551 	return (ARCHIVE_WARN);
552 }
553 
554 static int
_7z_write_header(struct archive_write * a,struct archive_entry * entry)555 _7z_write_header(struct archive_write *a, struct archive_entry *entry)
556 {
557 	struct _7zip *zip = a->format_data;
558 	struct file *file;
559 	int r;
560 
561 	zip->cur_file = NULL;
562 	zip->entry_bytes_remaining = 0;
563 
564 	if (zip->sconv == NULL) {
565 		zip->sconv = archive_string_conversion_to_charset(
566 		    &a->archive, "UTF-16LE", 1);
567 		if (zip->sconv == NULL)
568 			return (ARCHIVE_FATAL);
569 	}
570 
571 	r = file_new(a, entry, &file);
572 	if (r < ARCHIVE_WARN) {
573 		if (file != NULL)
574 			file_free(file);
575 		return (r);
576 	}
577 	if (file->size == 0 && file->dir) {
578 		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
579 		    (struct archive_rb_node *)file)) {
580 			/* We have already had the same file. */
581 			file_free(file);
582 			return (ARCHIVE_OK);
583 		}
584 	}
585 
586 	if (file->flg & MTIME_IS_SET)
587 		zip->total_number_time_defined[MTIME]++;
588 	if (file->flg & CTIME_IS_SET)
589 		zip->total_number_time_defined[CTIME]++;
590 	if (file->flg & ATIME_IS_SET)
591 		zip->total_number_time_defined[ATIME]++;
592 
593 	zip->total_number_entry++;
594 	zip->total_bytes_entry_name += file->name_len + 2;
595 	if (file->size == 0) {
596 		/* Count up the number of empty files. */
597 		zip->total_number_empty_entry++;
598 		if (file->dir)
599 			zip->total_number_dir_entry++;
600 		else
601 			file_register_empty(zip, file);
602 		return (r);
603 	}
604 
605 	/*
606 	 * Init compression.
607 	 */
608 	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
609 
610 		int level = zip->opt_compression_level;
611 #if HAVE_ZSTD_H
612 		if (zip->opt_compression == _7Z_ZSTD) {
613 			level = zip->opt_zstd_compression_level;
614 		} else if (level < 0 || level > 9) {
615 			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
616 				"compression-level option value `%d' out of range 0-9", level);
617 			file_free(file);
618 			return (ARCHIVE_FATAL);
619 		}
620 #endif
621 
622 		r = _7z_compression_init_encoder(a, zip->opt_compression, level);
623 		if (r < 0) {
624 			file_free(file);
625 			return (ARCHIVE_FATAL);
626 		}
627 	}
628 
629 	/* Register a non-empty file. */
630 	file_register(zip, file);
631 
632 	/*
633 	 * Set the current file to cur_file to read its contents.
634 	 */
635 	zip->cur_file = file;
636 
637 
638 	/* Save a offset of current file in temporary file. */
639 	zip->entry_bytes_remaining = file->size;
640 	zip->entry_crc32 = 0;
641 
642 	/*
643 	 * Store a symbolic link name as file contents.
644 	 */
645 	if (archive_entry_filetype(entry) == AE_IFLNK) {
646 		ssize_t bytes;
647 		const void *p = (const void *)archive_entry_symlink_utf8(entry);
648 		bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
649 		if (bytes < 0)
650 			return ((int)bytes);
651 		zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
652 		zip->entry_bytes_remaining -= bytes;
653 	}
654 
655 	return (r);
656 }
657 
658 /*
659  * Write data to a temporary file.
660  */
661 static int
write_to_temp(struct archive_write * a,const void * buff,size_t s)662 write_to_temp(struct archive_write *a, const void *buff, size_t s)
663 {
664 	struct _7zip *zip = a->format_data;
665 	const unsigned char *p;
666 	ssize_t ws;
667 
668 	/*
669 	 * Open a temporary file.
670 	 */
671 	if (zip->temp_fd == -1) {
672 		zip->temp_offset = 0;
673 		zip->temp_fd = __archive_mktemp(NULL);
674 		if (zip->temp_fd < 0) {
675 			archive_set_error(&a->archive, errno,
676 			    "Couldn't create temporary file");
677 			return (ARCHIVE_FATAL);
678 		}
679 	}
680 
681 	p = (const unsigned char *)buff;
682 	while (s) {
683 		ws = write(zip->temp_fd, p, s);
684 		if (ws < 0) {
685 			archive_set_error(&(a->archive), errno,
686 			    "write function failed");
687 			return (ARCHIVE_FATAL);
688 		}
689 		s -= ws;
690 		p += ws;
691 		zip->temp_offset += ws;
692 	}
693 	return (ARCHIVE_OK);
694 }
695 
696 static ssize_t
compress_out(struct archive_write * a,const void * buff,size_t s,enum la_zaction run)697 compress_out(struct archive_write *a, const void *buff, size_t s,
698     enum la_zaction run)
699 {
700 	struct _7zip *zip = a->format_data;
701 	int r;
702 
703 	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
704 		return (0);
705 
706 	if ((zip->crc32flg & PRECODE_CRC32) && s)
707 		zip->precode_crc32 = crc32(zip->precode_crc32, buff,
708 		    (unsigned)s);
709 	zip->stream.next_in = (const unsigned char *)buff;
710 	zip->stream.avail_in = s;
711 	for (;;) {
712 		/* Compress file data. */
713 		r = compression_code(&(a->archive), &(zip->stream), run);
714 		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
715 			return (ARCHIVE_FATAL);
716 		if (zip->stream.avail_out == 0) {
717 			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
718 			    != ARCHIVE_OK)
719 				return (ARCHIVE_FATAL);
720 			zip->stream.next_out = zip->wbuff;
721 			zip->stream.avail_out = sizeof(zip->wbuff);
722 			if (zip->crc32flg & ENCODED_CRC32)
723 				zip->encoded_crc32 = crc32(zip->encoded_crc32,
724 				    zip->wbuff, sizeof(zip->wbuff));
725 			if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
726 				continue;
727 		}
728 		if (zip->stream.avail_in == 0)
729 			break;
730 	}
731 	if (run == ARCHIVE_Z_FINISH) {
732 		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
733 		if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
734 			return (ARCHIVE_FATAL);
735 		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
736 			zip->encoded_crc32 = crc32(zip->encoded_crc32,
737 			    zip->wbuff, (unsigned)bytes);
738 	}
739 
740 	return (s);
741 }
742 
743 static ssize_t
_7z_write_data(struct archive_write * a,const void * buff,size_t s)744 _7z_write_data(struct archive_write *a, const void *buff, size_t s)
745 {
746 	struct _7zip *zip = a->format_data;
747 	ssize_t bytes;
748 
749 	if (s > zip->entry_bytes_remaining)
750 		s = (size_t)zip->entry_bytes_remaining;
751 	if (s == 0 || zip->cur_file == NULL)
752 		return (0);
753 	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
754 	if (bytes < 0)
755 		return (bytes);
756 	zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
757 	zip->entry_bytes_remaining -= bytes;
758 	return (bytes);
759 }
760 
761 static int
_7z_finish_entry(struct archive_write * a)762 _7z_finish_entry(struct archive_write *a)
763 {
764 	struct _7zip *zip = a->format_data;
765 	size_t s;
766 	ssize_t r;
767 
768 	if (zip->cur_file == NULL)
769 		return (ARCHIVE_OK);
770 
771 	while (zip->entry_bytes_remaining > 0) {
772 		s = (size_t)zip->entry_bytes_remaining;
773 		if (s > a->null_length)
774 			s = a->null_length;
775 		r = _7z_write_data(a, a->nulls, s);
776 		if (r < 0)
777 			return ((int)r);
778 	}
779 	zip->cur_file->crc32 = zip->entry_crc32;
780 	zip->cur_file = NULL;
781 
782 	return (ARCHIVE_OK);
783 }
784 
785 static int
flush_wbuff(struct archive_write * a)786 flush_wbuff(struct archive_write *a)
787 {
788 	struct _7zip *zip = a->format_data;
789 	int r;
790 	size_t s;
791 
792 	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
793 	r = __archive_write_output(a, zip->wbuff, s);
794 	if (r != ARCHIVE_OK)
795 		return (r);
796 	zip->wbuff_remaining = sizeof(zip->wbuff);
797 	return (r);
798 }
799 
800 static int
copy_out(struct archive_write * a,uint64_t offset,uint64_t length)801 copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
802 {
803 	struct _7zip *zip = a->format_data;
804 	int r;
805 
806 	if (zip->temp_offset > 0 &&
807 	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
808 		archive_set_error(&(a->archive), errno, "lseek failed");
809 		return (ARCHIVE_FATAL);
810 	}
811 	while (length) {
812 		size_t rsize;
813 		ssize_t rs;
814 		unsigned char *wb;
815 
816 		if (length > zip->wbuff_remaining)
817 			rsize = zip->wbuff_remaining;
818 		else
819 			rsize = (size_t)length;
820 		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
821 		rs = read(zip->temp_fd, wb, rsize);
822 		if (rs < 0) {
823 			archive_set_error(&(a->archive), errno,
824 			    "Can't read temporary file(%jd)",
825 			    (intmax_t)rs);
826 			return (ARCHIVE_FATAL);
827 		}
828 		if (rs == 0) {
829 			archive_set_error(&(a->archive),
830 			    ARCHIVE_ERRNO_FILE_FORMAT,
831 			    "Truncated 7-Zip archive");
832 			return (ARCHIVE_FATAL);
833 		}
834 		zip->wbuff_remaining -= rs;
835 		length -= rs;
836 		if (zip->wbuff_remaining == 0) {
837 			r = flush_wbuff(a);
838 			if (r != ARCHIVE_OK)
839 				return (r);
840 		}
841 	}
842 	return (ARCHIVE_OK);
843 }
844 
845 static int
_7z_close(struct archive_write * a)846 _7z_close(struct archive_write *a)
847 {
848 	struct _7zip *zip = a->format_data;
849 	unsigned char *wb;
850 	uint64_t header_offset, header_size, header_unpacksize;
851 	uint64_t length;
852 	uint32_t header_crc32;
853 	int r;
854 
855 	if (zip->total_number_entry > 0) {
856 		struct archive_rb_node *n;
857 		uint64_t data_offset, data_size, data_unpacksize;
858 		unsigned header_compression;
859 
860 		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
861 		if (r < 0)
862 			return (r);
863 		data_offset = 0;
864 		data_size = zip->stream.total_out;
865 		data_unpacksize = zip->stream.total_in;
866 		zip->coder.codec = zip->opt_compression;
867 		zip->coder.prop_size = zip->stream.prop_size;
868 		zip->coder.props = zip->stream.props;
869 		zip->stream.prop_size = 0;
870 		zip->stream.props = NULL;
871 		zip->total_number_nonempty_entry =
872 		    zip->total_number_entry - zip->total_number_empty_entry;
873 
874 		/* Connect an empty file list. */
875 		if (zip->empty_list.first != NULL) {
876 			*zip->file_list.last = zip->empty_list.first;
877 			zip->file_list.last = zip->empty_list.last;
878 		}
879 		/* Connect a directory file list. */
880 		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
881 			file_register(zip, (struct file *)n);
882 		}
883 
884 		/*
885 		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
886 		 * the compression type for encoding the header.
887 		 */
888 #if HAVE_LZMA_H
889 		header_compression = _7Z_LZMA1;
890 		if(zip->opt_compression == _7Z_LZMA2 ||
891 		   zip->opt_compression == _7Z_COPY)
892 			header_compression = zip->opt_compression;
893 
894 		/* If the stored file is only one, do not encode the header.
895 		 * This is the same way 7z command does. */
896 		if (zip->total_number_entry == 1)
897 			header_compression = _7Z_COPY;
898 #else
899 		header_compression = _7Z_COPY;
900 #endif
901 
902 		int level = zip->opt_compression_level;
903 		if (level < 0) level = 0;
904 		else if (level > 9) level = 9;
905 
906 		r = _7z_compression_init_encoder(a, header_compression, level);
907 		if (r < 0)
908 			return (r);
909 		zip->crc32flg = PRECODE_CRC32;
910 		zip->precode_crc32 = 0;
911 		r = make_header(a, data_offset, data_size, data_unpacksize,
912 			1, &(zip->coder));
913 		if (r < 0)
914 			return (r);
915 		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
916 		if (r < 0)
917 			return (r);
918 		header_offset = data_offset + data_size;
919 		header_size = zip->stream.total_out;
920 		header_crc32 = zip->precode_crc32;
921 		header_unpacksize = zip->stream.total_in;
922 
923 		if (header_compression != _7Z_COPY) {
924 			/*
925 			 * Encode the header in order to reduce the size
926 			 * of the archive.
927 			 */
928 			free(zip->coder.props);
929 			zip->coder.codec = header_compression;
930 			zip->coder.prop_size = zip->stream.prop_size;
931 			zip->coder.props = zip->stream.props;
932 			zip->stream.prop_size = 0;
933 			zip->stream.props = NULL;
934 
935 			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
936 			if (r < 0)
937 				return (r);
938 			zip->crc32flg = ENCODED_CRC32;
939 			zip->encoded_crc32 = 0;
940 
941 			/*
942 			 * Make EncodedHeader.
943 			 */
944 			r = enc_uint64(a, kEncodedHeader);
945 			if (r < 0)
946 				return (r);
947 			r = make_streamsInfo(a, header_offset, header_size,
948 			      header_unpacksize, 1, &(zip->coder), 0,
949 			      header_crc32);
950 			if (r < 0)
951 				return (r);
952 			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
953 			if (r < 0)
954 				return (r);
955 			header_offset = header_offset + header_size;
956 			header_size = zip->stream.total_out;
957 			header_crc32 = zip->encoded_crc32;
958 		}
959 		zip->crc32flg = 0;
960 	} else {
961 		header_offset = header_size = 0;
962 		header_crc32 = 0;
963 	}
964 
965 	length = zip->temp_offset;
966 
967 	/*
968 	 * Make the zip header on wbuff(write buffer).
969 	 */
970 	wb = zip->wbuff;
971 	zip->wbuff_remaining = sizeof(zip->wbuff);
972 	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
973 	wb[6] = 0;/* Major version. */
974 	wb[7] = 3;/* Minor version. */
975 	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
976 	archive_le64enc(&wb[20], header_size);/* Next Header Size */
977 	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
978 	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
979 	zip->wbuff_remaining -= 32;
980 
981 	/*
982 	 * Read all file contents and an encoded header from the temporary
983 	 * file and write out it.
984 	 */
985 	r = copy_out(a, 0, length);
986 	if (r != ARCHIVE_OK)
987 		return (r);
988 	r = flush_wbuff(a);
989 	return (r);
990 }
991 
992 /*
993  * Encode 64 bits value into 7-Zip's encoded UINT64 value.
994  */
995 static int
enc_uint64(struct archive_write * a,uint64_t val)996 enc_uint64(struct archive_write *a, uint64_t val)
997 {
998 	unsigned mask = 0x80;
999 	uint8_t numdata[9];
1000 	int i;
1001 
1002 	numdata[0] = 0;
1003 	for (i = 1; i < (int)sizeof(numdata); i++) {
1004 		if (val < mask) {
1005 			numdata[0] |= (uint8_t)val;
1006 			break;
1007 		}
1008 		numdata[i] = (uint8_t)val;
1009 		val >>= 8;
1010 		numdata[0] |= mask;
1011 		mask >>= 1;
1012 	}
1013 	return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
1014 }
1015 
1016 static int
make_substreamsInfo(struct archive_write * a,struct coder * coders)1017 make_substreamsInfo(struct archive_write *a, struct coder *coders)
1018 {
1019 	struct _7zip *zip = a->format_data;
1020 	struct file *file;
1021 	int r;
1022 
1023 	/*
1024 	 * Make SubStreamsInfo.
1025 	 */
1026 	r = enc_uint64(a, kSubStreamsInfo);
1027 	if (r < 0)
1028 		return (r);
1029 
1030 	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
1031 		/*
1032 		 * Make NumUnPackStream.
1033 		 */
1034 		r = enc_uint64(a, kNumUnPackStream);
1035 		if (r < 0)
1036 			return (r);
1037 
1038 		/* Write numUnpackStreams */
1039 		r = enc_uint64(a, zip->total_number_nonempty_entry);
1040 		if (r < 0)
1041 			return (r);
1042 
1043 		/*
1044 		 * Make kSize.
1045 		 */
1046 		r = enc_uint64(a, kSize);
1047 		if (r < 0)
1048 			return (r);
1049 		file = zip->file_list.first;
1050 		for (;file != NULL; file = file->next) {
1051 			if (file->next == NULL ||
1052 			    file->next->size == 0)
1053 				break;
1054 			r = enc_uint64(a, file->size);
1055 			if (r < 0)
1056 				return (r);
1057 		}
1058 	}
1059 
1060 	/*
1061 	 * Make CRC.
1062 	 */
1063 	r = enc_uint64(a, kCRC);
1064 	if (r < 0)
1065 		return (r);
1066 
1067 
1068 	/* All are defined */
1069 	r = enc_uint64(a, 1);
1070 	if (r < 0)
1071 		return (r);
1072 	file = zip->file_list.first;
1073 	for (;file != NULL; file = file->next) {
1074 		uint8_t crc[4];
1075 		if (file->size == 0)
1076 			break;
1077 		archive_le32enc(crc, file->crc32);
1078 		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
1079 		if (r < 0)
1080 			return (r);
1081 	}
1082 
1083 	/* Write End. */
1084 	r = enc_uint64(a, kEnd);
1085 	if (r < 0)
1086 		return (r);
1087 	return (ARCHIVE_OK);
1088 }
1089 
1090 static int
make_streamsInfo(struct archive_write * a,uint64_t offset,uint64_t pack_size,uint64_t unpack_size,int num_coder,struct coder * coders,int substrm,uint32_t header_crc)1091 make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
1092     uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
1093     uint32_t header_crc)
1094 {
1095 	struct _7zip *zip = a->format_data;
1096 	uint8_t codec_buff[8];
1097 	int numFolders, fi;
1098 	int codec_size;
1099 	int i, r;
1100 
1101 	if (coders->codec == _7Z_COPY)
1102 		numFolders = (int)zip->total_number_nonempty_entry;
1103 	else
1104 		numFolders = 1;
1105 
1106 	/*
1107 	 * Make PackInfo.
1108 	 */
1109 	r = enc_uint64(a, kPackInfo);
1110 	if (r < 0)
1111 		return (r);
1112 
1113 	/* Write PackPos. */
1114 	r = enc_uint64(a, offset);
1115 	if (r < 0)
1116 		return (r);
1117 
1118 	/* Write NumPackStreams. */
1119 	r = enc_uint64(a, numFolders);
1120 	if (r < 0)
1121 		return (r);
1122 
1123 	/* Make Size. */
1124 	r = enc_uint64(a, kSize);
1125 	if (r < 0)
1126 		return (r);
1127 
1128 	if (numFolders > 1) {
1129 		struct file *file = zip->file_list.first;
1130 		for (;file != NULL; file = file->next) {
1131 			if (file->size == 0)
1132 				break;
1133 			r = enc_uint64(a, file->size);
1134 			if (r < 0)
1135 				return (r);
1136 		}
1137 	} else {
1138 		/* Write size. */
1139 		r = enc_uint64(a, pack_size);
1140 		if (r < 0)
1141 			return (r);
1142 	}
1143 
1144 	r = enc_uint64(a, kEnd);
1145 	if (r < 0)
1146 		return (r);
1147 
1148 	/*
1149 	 * Make UnPackInfo.
1150 	 */
1151 	r = enc_uint64(a, kUnPackInfo);
1152 	if (r < 0)
1153 		return (r);
1154 
1155 	/*
1156 	 * Make Folder.
1157 	 */
1158 	r = enc_uint64(a, kFolder);
1159 	if (r < 0)
1160 		return (r);
1161 
1162 	/* Write NumFolders. */
1163 	r = enc_uint64(a, numFolders);
1164 	if (r < 0)
1165 		return (r);
1166 
1167 	/* Write External. */
1168 	r = enc_uint64(a, 0);
1169 	if (r < 0)
1170 		return (r);
1171 
1172 	for (fi = 0; fi < numFolders; fi++) {
1173 		/* Write NumCoders. */
1174 		r = enc_uint64(a, num_coder);
1175 		if (r < 0)
1176 			return (r);
1177 
1178 		for (i = 0; i < num_coder; i++) {
1179 			unsigned codec_id = coders[i].codec;
1180 
1181 			/* Write Codec flag. */
1182 			archive_be64enc(codec_buff, codec_id);
1183 			for (codec_size = 8; codec_size > 0; codec_size--) {
1184 				if (codec_buff[8 - codec_size])
1185 					break;
1186 			}
1187 			if (codec_size == 0)
1188 				codec_size = 1;
1189 			if (coders[i].prop_size)
1190 				r = enc_uint64(a, codec_size | 0x20);
1191 			else
1192 				r = enc_uint64(a, codec_size);
1193 			if (r < 0)
1194 				return (r);
1195 
1196 			/* Write Codec ID. */
1197 			codec_size &= 0x0f;
1198 			r = (int)compress_out(a, &codec_buff[8-codec_size],
1199 				codec_size, ARCHIVE_Z_RUN);
1200 			if (r < 0)
1201 				return (r);
1202 
1203 			if (coders[i].prop_size) {
1204 				/* Write Codec property size. */
1205 				r = enc_uint64(a, coders[i].prop_size);
1206 				if (r < 0)
1207 					return (r);
1208 
1209 				/* Write Codec properties. */
1210 				r = (int)compress_out(a, coders[i].props,
1211 					coders[i].prop_size, ARCHIVE_Z_RUN);
1212 				if (r < 0)
1213 					return (r);
1214 			}
1215 		}
1216 	}
1217 
1218 	/*
1219 	 * Make CodersUnPackSize.
1220 	 */
1221 	r = enc_uint64(a, kCodersUnPackSize);
1222 	if (r < 0)
1223 		return (r);
1224 
1225 	if (numFolders > 1) {
1226 		struct file *file = zip->file_list.first;
1227 		for (;file != NULL; file = file->next) {
1228 			if (file->size == 0)
1229 				break;
1230 			r = enc_uint64(a, file->size);
1231 			if (r < 0)
1232 				return (r);
1233 		}
1234 
1235 	} else {
1236 		/* Write UnPackSize. */
1237 		r = enc_uint64(a, unpack_size);
1238 		if (r < 0)
1239 			return (r);
1240 	}
1241 
1242 	if (!substrm) {
1243 		uint8_t crc[4];
1244 		/*
1245 		 * Make CRC.
1246 		 */
1247 		r = enc_uint64(a, kCRC);
1248 		if (r < 0)
1249 			return (r);
1250 
1251 		/* All are defined */
1252 		r = enc_uint64(a, 1);
1253 		if (r < 0)
1254 			return (r);
1255 		archive_le32enc(crc, header_crc);
1256 		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
1257 		if (r < 0)
1258 			return (r);
1259 	}
1260 
1261 	/* Write End. */
1262 	r = enc_uint64(a, kEnd);
1263 	if (r < 0)
1264 		return (r);
1265 
1266 	if (substrm) {
1267 		/*
1268 		 * Make SubStreamsInfo.
1269 		 */
1270 		r = make_substreamsInfo(a, coders);
1271 		if (r < 0)
1272 			return (r);
1273 	}
1274 
1275 
1276 	/* Write End. */
1277 	r = enc_uint64(a, kEnd);
1278 	if (r < 0)
1279 		return (r);
1280 
1281 	return (ARCHIVE_OK);
1282 }
1283 
1284 static int
make_time(struct archive_write * a,uint8_t type,unsigned flg,int ti)1285 make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
1286 {
1287 	struct _7zip *zip = a->format_data;
1288 	uint8_t filetime[8];
1289 	struct file *file;
1290 	int r;
1291 	uint8_t b, mask;
1292 
1293 	/*
1294 	 * Make Time Bools.
1295 	 */
1296 	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
1297 		/* Write Time Type. */
1298 		r = enc_uint64(a, type);
1299 		if (r < 0)
1300 			return (r);
1301 		/* Write EmptyStream Size. */
1302 		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
1303 		if (r < 0)
1304 			return (r);
1305 		/* All are defined. */
1306 		r = enc_uint64(a, 1);
1307 		if (r < 0)
1308 			return (r);
1309 	} else {
1310 		if (zip->total_number_time_defined[ti] == 0)
1311 			return (ARCHIVE_OK);
1312 
1313 		/* Write Time Type. */
1314 		r = enc_uint64(a, type);
1315 		if (r < 0)
1316 			return (r);
1317 		/* Write EmptyStream Size. */
1318 		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
1319 			+ zip->total_number_time_defined[ti] * 8);
1320 		if (r < 0)
1321 			return (r);
1322 
1323 		/* All are not defined. */
1324 		r = enc_uint64(a, 0);
1325 		if (r < 0)
1326 			return (r);
1327 
1328 		b = 0;
1329 		mask = 0x80;
1330 		file = zip->file_list.first;
1331 		for (;file != NULL; file = file->next) {
1332 			if (file->flg & flg)
1333 				b |= mask;
1334 			mask >>= 1;
1335 			if (mask == 0) {
1336 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1337 				if (r < 0)
1338 					return (r);
1339 				mask = 0x80;
1340 				b = 0;
1341 			}
1342 		}
1343 		if (mask != 0x80) {
1344 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1345 			if (r < 0)
1346 				return (r);
1347 		}
1348 	}
1349 
1350 	/* External. */
1351 	r = enc_uint64(a, 0);
1352 	if (r < 0)
1353 		return (r);
1354 
1355 	/*
1356 	 * Make Times.
1357 	 */
1358 	file = zip->file_list.first;
1359 	for (;file != NULL; file = file->next) {
1360 		if ((file->flg & flg) == 0)
1361 			continue;
1362 		archive_le64enc(filetime, unix_to_ntfs(file->times[ti].time,
1363 			file->times[ti].time_ns));
1364 		r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
1365 		if (r < 0)
1366 			return (r);
1367 	}
1368 
1369 	return (ARCHIVE_OK);
1370 }
1371 
1372 static int
make_header(struct archive_write * a,uint64_t offset,uint64_t pack_size,uint64_t unpack_size,int codernum,struct coder * coders)1373 make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
1374     uint64_t unpack_size, int codernum, struct coder *coders)
1375 {
1376 	struct _7zip *zip = a->format_data;
1377 	struct file *file;
1378 	int r;
1379 	uint8_t b, mask;
1380 
1381 	/*
1382 	 * Make FilesInfo.
1383 	 */
1384 	r = enc_uint64(a, kHeader);
1385 	if (r < 0)
1386 		return (r);
1387 
1388 	/*
1389 	 * If there are empty files only, do not write MainStreamInfo.
1390 	 */
1391 	if (zip->total_number_nonempty_entry) {
1392 		/*
1393 		 * Make MainStreamInfo.
1394 		 */
1395 		r = enc_uint64(a, kMainStreamsInfo);
1396 		if (r < 0)
1397 			return (r);
1398 		r = make_streamsInfo(a, offset, pack_size, unpack_size,
1399 		      codernum, coders, 1, 0);
1400 		if (r < 0)
1401 			return (r);
1402 	}
1403 
1404 	/*
1405 	 * Make FilesInfo.
1406 	 */
1407 	r = enc_uint64(a, kFilesInfo);
1408 	if (r < 0)
1409 		return (r);
1410 
1411 	/* Write numFiles. */
1412 	r = enc_uint64(a, zip->total_number_entry);
1413 	if (r < 0)
1414 		return (r);
1415 
1416 	if (zip->total_number_empty_entry > 0) {
1417 		/* Make EmptyStream. */
1418 		r = enc_uint64(a, kEmptyStream);
1419 		if (r < 0)
1420 			return (r);
1421 
1422 		/* Write EmptyStream Size. */
1423 		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
1424 		if (r < 0)
1425 			return (r);
1426 
1427 		b = 0;
1428 		mask = 0x80;
1429 		file = zip->file_list.first;
1430 		for (;file != NULL; file = file->next) {
1431 			if (file->size == 0)
1432 				b |= mask;
1433 			mask >>= 1;
1434 			if (mask == 0) {
1435 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1436 				if (r < 0)
1437 					return (r);
1438 				mask = 0x80;
1439 				b = 0;
1440 			}
1441 		}
1442 		if (mask != 0x80) {
1443 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1444 			if (r < 0)
1445 				return (r);
1446 		}
1447 	}
1448 
1449 	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
1450 		/* Make EmptyFile. */
1451 		r = enc_uint64(a, kEmptyFile);
1452 		if (r < 0)
1453 			return (r);
1454 
1455 		/* Write EmptyFile Size. */
1456 		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
1457 		if (r < 0)
1458 			return (r);
1459 
1460 		b = 0;
1461 		mask = 0x80;
1462 		file = zip->file_list.first;
1463 		for (;file != NULL; file = file->next) {
1464 			if (file->size)
1465 				continue;
1466 			if (!file->dir)
1467 				b |= mask;
1468 			mask >>= 1;
1469 			if (mask == 0) {
1470 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1471 				if (r < 0)
1472 					return (r);
1473 				mask = 0x80;
1474 				b = 0;
1475 			}
1476 		}
1477 		if (mask != 0x80) {
1478 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1479 			if (r < 0)
1480 				return (r);
1481 		}
1482 	}
1483 
1484 	/* Make Name. */
1485 	r = enc_uint64(a, kName);
1486 	if (r < 0)
1487 		return (r);
1488 
1489 	/* Write Name size. */
1490 	r = enc_uint64(a, zip->total_bytes_entry_name+1);
1491 	if (r < 0)
1492 		return (r);
1493 
1494 	/* Write dmy byte. */
1495 	r = enc_uint64(a, 0);
1496 	if (r < 0)
1497 		return (r);
1498 
1499 	file = zip->file_list.first;
1500 	for (;file != NULL; file = file->next) {
1501 		r = (int)compress_out(a, file->utf16name, file->name_len+2,
1502 			ARCHIVE_Z_RUN);
1503 		if (r < 0)
1504 			return (r);
1505 	}
1506 
1507 	/* Make MTime. */
1508 	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
1509 	if (r < 0)
1510 		return (r);
1511 
1512 	/* Make CTime. */
1513 	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
1514 	if (r < 0)
1515 		return (r);
1516 
1517 	/* Make ATime. */
1518 	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
1519 	if (r < 0)
1520 		return (r);
1521 
1522 	/* Make Attributes. */
1523 	r = enc_uint64(a, kAttributes);
1524 	if (r < 0)
1525 		return (r);
1526 
1527 	/* Write Attributes size. */
1528 	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
1529 	if (r < 0)
1530 		return (r);
1531 
1532 	/* Write "All Are Defined". */
1533 	r = enc_uint64(a, 1);
1534 	if (r < 0)
1535 		return (r);
1536 
1537 	/* Write dmy byte. */
1538 	r = enc_uint64(a, 0);
1539 	if (r < 0)
1540 		return (r);
1541 
1542 	file = zip->file_list.first;
1543 	for (;file != NULL; file = file->next) {
1544 		/*
1545 		 * High 16bits is unix mode.
1546 		 * Low 16bits is Windows attributes.
1547 		 */
1548 		uint32_t encattr, attr = 0;
1549 
1550 		if (file->dir)
1551 			attr |= FILE_ATTRIBUTE_DIRECTORY;
1552 		else
1553 			attr |= FILE_ATTRIBUTE_ARCHIVE;
1554 
1555 		if ((file->mode & 0222) == 0)
1556 			attr |= FILE_ATTRIBUTE_READONLY;
1557 
1558 		attr |= FILE_ATTRIBUTE_UNIX_EXTENSION;
1559 		attr |= ((uint32_t)file->mode) << 16;
1560 
1561 		archive_le32enc(&encattr, attr);
1562 		r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
1563 		if (r < 0)
1564 			return (r);
1565 	}
1566 
1567 	/* Write End. */
1568 	r = enc_uint64(a, kEnd);
1569 	if (r < 0)
1570 		return (r);
1571 
1572 	/* Write End. */
1573 	r = enc_uint64(a, kEnd);
1574 	if (r < 0)
1575 		return (r);
1576 
1577 	return (ARCHIVE_OK);
1578 }
1579 
1580 
1581 static int
_7z_free(struct archive_write * a)1582 _7z_free(struct archive_write *a)
1583 {
1584 	struct _7zip *zip = a->format_data;
1585 
1586 	/* Close the temporary file. */
1587 	if (zip->temp_fd >= 0)
1588 		close(zip->temp_fd);
1589 
1590 	file_free_register(zip);
1591 	compression_end(&(a->archive), &(zip->stream));
1592 	free(zip->coder.props);
1593 	free(zip);
1594 
1595 	return (ARCHIVE_OK);
1596 }
1597 
1598 static int
file_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)1599 file_cmp_node(const struct archive_rb_node *n1,
1600     const struct archive_rb_node *n2)
1601 {
1602 	const struct file *f1 = (const struct file *)n1;
1603 	const struct file *f2 = (const struct file *)n2;
1604 
1605 	if (f1->name_len == f2->name_len)
1606 		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
1607 	return (f1->name_len > f2->name_len)?1:-1;
1608 }
1609 
1610 static int
file_cmp_key(const struct archive_rb_node * n,const void * key)1611 file_cmp_key(const struct archive_rb_node *n, const void *key)
1612 {
1613 	const struct file *f = (const struct file *)n;
1614 
1615 	return (f->name_len - *(const char *)key);
1616 }
1617 
1618 static int
file_new(struct archive_write * a,struct archive_entry * entry,struct file ** newfile)1619 file_new(struct archive_write *a, struct archive_entry *entry,
1620     struct file **newfile)
1621 {
1622 	struct _7zip *zip = a->format_data;
1623 	struct file *file;
1624 	const char *u16;
1625 	size_t u16len;
1626 	int ret = ARCHIVE_OK;
1627 
1628 	*newfile = NULL;
1629 
1630 	file = calloc(1, sizeof(*file));
1631 	if (file == NULL) {
1632 		archive_set_error(&a->archive, ENOMEM,
1633 		    "Can't allocate memory");
1634 		return (ARCHIVE_FATAL);
1635 	}
1636 
1637 	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
1638 		if (errno == ENOMEM) {
1639 			free(file);
1640 			archive_set_error(&a->archive, ENOMEM,
1641 			    "Can't allocate memory for UTF-16LE");
1642 			return (ARCHIVE_FATAL);
1643 		}
1644 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1645 		    "A filename cannot be converted to UTF-16LE;"
1646 		    "You should disable making Joliet extension");
1647 		ret = ARCHIVE_WARN;
1648 	}
1649 	file->utf16name = malloc(u16len + 2);
1650 	if (file->utf16name == NULL) {
1651 		free(file);
1652 		archive_set_error(&a->archive, ENOMEM,
1653 		    "Can't allocate memory for Name");
1654 		return (ARCHIVE_FATAL);
1655 	}
1656 	memcpy(file->utf16name, u16, u16len);
1657 	file->utf16name[u16len+0] = 0;
1658 	file->utf16name[u16len+1] = 0;
1659 	file->name_len = (unsigned)u16len;
1660 	file->mode = archive_entry_mode(entry);
1661 	if (archive_entry_filetype(entry) == AE_IFREG)
1662 		file->size = archive_entry_size(entry);
1663 	else
1664 		archive_entry_set_size(entry, 0);
1665 	if (archive_entry_filetype(entry) == AE_IFDIR)
1666 		file->dir = 1;
1667 	else if (archive_entry_filetype(entry) == AE_IFLNK) {
1668 		const char* linkpath;
1669 		linkpath = archive_entry_symlink_utf8(entry);
1670 		if (linkpath == NULL) {
1671 			file_free(file);
1672 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1673 			    "symlink path could not be converted to UTF-8");
1674 			return (ARCHIVE_FAILED);
1675 		}
1676 		else
1677 			file->size = strlen(linkpath);
1678 	}
1679 	if (archive_entry_mtime_is_set(entry)) {
1680 		file->flg |= MTIME_IS_SET;
1681 		file->times[MTIME].time = archive_entry_mtime(entry);
1682 		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
1683 	}
1684 	if (archive_entry_atime_is_set(entry)) {
1685 		file->flg |= ATIME_IS_SET;
1686 		file->times[ATIME].time = archive_entry_atime(entry);
1687 		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
1688 	}
1689 	if (archive_entry_ctime_is_set(entry)) {
1690 		file->flg |= CTIME_IS_SET;
1691 		file->times[CTIME].time = archive_entry_ctime(entry);
1692 		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
1693 	}
1694 
1695 	*newfile = file;
1696 	return (ret);
1697 }
1698 
1699 static void
file_free(struct file * file)1700 file_free(struct file *file)
1701 {
1702 	free(file->utf16name);
1703 	free(file);
1704 }
1705 
1706 static void
file_register(struct _7zip * zip,struct file * file)1707 file_register(struct _7zip *zip, struct file *file)
1708 {
1709 	file->next = NULL;
1710 	*zip->file_list.last = file;
1711 	zip->file_list.last = &(file->next);
1712 }
1713 
1714 static void
file_init_register(struct _7zip * zip)1715 file_init_register(struct _7zip *zip)
1716 {
1717 	zip->file_list.first = NULL;
1718 	zip->file_list.last = &(zip->file_list.first);
1719 }
1720 
1721 static void
file_free_register(struct _7zip * zip)1722 file_free_register(struct _7zip *zip)
1723 {
1724 	struct file *file, *file_next;
1725 
1726 	file = zip->file_list.first;
1727 	while (file != NULL) {
1728 		file_next = file->next;
1729 		file_free(file);
1730 		file = file_next;
1731 	}
1732 }
1733 
1734 static void
file_register_empty(struct _7zip * zip,struct file * file)1735 file_register_empty(struct _7zip *zip, struct file *file)
1736 {
1737 	file->next = NULL;
1738 	*zip->empty_list.last = file;
1739 	zip->empty_list.last = &(file->next);
1740 }
1741 
1742 static void
file_init_register_empty(struct _7zip * zip)1743 file_init_register_empty(struct _7zip *zip)
1744 {
1745 	zip->empty_list.first = NULL;
1746 	zip->empty_list.last = &(zip->empty_list.first);
1747 }
1748 
1749 #if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
1750 	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H) ||\
1751 	 !(HAVE_ZSTD_H && HAVE_ZSTD_compressStream)
1752 static int
compression_unsupported_encoder(struct archive * a,struct la_zstream * lastrm,const char * name)1753 compression_unsupported_encoder(struct archive *a,
1754     struct la_zstream *lastrm, const char *name)
1755 {
1756 
1757 	archive_set_error(a, ARCHIVE_ERRNO_MISC,
1758 	    "%s compression not supported on this platform", name);
1759 	lastrm->valid = 0;
1760 	lastrm->real_stream = NULL;
1761 	return (ARCHIVE_FAILED);
1762 }
1763 #endif
1764 
1765 /*
1766  * _7_COPY compressor.
1767  */
1768 static int
compression_init_encoder_copy(struct archive * a,struct la_zstream * lastrm)1769 compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
1770 {
1771 
1772 	if (lastrm->valid)
1773 		compression_end(a, lastrm);
1774 	lastrm->valid = 1;
1775 	lastrm->code = compression_code_copy;
1776 	lastrm->end = compression_end_copy;
1777 	return (ARCHIVE_OK);
1778 }
1779 
1780 static int
compression_code_copy(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)1781 compression_code_copy(struct archive *a,
1782     struct la_zstream *lastrm, enum la_zaction action)
1783 {
1784 	size_t bytes;
1785 
1786 	(void)a; /* UNUSED */
1787 	if (lastrm->avail_out > lastrm->avail_in)
1788 		bytes = lastrm->avail_in;
1789 	else
1790 		bytes = lastrm->avail_out;
1791 	if (bytes) {
1792 		memcpy(lastrm->next_out, lastrm->next_in, bytes);
1793 		lastrm->next_in += bytes;
1794 		lastrm->avail_in -= bytes;
1795 		lastrm->total_in += bytes;
1796 		lastrm->next_out += bytes;
1797 		lastrm->avail_out -= bytes;
1798 		lastrm->total_out += bytes;
1799 	}
1800 	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
1801 		return (ARCHIVE_EOF);
1802 	return (ARCHIVE_OK);
1803 }
1804 
1805 static int
compression_end_copy(struct archive * a,struct la_zstream * lastrm)1806 compression_end_copy(struct archive *a, struct la_zstream *lastrm)
1807 {
1808 	(void)a; /* UNUSED */
1809 	lastrm->valid = 0;
1810 	return (ARCHIVE_OK);
1811 }
1812 
1813 /*
1814  * _7_DEFLATE compressor.
1815  */
1816 #ifdef HAVE_ZLIB_H
1817 static int
compression_init_encoder_deflate(struct archive * a,struct la_zstream * lastrm,int level,int withheader)1818 compression_init_encoder_deflate(struct archive *a,
1819     struct la_zstream *lastrm, int level, int withheader)
1820 {
1821 	z_stream *strm;
1822 
1823 	if (lastrm->valid)
1824 		compression_end(a, lastrm);
1825 	strm = calloc(1, sizeof(*strm));
1826 	if (strm == NULL) {
1827 		archive_set_error(a, ENOMEM,
1828 		    "Can't allocate memory for gzip stream");
1829 		return (ARCHIVE_FATAL);
1830 	}
1831 	/* zlib.h is not const-correct, so we need this one bit
1832 	 * of ugly hackery to convert a const * pointer to
1833 	 * a non-const pointer. */
1834 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1835 	strm->avail_in = (uInt)lastrm->avail_in;
1836 	strm->total_in = (uLong)lastrm->total_in;
1837 	strm->next_out = lastrm->next_out;
1838 	strm->avail_out = (uInt)lastrm->avail_out;
1839 	strm->total_out = (uLong)lastrm->total_out;
1840 	if (deflateInit2(strm, level, Z_DEFLATED,
1841 	    (withheader)?15:-15,
1842 	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
1843 		free(strm);
1844 		lastrm->real_stream = NULL;
1845 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1846 		    "Internal error initializing compression library");
1847 		return (ARCHIVE_FATAL);
1848 	}
1849 	lastrm->real_stream = strm;
1850 	lastrm->valid = 1;
1851 	lastrm->code = compression_code_deflate;
1852 	lastrm->end = compression_end_deflate;
1853 	return (ARCHIVE_OK);
1854 }
1855 
1856 static int
compression_code_deflate(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)1857 compression_code_deflate(struct archive *a,
1858     struct la_zstream *lastrm, enum la_zaction action)
1859 {
1860 	z_stream *strm;
1861 	int r;
1862 
1863 	strm = (z_stream *)lastrm->real_stream;
1864 	/* zlib.h is not const-correct, so we need this one bit
1865 	 * of ugly hackery to convert a const * pointer to
1866 	 * a non-const pointer. */
1867 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1868 	strm->avail_in = (uInt)lastrm->avail_in;
1869 	strm->total_in = (uLong)lastrm->total_in;
1870 	strm->next_out = lastrm->next_out;
1871 	strm->avail_out = (uInt)lastrm->avail_out;
1872 	strm->total_out = (uLong)lastrm->total_out;
1873 	r = deflate(strm,
1874 	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
1875 	lastrm->next_in = strm->next_in;
1876 	lastrm->avail_in = strm->avail_in;
1877 	lastrm->total_in = strm->total_in;
1878 	lastrm->next_out = strm->next_out;
1879 	lastrm->avail_out = strm->avail_out;
1880 	lastrm->total_out = strm->total_out;
1881 	switch (r) {
1882 	case Z_OK:
1883 		return (ARCHIVE_OK);
1884 	case Z_STREAM_END:
1885 		return (ARCHIVE_EOF);
1886 	default:
1887 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1888 		    "GZip compression failed:"
1889 		    " deflate() call returned status %d", r);
1890 		return (ARCHIVE_FATAL);
1891 	}
1892 }
1893 
1894 static int
compression_end_deflate(struct archive * a,struct la_zstream * lastrm)1895 compression_end_deflate(struct archive *a, struct la_zstream *lastrm)
1896 {
1897 	z_stream *strm;
1898 	int r;
1899 
1900 	strm = (z_stream *)lastrm->real_stream;
1901 	r = deflateEnd(strm);
1902 	free(strm);
1903 	lastrm->real_stream = NULL;
1904 	lastrm->valid = 0;
1905 	if (r != Z_OK) {
1906 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1907 		    "Failed to clean up compressor");
1908 		return (ARCHIVE_FATAL);
1909 	}
1910 	return (ARCHIVE_OK);
1911 }
1912 #else
1913 static int
compression_init_encoder_deflate(struct archive * a,struct la_zstream * lastrm,int level,int withheader)1914 compression_init_encoder_deflate(struct archive *a,
1915     struct la_zstream *lastrm, int level, int withheader)
1916 {
1917 
1918 	(void) level; /* UNUSED */
1919 	(void) withheader; /* UNUSED */
1920 	if (lastrm->valid)
1921 		compression_end(a, lastrm);
1922 	return (compression_unsupported_encoder(a, lastrm, "deflate"));
1923 }
1924 #endif
1925 
1926 /*
1927  * _7_BZIP2 compressor.
1928  */
1929 #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
1930 static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)1931 compression_init_encoder_bzip2(struct archive *a,
1932     struct la_zstream *lastrm, int level)
1933 {
1934 	bz_stream *strm;
1935 
1936 	if (lastrm->valid)
1937 		compression_end(a, lastrm);
1938 	strm = calloc(1, sizeof(*strm));
1939 	if (strm == NULL) {
1940 		archive_set_error(a, ENOMEM,
1941 		    "Can't allocate memory for bzip2 stream");
1942 		return (ARCHIVE_FATAL);
1943 	}
1944 	/* bzlib.h is not const-correct, so we need this one bit
1945 	 * of ugly hackery to convert a const * pointer to
1946 	 * a non-const pointer. */
1947 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1948 	strm->avail_in = (uint32_t)lastrm->avail_in;
1949 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1950 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1951 	strm->next_out = (char *)lastrm->next_out;
1952 	strm->avail_out = (uint32_t)lastrm->avail_out;
1953 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1954 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1955 	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
1956 		free(strm);
1957 		lastrm->real_stream = NULL;
1958 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1959 		    "Internal error initializing compression library");
1960 		return (ARCHIVE_FATAL);
1961 	}
1962 	lastrm->real_stream = strm;
1963 	lastrm->valid = 1;
1964 	lastrm->code = compression_code_bzip2;
1965 	lastrm->end = compression_end_bzip2;
1966 	return (ARCHIVE_OK);
1967 }
1968 
1969 static int
compression_code_bzip2(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)1970 compression_code_bzip2(struct archive *a,
1971     struct la_zstream *lastrm, enum la_zaction action)
1972 {
1973 	bz_stream *strm;
1974 	int r;
1975 
1976 	strm = (bz_stream *)lastrm->real_stream;
1977 	/* bzlib.h is not const-correct, so we need this one bit
1978 	 * of ugly hackery to convert a const * pointer to
1979 	 * a non-const pointer. */
1980 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1981 	strm->avail_in = (uint32_t)lastrm->avail_in;
1982 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1983 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1984 	strm->next_out = (char *)lastrm->next_out;
1985 	strm->avail_out = (uint32_t)lastrm->avail_out;
1986 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1987 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1988 	r = BZ2_bzCompress(strm,
1989 	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
1990 	lastrm->next_in = (const unsigned char *)strm->next_in;
1991 	lastrm->avail_in = strm->avail_in;
1992 	lastrm->total_in =
1993 	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
1994 	    + (uint64_t)(uint32_t)strm->total_in_lo32;
1995 	lastrm->next_out = (unsigned char *)strm->next_out;
1996 	lastrm->avail_out = strm->avail_out;
1997 	lastrm->total_out =
1998 	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
1999 	    + (uint64_t)(uint32_t)strm->total_out_lo32;
2000 	switch (r) {
2001 	case BZ_RUN_OK:     /* Non-finishing */
2002 	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
2003 		return (ARCHIVE_OK);
2004 	case BZ_STREAM_END: /* Finishing: all done */
2005 		/* Only occurs in finishing case */
2006 		return (ARCHIVE_EOF);
2007 	default:
2008 		/* Any other return value indicates an error */
2009 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2010 		    "Bzip2 compression failed:"
2011 		    " BZ2_bzCompress() call returned status %d", r);
2012 		return (ARCHIVE_FATAL);
2013 	}
2014 }
2015 
2016 static int
compression_end_bzip2(struct archive * a,struct la_zstream * lastrm)2017 compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
2018 {
2019 	bz_stream *strm;
2020 	int r;
2021 
2022 	strm = (bz_stream *)lastrm->real_stream;
2023 	r = BZ2_bzCompressEnd(strm);
2024 	free(strm);
2025 	lastrm->real_stream = NULL;
2026 	lastrm->valid = 0;
2027 	if (r != BZ_OK) {
2028 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2029 		    "Failed to clean up compressor");
2030 		return (ARCHIVE_FATAL);
2031 	}
2032 	return (ARCHIVE_OK);
2033 }
2034 
2035 #else
2036 static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)2037 compression_init_encoder_bzip2(struct archive *a,
2038     struct la_zstream *lastrm, int level)
2039 {
2040 
2041 	(void) level; /* UNUSED */
2042 	if (lastrm->valid)
2043 		compression_end(a, lastrm);
2044 	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
2045 }
2046 #endif
2047 
2048 /*
2049  * _7_LZMA1, _7_LZMA2 compressor.
2050  */
2051 #if defined(HAVE_LZMA_H)
2052 static int
compression_init_encoder_lzma(struct archive * a,struct la_zstream * lastrm,int level,uint64_t filter_id)2053 compression_init_encoder_lzma(struct archive *a,
2054     struct la_zstream *lastrm, int level, uint64_t filter_id)
2055 {
2056 	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
2057 	lzma_stream *strm;
2058 	lzma_filter *lzmafilters;
2059 	lzma_options_lzma lzma_opt;
2060 	int r;
2061 
2062 	if (lastrm->valid)
2063 		compression_end(a, lastrm);
2064 	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
2065 	if (strm == NULL) {
2066 		archive_set_error(a, ENOMEM,
2067 		    "Can't allocate memory for lzma stream");
2068 		return (ARCHIVE_FATAL);
2069 	}
2070 	lzmafilters = (lzma_filter *)(strm+1);
2071 	if (level > 9)
2072 		level = 9;
2073 	if (lzma_lzma_preset(&lzma_opt, level)) {
2074 		free(strm);
2075 		lastrm->real_stream = NULL;
2076 		archive_set_error(a, ENOMEM,
2077 		    "Internal error initializing compression library");
2078 		return (ARCHIVE_FATAL);
2079 	}
2080 	lzmafilters[0].id = filter_id;
2081 	lzmafilters[0].options = &lzma_opt;
2082 	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
2083 
2084 	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
2085 	if (r != LZMA_OK) {
2086 		free(strm);
2087 		lastrm->real_stream = NULL;
2088 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2089 		    "lzma_properties_size failed");
2090 		return (ARCHIVE_FATAL);
2091 	}
2092 	if (lastrm->prop_size) {
2093 		lastrm->props = malloc(lastrm->prop_size);
2094 		if (lastrm->props == NULL) {
2095 			free(strm);
2096 			lastrm->real_stream = NULL;
2097 			archive_set_error(a, ENOMEM,
2098 			    "Cannot allocate memory");
2099 			return (ARCHIVE_FATAL);
2100 		}
2101 		r = lzma_properties_encode(lzmafilters,  lastrm->props);
2102 		if (r != LZMA_OK) {
2103 			free(strm);
2104 			lastrm->real_stream = NULL;
2105 			archive_set_error(a, ARCHIVE_ERRNO_MISC,
2106 			    "lzma_properties_encode failed");
2107 			return (ARCHIVE_FATAL);
2108 		}
2109 	}
2110 
2111 	*strm = lzma_init_data;
2112 	r = lzma_raw_encoder(strm, lzmafilters);
2113 	switch (r) {
2114 	case LZMA_OK:
2115 		lastrm->real_stream = strm;
2116 		lastrm->valid = 1;
2117 		lastrm->code = compression_code_lzma;
2118 		lastrm->end = compression_end_lzma;
2119 		r = ARCHIVE_OK;
2120 		break;
2121 	case LZMA_MEM_ERROR:
2122 		free(strm);
2123 		lastrm->real_stream = NULL;
2124 		archive_set_error(a, ENOMEM,
2125 		    "Internal error initializing compression library: "
2126 		    "Cannot allocate memory");
2127 		r =  ARCHIVE_FATAL;
2128 		break;
2129         default:
2130 		free(strm);
2131 		lastrm->real_stream = NULL;
2132 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2133 		    "Internal error initializing compression library: "
2134 		    "It's a bug in liblzma");
2135 		r =  ARCHIVE_FATAL;
2136 		break;
2137 	}
2138 	return (r);
2139 }
2140 
2141 static int
compression_init_encoder_lzma1(struct archive * a,struct la_zstream * lastrm,int level)2142 compression_init_encoder_lzma1(struct archive *a,
2143     struct la_zstream *lastrm, int level)
2144 {
2145 	return compression_init_encoder_lzma(a, lastrm, level,
2146 		    LZMA_FILTER_LZMA1);
2147 }
2148 
2149 static int
compression_init_encoder_lzma2(struct archive * a,struct la_zstream * lastrm,int level)2150 compression_init_encoder_lzma2(struct archive *a,
2151     struct la_zstream *lastrm, int level)
2152 {
2153 	return compression_init_encoder_lzma(a, lastrm, level,
2154 		    LZMA_FILTER_LZMA2);
2155 }
2156 
2157 static int
compression_code_lzma(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2158 compression_code_lzma(struct archive *a,
2159     struct la_zstream *lastrm, enum la_zaction action)
2160 {
2161 	lzma_stream *strm;
2162 	int r;
2163 
2164 	strm = (lzma_stream *)lastrm->real_stream;
2165 	strm->next_in = lastrm->next_in;
2166 	strm->avail_in = lastrm->avail_in;
2167 	strm->total_in = lastrm->total_in;
2168 	strm->next_out = lastrm->next_out;
2169 	strm->avail_out = lastrm->avail_out;
2170 	strm->total_out = lastrm->total_out;
2171 	r = lzma_code(strm,
2172 	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
2173 	lastrm->next_in = strm->next_in;
2174 	lastrm->avail_in = strm->avail_in;
2175 	lastrm->total_in = strm->total_in;
2176 	lastrm->next_out = strm->next_out;
2177 	lastrm->avail_out = strm->avail_out;
2178 	lastrm->total_out = strm->total_out;
2179 	switch (r) {
2180 	case LZMA_OK:
2181 		/* Non-finishing case */
2182 		return (ARCHIVE_OK);
2183 	case LZMA_STREAM_END:
2184 		/* This return can only occur in finishing case. */
2185 		return (ARCHIVE_EOF);
2186 	case LZMA_MEMLIMIT_ERROR:
2187 		archive_set_error(a, ENOMEM,
2188 		    "lzma compression error:"
2189 		    " %ju MiB would have been needed",
2190 		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
2191 			/ (1024 * 1024)));
2192 		return (ARCHIVE_FATAL);
2193 	default:
2194 		/* Any other return value indicates an error */
2195 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2196 		    "lzma compression failed:"
2197 		    " lzma_code() call returned status %d", r);
2198 		return (ARCHIVE_FATAL);
2199 	}
2200 }
2201 
2202 static int
compression_end_lzma(struct archive * a,struct la_zstream * lastrm)2203 compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
2204 {
2205 	lzma_stream *strm;
2206 
2207 	(void)a; /* UNUSED */
2208 	strm = (lzma_stream *)lastrm->real_stream;
2209 	lzma_end(strm);
2210 	free(strm);
2211 	lastrm->valid = 0;
2212 	lastrm->real_stream = NULL;
2213 	return (ARCHIVE_OK);
2214 }
2215 #else
2216 static int
compression_init_encoder_lzma1(struct archive * a,struct la_zstream * lastrm,int level)2217 compression_init_encoder_lzma1(struct archive *a,
2218     struct la_zstream *lastrm, int level)
2219 {
2220 
2221 	(void) level; /* UNUSED */
2222 	if (lastrm->valid)
2223 		compression_end(a, lastrm);
2224 	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2225 }
2226 static int
compression_init_encoder_lzma2(struct archive * a,struct la_zstream * lastrm,int level)2227 compression_init_encoder_lzma2(struct archive *a,
2228     struct la_zstream *lastrm, int level)
2229 {
2230 
2231 	(void) level; /* UNUSED */
2232 	if (lastrm->valid)
2233 		compression_end(a, lastrm);
2234 	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2235 }
2236 #endif
2237 
2238 /*
2239  * _7_PPMD compressor.
2240  */
2241 static void
ppmd_write(void * p,Byte b)2242 ppmd_write(void *p, Byte b)
2243 {
2244 	struct archive_write *a = ((IByteOut *)p)->a;
2245 	struct _7zip *zip = a->format_data;
2246 	struct la_zstream *lastrm = &(zip->stream);
2247 	struct ppmd_stream *strm;
2248 
2249 	if (lastrm->avail_out) {
2250 		*lastrm->next_out++ = b;
2251 		lastrm->avail_out--;
2252 		lastrm->total_out++;
2253 		return;
2254 	}
2255 	strm = (struct ppmd_stream *)lastrm->real_stream;
2256 	if (strm->buff_ptr < strm->buff_end) {
2257 		*strm->buff_ptr++ = b;
2258 		strm->buff_bytes++;
2259 	}
2260 }
2261 
2262 static int
compression_init_encoder_ppmd(struct archive * a,struct la_zstream * lastrm,uint8_t maxOrder,uint32_t msize)2263 compression_init_encoder_ppmd(struct archive *a,
2264     struct la_zstream *lastrm, uint8_t maxOrder, uint32_t msize)
2265 {
2266 	struct ppmd_stream *strm;
2267 	uint8_t *props;
2268 	int r;
2269 
2270 	if (lastrm->valid)
2271 		compression_end(a, lastrm);
2272 	strm = calloc(1, sizeof(*strm));
2273 	if (strm == NULL) {
2274 		archive_set_error(a, ENOMEM,
2275 		    "Can't allocate memory for PPMd");
2276 		return (ARCHIVE_FATAL);
2277 	}
2278 	strm->buff = malloc(32);
2279 	if (strm->buff == NULL) {
2280 		free(strm);
2281 		archive_set_error(a, ENOMEM,
2282 		    "Can't allocate memory for PPMd");
2283 		return (ARCHIVE_FATAL);
2284 	}
2285 	strm->buff_ptr = strm->buff;
2286 	strm->buff_end = strm->buff + 32;
2287 
2288 	props = malloc(1+4);
2289 	if (props == NULL) {
2290 		free(strm->buff);
2291 		free(strm);
2292 		archive_set_error(a, ENOMEM,
2293 		    "Coludn't allocate memory for PPMd");
2294 		return (ARCHIVE_FATAL);
2295 	}
2296 	props[0] = maxOrder;
2297 	archive_le32enc(props+1, msize);
2298 	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
2299 	r = __archive_ppmd7_functions.Ppmd7_Alloc(
2300 		&strm->ppmd7_context, msize);
2301 	if (r == 0) {
2302 		free(strm->buff);
2303 		free(strm);
2304 		free(props);
2305 		archive_set_error(a, ENOMEM,
2306 		    "Coludn't allocate memory for PPMd");
2307 		return (ARCHIVE_FATAL);
2308 	}
2309 	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
2310 	strm->byteout.a = (struct archive_write *)a;
2311 	strm->byteout.Write = ppmd_write;
2312 	strm->range_enc.Stream = &(strm->byteout);
2313 	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
2314 	strm->stat = 0;
2315 
2316 	lastrm->real_stream = strm;
2317 	lastrm->valid = 1;
2318 	lastrm->code = compression_code_ppmd;
2319 	lastrm->end = compression_end_ppmd;
2320 	lastrm->prop_size = 5;
2321 	lastrm->props = props;
2322 	return (ARCHIVE_OK);
2323 }
2324 
2325 static int
compression_code_ppmd(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2326 compression_code_ppmd(struct archive *a,
2327     struct la_zstream *lastrm, enum la_zaction action)
2328 {
2329 	struct ppmd_stream *strm;
2330 
2331 	(void)a; /* UNUSED */
2332 
2333 	strm = (struct ppmd_stream *)lastrm->real_stream;
2334 
2335 	/* Copy encoded data if there are remaining bytes from previous call. */
2336 	if (strm->buff_bytes) {
2337 		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
2338 		while (lastrm->avail_out && strm->buff_bytes) {
2339 			*lastrm->next_out++ = *p++;
2340 			lastrm->avail_out--;
2341 			lastrm->total_out++;
2342 			strm->buff_bytes--;
2343 		}
2344 		if (strm->buff_bytes)
2345 			return (ARCHIVE_OK);
2346 		if (strm->stat == 1)
2347 			return (ARCHIVE_EOF);
2348 		strm->buff_ptr = strm->buff;
2349 	}
2350 	while (lastrm->avail_in && lastrm->avail_out) {
2351 		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
2352 			&(strm->ppmd7_context), &(strm->range_enc),
2353 			*lastrm->next_in++);
2354 		lastrm->avail_in--;
2355 		lastrm->total_in++;
2356 	}
2357 	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
2358 		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
2359 			&(strm->range_enc));
2360 		strm->stat = 1;
2361 		/* Return EOF if there are no remaining bytes. */
2362 		if (strm->buff_bytes == 0)
2363 			return (ARCHIVE_EOF);
2364 	}
2365 	return (ARCHIVE_OK);
2366 }
2367 
2368 static int
compression_end_ppmd(struct archive * a,struct la_zstream * lastrm)2369 compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
2370 {
2371 	struct ppmd_stream *strm;
2372 
2373 	(void)a; /* UNUSED */
2374 
2375 	strm = (struct ppmd_stream *)lastrm->real_stream;
2376 	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context);
2377 	free(strm->buff);
2378 	free(strm);
2379 	lastrm->real_stream = NULL;
2380 	lastrm->valid = 0;
2381 	return (ARCHIVE_OK);
2382 }
2383 
2384 #if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
2385 static int
compression_init_encoder_zstd(struct archive * a,struct la_zstream * lastrm,int level,int threads)2386 compression_init_encoder_zstd(struct archive *a, struct la_zstream *lastrm, int level, int threads)
2387 {
2388 	if (lastrm->valid)
2389 		compression_end(a, lastrm);
2390 
2391 	ZSTD_CStream *strm = ZSTD_createCStream();
2392 	if (strm == NULL) {
2393 		archive_set_error(a, ENOMEM,
2394 			"Can't allocate memory for zstd stream");
2395 		return (ARCHIVE_FATAL);
2396 	}
2397 
2398 	if (ZSTD_isError(ZSTD_initCStream(strm, level))) {
2399 		ZSTD_freeCStream(strm);
2400 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2401 			"Internal error initializing zstd compressor object");
2402 		return (ARCHIVE_FATAL);
2403 	}
2404 
2405 	ZSTD_CCtx_setParameter(strm, ZSTD_c_nbWorkers, threads);
2406 
2407 	// p7zip-zstd fails to unpack archives that don't have prop_size 5.
2408 	// 7-Zip-zstd fails to unpack archives that don't have prop_size 3 or 5.
2409 	// So let's use 5...
2410 	lastrm->prop_size = 5;
2411 	lastrm->props = calloc(5, 1);
2412 	if (lastrm->props == NULL) {
2413 		ZSTD_freeCStream(strm);
2414 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2415 			"Internal error initializing zstd compressor properties");
2416 		return (ARCHIVE_FATAL);
2417 	}
2418 
2419 	// Refer to the DProps struct in 7-Zip-zstd's ZstdDecoder.h:
2420 	// https://github.com/mcmilk/7-Zip-zstd/blob/79b2c78e9e7735ddf90147129b75cf2797ff6522/CPP/7zip/Compress/ZstdDecoder.h#L34S
2421 	lastrm->props[0] = ZSTD_VERSION_MAJOR;
2422 	lastrm->props[1] = ZSTD_VERSION_MINOR;
2423 	lastrm->props[2] = level;
2424 	// lastrm->props[3] and lastrm->props[4] are reserved. Leave them as 0.
2425 
2426 	lastrm->real_stream = strm;
2427 	lastrm->valid = 1;
2428 	lastrm->code = compression_code_zstd;
2429 	lastrm->end = compression_end_zstd;
2430 
2431 	return (ARCHIVE_OK);
2432 }
2433 
2434 static int
compression_code_zstd(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2435 compression_code_zstd(struct archive *a,
2436     struct la_zstream *lastrm, enum la_zaction action)
2437 {
2438 	ZSTD_CStream *strm = (ZSTD_CStream *)lastrm->real_stream;
2439 
2440 	ZSTD_outBuffer out = { .dst = lastrm->next_out, .size = lastrm->avail_out, .pos = 0 };
2441 	ZSTD_inBuffer  in  = { .src = lastrm->next_in,  .size = lastrm->avail_in,  .pos = 0 };
2442 
2443 	size_t zret;
2444 
2445 	ZSTD_EndDirective mode = (action == ARCHIVE_Z_RUN) ? ZSTD_e_continue : ZSTD_e_end;
2446 
2447 	zret = ZSTD_compressStream2(strm, &out, &in, mode);
2448 	if (ZSTD_isError(zret)) {
2449 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2450 			"zstd compression failed, ZSTD_compressStream2 returned: %s",
2451 			ZSTD_getErrorName(zret));
2452 		return (ARCHIVE_FATAL);
2453 	}
2454 
2455 	lastrm->next_in += in.pos;
2456 	lastrm->avail_in -= in.pos;
2457 	lastrm->total_in += in.pos;
2458 
2459 	lastrm->next_out += out.pos;
2460 	lastrm->avail_out -= out.pos;
2461 	lastrm->total_out += out.pos;
2462 
2463 	if (action == ARCHIVE_Z_FINISH && zret == 0)
2464 		return (ARCHIVE_EOF); // All done.
2465 
2466 	return (ARCHIVE_OK); // More work to do.
2467 }
2468 
2469 static int
compression_end_zstd(struct archive * a,struct la_zstream * lastrm)2470 compression_end_zstd(struct archive *a, struct la_zstream *lastrm)
2471 {
2472 	ZSTD_CStream *strm;
2473 
2474 	(void)a; /* UNUSED */
2475 	strm = (ZSTD_CStream *)lastrm->real_stream;
2476 	ZSTD_freeCStream(strm);
2477 	lastrm->valid = 0;
2478 	lastrm->real_stream = NULL;
2479 	return (ARCHIVE_OK);
2480 }
2481 
2482 #else
2483 
2484 static int
compression_init_encoder_zstd(struct archive * a,struct la_zstream * lastrm,int level,int threads)2485 compression_init_encoder_zstd(struct archive *a, struct la_zstream *lastrm, int level, int threads)
2486 {
2487 	(void) level; /* UNUSED */
2488 	(void) threads; /* UNUSED */
2489 	if (lastrm->valid)
2490 		compression_end(a, lastrm);
2491 	return (compression_unsupported_encoder(a, lastrm, "zstd"));
2492 }
2493 #endif
2494 
2495 /*
2496  * Universal compressor initializer.
2497  */
2498 static int
_7z_compression_init_encoder(struct archive_write * a,unsigned compression,int compression_level)2499 _7z_compression_init_encoder(struct archive_write *a, unsigned compression,
2500     int compression_level)
2501 {
2502 	struct _7zip *zip = a->format_data;
2503 	int r;
2504 
2505 	switch (compression) {
2506 	case _7Z_DEFLATE:
2507 		r = compression_init_encoder_deflate(
2508 		    &(a->archive), &(zip->stream),
2509 		    compression_level, 0);
2510 		break;
2511 	case _7Z_BZIP2:
2512 		r = compression_init_encoder_bzip2(
2513 		    &(a->archive), &(zip->stream),
2514 		    compression_level);
2515 		break;
2516 	case _7Z_LZMA1:
2517 		r = compression_init_encoder_lzma1(
2518 		    &(a->archive), &(zip->stream),
2519 		    compression_level);
2520 		break;
2521 	case _7Z_LZMA2:
2522 		r = compression_init_encoder_lzma2(
2523 		    &(a->archive), &(zip->stream),
2524 		    compression_level);
2525 		break;
2526 	case _7Z_PPMD:
2527 		r = compression_init_encoder_ppmd(
2528 		    &(a->archive), &(zip->stream),
2529 		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
2530 		break;
2531 	case _7Z_ZSTD:
2532 		r = compression_init_encoder_zstd(
2533 		    &(a->archive), &(zip->stream),
2534 		    compression_level, zip->opt_threads);
2535 		break;
2536 	case _7Z_COPY:
2537 	default:
2538 		r = compression_init_encoder_copy(
2539 		    &(a->archive), &(zip->stream));
2540 		break;
2541 	}
2542 	if (r == ARCHIVE_OK) {
2543 		zip->stream.total_in = 0;
2544 		zip->stream.next_out = zip->wbuff;
2545 		zip->stream.avail_out = sizeof(zip->wbuff);
2546 		zip->stream.total_out = 0;
2547 	}
2548 
2549 	return (r);
2550 }
2551 
2552 static int
compression_code(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)2553 compression_code(struct archive *a, struct la_zstream *lastrm,
2554     enum la_zaction action)
2555 {
2556 	if (lastrm->valid)
2557 		return (lastrm->code(a, lastrm, action));
2558 	return (ARCHIVE_OK);
2559 }
2560 
2561 static int
compression_end(struct archive * a,struct la_zstream * lastrm)2562 compression_end(struct archive *a, struct la_zstream *lastrm)
2563 {
2564 	if (lastrm->valid) {
2565 		lastrm->prop_size = 0;
2566 		free(lastrm->props);
2567 		lastrm->props = NULL;
2568 		return (lastrm->end(a, lastrm));
2569 	}
2570 	return (ARCHIVE_OK);
2571 }
2572