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