compress.c 20 KB

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