002-xz_wrapper-make-new-OpenWrt-extended-options-non-def.patch 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. From 5fb9fdfb8757fc9afb6318a3dcf9dce0a97de352 Mon Sep 17 00:00:00 2001
  2. From: Phillip Lougher <[email protected]>
  3. Date: Wed, 19 Apr 2023 18:35:53 +0100
  4. Subject: [PATCH] xz_wrapper: make new OpenWrt extended options non-default
  5. The reason why these options are being made non-default are
  6. described here:
  7. https://github.com/plougher/squashfs-tools/pull/218#issuecomment-1515197256
  8. The new options can be enabled by editing the Makefile or by defining
  9. XZ_EXTENDED_OPTIONS on the Make command line, e.g.
  10. % CONFIG=1 XZ_SUPPORT=1 XZ_EXTENDED_OPTIONS=1 make
  11. Signed-off-by: Phillip Lougher <[email protected]>
  12. ---
  13. squashfs-tools/Makefile | 12 +
  14. squashfs-tools/xz_wrapper.c | 117 +----
  15. squashfs-tools/xz_wrapper_extended.c | 664 +++++++++++++++++++++++++++
  16. 3 files changed, 679 insertions(+), 114 deletions(-)
  17. create mode 100644 squashfs-tools/xz_wrapper_extended.c
  18. --- a/squashfs-tools/Makefile
  19. +++ b/squashfs-tools/Makefile
  20. @@ -39,6 +39,10 @@ GZIP_SUPPORT = 1
  21. #
  22. #XZ_SUPPORT = 1
  23. +# Enable support for OpenWrt extended compression options by uncommenting
  24. +# next line. Do not do this unless you understand the implications.
  25. +#XZ_EXTENDED_OPTIONS = 1
  26. +
  27. ############ Building LZO support ##############
  28. #
  29. @@ -197,6 +201,7 @@ INSTALL_MANPAGES_DIR ?= $(INSTALL_PREFIX
  30. LZMA_XZ_SUPPORT ?= 0
  31. LZMA_SUPPORT ?= 0
  32. LZMA_DIR ?= ../../../../LZMA/lzma465
  33. +XZ_EXTENDED_OPTIONS ?= 0
  34. endif
  35. @@ -248,8 +253,13 @@ endif
  36. ifeq ($(XZ_SUPPORT),1)
  37. CFLAGS += -DXZ_SUPPORT
  38. +ifeq ($(XZ_EXTENDED_OPTIONS),1)
  39. +MKSQUASHFS_OBJS += xz_wrapper_extended.o
  40. +UNSQUASHFS_OBJS += xz_wrapper_extended.o
  41. +else
  42. MKSQUASHFS_OBJS += xz_wrapper.o
  43. UNSQUASHFS_OBJS += xz_wrapper.o
  44. +endif
  45. LIBS += -llzma
  46. COMPRESSORS += xz
  47. endif
  48. @@ -428,6 +438,8 @@ lz4_wrapper.o: lz4_wrapper.c squashfs_fs
  49. xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
  50. +xz_wrapper_extended.o: xz_wrapper_extended.c squashfs_fs.h xz_wrapper.h compressor.h
  51. +
  52. unsquashfs: $(UNSQUASHFS_OBJS)
  53. $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
  54. ln -sf unsquashfs sqfscat
  55. --- a/squashfs-tools/xz_wrapper.c
  56. +++ b/squashfs-tools/xz_wrapper.c
  57. @@ -44,10 +44,7 @@ static struct bcj bcj[] = {
  58. static int filter_count = 1;
  59. static int dictionary_size = 0;
  60. static float dictionary_percent = 0;
  61. -static int preset = LZMA_PRESET_DEFAULT;
  62. -static int lc = -1;
  63. -static int lp = -1;
  64. -static int pb = -1;
  65. +
  66. /*
  67. * This function is called by the options parsing code in mksquashfs.c
  68. @@ -56,11 +53,6 @@ static int pb = -1;
  69. * Two specific options are supported:
  70. * -Xbcj
  71. * -Xdict-size
  72. - * -Xpreset
  73. - * -Xe
  74. - * -Xlc
  75. - * -Xlp
  76. - * -Xpb
  77. *
  78. * This function returns:
  79. * >=0 (number of additional args parsed) on success
  80. @@ -149,85 +141,6 @@ static int xz_options(char *argv[], int
  81. }
  82. return 1;
  83. - } else if(strcmp(argv[0], "-Xpreset") == 0) {
  84. - char *b;
  85. - long val;
  86. -
  87. - if(argc < 2) {
  88. - fprintf(stderr, "xz: -Xpreset missing preset-level "
  89. - "(valid value 0-9)\n");
  90. - goto failed;
  91. - }
  92. -
  93. - val = strtol(argv[1], &b, 10);
  94. - if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
  95. - fprintf(stderr, "xz: -Xpreset can't be "
  96. - "negative or more than the max preset\n");
  97. - goto failed;
  98. - }
  99. -
  100. - preset &= ~LZMA_PRESET_LEVEL_MASK;
  101. - preset |= (int) val;
  102. -
  103. - return 1;
  104. - } else if(strcmp(argv[0], "-Xe") == 0) {
  105. - preset |= LZMA_PRESET_EXTREME;
  106. -
  107. - return 0;
  108. - } else if(strcmp(argv[0], "-Xlc") == 0) {
  109. - char *b;
  110. - long val;
  111. -
  112. - if(argc < 2) {
  113. - fprintf(stderr, "xz: -Xlc missing value\n");
  114. - goto failed;
  115. - }
  116. -
  117. - val = strtol(argv[1], &b, 10);
  118. - if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
  119. - fprintf(stderr, "xz: -Xlc invalid value\n");
  120. - goto failed;
  121. - }
  122. -
  123. - lc = (int) val;
  124. -
  125. - return 1;
  126. - } else if(strcmp(argv[0], "-Xlp") == 0) {
  127. - char *b;
  128. - long val;
  129. -
  130. - if(argc < 2) {
  131. - fprintf(stderr, "xz: -Xlp missing value\n");
  132. - goto failed;
  133. - }
  134. -
  135. - val = strtol(argv[1], &b, 10);
  136. - if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
  137. - fprintf(stderr, "xz: -Xlp invalid value\n");
  138. - goto failed;
  139. - }
  140. -
  141. - lp = (int) val;
  142. -
  143. - return 1;
  144. - } else if(strcmp(argv[0], "-Xpb") == 0) {
  145. - char *b;
  146. - long val;
  147. -
  148. - if(argc < 2) {
  149. - fprintf(stderr, "xz: -Xpb missing value\n");
  150. - goto failed;
  151. - }
  152. -
  153. - val = strtol(argv[1], &b, 10);
  154. - if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
  155. - fprintf(stderr, "xz: -Xpb invalid value\n");
  156. - goto failed;
  157. - }
  158. -
  159. - pb = (int) val;
  160. -
  161. - return 1;
  162. }
  163. return -1;
  164. @@ -533,20 +446,11 @@ static int xz_compress(void *strm, void
  165. for(i = 0; i < stream->filters; i++) {
  166. struct filter *filter = &stream->filter[i];
  167. - if(lzma_lzma_preset(&stream->opt, preset))
  168. + if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
  169. goto failed;
  170. stream->opt.dict_size = stream->dictionary_size;
  171. - if (lc >= 0)
  172. - stream->opt.lc = lc;
  173. -
  174. - if (lp >= 0)
  175. - stream->opt.lp = lp;
  176. -
  177. - if (pb >= 0)
  178. - stream->opt.pb = pb;
  179. -
  180. filter->length = 0;
  181. res = lzma_stream_buffer_encode(filter->filter,
  182. LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
  183. @@ -617,28 +521,13 @@ static void xz_usage(FILE *stream)
  184. fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
  185. fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
  186. fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
  187. - fprintf(stream, "\t -Xpreset <preset-level>\n");
  188. - fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
  189. - fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
  190. - fprintf(stream, " (default 6)\n");
  191. - fprintf(stream, "\t -Xe\n");
  192. - fprintf(stream, "\t\tEnable additional compression settings by passing");
  193. - fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
  194. - fprintf(stream, "\t -Xlc <value>\n");
  195. - fprintf(stream, "\t -Xlp <value>\n");
  196. - fprintf(stream, "\t -Xpb <value>\n");
  197. }
  198. static int option_args(char *option)
  199. {
  200. if(strcmp(option, "-Xbcj") == 0 ||
  201. - strcmp(option, "-Xdict-size") == 0 ||
  202. - strcmp(option, "-Xpreset") == 0 ||
  203. - strcmp(option, "-Xe") == 0 ||
  204. - strcmp(option, "-Xlc") == 0 ||
  205. - strcmp(option, "-Xlp") == 0 ||
  206. - strcmp(option, "-Xpb") == 0)
  207. + strcmp(option, "-Xdict-size") == 0)
  208. return 1;
  209. return 0;
  210. --- /dev/null
  211. +++ b/squashfs-tools/xz_wrapper_extended.c
  212. @@ -0,0 +1,664 @@
  213. +/*
  214. + * Copyright (c) 2010, 2011, 2012, 2013, 2021, 2022
  215. + * Phillip Lougher <[email protected]>
  216. + *
  217. + * This program is free software; you can redistribute it and/or
  218. + * modify it under the terms of the GNU General Public License
  219. + * as published by the Free Software Foundation; either version 2,
  220. + * or (at your option) any later version.
  221. + *
  222. + * This program is distributed in the hope that it will be useful,
  223. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  224. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  225. + * GNU General Public License for more details.
  226. + *
  227. + * You should have received a copy of the GNU General Public License
  228. + * along with this program; if not, write to the Free Software
  229. + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  230. + *
  231. + * xz_wrapper_extended.c
  232. + *
  233. + * Support for XZ (LZMA2) compression using XZ Utils liblzma
  234. + * http://tukaani.org/xz/
  235. + *
  236. + * This file supports OpenWrt extended XZ compression options.
  237. + */
  238. +
  239. +#include <stdio.h>
  240. +#include <string.h>
  241. +#include <stdlib.h>
  242. +#include <lzma.h>
  243. +
  244. +#include "squashfs_fs.h"
  245. +#include "xz_wrapper.h"
  246. +#include "compressor.h"
  247. +
  248. +static struct bcj bcj[] = {
  249. + { "x86", LZMA_FILTER_X86, 0 },
  250. + { "powerpc", LZMA_FILTER_POWERPC, 0 },
  251. + { "ia64", LZMA_FILTER_IA64, 0 },
  252. + { "arm", LZMA_FILTER_ARM, 0 },
  253. + { "armthumb", LZMA_FILTER_ARMTHUMB, 0 },
  254. + { "sparc", LZMA_FILTER_SPARC, 0 },
  255. + { NULL, LZMA_VLI_UNKNOWN, 0 }
  256. +};
  257. +
  258. +static int filter_count = 1;
  259. +static int dictionary_size = 0;
  260. +static float dictionary_percent = 0;
  261. +static int preset = LZMA_PRESET_DEFAULT;
  262. +static int lc = -1;
  263. +static int lp = -1;
  264. +static int pb = -1;
  265. +
  266. +/*
  267. + * This function is called by the options parsing code in mksquashfs.c
  268. + * to parse any -X compressor option.
  269. + *
  270. + * Two specific options are supported:
  271. + * -Xbcj
  272. + * -Xdict-size
  273. + * -Xpreset
  274. + * -Xe
  275. + * -Xlc
  276. + * -Xlp
  277. + * -Xpb
  278. + *
  279. + * This function returns:
  280. + * >=0 (number of additional args parsed) on success
  281. + * -1 if the option was unrecognised, or
  282. + * -2 if the option was recognised, but otherwise bad in
  283. + * some way (e.g. invalid parameter)
  284. + *
  285. + * Note: this function sets internal compressor state, but does not
  286. + * pass back the results of the parsing other than success/failure.
  287. + * The xz_dump_options() function is called later to get the options in
  288. + * a format suitable for writing to the filesystem.
  289. + */
  290. +static int xz_options(char *argv[], int argc)
  291. +{
  292. + int i;
  293. + char *name;
  294. +
  295. + if(strcmp(argv[0], "-Xbcj") == 0) {
  296. + if(argc < 2) {
  297. + fprintf(stderr, "xz: -Xbcj missing filter\n");
  298. + goto failed;
  299. + }
  300. +
  301. + name = argv[1];
  302. + while(name[0] != '\0') {
  303. + for(i = 0; bcj[i].name; i++) {
  304. + int n = strlen(bcj[i].name);
  305. + if((strncmp(name, bcj[i].name, n) == 0) &&
  306. + (name[n] == '\0' ||
  307. + name[n] == ',')) {
  308. + if(bcj[i].selected == 0) {
  309. + bcj[i].selected = 1;
  310. + filter_count++;
  311. + }
  312. + name += name[n] == ',' ? n + 1 : n;
  313. + break;
  314. + }
  315. + }
  316. + if(bcj[i].name == NULL) {
  317. + fprintf(stderr, "xz: -Xbcj unrecognised "
  318. + "filter\n");
  319. + goto failed;
  320. + }
  321. + }
  322. +
  323. + return 1;
  324. + } else if(strcmp(argv[0], "-Xdict-size") == 0) {
  325. + char *b;
  326. + float size;
  327. +
  328. + if(argc < 2) {
  329. + fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
  330. + goto failed;
  331. + }
  332. +
  333. + size = strtof(argv[1], &b);
  334. + if(*b == '%') {
  335. + if(size <= 0 || size > 100) {
  336. + fprintf(stderr, "xz: -Xdict-size percentage "
  337. + "should be 0 < dict-size <= 100\n");
  338. + goto failed;
  339. + }
  340. +
  341. + dictionary_percent = size;
  342. + dictionary_size = 0;
  343. + } else {
  344. + if((float) ((int) size) != size) {
  345. + fprintf(stderr, "xz: -Xdict-size can't be "
  346. + "fractional unless a percentage of the"
  347. + " block size\n");
  348. + goto failed;
  349. + }
  350. +
  351. + dictionary_percent = 0;
  352. + dictionary_size = (int) size;
  353. +
  354. + if(*b == 'k' || *b == 'K')
  355. + dictionary_size *= 1024;
  356. + else if(*b == 'm' || *b == 'M')
  357. + dictionary_size *= 1024 * 1024;
  358. + else if(*b != '\0') {
  359. + fprintf(stderr, "xz: -Xdict-size invalid "
  360. + "dict-size\n");
  361. + goto failed;
  362. + }
  363. + }
  364. +
  365. + return 1;
  366. + } else if(strcmp(argv[0], "-Xpreset") == 0) {
  367. + char *b;
  368. + long val;
  369. +
  370. + if(argc < 2) {
  371. + fprintf(stderr, "xz: -Xpreset missing preset-level "
  372. + "(valid value 0-9)\n");
  373. + goto failed;
  374. + }
  375. +
  376. + val = strtol(argv[1], &b, 10);
  377. + if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
  378. + fprintf(stderr, "xz: -Xpreset can't be "
  379. + "negative or more than the max preset\n");
  380. + goto failed;
  381. + }
  382. +
  383. + preset &= ~LZMA_PRESET_LEVEL_MASK;
  384. + preset |= (int) val;
  385. +
  386. + return 1;
  387. + } else if(strcmp(argv[0], "-Xe") == 0) {
  388. + preset |= LZMA_PRESET_EXTREME;
  389. +
  390. + return 0;
  391. + } else if(strcmp(argv[0], "-Xlc") == 0) {
  392. + char *b;
  393. + long val;
  394. +
  395. + if(argc < 2) {
  396. + fprintf(stderr, "xz: -Xlc missing value\n");
  397. + goto failed;
  398. + }
  399. +
  400. + val = strtol(argv[1], &b, 10);
  401. + if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
  402. + fprintf(stderr, "xz: -Xlc invalid value\n");
  403. + goto failed;
  404. + }
  405. +
  406. + lc = (int) val;
  407. +
  408. + return 1;
  409. + } else if(strcmp(argv[0], "-Xlp") == 0) {
  410. + char *b;
  411. + long val;
  412. +
  413. + if(argc < 2) {
  414. + fprintf(stderr, "xz: -Xlp missing value\n");
  415. + goto failed;
  416. + }
  417. +
  418. + val = strtol(argv[1], &b, 10);
  419. + if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
  420. + fprintf(stderr, "xz: -Xlp invalid value\n");
  421. + goto failed;
  422. + }
  423. +
  424. + lp = (int) val;
  425. +
  426. + return 1;
  427. + } else if(strcmp(argv[0], "-Xpb") == 0) {
  428. + char *b;
  429. + long val;
  430. +
  431. + if(argc < 2) {
  432. + fprintf(stderr, "xz: -Xpb missing value\n");
  433. + goto failed;
  434. + }
  435. +
  436. + val = strtol(argv[1], &b, 10);
  437. + if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
  438. + fprintf(stderr, "xz: -Xpb invalid value\n");
  439. + goto failed;
  440. + }
  441. +
  442. + pb = (int) val;
  443. +
  444. + return 1;
  445. + }
  446. +
  447. + return -1;
  448. +
  449. +failed:
  450. + return -2;
  451. +}
  452. +
  453. +
  454. +/*
  455. + * This function is called after all options have been parsed.
  456. + * It is used to do post-processing on the compressor options using
  457. + * values that were not expected to be known at option parse time.
  458. + *
  459. + * In this case block_size may not be known until after -Xdict-size has
  460. + * been processed (in the case where -b is specified after -Xdict-size)
  461. + *
  462. + * This function returns 0 on successful post processing, or
  463. + * -1 on error
  464. + */
  465. +static int xz_options_post(int block_size)
  466. +{
  467. + /*
  468. + * if -Xdict-size has been specified use this to compute the datablock
  469. + * dictionary size
  470. + */
  471. + if(dictionary_size || dictionary_percent) {
  472. + int n;
  473. +
  474. + if(dictionary_size) {
  475. + if(dictionary_size > block_size) {
  476. + fprintf(stderr, "xz: -Xdict-size is larger than"
  477. + " block_size\n");
  478. + goto failed;
  479. + }
  480. + } else
  481. + dictionary_size = block_size * dictionary_percent / 100;
  482. +
  483. + if(dictionary_size < 8192) {
  484. + fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
  485. + "or larger\n");
  486. + goto failed;
  487. + }
  488. +
  489. + /*
  490. + * dictionary_size must be storable in xz header as either
  491. + * 2^n or as 2^n+2^(n+1)
  492. + */
  493. + n = ffs(dictionary_size) - 1;
  494. + if(dictionary_size != (1 << n) &&
  495. + dictionary_size != ((1 << n) + (1 << (n + 1)))) {
  496. + fprintf(stderr, "xz: -Xdict-size is an unsupported "
  497. + "value, dict-size must be storable in xz "
  498. + "header\n");
  499. + fprintf(stderr, "as either 2^n or as 2^n+2^(n+1). "
  500. + "Example dict-sizes are 75%%, 50%%, 37.5%%, "
  501. + "25%%,\n");
  502. + fprintf(stderr, "or 32K, 16K, 8K etc.\n");
  503. + goto failed;
  504. + }
  505. +
  506. + } else
  507. + /* No -Xdict-size specified, use defaults */
  508. + dictionary_size = block_size;
  509. +
  510. + return 0;
  511. +
  512. +failed:
  513. + return -1;
  514. +}
  515. +
  516. +
  517. +/*
  518. + * This function is called by mksquashfs to dump the parsed
  519. + * compressor options in a format suitable for writing to the
  520. + * compressor options field in the filesystem (stored immediately
  521. + * after the superblock).
  522. + *
  523. + * This function returns a pointer to the compression options structure
  524. + * to be stored (and the size), or NULL if there are no compression
  525. + * options
  526. + */
  527. +static void *xz_dump_options(int block_size, int *size)
  528. +{
  529. + static struct comp_opts comp_opts;
  530. + int flags = 0, i;
  531. +
  532. + /*
  533. + * don't store compressor specific options in file system if the
  534. + * default options are being used - no compressor options in the
  535. + * file system means the default options are always assumed
  536. + *
  537. + * Defaults are:
  538. + * metadata dictionary size: SQUASHFS_METADATA_SIZE
  539. + * datablock dictionary size: block_size
  540. + * 1 filter
  541. + */
  542. + if(dictionary_size == block_size && filter_count == 1)
  543. + return NULL;
  544. +
  545. + for(i = 0; bcj[i].name; i++)
  546. + flags |= bcj[i].selected << i;
  547. +
  548. + comp_opts.dictionary_size = dictionary_size;
  549. + comp_opts.flags = flags;
  550. +
  551. + SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
  552. +
  553. + *size = sizeof(comp_opts);
  554. + return &comp_opts;
  555. +}
  556. +
  557. +
  558. +/*
  559. + * This function is a helper specifically for the append mode of
  560. + * mksquashfs. Its purpose is to set the internal compressor state
  561. + * to the stored compressor options in the passed compressor options
  562. + * structure.
  563. + *
  564. + * In effect this function sets up the compressor options
  565. + * to the same state they were when the filesystem was originally
  566. + * generated, this is to ensure on appending, the compressor uses
  567. + * the same compression options that were used to generate the
  568. + * original filesystem.
  569. + *
  570. + * Note, even if there are no compressor options, this function is still
  571. + * called with an empty compressor structure (size == 0), to explicitly
  572. + * set the default options, this is to ensure any user supplied
  573. + * -X options on the appending mksquashfs command line are over-ridden
  574. + *
  575. + * This function returns 0 on sucessful extraction of options, and
  576. + * -1 on error
  577. + */
  578. +static int xz_extract_options(int block_size, void *buffer, int size)
  579. +{
  580. + struct comp_opts *comp_opts = buffer;
  581. + int flags, i, n;
  582. +
  583. + if(size == 0) {
  584. + /* set defaults */
  585. + dictionary_size = block_size;
  586. + flags = 0;
  587. + } else {
  588. + /* check passed comp opts struct is of the correct length */
  589. + if(size != sizeof(struct comp_opts))
  590. + goto failed;
  591. +
  592. + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
  593. +
  594. + dictionary_size = comp_opts->dictionary_size;
  595. + flags = comp_opts->flags;
  596. +
  597. + /*
  598. + * check that the dictionary size seems correct - the dictionary
  599. + * size should 2^n or 2^n+2^(n+1)
  600. + */
  601. + n = ffs(dictionary_size) - 1;
  602. + if(dictionary_size != (1 << n) &&
  603. + dictionary_size != ((1 << n) + (1 << (n + 1))))
  604. + goto failed;
  605. + }
  606. +
  607. + filter_count = 1;
  608. + for(i = 0; bcj[i].name; i++) {
  609. + if((flags >> i) & 1) {
  610. + bcj[i].selected = 1;
  611. + filter_count ++;
  612. + } else
  613. + bcj[i].selected = 0;
  614. + }
  615. +
  616. + return 0;
  617. +
  618. +failed:
  619. + fprintf(stderr, "xz: error reading stored compressor options from "
  620. + "filesystem!\n");
  621. +
  622. + return -1;
  623. +}
  624. +
  625. +
  626. +static void xz_display_options(void *buffer, int size)
  627. +{
  628. + struct comp_opts *comp_opts = buffer;
  629. + int dictionary_size, flags, printed;
  630. + int i, n;
  631. +
  632. + /* check passed comp opts struct is of the correct length */
  633. + if(size != sizeof(struct comp_opts))
  634. + goto failed;
  635. +
  636. + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
  637. +
  638. + dictionary_size = comp_opts->dictionary_size;
  639. + flags = comp_opts->flags;
  640. +
  641. + /*
  642. + * check that the dictionary size seems correct - the dictionary
  643. + * size should 2^n or 2^n+2^(n+1)
  644. + */
  645. + n = ffs(dictionary_size) - 1;
  646. + if(dictionary_size != (1 << n) &&
  647. + dictionary_size != ((1 << n) + (1 << (n + 1))))
  648. + goto failed;
  649. +
  650. + printf("\tDictionary size %d\n", dictionary_size);
  651. +
  652. + printed = 0;
  653. + for(i = 0; bcj[i].name; i++) {
  654. + if((flags >> i) & 1) {
  655. + if(printed)
  656. + printf(", ");
  657. + else
  658. + printf("\tFilters selected: ");
  659. + printf("%s", bcj[i].name);
  660. + printed = 1;
  661. + }
  662. + }
  663. +
  664. + if(!printed)
  665. + printf("\tNo filters specified\n");
  666. + else
  667. + printf("\n");
  668. +
  669. + return;
  670. +
  671. +failed:
  672. + fprintf(stderr, "xz: error reading stored compressor options from "
  673. + "filesystem!\n");
  674. +}
  675. +
  676. +
  677. +/*
  678. + * This function is called by mksquashfs to initialise the
  679. + * compressor, before compress() is called.
  680. + *
  681. + * This function returns 0 on success, and
  682. + * -1 on error
  683. + */
  684. +static int xz_init(void **strm, int block_size, int datablock)
  685. +{
  686. + int i, j, filters = datablock ? filter_count : 1;
  687. + struct filter *filter = malloc(filters * sizeof(struct filter));
  688. + struct xz_stream *stream;
  689. +
  690. + if(filter == NULL)
  691. + goto failed;
  692. +
  693. + stream = *strm = malloc(sizeof(struct xz_stream));
  694. + if(stream == NULL)
  695. + goto failed2;
  696. +
  697. + stream->filter = filter;
  698. + stream->filters = filters;
  699. +
  700. + memset(filter, 0, filters * sizeof(struct filter));
  701. +
  702. + stream->dictionary_size = datablock ? dictionary_size :
  703. + SQUASHFS_METADATA_SIZE;
  704. +
  705. + filter[0].filter[0].id = LZMA_FILTER_LZMA2;
  706. + filter[0].filter[0].options = &stream->opt;
  707. + filter[0].filter[1].id = LZMA_VLI_UNKNOWN;
  708. +
  709. + for(i = 0, j = 1; datablock && bcj[i].name; i++) {
  710. + if(bcj[i].selected) {
  711. + filter[j].buffer = malloc(block_size);
  712. + if(filter[j].buffer == NULL)
  713. + goto failed3;
  714. + filter[j].filter[0].id = bcj[i].id;
  715. + filter[j].filter[1].id = LZMA_FILTER_LZMA2;
  716. + filter[j].filter[1].options = &stream->opt;
  717. + filter[j].filter[2].id = LZMA_VLI_UNKNOWN;
  718. + j++;
  719. + }
  720. + }
  721. +
  722. + return 0;
  723. +
  724. +failed3:
  725. + for(i = 1; i < filters; i++)
  726. + free(filter[i].buffer);
  727. + free(stream);
  728. +
  729. +failed2:
  730. + free(filter);
  731. +
  732. +failed:
  733. + return -1;
  734. +}
  735. +
  736. +
  737. +static int xz_compress(void *strm, void *dest, void *src, int size,
  738. + int block_size, int *error)
  739. +{
  740. + int i;
  741. + lzma_ret res = 0;
  742. + struct xz_stream *stream = strm;
  743. + struct filter *selected = NULL;
  744. +
  745. + stream->filter[0].buffer = dest;
  746. +
  747. + for(i = 0; i < stream->filters; i++) {
  748. + struct filter *filter = &stream->filter[i];
  749. +
  750. + if(lzma_lzma_preset(&stream->opt, preset))
  751. + goto failed;
  752. +
  753. + stream->opt.dict_size = stream->dictionary_size;
  754. +
  755. + if (lc >= 0)
  756. + stream->opt.lc = lc;
  757. +
  758. + if (lp >= 0)
  759. + stream->opt.lp = lp;
  760. +
  761. + if (pb >= 0)
  762. + stream->opt.pb = pb;
  763. +
  764. + filter->length = 0;
  765. + res = lzma_stream_buffer_encode(filter->filter,
  766. + LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
  767. + &filter->length, block_size);
  768. +
  769. + if(res == LZMA_OK) {
  770. + if(!selected || selected->length > filter->length)
  771. + selected = filter;
  772. + } else if(res != LZMA_BUF_ERROR)
  773. + goto failed;
  774. + }
  775. +
  776. + if(!selected)
  777. + /*
  778. + * Output buffer overflow. Return out of buffer space
  779. + */
  780. + return 0;
  781. +
  782. + if(selected->buffer != dest)
  783. + memcpy(dest, selected->buffer, selected->length);
  784. +
  785. + return (int) selected->length;
  786. +
  787. +failed:
  788. + /*
  789. + * All other errors return failure, with the compressor
  790. + * specific error code in *error
  791. + */
  792. + *error = res;
  793. + return -1;
  794. +}
  795. +
  796. +
  797. +static int xz_uncompress(void *dest, void *src, int size, int outsize,
  798. + int *error)
  799. +{
  800. + size_t src_pos = 0;
  801. + size_t dest_pos = 0;
  802. + uint64_t memlimit = MEMLIMIT;
  803. +
  804. + lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
  805. + src, &src_pos, size, dest, &dest_pos, outsize);
  806. +
  807. + if(res == LZMA_OK && size == (int) src_pos)
  808. + return (int) dest_pos;
  809. + else {
  810. + *error = res;
  811. + return -1;
  812. + }
  813. +}
  814. +
  815. +
  816. +static void xz_usage(FILE *stream)
  817. +{
  818. + fprintf(stream, "\t -Xbcj filter1,filter2,...,filterN\n");
  819. + fprintf(stream, "\t\tCompress using filter1,filter2,...,filterN in");
  820. + fprintf(stream, " turn\n\t\t(in addition to no filter), and choose");
  821. + fprintf(stream, " the best compression.\n");
  822. + fprintf(stream, "\t\tAvailable filters: x86, arm, armthumb,");
  823. + fprintf(stream, " powerpc, sparc, ia64\n");
  824. + fprintf(stream, "\t -Xdict-size <dict-size>\n");
  825. + fprintf(stream, "\t\tUse <dict-size> as the XZ dictionary size. The");
  826. + fprintf(stream, " dictionary size\n\t\tcan be specified as a");
  827. + fprintf(stream, " percentage of the block size, or as an\n\t\t");
  828. + fprintf(stream, "absolute value. The dictionary size must be less");
  829. + fprintf(stream, " than or equal\n\t\tto the block size and 8192 bytes");
  830. + fprintf(stream, " or larger. It must also be\n\t\tstorable in the xz");
  831. + fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
  832. + fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
  833. + fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
  834. + fprintf(stream, "\t -Xpreset <preset-level>\n");
  835. + fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
  836. + fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
  837. + fprintf(stream, " (default 6)\n");
  838. + fprintf(stream, "\t -Xe\n");
  839. + fprintf(stream, "\t\tEnable additional compression settings by passing");
  840. + fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
  841. + fprintf(stream, "\t -Xlc <value>\n");
  842. + fprintf(stream, "\t -Xlp <value>\n");
  843. + fprintf(stream, "\t -Xpb <value>\n");
  844. +}
  845. +
  846. +
  847. +static int option_args(char *option)
  848. +{
  849. + if(strcmp(option, "-Xbcj") == 0 ||
  850. + strcmp(option, "-Xdict-size") == 0 ||
  851. + strcmp(option, "-Xpreset") == 0 ||
  852. + strcmp(option, "-Xe") == 0 ||
  853. + strcmp(option, "-Xlc") == 0 ||
  854. + strcmp(option, "-Xlp") == 0 ||
  855. + strcmp(option, "-Xpb") == 0)
  856. + return 1;
  857. +
  858. + return 0;
  859. +}
  860. +
  861. +
  862. +struct compressor xz_comp_ops = {
  863. + .init = xz_init,
  864. + .compress = xz_compress,
  865. + .uncompress = xz_uncompress,
  866. + .options = xz_options,
  867. + .options_post = xz_options_post,
  868. + .dump_options = xz_dump_options,
  869. + .extract_options = xz_extract_options,
  870. + .display_options = xz_display_options,
  871. + .usage = xz_usage,
  872. + .option_args = option_args,
  873. + .id = XZ_COMPRESSION,
  874. + .name = "xz",
  875. + .supported = 1
  876. +};