dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / compress.c
CommitLineData
1479465f
GJ
1/*
2 * libdpkg - Debian packaging suite library routines
3 * compress.c - compression support functions
4 *
5 * Copyright © 2000 Wichert Akkerman <wakkerma@debian.org>
6 * Copyright © 2004 Scott James Remnant <scott@netsplit.com>
7 * Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
8 *
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.
13 *
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.
18 *
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/>.
21 */
22
23#include <config.h>
24#include <compat.h>
25
26#include <errno.h>
27#include <string.h>
28#include <unistd.h>
29#include <stdbool.h>
30#include <stdlib.h>
31
32#ifdef WITH_LIBZ
33#include <zlib.h>
34#endif
35#ifdef WITH_LIBLZMA
36#include <lzma.h>
37#endif
38#ifdef WITH_LIBBZ2
39#include <bzlib.h>
40#endif
41
42#include <dpkg/i18n.h>
43#include <dpkg/dpkg.h>
44#include <dpkg/error.h>
45#include <dpkg/varbuf.h>
46#include <dpkg/fdio.h>
47#include <dpkg/buffer.h>
48#include <dpkg/command.h>
49#include <dpkg/compress.h>
50#if !defined(WITH_LIBZ) || !defined(WITH_LIBLZMA) || !defined(WITH_LIBBZ2)
51#include <dpkg/subproc.h>
52
53static void DPKG_ATTR_SENTINEL
54fd_fd_filter(int fd_in, int fd_out, const char *desc, const char *delenv[],
55 const char *file, ...)
56{
57 va_list args;
58 struct command cmd;
59 pid_t pid;
60 int i;
61
62 pid = subproc_fork();
63 if (pid == 0) {
64 if (fd_in != 0) {
65 m_dup2(fd_in, 0);
66 close(fd_in);
67 }
68 if (fd_out != 1) {
69 m_dup2(fd_out, 1);
70 close(fd_out);
71 }
72
73 for (i = 0; delenv[i]; i++)
74 unsetenv(delenv[i]);
75
76 command_init(&cmd, file, desc);
77 command_add_arg(&cmd, file);
78 va_start(args, file);
79 command_add_argv(&cmd, args);
80 va_end(args);
81
82 command_exec(&cmd);
83 }
84 subproc_reap(pid, desc, 0);
85}
86#endif
87
88struct compressor {
89 const char *name;
90 const char *extension;
91 int default_level;
92 void (*fixup_params)(struct compress_params *params);
93 void (*compress)(int fd_in, int fd_out, struct compress_params *params,
94 const char *desc);
95 void (*decompress)(int fd_in, int fd_out, const char *desc);
96};
97
98/*
99 * No compressor (pass-through).
100 */
101
102static void
103fixup_none_params(struct compress_params *params)
104{
105}
106
107static void
108decompress_none(int fd_in, int fd_out, const char *desc)
109{
110 struct dpkg_error err;
111
112 if (fd_fd_copy(fd_in, fd_out, -1, &err) < 0)
113 ohshit(_("%s: pass-through copy error: %s"), desc, err.str);
114}
115
116static void
117compress_none(int fd_in, int fd_out, struct compress_params *params, const char *desc)
118{
119 struct dpkg_error err;
120
121 if (fd_fd_copy(fd_in, fd_out, -1, &err) < 0)
122 ohshit(_("%s: pass-through copy error: %s"), desc, err.str);
123}
124
125static const struct compressor compressor_none = {
126 .name = "none",
127 .extension = "",
128 .default_level = 0,
129 .fixup_params = fixup_none_params,
130 .compress = compress_none,
131 .decompress = decompress_none,
132};
133
134/*
135 * Gzip compressor.
136 */
137
138#define GZIP "gzip"
139
140static void
141fixup_gzip_params(struct compress_params *params)
142{
143 /* Normalize compression level. */
144 if (params->level == 0)
145 params->type = COMPRESSOR_TYPE_NONE;
146}
147
148#ifdef WITH_LIBZ
149static void
150decompress_gzip(int fd_in, int fd_out, const char *desc)
151{
152 char buffer[DPKG_BUFFER_SIZE];
153 gzFile gzfile = gzdopen(fd_in, "r");
154
155 if (gzfile == NULL)
156 ohshit(_("%s: error binding input to gzip stream"), desc);
157
158 for (;;) {
159 int actualread, actualwrite;
160
161 actualread = gzread(gzfile, buffer, sizeof(buffer));
162 if (actualread < 0) {
163 int z_errnum = 0;
164 const char *errmsg = gzerror(gzfile, &z_errnum);
165
166 if (z_errnum == Z_ERRNO)
167 errmsg = strerror(errno);
168 ohshit(_("%s: internal gzip read error: '%s'"), desc,
169 errmsg);
170 }
171 if (actualread == 0) /* EOF. */
172 break;
173
174 actualwrite = fd_write(fd_out, buffer, actualread);
175 if (actualwrite != actualread)
176 ohshite(_("%s: internal gzip write error"), desc);
177 }
178
179 if (close(fd_out))
180 ohshite(_("%s: internal gzip write error"), desc);
181}
182
183static void
184compress_gzip(int fd_in, int fd_out, struct compress_params *params, const char *desc)
185{
186 char buffer[DPKG_BUFFER_SIZE];
187 char combuf[6];
188 int strategy;
189 int z_errnum;
190 gzFile gzfile;
191
192 if (params->strategy == COMPRESSOR_STRATEGY_FILTERED)
193 strategy = 'f';
194 else if (params->strategy == COMPRESSOR_STRATEGY_HUFFMAN)
195 strategy = 'h';
196 else if (params->strategy == COMPRESSOR_STRATEGY_RLE)
197 strategy = 'R';
198 else if (params->strategy == COMPRESSOR_STRATEGY_FIXED)
199 strategy = 'F';
200 else
201 strategy = ' ';
202
203 snprintf(combuf, sizeof(combuf), "w%d%c", params->level, strategy);
204 gzfile = gzdopen(fd_out, combuf);
205 if (gzfile == NULL)
206 ohshit(_("%s: error binding output to gzip stream"), desc);
207
208 for (;;) {
209 int actualread, actualwrite;
210
211 actualread = fd_read(fd_in, buffer, sizeof(buffer));
212 if (actualread < 0)
213 ohshite(_("%s: internal gzip read error"), desc);
214 if (actualread == 0) /* EOF. */
215 break;
216
217 actualwrite = gzwrite(gzfile, buffer, actualread);
218 if (actualwrite != actualread) {
219 const char *errmsg = gzerror(gzfile, &z_errnum);
220
221 if (z_errnum == Z_ERRNO)
222 errmsg = strerror(errno);
223 ohshit(_("%s: internal gzip write error: '%s'"), desc,
224 errmsg);
225 }
226 }
227
228 z_errnum = gzclose(gzfile);
229 if (z_errnum) {
230 const char *errmsg;
231
232 if (z_errnum == Z_ERRNO)
233 errmsg = strerror(errno);
234 else
235 errmsg = zError(z_errnum);
236 ohshit(_("%s: internal gzip write error: %s"), desc, errmsg);
237 }
238}
239#else
240static const char *env_gzip[] = { "GZIP", NULL };
241
242static void
243decompress_gzip(int fd_in, int fd_out, const char *desc)
244{
245 fd_fd_filter(fd_in, fd_out, desc, env_gzip, GZIP, "-dc", NULL);
246}
247
248static void
249compress_gzip(int fd_in, int fd_out, struct compress_params *params, const char *desc)
250{
251 char combuf[6];
252
253 snprintf(combuf, sizeof(combuf), "-c%d", params->level);
254 fd_fd_filter(fd_in, fd_out, desc, env_gzip, GZIP, "-n", combuf, NULL);
255}
256#endif
257
258static const struct compressor compressor_gzip = {
259 .name = "gzip",
260 .extension = ".gz",
261 .default_level = 9,
262 .fixup_params = fixup_gzip_params,
263 .compress = compress_gzip,
264 .decompress = decompress_gzip,
265};
266
267/*
268 * Bzip2 compressor.
269 */
270
271#define BZIP2 "bzip2"
272
273static void
274fixup_bzip2_params(struct compress_params *params)
275{
276 /* Normalize compression level. */
277 if (params->level == 0)
278 params->level = 1;
279}
280
281#ifdef WITH_LIBBZ2
282static void
283decompress_bzip2(int fd_in, int fd_out, const char *desc)
284{
285 char buffer[DPKG_BUFFER_SIZE];
286 BZFILE *bzfile = BZ2_bzdopen(fd_in, "r");
287
288 if (bzfile == NULL)
289 ohshit(_("%s: error binding input to bzip2 stream"), desc);
290
291 for (;;) {
292 int actualread, actualwrite;
293
294 actualread = BZ2_bzread(bzfile, buffer, sizeof(buffer));
295 if (actualread < 0) {
296 int bz_errnum = 0;
297 const char *errmsg = BZ2_bzerror(bzfile, &bz_errnum);
298
299 if (bz_errnum == BZ_IO_ERROR)
300 errmsg = strerror(errno);
301 ohshit(_("%s: internal bzip2 read error: '%s'"), desc,
302 errmsg);
303 }
304 if (actualread == 0) /* EOF. */
305 break;
306
307 actualwrite = fd_write(fd_out, buffer, actualread);
308 if (actualwrite != actualread)
309 ohshite(_("%s: internal bzip2 write error"), desc);
310 }
311
312 if (close(fd_out))
313 ohshite(_("%s: internal bzip2 write error"), desc);
314}
315
316static void
317compress_bzip2(int fd_in, int fd_out, struct compress_params *params, const char *desc)
318{
319 char buffer[DPKG_BUFFER_SIZE];
320 char combuf[6];
321 int bz_errnum;
322 BZFILE *bzfile;
323
324 snprintf(combuf, sizeof(combuf), "w%d", params->level);
325 bzfile = BZ2_bzdopen(fd_out, combuf);
326 if (bzfile == NULL)
327 ohshit(_("%s: error binding output to bzip2 stream"), desc);
328
329 for (;;) {
330 int actualread, actualwrite;
331
332 actualread = fd_read(fd_in, buffer, sizeof(buffer));
333 if (actualread < 0)
334 ohshite(_("%s: internal bzip2 read error"), desc);
335 if (actualread == 0) /* EOF. */
336 break;
337
338 actualwrite = BZ2_bzwrite(bzfile, buffer, actualread);
339 if (actualwrite != actualread) {
340 const char *errmsg = BZ2_bzerror(bzfile, &bz_errnum);
341
342 if (bz_errnum == BZ_IO_ERROR)
343 errmsg = strerror(errno);
344 ohshit(_("%s: internal bzip2 write error: '%s'"), desc,
345 errmsg);
346 }
347 }
348
349 BZ2_bzWriteClose(&bz_errnum, bzfile, 0, NULL, NULL);
350 if (bz_errnum != BZ_OK) {
351 const char *errmsg = _("unexpected bzip2 error");
352
353 if (bz_errnum == BZ_IO_ERROR)
354 errmsg = strerror(errno);
355 ohshit(_("%s: internal bzip2 write error: '%s'"), desc,
356 errmsg);
357 }
358
359 /* Because BZ2_bzWriteClose has done a fflush on the file handle,
360 * doing a close on the file descriptor associated with it should
361 * be safe™. */
362 if (close(fd_out))
363 ohshite(_("%s: internal bzip2 write error"), desc);
364}
365#else
366static const char *env_bzip2[] = { "BZIP", "BZIP2", NULL };
367
368static void
369decompress_bzip2(int fd_in, int fd_out, const char *desc)
370{
371 fd_fd_filter(fd_in, fd_out, desc, env_bzip2, BZIP2, "-dc", NULL);
372}
373
374static void
375compress_bzip2(int fd_in, int fd_out, struct compress_params *params, const char *desc)
376{
377 char combuf[6];
378
379 snprintf(combuf, sizeof(combuf), "-c%d", params->level);
380 fd_fd_filter(fd_in, fd_out, desc, env_bzip2, BZIP2, combuf, NULL);
381}
382#endif
383
384static const struct compressor compressor_bzip2 = {
385 .name = "bzip2",
386 .extension = ".bz2",
387 .default_level = 9,
388 .fixup_params = fixup_bzip2_params,
389 .compress = compress_bzip2,
390 .decompress = decompress_bzip2,
391};
392
393/*
394 * Xz compressor.
395 */
396
397#define XZ "xz"
398
399#ifdef WITH_LIBLZMA
400enum dpkg_stream_status {
401 DPKG_STREAM_INIT = DPKG_BIT(1),
402 DPKG_STREAM_RUN = DPKG_BIT(2),
403 DPKG_STREAM_COMPRESS = DPKG_BIT(3),
404 DPKG_STREAM_DECOMPRESS = DPKG_BIT(4),
405 DPKG_STREAM_FILTER = DPKG_STREAM_COMPRESS | DPKG_STREAM_DECOMPRESS,
406};
407
408/* XXX: liblzma does not expose error messages. */
409static const char *
410dpkg_lzma_strerror(lzma_ret code, enum dpkg_stream_status status)
411{
412 const char *const impossible = _("internal error (bug)");
413
414 switch (code) {
415 case LZMA_MEM_ERROR:
416 return strerror(ENOMEM);
417 case LZMA_MEMLIMIT_ERROR:
418 if (status & DPKG_STREAM_RUN)
419 return _("memory usage limit reached");
420 return impossible;
421 case LZMA_OPTIONS_ERROR:
422 if (status == (DPKG_STREAM_INIT | DPKG_STREAM_COMPRESS))
423 return _("unsupported compression preset");
424 if (status == (DPKG_STREAM_RUN | DPKG_STREAM_DECOMPRESS))
425 return _("unsupported options in file header");
426 return impossible;
427 case LZMA_DATA_ERROR:
428 if (status & DPKG_STREAM_RUN)
429 return _("compressed data is corrupt");
430 return impossible;
431 case LZMA_BUF_ERROR:
432 if (status & DPKG_STREAM_RUN)
433 return _("unexpected end of input");
434 return impossible;
435 case LZMA_FORMAT_ERROR:
436 if (status == (DPKG_STREAM_RUN | DPKG_STREAM_DECOMPRESS))
437 return _("file format not recognized");
438 return impossible;
439 case LZMA_UNSUPPORTED_CHECK:
440 if (status == (DPKG_STREAM_INIT | DPKG_STREAM_COMPRESS))
441 return _("unsupported type of integrity check");
442 return impossible;
443 default:
444 return impossible;
445 }
446}
447
448struct io_lzma {
449 const char *desc;
450
451 struct compress_params *params;
452 enum dpkg_stream_status status;
453 lzma_action action;
454
455 void (*init)(struct io_lzma *io, lzma_stream *s);
456 int (*code)(struct io_lzma *io, lzma_stream *s);
457 void (*done)(struct io_lzma *io, lzma_stream *s);
458};
459
460static void
461filter_lzma(struct io_lzma *io, int fd_in, int fd_out)
462{
463 uint8_t buf_in[DPKG_BUFFER_SIZE];
464 uint8_t buf_out[DPKG_BUFFER_SIZE];
465 lzma_stream s = LZMA_STREAM_INIT;
466 lzma_ret ret;
467
468 s.next_out = buf_out;
469 s.avail_out = sizeof(buf_out);
470
471 io->action = LZMA_RUN;
472 io->status = DPKG_STREAM_INIT;
473 io->init(io, &s);
474 io->status = (io->status & DPKG_STREAM_FILTER) | DPKG_STREAM_RUN;
475
476 do {
477 ssize_t len;
478
479 if (s.avail_in == 0 && io->action != LZMA_FINISH) {
480 len = fd_read(fd_in, buf_in, sizeof(buf_in));
481 if (len < 0)
482 ohshite(_("%s: lzma read error"), io->desc);
483 if (len == 0)
484 io->action = LZMA_FINISH;
485 s.next_in = buf_in;
486 s.avail_in = len;
487 }
488
489 ret = io->code(io, &s);
490
491 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
492 len = fd_write(fd_out, buf_out, s.next_out - buf_out);
493 if (len < 0)
494 ohshite(_("%s: lzma write error"), io->desc);
495 s.next_out = buf_out;
496 s.avail_out = sizeof(buf_out);
497 }
498 } while (ret != LZMA_STREAM_END);
499
500 io->done(io, &s);
501
502 if (close(fd_out))
503 ohshite(_("%s: lzma close error"), io->desc);
504}
505
506static void DPKG_ATTR_NORET
507filter_lzma_error(struct io_lzma *io, lzma_ret ret)
508{
509 ohshit(_("%s: lzma error: %s"), io->desc,
510 dpkg_lzma_strerror(ret, io->status));
511}
512
513static void
514filter_unxz_init(struct io_lzma *io, lzma_stream *s)
515{
516 uint64_t memlimit = UINT64_MAX;
517 lzma_ret ret;
518
519 io->status |= DPKG_STREAM_DECOMPRESS;
520
521 ret = lzma_stream_decoder(s, memlimit, 0);
522 if (ret != LZMA_OK)
523 filter_lzma_error(io, ret);
524}
525
526static void
527filter_xz_init(struct io_lzma *io, lzma_stream *s)
528{
529 uint32_t preset;
530 lzma_check check = LZMA_CHECK_CRC64;
531#ifdef HAVE_LZMA_MT
532 uint64_t mt_memlimit;
533 lzma_mt mt_options = {
534 .flags = 0,
535 .block_size = 0,
536 .timeout = 0,
537 .filters = NULL,
538 .check = check,
539 };
540#endif
541 lzma_ret ret;
542
543 io->status |= DPKG_STREAM_COMPRESS;
544
545 preset = io->params->level;
546 if (io->params->strategy == COMPRESSOR_STRATEGY_EXTREME)
547 preset |= LZMA_PRESET_EXTREME;
548
549#ifdef HAVE_LZMA_MT
550 mt_options.preset = preset;
551
552 /* Initialize the multi-threaded memory limit to half the physical
553 * RAM, or to 128 MiB if we cannot infer the number. */
554 mt_memlimit = lzma_physmem() / 2;
555 if (mt_memlimit == 0)
556 mt_memlimit = 128 * 1024 * 1024;
557 /* Clamp the multi-threaded memory limit to half the addressable
558 * memory on this architecture. */
559 if (mt_memlimit > INTPTR_MAX)
560 mt_memlimit = INTPTR_MAX;
561
562 mt_options.threads = lzma_cputhreads();
563 if (mt_options.threads == 0)
564 mt_options.threads = 1;
565
566 /* Guess whether we have enough RAM to use the multi-threaded encoder,
567 * and decrease them up to single-threaded to reduce memory usage. */
568 for (; mt_options.threads > 1; mt_options.threads--) {
569 uint64_t mt_memusage;
570
571 mt_memusage = lzma_stream_encoder_mt_memusage(&mt_options);
572 if (mt_memusage < mt_memlimit)
573 break;
574 }
575
576 ret = lzma_stream_encoder_mt(s, &mt_options);
577#else
578 ret = lzma_easy_encoder(s, preset, check);
579#endif
580
581 if (ret != LZMA_OK)
582 filter_lzma_error(io, ret);
583}
584
585static int
586filter_lzma_code(struct io_lzma *io, lzma_stream *s)
587{
588 lzma_ret ret;
589
590 ret = lzma_code(s, io->action);
591 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
592 filter_lzma_error(io, ret);
593
594 return ret;
595}
596
597static void
598filter_lzma_done(struct io_lzma *io, lzma_stream *s)
599{
600 lzma_end(s);
601}
602
603static void
604decompress_xz(int fd_in, int fd_out, const char *desc)
605{
606 struct io_lzma io;
607
608 io.init = filter_unxz_init;
609 io.code = filter_lzma_code;
610 io.done = filter_lzma_done;
611 io.desc = desc;
612
613 filter_lzma(&io, fd_in, fd_out);
614}
615
616static void
617compress_xz(int fd_in, int fd_out, struct compress_params *params, const char *desc)
618{
619 struct io_lzma io;
620
621 io.init = filter_xz_init;
622 io.code = filter_lzma_code;
623 io.done = filter_lzma_done;
624 io.desc = desc;
625 io.params = params;
626
627 filter_lzma(&io, fd_in, fd_out);
628}
629#else
630static const char *env_xz[] = { "XZ_DEFAULTS", "XZ_OPT", NULL };
631
632static void
633decompress_xz(int fd_in, int fd_out, const char *desc)
634{
635 fd_fd_filter(fd_in, fd_out, desc, env_xz, XZ, "-dc", NULL);
636}
637
638static void
639compress_xz(int fd_in, int fd_out, struct compress_params *params, const char *desc)
640{
641 char combuf[6];
642 const char *strategy;
643
644 if (params->strategy == COMPRESSOR_STRATEGY_EXTREME)
645 strategy = "-e";
646 else
647 strategy = NULL;
648
649 snprintf(combuf, sizeof(combuf), "-c%d", params->level);
650 fd_fd_filter(fd_in, fd_out, desc, env_xz, XZ, combuf, strategy, NULL);
651}
652#endif
653
654static const struct compressor compressor_xz = {
655 .name = "xz",
656 .extension = ".xz",
657 .default_level = 6,
658 .fixup_params = fixup_none_params,
659 .compress = compress_xz,
660 .decompress = decompress_xz,
661};
662
663/*
664 * Lzma compressor.
665 */
666
667#ifdef WITH_LIBLZMA
668static void
669filter_unlzma_init(struct io_lzma *io, lzma_stream *s)
670{
671 uint64_t memlimit = UINT64_MAX;
672 lzma_ret ret;
673
674 io->status |= DPKG_STREAM_DECOMPRESS;
675
676 ret = lzma_alone_decoder(s, memlimit);
677 if (ret != LZMA_OK)
678 filter_lzma_error(io, ret);
679}
680
681static void
682filter_lzma_init(struct io_lzma *io, lzma_stream *s)
683{
684 uint32_t preset;
685 lzma_options_lzma options;
686 lzma_ret ret;
687
688 io->status |= DPKG_STREAM_COMPRESS;
689
690 preset = io->params->level;
691 if (io->params->strategy == COMPRESSOR_STRATEGY_EXTREME)
692 preset |= LZMA_PRESET_EXTREME;
693 if (lzma_lzma_preset(&options, preset))
694 filter_lzma_error(io, LZMA_OPTIONS_ERROR);
695
696 ret = lzma_alone_encoder(s, &options);
697 if (ret != LZMA_OK)
698 filter_lzma_error(io, ret);
699}
700
701static void
702decompress_lzma(int fd_in, int fd_out, const char *desc)
703{
704 struct io_lzma io;
705
706 io.init = filter_unlzma_init;
707 io.code = filter_lzma_code;
708 io.done = filter_lzma_done;
709 io.desc = desc;
710
711 filter_lzma(&io, fd_in, fd_out);
712}
713
714static void
715compress_lzma(int fd_in, int fd_out, struct compress_params *params, const char *desc)
716{
717 struct io_lzma io;
718
719 io.init = filter_lzma_init;
720 io.code = filter_lzma_code;
721 io.done = filter_lzma_done;
722 io.desc = desc;
723 io.params = params;
724
725 filter_lzma(&io, fd_in, fd_out);
726}
727#else
728static void
729decompress_lzma(int fd_in, int fd_out, const char *desc)
730{
731 fd_fd_filter(fd_in, fd_out, desc, env_xz, XZ, "-dc", "--format=lzma", NULL);
732}
733
734static void
735compress_lzma(int fd_in, int fd_out, struct compress_params *params, const char *desc)
736{
737 char combuf[6];
738
739 snprintf(combuf, sizeof(combuf), "-c%d", params->level);
740 fd_fd_filter(fd_in, fd_out, desc, env_xz, XZ, combuf, "--format=lzma", NULL);
741}
742#endif
743
744static const struct compressor compressor_lzma = {
745 .name = "lzma",
746 .extension = ".lzma",
747 .default_level = 6,
748 .fixup_params = fixup_none_params,
749 .compress = compress_lzma,
750 .decompress = decompress_lzma,
751};
752
753/*
754 * Generic compressor filter.
755 */
756
757static const struct compressor *compressor_array[] = {
758 [COMPRESSOR_TYPE_NONE] = &compressor_none,
759 [COMPRESSOR_TYPE_GZIP] = &compressor_gzip,
760 [COMPRESSOR_TYPE_XZ] = &compressor_xz,
761 [COMPRESSOR_TYPE_BZIP2] = &compressor_bzip2,
762 [COMPRESSOR_TYPE_LZMA] = &compressor_lzma,
763};
764
765static const struct compressor *
766compressor(enum compressor_type type)
767{
768 const enum compressor_type max_type = array_count(compressor_array);
769
770 if (type < 0 || type >= max_type)
771 internerr("compressor_type %d is out of range", type);
772
773 return compressor_array[type];
774}
775
776const char *
777compressor_get_name(enum compressor_type type)
778{
779 return compressor(type)->name;
780}
781
782const char *
783compressor_get_extension(enum compressor_type type)
784{
785 return compressor(type)->extension;
786}
787
788enum compressor_type
789compressor_find_by_name(const char *name)
790{
791 size_t i;
792
793 for (i = 0; i < array_count(compressor_array); i++)
794 if (strcmp(compressor_array[i]->name, name) == 0)
795 return i;
796
797 return COMPRESSOR_TYPE_UNKNOWN;
798}
799
800enum compressor_type
801compressor_find_by_extension(const char *extension)
802{
803 size_t i;
804
805 for (i = 0; i < array_count(compressor_array); i++)
806 if (strcmp(compressor_array[i]->extension, extension) == 0)
807 return i;
808
809 return COMPRESSOR_TYPE_UNKNOWN;
810}
811
812enum compressor_strategy
813compressor_get_strategy(const char *name)
814{
815 if (strcmp(name, "none") == 0)
816 return COMPRESSOR_STRATEGY_NONE;
817 if (strcmp(name, "filtered") == 0)
818 return COMPRESSOR_STRATEGY_FILTERED;
819 if (strcmp(name, "huffman") == 0)
820 return COMPRESSOR_STRATEGY_HUFFMAN;
821 if (strcmp(name, "rle") == 0)
822 return COMPRESSOR_STRATEGY_RLE;
823 if (strcmp(name, "fixed") == 0)
824 return COMPRESSOR_STRATEGY_FIXED;
825 if (strcmp(name, "extreme") == 0)
826 return COMPRESSOR_STRATEGY_EXTREME;
827
828 return COMPRESSOR_STRATEGY_UNKNOWN;
829}
830
831static void
832compressor_fixup_params(struct compress_params *params)
833{
834 compressor(params->type)->fixup_params(params);
835
836 if (params->level < 0)
837 params->level = compressor(params->type)->default_level;
838}
839
840bool
841compressor_check_params(struct compress_params *params, struct dpkg_error *err)
842{
843 compressor_fixup_params(params);
844
845 if (params->strategy == COMPRESSOR_STRATEGY_NONE)
846 return true;
847
848 if (params->type == COMPRESSOR_TYPE_GZIP &&
849 (params->strategy == COMPRESSOR_STRATEGY_FILTERED ||
850 params->strategy == COMPRESSOR_STRATEGY_HUFFMAN ||
851 params->strategy == COMPRESSOR_STRATEGY_RLE ||
852 params->strategy == COMPRESSOR_STRATEGY_FIXED))
853 return true;
854
855 if (params->type == COMPRESSOR_TYPE_XZ &&
856 params->strategy == COMPRESSOR_STRATEGY_EXTREME)
857 return true;
858
859 dpkg_put_error(err, _("unknown compression strategy"));
860 return false;
861}
862
863void
864decompress_filter(enum compressor_type type, int fd_in, int fd_out,
865 const char *desc_fmt, ...)
866{
867 va_list args;
868 struct varbuf desc = VARBUF_INIT;
869
870 va_start(args, desc_fmt);
871 varbuf_vprintf(&desc, desc_fmt, args);
872 va_end(args);
873
874 compressor(type)->decompress(fd_in, fd_out, desc.buf);
875
876 varbuf_destroy(&desc);
877}
878
879void
880compress_filter(struct compress_params *params, int fd_in, int fd_out,
881 const char *desc_fmt, ...)
882{
883 va_list args;
884 struct varbuf desc = VARBUF_INIT;
885
886 va_start(args, desc_fmt);
887 varbuf_vprintf(&desc, desc_fmt, args);
888 va_end(args);
889
890 compressor(params->type)->compress(fd_in, fd_out, params, desc.buf);
891
892 varbuf_destroy(&desc);
893}