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/>.
32 #if USE_LIBZ_IMPL != USE_LIBZ_IMPL_NONE
33 #include <compat-zlib.h>
40 #define DPKG_ZSTD_MAX_LEVEL ZSTD_maxCLevel()
42 #define DPKG_ZSTD_MAX_LEVEL 22
43 #define ZSTD_CLEVEL_DEFAULT 3
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) || \
62 #include <dpkg/subproc.h>
65 fd_fd_filter(struct command
*cmd
, int fd_in
, int fd_out
, const char *delenv
[])
82 for (i
= 0; delenv
[i
]; i
++)
87 subproc_reap(pid
, cmd
->name
, 0);
91 command_compress_init(struct command
*cmd
, const char *name
, const char *desc
,
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
);
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");
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,
121 DPKG_STREAM_FINISH
= 2,
124 enum dpkg_stream_status
{
133 const char *extension
;
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).
147 fixup_none_params(struct compress_params
*params
)
152 decompress_none(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
162 compress_none(struct compress_params
*params
, int fd_in
, int fd_out
,
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
= {
175 .fixup_params
= fixup_none_params
,
176 .compress
= compress_none
,
177 .decompress
= decompress_none
,
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
196 decompress_gzip(struct compress_params
*params
, int fd_in
, int fd_out
,
200 size_t bufsize
= DPKG_BUFFER_SIZE
;
202 gzFile gzfile
= gzdopen(fd_in
, "r");
205 ohshit(_("%s: error binding input to gzip stream"), desc
);
207 buffer
= m_malloc(bufsize
);
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
,
221 if (actualread
== 0) /* EOF. */
224 actualwrite
= fd_write(fd_out
, buffer
, actualread
);
225 if (actualwrite
!= actualread
)
226 ohshite(_("%s: internal gzip write error"), desc
);
231 z_errnum
= gzclose(gzfile
);
235 if (z_errnum
== Z_ERRNO
)
236 errmsg
= strerror(errno
);
238 errmsg
= zError(z_errnum
);
239 ohshit(_("%s: internal gzip read error: %s"), desc
, errmsg
);
243 ohshite(_("%s: internal gzip write error"), desc
);
247 compress_gzip(struct compress_params
*params
, int fd_in
, int fd_out
,
252 size_t bufsize
= DPKG_BUFFER_SIZE
;
257 if (params
->strategy
== COMPRESSOR_STRATEGY_FILTERED
)
259 else if (params
->strategy
== COMPRESSOR_STRATEGY_HUFFMAN
)
261 else if (params
->strategy
== COMPRESSOR_STRATEGY_RLE
)
263 else if (params
->strategy
== COMPRESSOR_STRATEGY_FIXED
)
268 snprintf(combuf
, sizeof(combuf
), "w%d%c", params
->level
, strategy
);
269 gzfile
= gzdopen(fd_out
, combuf
);
271 ohshit(_("%s: error binding output to gzip stream"), desc
);
273 buffer
= m_malloc(bufsize
);
276 int actualread
, actualwrite
;
278 actualread
= fd_read(fd_in
, buffer
, bufsize
);
280 ohshite(_("%s: internal gzip read error"), desc
);
281 if (actualread
== 0) /* EOF. */
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
,
297 z_errnum
= gzclose(gzfile
);
301 if (z_errnum
== Z_ERRNO
)
302 errmsg
= strerror(errno
);
304 errmsg
= zError(z_errnum
);
305 ohshit(_("%s: internal gzip write error: %s"), desc
, errmsg
);
309 static const char *env_gzip
[] = { "GZIP", NULL
};
312 decompress_gzip(struct compress_params
*params
, int fd_in
, int fd_out
,
317 command_decompress_init(&cmd
, GZIP
, desc
);
319 fd_fd_filter(&cmd
, fd_in
, fd_out
, env_gzip
);
321 command_destroy(&cmd
);
325 compress_gzip(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
339 static const struct compressor compressor_gzip
= {
343 .fixup_params
= fixup_gzip_params
,
344 .compress
= compress_gzip
,
345 .decompress
= decompress_gzip
,
352 #define BZIP2 "bzip2"
355 fixup_bzip2_params(struct compress_params
*params
)
357 /* Normalize compression level. */
358 if (params
->level
== 0)
364 decompress_bzip2(struct compress_params
*params
, int fd_in
, int fd_out
,
368 size_t bufsize
= DPKG_BUFFER_SIZE
;
369 BZFILE
*bzfile
= BZ2_bzdopen(fd_in
, "r");
372 ohshit(_("%s: error binding input to bzip2 stream"), desc
);
374 buffer
= m_malloc(bufsize
);
377 int actualread
, actualwrite
;
379 actualread
= BZ2_bzread(bzfile
, buffer
, bufsize
);
380 if (actualread
< 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
,
389 if (actualread
== 0) /* EOF. */
392 actualwrite
= fd_write(fd_out
, buffer
, actualread
);
393 if (actualwrite
!= actualread
)
394 ohshite(_("%s: internal bzip2 write error"), desc
);
402 ohshite(_("%s: internal bzip2 write error"), desc
);
406 compress_bzip2(struct compress_params
*params
, int fd_in
, int fd_out
,
411 size_t bufsize
= DPKG_BUFFER_SIZE
;
415 snprintf(combuf
, sizeof(combuf
), "w%d", params
->level
);
416 bzfile
= BZ2_bzdopen(fd_out
, combuf
);
418 ohshit(_("%s: error binding output to bzip2 stream"), desc
);
420 buffer
= m_malloc(bufsize
);
423 int actualread
, actualwrite
;
425 actualread
= fd_read(fd_in
, buffer
, bufsize
);
427 ohshite(_("%s: internal bzip2 read error"), desc
);
428 if (actualread
== 0) /* EOF. */
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
,
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
,
454 /* Because BZ2_bzWriteClose has done a fflush on the file handle,
455 * doing a close on the file descriptor associated with it should
458 ohshite(_("%s: internal bzip2 write error"), desc
);
461 static const char *env_bzip2
[] = { "BZIP", "BZIP2", NULL
};
464 decompress_bzip2(struct compress_params
*params
, int fd_in
, int fd_out
,
469 command_decompress_init(&cmd
, BZIP2
, desc
);
471 fd_fd_filter(&cmd
, fd_in
, fd_out
, env_bzip2
);
473 command_destroy(&cmd
);
477 compress_bzip2(struct compress_params
*params
, int fd_in
, int fd_out
,
482 command_compress_init(&cmd
, BZIP2
, desc
, params
->level
);
484 fd_fd_filter(&cmd
, fd_in
, fd_out
, env_bzip2
);
486 command_destroy(&cmd
);
490 static const struct compressor compressor_bzip2
= {
494 .fixup_params
= fixup_bzip2_params
,
495 .compress
= compress_bzip2
,
496 .decompress
= decompress_bzip2
,
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. */
522 dpkg_lzma_strerror(struct io_lzma
*io
, lzma_ret code
)
524 const char *const impossible
= _("internal error (bug)");
528 return strerror(ENOMEM
);
529 case LZMA_MEMLIMIT_ERROR
:
530 if (io
->action
== DPKG_STREAM_RUN
)
531 return _("memory usage limit reached");
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");
541 case LZMA_DATA_ERROR
:
542 if (io
->action
== DPKG_STREAM_RUN
)
543 return _("compressed data is corrupt");
546 if (io
->action
== DPKG_STREAM_RUN
)
547 return _("unexpected end of input");
549 case LZMA_FORMAT_ERROR
:
550 if (io
->filter
== DPKG_STREAM_DECOMPRESS
&&
551 io
->action
== DPKG_STREAM_RUN
)
552 return _("file format not recognized");
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");
565 filter_lzma(struct io_lzma
*io
, int fd_in
, int fd_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
;
581 io
->action
= DPKG_STREAM_RUN
;
586 if (s
.avail_in
== 0 && io
->action
!= DPKG_STREAM_FINISH
) {
587 len
= fd_read(fd_in
, buf_in
, buf_size
);
589 ohshite(_("%s: lzma read error"), io
->desc
);
591 io
->action
= DPKG_STREAM_FINISH
;
598 if (s
.avail_out
== 0 || io
->status
== DPKG_STREAM_END
) {
599 len
= fd_write(fd_out
, buf_out
, s
.next_out
- buf_out
);
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
);
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
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
;
646 filter_xz_get_cputhreads(struct compress_params
*params
)
650 threads_max
= lzma_cputhreads();
651 if (threads_max
== 0)
654 if (params
->threads_max
>= 0)
655 return clamp(params
->threads_max
, 1, threads_max
);
662 filter_unxz_init(struct io_lzma
*io
, lzma_stream
*s
)
664 #ifdef HAVE_LZMA_MT_DECODER
665 lzma_mt mt_options
= {
672 uint64_t memlimit
= UINT64_MAX
;
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
);
685 ret
= lzma_stream_decoder(s
, memlimit
, 0);
688 filter_lzma_error(io
, ret
);
692 filter_xz_init(struct io_lzma
*io
, lzma_stream
*s
)
695 lzma_check check
= LZMA_CHECK_CRC64
;
696 #ifdef HAVE_LZMA_MT_ENCODER
697 uint64_t mt_memlimit
;
698 lzma_mt mt_options
= {
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
)
729 ret
= lzma_stream_encoder_mt(s
, &mt_options
);
731 ret
= lzma_easy_encoder(s
, preset
, check
);
735 filter_lzma_error(io
, ret
);
739 filter_lzma_code(struct io_lzma
*io
, lzma_stream
*s
)
744 if (io
->action
== DPKG_STREAM_RUN
)
746 else if (io
->action
== DPKG_STREAM_FINISH
)
747 action
= LZMA_FINISH
;
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
);
760 filter_lzma_done(struct io_lzma
*io
, lzma_stream
*s
)
766 decompress_xz(struct compress_params
*params
, int fd_in
, int fd_out
,
771 io
.init
= filter_unxz_init
;
772 io
.code
= filter_lzma_code
;
773 io
.done
= filter_lzma_done
;
777 filter_lzma(&io
, fd_in
, fd_out
);
781 compress_xz(struct compress_params
*params
, int fd_in
, int fd_out
,
786 io
.init
= filter_xz_init
;
787 io
.code
= filter_lzma_code
;
788 io
.done
= filter_lzma_done
;
792 filter_lzma(&io
, fd_in
, fd_out
);
795 static const char *env_xz
[] = { "XZ_DEFAULTS", "XZ_OPT", NULL
};
798 decompress_xz(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
818 compress_xz(struct compress_params
*params
, int fd_in
, int fd_out
,
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");
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
);
858 static const struct compressor compressor_xz
= {
862 .fixup_params
= fixup_none_params
,
863 .compress
= compress_xz
,
864 .decompress
= decompress_xz
,
873 filter_unlzma_init(struct io_lzma
*io
, lzma_stream
*s
)
875 uint64_t memlimit
= UINT64_MAX
;
878 io
->filter
= DPKG_STREAM_DECOMPRESS
;
880 ret
= lzma_alone_decoder(s
, memlimit
);
882 filter_lzma_error(io
, ret
);
886 filter_lzma_init(struct io_lzma
*io
, lzma_stream
*s
)
889 lzma_options_lzma options
;
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
);
902 filter_lzma_error(io
, ret
);
906 decompress_lzma(struct compress_params
*params
, int fd_in
, int fd_out
,
911 io
.init
= filter_unlzma_init
;
912 io
.code
= filter_lzma_code
;
913 io
.done
= filter_lzma_done
;
917 filter_lzma(&io
, fd_in
, fd_out
);
921 compress_lzma(struct compress_params
*params
, int fd_in
, int fd_out
,
926 io
.init
= filter_lzma_init
;
927 io
.code
= filter_lzma_code
;
928 io
.done
= filter_lzma_done
;
932 filter_lzma(&io
, fd_in
, fd_out
);
936 decompress_lzma(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
950 compress_lzma(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
964 static const struct compressor compressor_lzma
= {
966 .extension
= ".lzma",
968 .fixup_params
= fixup_none_params
,
969 .compress
= compress_lzma
,
970 .decompress
= decompress_lzma
,
974 * ZStandard compressor.
980 struct io_zstd_stream
{
981 enum dpkg_stream_filter filter
;
982 enum dpkg_stream_action action
;
983 enum dpkg_stream_status status
;
990 const uint8_t *next_in
;
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
));
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)
1023 #ifdef _SC_NPROCESSORS_ONLN
1024 threads_max
= sysconf(_SC_NPROCESSORS_ONLN
);
1025 if (threads_max
< 0)
1029 if (params
->threads_max
>= 0)
1030 return clamp(params
->threads_max
, 1, threads_max
);
1036 filter_zstd_get_buf_in_size(struct io_zstd_stream
*s
)
1038 if (s
->filter
== DPKG_STREAM_DECOMPRESS
)
1039 return ZSTD_DStreamInSize();
1041 return ZSTD_CStreamInSize();
1045 filter_zstd_get_buf_out_size(struct io_zstd_stream
*s
)
1047 if (s
->filter
== DPKG_STREAM_DECOMPRESS
)
1048 return ZSTD_DStreamOutSize();
1050 return ZSTD_CStreamOutSize();
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"),
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 };
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
;
1083 s
->status
= DPKG_STREAM_END
;
1087 filter_unzstd_done(struct io_zstd
*io
, struct io_zstd_stream
*s
)
1089 ZSTD_freeDCtx(s
->ctx
.d
);
1093 filter_zstd_init(struct io_zstd
*io
, struct io_zstd_stream
*s
)
1095 int clevel
= io
->params
->level
;
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"),
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
);
1117 ZSTD_CCtx_setParameter(s
->ctx
.c
, ZSTD_c_nbWorkers
, nthreads
);
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
;
1128 if (s
->action
== DPKG_STREAM_FINISH
)
1129 action
= ZSTD_e_end
;
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
;
1147 filter_zstd_done(struct io_zstd
*io
, struct io_zstd_stream
*s
)
1149 ZSTD_freeCCtx(s
->ctx
.c
);
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
;
1159 struct io_zstd_stream s
= {
1160 .action
= DPKG_STREAM_INIT
,
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
;
1176 if (s
.avail_in
== 0 && s
.action
!= DPKG_STREAM_FINISH
) {
1177 len
= fd_read(fd_in
, buf_in
, buf_in_size
);
1179 ohshite(_("%s: zstd read error"), io
->desc
);
1180 if (len
< buf_in_size
)
1181 s
.action
= DPKG_STREAM_FINISH
;
1188 if (s
.avail_out
== 0 || s
.status
== DPKG_STREAM_END
) {
1189 len
= fd_write(fd_out
, buf_out
, s
.next_out
- buf_out
);
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
);
1203 ohshite(_("%s: zstd close error"), io
->desc
);
1207 decompress_zstd(struct compress_params
*params
, int fd_in
, int fd_out
,
1212 io
.init
= filter_unzstd_init
;
1213 io
.code
= filter_unzstd_code
;
1214 io
.done
= filter_unzstd_done
;
1218 filter_zstd(&io
, fd_in
, fd_out
);
1222 compress_zstd(struct compress_params
*params
, int fd_in
, int fd_out
,
1227 io
.init
= filter_zstd_init
;
1228 io
.code
= filter_zstd_code
;
1229 io
.done
= filter_zstd_done
;
1233 filter_zstd(&io
, fd_in
, fd_out
);
1236 static const char *env_zstd
[] = {
1243 decompress_zstd(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
1264 compress_zstd(struct compress_params
*params
, int fd_in
, int fd_out
,
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
);
1288 static const struct compressor compressor_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
];
1322 compressor_get_name(enum compressor_type type
)
1324 return compressor(type
)->name
;
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
)
1338 for (i
= 0; i
< array_count(compressor_array
); i
++)
1339 if (strcmp(compressor_array
[i
]->name
, name
) == 0)
1342 return COMPRESSOR_TYPE_UNKNOWN
;
1345 enum compressor_type
1346 compressor_find_by_extension(const char *extension
)
1350 for (i
= 0; i
< array_count(compressor_array
); i
++)
1351 if (strcmp(compressor_array
[i
]->extension
, extension
) == 0)
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
;
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
;
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"),
1399 if (params
->strategy
== COMPRESSOR_STRATEGY_NONE
)
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
))
1409 if (params
->type
== COMPRESSOR_TYPE_XZ
&&
1410 params
->strategy
== COMPRESSOR_STRATEGY_EXTREME
)
1413 dpkg_put_error(err
, _("unknown compression strategy"));
1418 decompress_filter(struct compress_params
*params
, int fd_in
, int fd_out
,
1419 const char *desc_fmt
, ...)
1422 struct varbuf desc
= VARBUF_INIT
;
1424 va_start(args
, desc_fmt
);
1425 varbuf_vprintf(&desc
, desc_fmt
, args
);
1428 compressor(params
->type
)->decompress(params
, fd_in
, fd_out
, desc
.buf
);
1430 varbuf_destroy(&desc
);
1434 compress_filter(struct compress_params
*params
, int fd_in
, int fd_out
,
1435 const char *desc_fmt
, ...)
1438 struct varbuf desc
= VARBUF_INIT
;
1440 va_start(args
, desc_fmt
);
1441 varbuf_vprintf(&desc
, desc_fmt
, args
);
1444 compressor(params
->type
)->compress(params
, fd_in
, fd_out
, desc
.buf
);
1446 varbuf_destroy(&desc
);