Dpkg::Vendor::Debian: Add support for new hardening branch feature
[dpkg.git] / lib / dpkg / compress.c
blobadf26ea769e1658dc78fb31978167bb212c7eeaf
1 /*
2 * libdpkg - Debian packaging suite library routines
3 * compress.c - compression support functions
5 * Copyright © 2000 Wichert Akkerman <wakkerma@debian.org>
6 * Copyright © 2004 Scott James Remnant <scott@netsplit.com>
7 * Copyright © 2006-2023 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 #include <config.h>
24 #include <compat.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
32 #if USE_LIBZ_IMPL != USE_LIBZ_IMPL_NONE
33 #include <compat-zlib.h>
34 #endif
35 #ifdef WITH_LIBLZMA
36 #include <lzma.h>
37 #endif
38 #ifdef WITH_LIBZSTD
39 #include <zstd.h>
40 #define DPKG_ZSTD_MAX_LEVEL ZSTD_maxCLevel()
41 #else
42 #define DPKG_ZSTD_MAX_LEVEL 22
43 #define ZSTD_CLEVEL_DEFAULT 3
44 #endif
45 #ifdef WITH_LIBBZ2
46 #include <bzlib.h>
47 #endif
49 #include <dpkg/i18n.h>
50 #include <dpkg/dpkg.h>
51 #include <dpkg/error.h>
52 #include <dpkg/varbuf.h>
53 #include <dpkg/fdio.h>
54 #include <dpkg/buffer.h>
55 #include <dpkg/meminfo.h>
56 #include <dpkg/command.h>
57 #include <dpkg/compress.h>
58 #if USE_LIBZ_IMPL == USE_LIBZ_IMPL_NONE || \
59 !defined(WITH_LIBLZMA) || \
60 !defined(WITH_LIBZSTD) || \
61 !defined(WITH_LIBBZ2)
62 #include <dpkg/subproc.h>
64 static void
65 fd_fd_filter(struct command *cmd, int fd_in, int fd_out, const char *delenv[])
67 pid_t pid;
69 pid = subproc_fork();
70 if (pid == 0) {
71 int i;
73 if (fd_in != 0) {
74 m_dup2(fd_in, 0);
75 close(fd_in);
77 if (fd_out != 1) {
78 m_dup2(fd_out, 1);
79 close(fd_out);
82 for (i = 0; delenv[i]; i++)
83 unsetenv(delenv[i]);
85 command_exec(cmd);
87 subproc_reap(pid, cmd->name, 0);
90 static void
91 command_compress_init(struct command *cmd, const char *name, const char *desc,
92 int level)
94 static char combuf[6];
96 command_init(cmd, name, desc);
97 command_add_arg(cmd, name);
99 snprintf(combuf, sizeof(combuf), "-c%d", level);
100 command_add_arg(cmd, combuf);
103 static void
104 command_decompress_init(struct command *cmd, const char *name, const char *desc)
106 command_init(cmd, name, desc);
107 command_add_arg(cmd, name);
108 command_add_arg(cmd, "-dc");
110 #endif
112 #if defined(WITH_LIBLZMA) || defined(WITH_LIBZSTD)
113 enum dpkg_stream_filter {
114 DPKG_STREAM_COMPRESS = 1,
115 DPKG_STREAM_DECOMPRESS = 2,
118 enum dpkg_stream_action {
119 DPKG_STREAM_INIT = 0,
120 DPKG_STREAM_RUN = 1,
121 DPKG_STREAM_FINISH = 2,
124 enum dpkg_stream_status {
125 DPKG_STREAM_OK,
126 DPKG_STREAM_END,
127 DPKG_STREAM_ERROR,
129 #endif
131 struct compressor {
132 const char *name;
133 const char *extension;
134 int default_level;
135 void (*fixup_params)(struct compress_params *params);
136 void (*compress)(struct compress_params *params,
137 int fd_in, int fd_out, const char *desc);
138 void (*decompress)(struct compress_params *params,
139 int fd_in, int fd_out, const char *desc);
143 * No compressor (pass-through).
146 static void
147 fixup_none_params(struct compress_params *params)
151 static void
152 decompress_none(struct compress_params *params, int fd_in, int fd_out,
153 const char *desc)
155 struct dpkg_error err;
157 if (fd_fd_copy(fd_in, fd_out, -1, &err) < 0)
158 ohshit(_("%s: pass-through copy error: %s"), desc, err.str);
161 static void
162 compress_none(struct compress_params *params, int fd_in, int fd_out,
163 const char *desc)
165 struct dpkg_error err;
167 if (fd_fd_copy(fd_in, fd_out, -1, &err) < 0)
168 ohshit(_("%s: pass-through copy error: %s"), desc, err.str);
171 static const struct compressor compressor_none = {
172 .name = "none",
173 .extension = "",
174 .default_level = 0,
175 .fixup_params = fixup_none_params,
176 .compress = compress_none,
177 .decompress = decompress_none,
181 * Gzip compressor.
184 #define GZIP "gzip"
186 static void
187 fixup_gzip_params(struct compress_params *params)
189 /* Normalize compression level. */
190 if (params->level == 0)
191 params->type = COMPRESSOR_TYPE_NONE;
194 #if USE_LIBZ_IMPL != USE_LIBZ_IMPL_NONE
195 static void
196 decompress_gzip(struct compress_params *params, int fd_in, int fd_out,
197 const char *desc)
199 char *buffer;
200 size_t bufsize = DPKG_BUFFER_SIZE;
201 int z_errnum;
202 gzFile gzfile = gzdopen(fd_in, "r");
204 if (gzfile == NULL)
205 ohshit(_("%s: error binding input to gzip stream"), desc);
207 buffer = m_malloc(bufsize);
209 for (;;) {
210 int actualread, actualwrite;
212 actualread = gzread(gzfile, buffer, bufsize);
213 if (actualread < 0) {
214 const char *errmsg = gzerror(gzfile, &z_errnum);
216 if (z_errnum == Z_ERRNO)
217 errmsg = strerror(errno);
218 ohshit(_("%s: internal gzip read error: '%s'"), desc,
219 errmsg);
221 if (actualread == 0) /* EOF. */
222 break;
224 actualwrite = fd_write(fd_out, buffer, actualread);
225 if (actualwrite != actualread)
226 ohshite(_("%s: internal gzip write error"), desc);
229 free(buffer);
231 z_errnum = gzclose(gzfile);
232 if (z_errnum) {
233 const char *errmsg;
235 if (z_errnum == Z_ERRNO)
236 errmsg = strerror(errno);
237 else
238 errmsg = zError(z_errnum);
239 ohshit(_("%s: internal gzip read error: %s"), desc, errmsg);
242 if (close(fd_out))
243 ohshite(_("%s: internal gzip write error"), desc);
246 static void
247 compress_gzip(struct compress_params *params, int fd_in, int fd_out,
248 const char *desc)
250 char *buffer;
251 char combuf[6];
252 size_t bufsize = DPKG_BUFFER_SIZE;
253 int strategy;
254 int z_errnum;
255 gzFile gzfile;
257 if (params->strategy == COMPRESSOR_STRATEGY_FILTERED)
258 strategy = 'f';
259 else if (params->strategy == COMPRESSOR_STRATEGY_HUFFMAN)
260 strategy = 'h';
261 else if (params->strategy == COMPRESSOR_STRATEGY_RLE)
262 strategy = 'R';
263 else if (params->strategy == COMPRESSOR_STRATEGY_FIXED)
264 strategy = 'F';
265 else
266 strategy = ' ';
268 snprintf(combuf, sizeof(combuf), "w%d%c", params->level, strategy);
269 gzfile = gzdopen(fd_out, combuf);
270 if (gzfile == NULL)
271 ohshit(_("%s: error binding output to gzip stream"), desc);
273 buffer = m_malloc(bufsize);
275 for (;;) {
276 int actualread, actualwrite;
278 actualread = fd_read(fd_in, buffer, bufsize);
279 if (actualread < 0)
280 ohshite(_("%s: internal gzip read error"), desc);
281 if (actualread == 0) /* EOF. */
282 break;
284 actualwrite = gzwrite(gzfile, buffer, actualread);
285 if (actualwrite != actualread) {
286 const char *errmsg = gzerror(gzfile, &z_errnum);
288 if (z_errnum == Z_ERRNO)
289 errmsg = strerror(errno);
290 ohshit(_("%s: internal gzip write error: '%s'"), desc,
291 errmsg);
295 free(buffer);
297 z_errnum = gzclose(gzfile);
298 if (z_errnum) {
299 const char *errmsg;
301 if (z_errnum == Z_ERRNO)
302 errmsg = strerror(errno);
303 else
304 errmsg = zError(z_errnum);
305 ohshit(_("%s: internal gzip write error: %s"), desc, errmsg);
308 #else
309 static const char *env_gzip[] = { "GZIP", NULL };
311 static void
312 decompress_gzip(struct compress_params *params, int fd_in, int fd_out,
313 const char *desc)
315 struct command cmd;
317 command_decompress_init(&cmd, GZIP, desc);
319 fd_fd_filter(&cmd, fd_in, fd_out, env_gzip);
321 command_destroy(&cmd);
324 static void
325 compress_gzip(struct compress_params *params, int fd_in, int fd_out,
326 const char *desc)
328 struct command cmd;
330 command_compress_init(&cmd, GZIP, desc, params->level);
331 command_add_arg(&cmd, "-n");
333 fd_fd_filter(&cmd, fd_in, fd_out, env_gzip);
335 command_destroy(&cmd);
337 #endif
339 static const struct compressor compressor_gzip = {
340 .name = "gzip",
341 .extension = ".gz",
342 .default_level = 9,
343 .fixup_params = fixup_gzip_params,
344 .compress = compress_gzip,
345 .decompress = decompress_gzip,
349 * Bzip2 compressor.
352 #define BZIP2 "bzip2"
354 static void
355 fixup_bzip2_params(struct compress_params *params)
357 /* Normalize compression level. */
358 if (params->level == 0)
359 params->level = 1;
362 #ifdef WITH_LIBBZ2
363 static void
364 decompress_bzip2(struct compress_params *params, int fd_in, int fd_out,
365 const char *desc)
367 char *buffer;
368 size_t bufsize = DPKG_BUFFER_SIZE;
369 BZFILE *bzfile = BZ2_bzdopen(fd_in, "r");
371 if (bzfile == NULL)
372 ohshit(_("%s: error binding input to bzip2 stream"), desc);
374 buffer = m_malloc(bufsize);
376 for (;;) {
377 int actualread, actualwrite;
379 actualread = BZ2_bzread(bzfile, buffer, bufsize);
380 if (actualread < 0) {
381 int bz_errnum = 0;
382 const char *errmsg = BZ2_bzerror(bzfile, &bz_errnum);
384 if (bz_errnum == BZ_IO_ERROR)
385 errmsg = strerror(errno);
386 ohshit(_("%s: internal bzip2 read error: '%s'"), desc,
387 errmsg);
389 if (actualread == 0) /* EOF. */
390 break;
392 actualwrite = fd_write(fd_out, buffer, actualread);
393 if (actualwrite != actualread)
394 ohshite(_("%s: internal bzip2 write error"), desc);
397 free(buffer);
399 BZ2_bzclose(bzfile);
401 if (close(fd_out))
402 ohshite(_("%s: internal bzip2 write error"), desc);
405 static void
406 compress_bzip2(struct compress_params *params, int fd_in, int fd_out,
407 const char *desc)
409 char *buffer;
410 char combuf[6];
411 size_t bufsize = DPKG_BUFFER_SIZE;
412 int bz_errnum;
413 BZFILE *bzfile;
415 snprintf(combuf, sizeof(combuf), "w%d", params->level);
416 bzfile = BZ2_bzdopen(fd_out, combuf);
417 if (bzfile == NULL)
418 ohshit(_("%s: error binding output to bzip2 stream"), desc);
420 buffer = m_malloc(bufsize);
422 for (;;) {
423 int actualread, actualwrite;
425 actualread = fd_read(fd_in, buffer, bufsize);
426 if (actualread < 0)
427 ohshite(_("%s: internal bzip2 read error"), desc);
428 if (actualread == 0) /* EOF. */
429 break;
431 actualwrite = BZ2_bzwrite(bzfile, buffer, actualread);
432 if (actualwrite != actualread) {
433 const char *errmsg = BZ2_bzerror(bzfile, &bz_errnum);
435 if (bz_errnum == BZ_IO_ERROR)
436 errmsg = strerror(errno);
437 ohshit(_("%s: internal bzip2 write error: '%s'"), desc,
438 errmsg);
442 free(buffer);
444 BZ2_bzWriteClose(&bz_errnum, bzfile, 0, NULL, NULL);
445 if (bz_errnum != BZ_OK) {
446 const char *errmsg = _("unexpected bzip2 error");
448 if (bz_errnum == BZ_IO_ERROR)
449 errmsg = strerror(errno);
450 ohshit(_("%s: internal bzip2 write error: '%s'"), desc,
451 errmsg);
454 /* Because BZ2_bzWriteClose has done a fflush on the file handle,
455 * doing a close on the file descriptor associated with it should
456 * be safe™. */
457 if (close(fd_out))
458 ohshite(_("%s: internal bzip2 write error"), desc);
460 #else
461 static const char *env_bzip2[] = { "BZIP", "BZIP2", NULL };
463 static void
464 decompress_bzip2(struct compress_params *params, int fd_in, int fd_out,
465 const char *desc)
467 struct command cmd;
469 command_decompress_init(&cmd, BZIP2, desc);
471 fd_fd_filter(&cmd, fd_in, fd_out, env_bzip2);
473 command_destroy(&cmd);
476 static void
477 compress_bzip2(struct compress_params *params, int fd_in, int fd_out,
478 const char *desc)
480 struct command cmd;
482 command_compress_init(&cmd, BZIP2, desc, params->level);
484 fd_fd_filter(&cmd, fd_in, fd_out, env_bzip2);
486 command_destroy(&cmd);
488 #endif
490 static const struct compressor compressor_bzip2 = {
491 .name = "bzip2",
492 .extension = ".bz2",
493 .default_level = 9,
494 .fixup_params = fixup_bzip2_params,
495 .compress = compress_bzip2,
496 .decompress = decompress_bzip2,
500 * Xz compressor.
503 #define XZ "xz"
505 #ifdef WITH_LIBLZMA
506 struct io_lzma {
507 const char *desc;
509 struct compress_params *params;
511 enum dpkg_stream_filter filter;
512 enum dpkg_stream_action action;
513 enum dpkg_stream_status status;
515 void (*init)(struct io_lzma *io, lzma_stream *s);
516 void (*code)(struct io_lzma *io, lzma_stream *s);
517 void (*done)(struct io_lzma *io, lzma_stream *s);
520 /* XXX: liblzma does not expose error messages. */
521 static const char *
522 dpkg_lzma_strerror(struct io_lzma *io, lzma_ret code)
524 const char *const impossible = _("internal error (bug)");
526 switch (code) {
527 case LZMA_MEM_ERROR:
528 return strerror(ENOMEM);
529 case LZMA_MEMLIMIT_ERROR:
530 if (io->action == DPKG_STREAM_RUN)
531 return _("memory usage limit reached");
532 return impossible;
533 case LZMA_OPTIONS_ERROR:
534 if (io->filter == DPKG_STREAM_COMPRESS &&
535 io->action == DPKG_STREAM_INIT)
536 return _("unsupported compression preset");
537 if (io->filter == DPKG_STREAM_DECOMPRESS &&
538 io->action == DPKG_STREAM_RUN)
539 return _("unsupported options in file header");
540 return impossible;
541 case LZMA_DATA_ERROR:
542 if (io->action == DPKG_STREAM_RUN)
543 return _("compressed data is corrupt");
544 return impossible;
545 case LZMA_BUF_ERROR:
546 if (io->action == DPKG_STREAM_RUN)
547 return _("unexpected end of input");
548 return impossible;
549 case LZMA_FORMAT_ERROR:
550 if (io->filter == DPKG_STREAM_DECOMPRESS &&
551 io->action == DPKG_STREAM_RUN)
552 return _("file format not recognized");
553 return impossible;
554 case LZMA_UNSUPPORTED_CHECK:
555 if (io->filter == DPKG_STREAM_COMPRESS &&
556 io->action == DPKG_STREAM_INIT)
557 return _("unsupported type of integrity check");
558 return impossible;
559 default:
560 return impossible;
564 static void
565 filter_lzma(struct io_lzma *io, int fd_in, int fd_out)
567 uint8_t *buf_in;
568 uint8_t *buf_out;
569 size_t buf_size = DPKG_BUFFER_SIZE;
570 lzma_stream s = LZMA_STREAM_INIT;
572 buf_in = m_malloc(buf_size);
573 buf_out = m_malloc(buf_size);
575 s.next_out = buf_out;
576 s.avail_out = buf_size;
578 io->status = DPKG_STREAM_OK;
579 io->action = DPKG_STREAM_INIT;
580 io->init(io, &s);
581 io->action = DPKG_STREAM_RUN;
583 do {
584 ssize_t len;
586 if (s.avail_in == 0 && io->action != DPKG_STREAM_FINISH) {
587 len = fd_read(fd_in, buf_in, buf_size);
588 if (len < 0)
589 ohshite(_("%s: lzma read error"), io->desc);
590 if (len == 0)
591 io->action = DPKG_STREAM_FINISH;
592 s.next_in = buf_in;
593 s.avail_in = len;
596 io->code(io, &s);
598 if (s.avail_out == 0 || io->status == DPKG_STREAM_END) {
599 len = fd_write(fd_out, buf_out, s.next_out - buf_out);
600 if (len < 0)
601 ohshite(_("%s: lzma write error"), io->desc);
602 s.next_out = buf_out;
603 s.avail_out = buf_size;
605 } while (io->status != DPKG_STREAM_END);
607 io->done(io, &s);
609 free(buf_in);
610 free(buf_out);
612 if (close(fd_out))
613 ohshite(_("%s: lzma close error"), io->desc);
616 static void DPKG_ATTR_NORET
617 filter_lzma_error(struct io_lzma *io, lzma_ret ret)
619 ohshit(_("%s: lzma error: %s"), io->desc,
620 dpkg_lzma_strerror(io, ret));
623 #ifdef HAVE_LZMA_MT_ENCODER
624 static uint64_t
625 filter_xz_get_memlimit(void)
627 uint64_t mt_memlimit;
629 /* Ask the kernel what is currently available for us. If this fails
630 * initialize the memory limit to half the physical RAM, or to 128 MiB
631 * if we cannot infer the number. */
632 if (meminfo_get_available(&mt_memlimit) < 0) {
633 mt_memlimit = lzma_physmem() / 2;
634 if (mt_memlimit == 0)
635 mt_memlimit = 128 * 1024 * 1024;
637 /* Clamp the multi-threaded memory limit to half the addressable
638 * memory on this architecture. */
639 if (mt_memlimit > INTPTR_MAX)
640 mt_memlimit = INTPTR_MAX;
642 return mt_memlimit;
645 static uint32_t
646 filter_xz_get_cputhreads(struct compress_params *params)
648 long threads_max;
650 threads_max = lzma_cputhreads();
651 if (threads_max == 0)
652 threads_max = 1;
654 if (params->threads_max >= 0)
655 return clamp(params->threads_max, 1, threads_max);
657 return threads_max;
659 #endif
661 static void
662 filter_unxz_init(struct io_lzma *io, lzma_stream *s)
664 #ifdef HAVE_LZMA_MT_DECODER
665 lzma_mt mt_options = {
666 .flags = 0,
667 .block_size = 0,
668 .timeout = 0,
669 .filters = NULL,
671 #else
672 uint64_t memlimit = UINT64_MAX;
673 #endif
674 lzma_ret ret;
676 io->filter = DPKG_STREAM_DECOMPRESS;
678 #ifdef HAVE_LZMA_MT_DECODER
679 mt_options.memlimit_stop = UINT64_MAX;
680 mt_options.memlimit_threading = filter_xz_get_memlimit();
681 mt_options.threads = filter_xz_get_cputhreads(io->params);
683 ret = lzma_stream_decoder_mt(s, &mt_options);
684 #else
685 ret = lzma_stream_decoder(s, memlimit, 0);
686 #endif
687 if (ret != LZMA_OK)
688 filter_lzma_error(io, ret);
691 static void
692 filter_xz_init(struct io_lzma *io, lzma_stream *s)
694 uint32_t preset;
695 lzma_check check = LZMA_CHECK_CRC64;
696 #ifdef HAVE_LZMA_MT_ENCODER
697 uint64_t mt_memlimit;
698 lzma_mt mt_options = {
699 .flags = 0,
700 .block_size = 0,
701 .timeout = 0,
702 .filters = NULL,
703 .check = check,
705 #endif
706 lzma_ret ret;
708 io->filter = DPKG_STREAM_COMPRESS;
710 preset = io->params->level;
711 if (io->params->strategy == COMPRESSOR_STRATEGY_EXTREME)
712 preset |= LZMA_PRESET_EXTREME;
714 #ifdef HAVE_LZMA_MT_ENCODER
715 mt_options.preset = preset;
716 mt_memlimit = filter_xz_get_memlimit();
717 mt_options.threads = filter_xz_get_cputhreads(io->params);
719 /* Guess whether we have enough RAM to use the multi-threaded encoder,
720 * and decrease them up to single-threaded to reduce memory usage. */
721 for (; mt_options.threads > 1; mt_options.threads--) {
722 uint64_t mt_memusage;
724 mt_memusage = lzma_stream_encoder_mt_memusage(&mt_options);
725 if (mt_memusage < mt_memlimit)
726 break;
729 ret = lzma_stream_encoder_mt(s, &mt_options);
730 #else
731 ret = lzma_easy_encoder(s, preset, check);
732 #endif
734 if (ret != LZMA_OK)
735 filter_lzma_error(io, ret);
738 static void
739 filter_lzma_code(struct io_lzma *io, lzma_stream *s)
741 lzma_ret ret;
742 lzma_action action;
744 if (io->action == DPKG_STREAM_RUN)
745 action = LZMA_RUN;
746 else if (io->action == DPKG_STREAM_FINISH)
747 action = LZMA_FINISH;
748 else
749 internerr("unknown stream filter action %d\n", io->action);
751 ret = lzma_code(s, action);
753 if (ret == LZMA_STREAM_END)
754 io->status = DPKG_STREAM_END;
755 else if (ret != LZMA_OK)
756 filter_lzma_error(io, ret);
759 static void
760 filter_lzma_done(struct io_lzma *io, lzma_stream *s)
762 lzma_end(s);
765 static void
766 decompress_xz(struct compress_params *params, int fd_in, int fd_out,
767 const char *desc)
769 struct io_lzma io;
771 io.init = filter_unxz_init;
772 io.code = filter_lzma_code;
773 io.done = filter_lzma_done;
774 io.desc = desc;
775 io.params = params;
777 filter_lzma(&io, fd_in, fd_out);
780 static void
781 compress_xz(struct compress_params *params, int fd_in, int fd_out,
782 const char *desc)
784 struct io_lzma io;
786 io.init = filter_xz_init;
787 io.code = filter_lzma_code;
788 io.done = filter_lzma_done;
789 io.desc = desc;
790 io.params = params;
792 filter_lzma(&io, fd_in, fd_out);
794 #else
795 static const char *env_xz[] = { "XZ_DEFAULTS", "XZ_OPT", NULL };
797 static void
798 decompress_xz(struct compress_params *params, int fd_in, int fd_out,
799 const char *desc)
801 struct command cmd;
802 char *threads_opt = NULL;
804 command_decompress_init(&cmd, XZ, desc);
806 if (params->threads_max > 0) {
807 threads_opt = str_fmt("-T%d", params->threads_max);
808 command_add_arg(&cmd, threads_opt);
811 fd_fd_filter(&cmd, fd_in, fd_out, env_xz);
813 command_destroy(&cmd);
814 free(threads_opt);
817 static void
818 compress_xz(struct compress_params *params, int fd_in, int fd_out,
819 const char *desc)
821 struct command cmd;
822 char *threads_opt = NULL;
824 command_compress_init(&cmd, XZ, desc, params->level);
826 if (params->strategy == COMPRESSOR_STRATEGY_EXTREME)
827 command_add_arg(&cmd, "-e");
829 if (params->threads_max > 0) {
830 /* Do not generate warnings when adjusting memory usage, nor
831 * exit with non-zero due to those not emitted warnings. */
832 command_add_arg(&cmd, "--quiet");
833 command_add_arg(&cmd, "--no-warn");
835 /* Do not let xz fallback to single-threaded mode, to avoid
836 * non-reproducible output. */
837 command_add_arg(&cmd, "--no-adjust");
839 /* The xz -T1 option selects a single-threaded mode which
840 * generates different output than in multi-threaded mode.
841 * To avoid the non-reproducible output we pass -T+1
842 * (supported with xz >= 5.4.0) to request multi-threaded
843 * mode with a single thread. */
844 if (params->threads_max == 1)
845 threads_opt = m_strdup("-T+1");
846 else
847 threads_opt = str_fmt("-T%d", params->threads_max);
848 command_add_arg(&cmd, threads_opt);
851 fd_fd_filter(&cmd, fd_in, fd_out, env_xz);
853 command_destroy(&cmd);
854 free(threads_opt);
856 #endif
858 static const struct compressor compressor_xz = {
859 .name = "xz",
860 .extension = ".xz",
861 .default_level = 6,
862 .fixup_params = fixup_none_params,
863 .compress = compress_xz,
864 .decompress = decompress_xz,
868 * Lzma compressor.
871 #ifdef WITH_LIBLZMA
872 static void
873 filter_unlzma_init(struct io_lzma *io, lzma_stream *s)
875 uint64_t memlimit = UINT64_MAX;
876 lzma_ret ret;
878 io->filter = DPKG_STREAM_DECOMPRESS;
880 ret = lzma_alone_decoder(s, memlimit);
881 if (ret != LZMA_OK)
882 filter_lzma_error(io, ret);
885 static void
886 filter_lzma_init(struct io_lzma *io, lzma_stream *s)
888 uint32_t preset;
889 lzma_options_lzma options;
890 lzma_ret ret;
892 io->filter = DPKG_STREAM_COMPRESS;
894 preset = io->params->level;
895 if (io->params->strategy == COMPRESSOR_STRATEGY_EXTREME)
896 preset |= LZMA_PRESET_EXTREME;
897 if (lzma_lzma_preset(&options, preset))
898 filter_lzma_error(io, LZMA_OPTIONS_ERROR);
900 ret = lzma_alone_encoder(s, &options);
901 if (ret != LZMA_OK)
902 filter_lzma_error(io, ret);
905 static void
906 decompress_lzma(struct compress_params *params, int fd_in, int fd_out,
907 const char *desc)
909 struct io_lzma io;
911 io.init = filter_unlzma_init;
912 io.code = filter_lzma_code;
913 io.done = filter_lzma_done;
914 io.desc = desc;
915 io.params = params;
917 filter_lzma(&io, fd_in, fd_out);
920 static void
921 compress_lzma(struct compress_params *params, int fd_in, int fd_out,
922 const char *desc)
924 struct io_lzma io;
926 io.init = filter_lzma_init;
927 io.code = filter_lzma_code;
928 io.done = filter_lzma_done;
929 io.desc = desc;
930 io.params = params;
932 filter_lzma(&io, fd_in, fd_out);
934 #else
935 static void
936 decompress_lzma(struct compress_params *params, int fd_in, int fd_out,
937 const char *desc)
939 struct command cmd;
941 command_decompress_init(&cmd, XZ, desc);
942 command_add_arg(&cmd, "--format=lzma");
944 fd_fd_filter(&cmd, fd_in, fd_out, env_xz);
946 command_destroy(&cmd);
949 static void
950 compress_lzma(struct compress_params *params, int fd_in, int fd_out,
951 const char *desc)
953 struct command cmd;
955 command_compress_init(&cmd, XZ, desc, params->level);
956 command_add_arg(&cmd, "--format=lzma");
958 fd_fd_filter(&cmd, fd_in, fd_out, env_xz);
960 command_destroy(&cmd);
962 #endif
964 static const struct compressor compressor_lzma = {
965 .name = "lzma",
966 .extension = ".lzma",
967 .default_level = 6,
968 .fixup_params = fixup_none_params,
969 .compress = compress_lzma,
970 .decompress = decompress_lzma,
974 * ZStandard compressor.
977 #define ZSTD "zstd"
979 #ifdef WITH_LIBZSTD
980 struct io_zstd_stream {
981 enum dpkg_stream_filter filter;
982 enum dpkg_stream_action action;
983 enum dpkg_stream_status status;
985 union {
986 ZSTD_CCtx *c;
987 ZSTD_DCtx *d;
988 } ctx;
990 const uint8_t *next_in;
991 size_t avail_in;
992 uint8_t *next_out;
993 size_t avail_out;
996 struct io_zstd {
997 const char *desc;
999 struct compress_params *params;
1001 void (*init)(struct io_zstd *io, struct io_zstd_stream *s);
1002 void (*code)(struct io_zstd *io, struct io_zstd_stream *s);
1003 void (*done)(struct io_zstd *io, struct io_zstd_stream *s);
1006 static void DPKG_ATTR_NORET
1007 filter_zstd_error(struct io_zstd *io, size_t ret)
1009 ohshit(_("%s: zstd error: %s"), io->desc, ZSTD_getErrorName(ret));
1012 static uint32_t
1013 filter_zstd_get_cputhreads(struct compress_params *params)
1015 ZSTD_bounds workers;
1016 long threads_max = 1;
1018 /* The shared library has not been built with multi-threading. */
1019 workers = ZSTD_cParam_getBounds(ZSTD_c_nbWorkers);
1020 if (workers.upperBound == 0)
1021 return 1;
1023 #ifdef _SC_NPROCESSORS_ONLN
1024 threads_max = sysconf(_SC_NPROCESSORS_ONLN);
1025 if (threads_max < 0)
1026 return 1;
1027 #endif
1029 if (params->threads_max >= 0)
1030 return clamp(params->threads_max, 1, threads_max);
1032 return threads_max;
1035 static size_t
1036 filter_zstd_get_buf_in_size(struct io_zstd_stream *s)
1038 if (s->filter == DPKG_STREAM_DECOMPRESS)
1039 return ZSTD_DStreamInSize();
1040 else
1041 return ZSTD_CStreamInSize();
1044 static size_t
1045 filter_zstd_get_buf_out_size(struct io_zstd_stream *s)
1047 if (s->filter == DPKG_STREAM_DECOMPRESS)
1048 return ZSTD_DStreamOutSize();
1049 else
1050 return ZSTD_CStreamOutSize();
1053 static void
1054 filter_unzstd_init(struct io_zstd *io, struct io_zstd_stream *s)
1056 s->filter = DPKG_STREAM_DECOMPRESS;
1057 s->action = DPKG_STREAM_RUN;
1058 s->status = DPKG_STREAM_OK;
1060 s->ctx.d = ZSTD_createDCtx();
1061 if (s->ctx.d == NULL)
1062 ohshit(_("%s: cannot create zstd decompression context"),
1063 io->desc);
1066 static void
1067 filter_unzstd_code(struct io_zstd *io, struct io_zstd_stream *s)
1069 ZSTD_inBuffer buf_in = { s->next_in, s->avail_in, 0 };
1070 ZSTD_outBuffer buf_out = { s->next_out, s->avail_out, 0 };
1071 size_t ret;
1073 ret = ZSTD_decompressStream(s->ctx.d, &buf_out, &buf_in);
1074 if (ZSTD_isError(ret))
1075 filter_zstd_error(io, ret);
1077 s->next_in += buf_in.pos;
1078 s->avail_in -= buf_in.pos;
1079 s->next_out += buf_out.pos;
1080 s->avail_out -= buf_out.pos;
1082 if (ret == 0)
1083 s->status = DPKG_STREAM_END;
1086 static void
1087 filter_unzstd_done(struct io_zstd *io, struct io_zstd_stream *s)
1089 ZSTD_freeDCtx(s->ctx.d);
1092 static void
1093 filter_zstd_init(struct io_zstd *io, struct io_zstd_stream *s)
1095 int clevel = io->params->level;
1096 uint32_t nthreads;
1097 size_t ret;
1099 s->filter = DPKG_STREAM_COMPRESS;
1100 s->action = DPKG_STREAM_RUN;
1101 s->status = DPKG_STREAM_OK;
1103 s->ctx.c = ZSTD_createCCtx();
1104 if (s->ctx.c == NULL)
1105 ohshit(_("%s: cannot create zstd compression context"),
1106 io->desc);
1108 ret = ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_compressionLevel, clevel);
1109 if (ZSTD_isError(ret))
1110 filter_zstd_error(io, ret);
1111 ret = ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_checksumFlag, 1);
1112 if (ZSTD_isError(ret))
1113 filter_zstd_error(io, ret);
1115 nthreads = filter_zstd_get_cputhreads(io->params);
1116 if (nthreads > 1)
1117 ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_nbWorkers, nthreads);
1120 static void
1121 filter_zstd_code(struct io_zstd *io, struct io_zstd_stream *s)
1123 ZSTD_inBuffer buf_in = { s->next_in, s->avail_in, 0 };
1124 ZSTD_outBuffer buf_out = { s->next_out, s->avail_out, 0 };
1125 ZSTD_EndDirective action;
1126 size_t ret;
1128 if (s->action == DPKG_STREAM_FINISH)
1129 action = ZSTD_e_end;
1130 else
1131 action = ZSTD_e_continue;
1133 ret = ZSTD_compressStream2(s->ctx.c, &buf_out, &buf_in, action);
1134 if (ZSTD_isError(ret))
1135 filter_zstd_error(io, ret);
1137 s->next_in += buf_in.pos;
1138 s->avail_in -= buf_in.pos;
1139 s->next_out += buf_out.pos;
1140 s->avail_out -= buf_out.pos;
1142 if (s->action == DPKG_STREAM_FINISH && ret == 0)
1143 s->status = DPKG_STREAM_END;
1146 static void
1147 filter_zstd_done(struct io_zstd *io, struct io_zstd_stream *s)
1149 ZSTD_freeCCtx(s->ctx.c);
1152 static void
1153 filter_zstd(struct io_zstd *io, int fd_in, int fd_out)
1155 ssize_t buf_in_size;
1156 ssize_t buf_out_size;
1157 uint8_t *buf_in;
1158 uint8_t *buf_out;
1159 struct io_zstd_stream s = {
1160 .action = DPKG_STREAM_INIT,
1163 io->init(io, &s);
1165 buf_in_size = filter_zstd_get_buf_in_size(&s);
1166 buf_in = m_malloc(buf_in_size);
1167 buf_out_size = filter_zstd_get_buf_out_size(&s);
1168 buf_out = m_malloc(buf_out_size);
1170 s.next_out = buf_out;
1171 s.avail_out = buf_out_size;
1173 do {
1174 ssize_t len;
1176 if (s.avail_in == 0 && s.action != DPKG_STREAM_FINISH) {
1177 len = fd_read(fd_in, buf_in, buf_in_size);
1178 if (len < 0)
1179 ohshite(_("%s: zstd read error"), io->desc);
1180 if (len < buf_in_size)
1181 s.action = DPKG_STREAM_FINISH;
1182 s.next_in = buf_in;
1183 s.avail_in = len;
1186 io->code(io, &s);
1188 if (s.avail_out == 0 || s.status == DPKG_STREAM_END) {
1189 len = fd_write(fd_out, buf_out, s.next_out - buf_out);
1190 if (len < 0)
1191 ohshite(_("%s: zstd write error"), io->desc);
1192 s.next_out = buf_out;
1193 s.avail_out = buf_out_size;
1195 } while (s.status != DPKG_STREAM_END);
1197 io->done(io, &s);
1199 free(buf_in);
1200 free(buf_out);
1202 if (close(fd_out))
1203 ohshite(_("%s: zstd close error"), io->desc);
1206 static void
1207 decompress_zstd(struct compress_params *params, int fd_in, int fd_out,
1208 const char *desc)
1210 struct io_zstd io;
1212 io.init = filter_unzstd_init;
1213 io.code = filter_unzstd_code;
1214 io.done = filter_unzstd_done;
1215 io.desc = desc;
1216 io.params = params;
1218 filter_zstd(&io, fd_in, fd_out);
1221 static void
1222 compress_zstd(struct compress_params *params, int fd_in, int fd_out,
1223 const char *desc)
1225 struct io_zstd io;
1227 io.init = filter_zstd_init;
1228 io.code = filter_zstd_code;
1229 io.done = filter_zstd_done;
1230 io.desc = desc;
1231 io.params = params;
1233 filter_zstd(&io, fd_in, fd_out);
1235 #else
1236 static const char *env_zstd[] = {
1237 "ZSTD_CLEVEL",
1238 "ZSTD_NBTHREADS",
1239 NULL,
1242 static void
1243 decompress_zstd(struct compress_params *params, int fd_in, int fd_out,
1244 const char *desc)
1246 struct command cmd;
1247 char *threads_opt = NULL;
1249 command_decompress_init(&cmd, ZSTD, desc);
1250 command_add_arg(&cmd, "-q");
1252 if (params->threads_max > 0) {
1253 threads_opt = str_fmt("-T%d", params->threads_max);
1254 command_add_arg(&cmd, threads_opt);
1257 fd_fd_filter(&cmd, fd_in, fd_out, env_zstd);
1259 command_destroy(&cmd);
1260 free(threads_opt);
1263 static void
1264 compress_zstd(struct compress_params *params, int fd_in, int fd_out,
1265 const char *desc)
1267 struct command cmd;
1268 char *threads_opt = NULL;
1270 command_compress_init(&cmd, ZSTD, desc, params->level);
1271 command_add_arg(&cmd, "-q");
1273 if (params->level > 19)
1274 command_add_arg(&cmd, "--ultra");
1276 if (params->threads_max > 0) {
1277 threads_opt = str_fmt("-T%d", params->threads_max);
1278 command_add_arg(&cmd, threads_opt);
1281 fd_fd_filter(&cmd, fd_in, fd_out, env_zstd);
1283 command_destroy(&cmd);
1284 free(threads_opt);
1286 #endif
1288 static const struct compressor compressor_zstd = {
1289 .name = "zstd",
1290 .extension = ".zst",
1291 .default_level = ZSTD_CLEVEL_DEFAULT,
1292 .fixup_params = fixup_none_params,
1293 .compress = compress_zstd,
1294 .decompress = decompress_zstd,
1298 * Generic compressor filter.
1301 static const struct compressor *compressor_array[] = {
1302 [COMPRESSOR_TYPE_NONE] = &compressor_none,
1303 [COMPRESSOR_TYPE_GZIP] = &compressor_gzip,
1304 [COMPRESSOR_TYPE_XZ] = &compressor_xz,
1305 [COMPRESSOR_TYPE_ZSTD] = &compressor_zstd,
1306 [COMPRESSOR_TYPE_BZIP2] = &compressor_bzip2,
1307 [COMPRESSOR_TYPE_LZMA] = &compressor_lzma,
1310 static const struct compressor *
1311 compressor(enum compressor_type type)
1313 const enum compressor_type max_type = array_count(compressor_array);
1315 if (type < 0 || type >= max_type)
1316 internerr("compressor_type %d is out of range", type);
1318 return compressor_array[type];
1321 const char *
1322 compressor_get_name(enum compressor_type type)
1324 return compressor(type)->name;
1327 const char *
1328 compressor_get_extension(enum compressor_type type)
1330 return compressor(type)->extension;
1333 enum compressor_type
1334 compressor_find_by_name(const char *name)
1336 size_t i;
1338 for (i = 0; i < array_count(compressor_array); i++)
1339 if (strcmp(compressor_array[i]->name, name) == 0)
1340 return i;
1342 return COMPRESSOR_TYPE_UNKNOWN;
1345 enum compressor_type
1346 compressor_find_by_extension(const char *extension)
1348 size_t i;
1350 for (i = 0; i < array_count(compressor_array); i++)
1351 if (strcmp(compressor_array[i]->extension, extension) == 0)
1352 return i;
1354 return COMPRESSOR_TYPE_UNKNOWN;
1357 enum compressor_strategy
1358 compressor_get_strategy(const char *name)
1360 if (strcmp(name, "none") == 0)
1361 return COMPRESSOR_STRATEGY_NONE;
1362 if (strcmp(name, "filtered") == 0)
1363 return COMPRESSOR_STRATEGY_FILTERED;
1364 if (strcmp(name, "huffman") == 0)
1365 return COMPRESSOR_STRATEGY_HUFFMAN;
1366 if (strcmp(name, "rle") == 0)
1367 return COMPRESSOR_STRATEGY_RLE;
1368 if (strcmp(name, "fixed") == 0)
1369 return COMPRESSOR_STRATEGY_FIXED;
1370 if (strcmp(name, "extreme") == 0)
1371 return COMPRESSOR_STRATEGY_EXTREME;
1373 return COMPRESSOR_STRATEGY_UNKNOWN;
1376 static void
1377 compressor_fixup_params(struct compress_params *params)
1379 compressor(params->type)->fixup_params(params);
1381 if (params->level < 0)
1382 params->level = compressor(params->type)->default_level;
1385 bool
1386 compressor_check_params(struct compress_params *params, struct dpkg_error *err)
1388 compressor_fixup_params(params);
1390 if ((params->type == COMPRESSOR_TYPE_ZSTD &&
1391 params->level > DPKG_ZSTD_MAX_LEVEL) ||
1392 (params->type != COMPRESSOR_TYPE_ZSTD &&
1393 params->level > 9)) {
1394 dpkg_put_error(err, _("invalid compression level %d"),
1395 params->level);
1396 return false;
1399 if (params->strategy == COMPRESSOR_STRATEGY_NONE)
1400 return true;
1402 if (params->type == COMPRESSOR_TYPE_GZIP &&
1403 (params->strategy == COMPRESSOR_STRATEGY_FILTERED ||
1404 params->strategy == COMPRESSOR_STRATEGY_HUFFMAN ||
1405 params->strategy == COMPRESSOR_STRATEGY_RLE ||
1406 params->strategy == COMPRESSOR_STRATEGY_FIXED))
1407 return true;
1409 if (params->type == COMPRESSOR_TYPE_XZ &&
1410 params->strategy == COMPRESSOR_STRATEGY_EXTREME)
1411 return true;
1413 dpkg_put_error(err, _("unknown compression strategy"));
1414 return false;
1417 void
1418 decompress_filter(struct compress_params *params, int fd_in, int fd_out,
1419 const char *desc_fmt, ...)
1421 va_list args;
1422 struct varbuf desc = VARBUF_INIT;
1424 va_start(args, desc_fmt);
1425 varbuf_vprintf(&desc, desc_fmt, args);
1426 va_end(args);
1428 compressor(params->type)->decompress(params, fd_in, fd_out, desc.buf);
1430 varbuf_destroy(&desc);
1433 void
1434 compress_filter(struct compress_params *params, int fd_in, int fd_out,
1435 const char *desc_fmt, ...)
1437 va_list args;
1438 struct varbuf desc = VARBUF_INIT;
1440 va_start(args, desc_fmt);
1441 varbuf_vprintf(&desc, desc_fmt, args);
1442 va_end(args);
1444 compressor(params->type)->compress(params, fd_in, fd_out, desc.buf);
1446 varbuf_destroy(&desc);