You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1618 lines
49 KiB

  1. /*
  2. * Copyright (c) 2009 - 2020 Thomas Schmitt
  3. *
  4. * This file is part of the libisofs project; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License version 2
  6. * or later as published by the Free Software Foundation.
  7. * See COPYING file for details.
  8. *
  9. * It implements a filter facility which can pipe a IsoStream into zisofs
  10. * compression resp. uncompression, read its output and forward it as IsoStream
  11. * output to an IsoFile.
  12. * The zisofs format was invented by H. Peter Anvin. See doc/zisofs_format.txt
  13. * It is writeable and readable by zisofs-tools, readable by Linux kernels.
  14. *
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "../config.h"
  18. #endif
  19. #include "../libisofs.h"
  20. #include "../filter.h"
  21. #include "../fsource.h"
  22. #include "../util.h"
  23. #include "../stream.h"
  24. #include "../messages.h"
  25. #include <sys/types.h>
  26. #include <sys/time.h>
  27. #include <sys/wait.h>
  28. #include <unistd.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #ifdef Libisofs_with_zliB
  33. #include <zlib.h>
  34. #else
  35. /* If zlib is not available then this code is a dummy */
  36. #endif
  37. /*
  38. * A filter that encodes or decodes the content of zisofs compressed files.
  39. */
  40. /* The lowest size of a file which shall not be represented by zisofs v1 */
  41. #define ISO_ZISOFS_V1_LIMIT 4294967296
  42. /* zisofs2: Test value for small mixed-version ISOs: 1 million
  43. ISO_ZISOFS_V1_LIMIT 1000000
  44. */
  45. /* Limit for overall count of allocated block pointers:
  46. 2 exp 25 = 256 MiB blocklist buffer = 4 TiB uncompressed at 128 KiB
  47. */
  48. #define ISO_ZISOFS_MAX_BLOCKS_T 0x2000000
  49. /* Function to account for global block pointers */
  50. static uint64_t ziso_block_pointer_mgt(uint64_t num, int mode);
  51. /* Limit for single files:
  52. 2 exp 25 = 256 MiB blocklist buffer = 4 TiB uncompressed at 128 KiB
  53. */
  54. #define ISO_ZISOFS_MAX_BLOCKS_F 0x2000000
  55. #ifdef Not_yeT
  56. /* The number of blocks from which on the block pointer list shall be discarded
  57. * on iso_stream_close() of a compressing stream. This means that list and size
  58. * have to be determined again on next ziso_stream_get_size().
  59. * zisofs v1 with uint32_t pointers could at most have 131072 pointers.
  60. * Since pointers are now uint64_t, the limit tolerates half of this.
  61. */
  62. #define ISO_ZISOFS_MANY_BLOCKS 65537
  63. #endif /* Not_yeT */
  64. /* Minimum and maximum blocks sizes for version 1 and 2 */
  65. #define ISO_ZISOFS_V1_MIN_LOG2 15
  66. #define ISO_ZISOFS_V1_MAX_LOG2 17
  67. #define ISO_ZISOFS_V2_MIN_LOG2 15
  68. #define ISO_ZISOFS_V2_MAX_LOG2 20
  69. /* --------------------------- ZisofsFilterRuntime ------------------------- */
  70. /* Sizes to be used for compression. Decompression learns from input header. */
  71. static uint8_t ziso_block_size_log2 = 15;
  72. static int ziso_block_size = 32768;
  73. static int ziso_v2_enabled = 0;
  74. static int ziso_v2_block_size_log2 = 17;
  75. static int ziso_v2_block_size = 1 << 17;
  76. static int64_t ziso_max_total_blocks = ISO_ZISOFS_MAX_BLOCKS_T;
  77. static int64_t ziso_max_file_blocks = ISO_ZISOFS_MAX_BLOCKS_F;
  78. /* Individual runtime properties exist only as long as the stream is opened.
  79. */
  80. typedef struct
  81. {
  82. int state; /* processing: 0= header, 1= block pointers, 2= data blocks */
  83. int zisofs_version; /* 1 or 2 */
  84. int block_size;
  85. int64_t block_pointer_fill;
  86. int64_t block_pointer_rpos;
  87. uint64_t *block_pointers; /* These are in use only with uncompression.
  88. Compression streams hold the pointer in
  89. their persistent data.
  90. */
  91. char *read_buffer;
  92. char *block_buffer;
  93. int buffer_size;
  94. int buffer_fill;
  95. int buffer_rpos;
  96. off_t block_counter;
  97. off_t in_counter;
  98. off_t out_counter;
  99. int error_ret;
  100. } ZisofsFilterRuntime;
  101. static
  102. int ziso_running_destroy(ZisofsFilterRuntime **running, int flag)
  103. {
  104. ZisofsFilterRuntime *o= *running;
  105. if (o == NULL)
  106. return 0;
  107. if (o->block_pointers != NULL) {
  108. ziso_block_pointer_mgt((uint64_t) o->block_pointer_fill, 2);
  109. free(o->block_pointers);
  110. }
  111. if (o->read_buffer != NULL)
  112. free(o->read_buffer);
  113. if (o->block_buffer != NULL)
  114. free(o->block_buffer);
  115. free((char *) o);
  116. *running = NULL;
  117. return 1;
  118. }
  119. /*
  120. * @param flag bit0= do not set block_size, do not allocate buffers
  121. * bit1= use ziso_v2_block_size
  122. */
  123. static
  124. int ziso_running_new(ZisofsFilterRuntime **running, int flag)
  125. {
  126. ZisofsFilterRuntime *o;
  127. *running = o = calloc(sizeof(ZisofsFilterRuntime), 1);
  128. if (o == NULL) {
  129. return ISO_OUT_OF_MEM;
  130. }
  131. o->state = 0;
  132. o->block_size= 0;
  133. o->zisofs_version = 0;
  134. o->block_pointer_fill = 0;
  135. o->block_pointer_rpos = 0;
  136. o->block_pointers = NULL;
  137. o->read_buffer = NULL;
  138. o->block_buffer = NULL;
  139. o->buffer_size = 0;
  140. o->buffer_fill = 0;
  141. o->buffer_rpos = 0;
  142. o->block_counter = 0;
  143. o->in_counter = 0;
  144. o->out_counter = 0;
  145. o->error_ret = 0;
  146. if (flag & 1)
  147. return 1;
  148. if (flag & 2)
  149. o->block_size = ziso_v2_block_size;
  150. else
  151. o->block_size = ziso_block_size;
  152. #ifdef Libisofs_with_zliB
  153. o->buffer_size = compressBound((uLong) o->block_size);
  154. #else
  155. o->buffer_size = 2 * o->block_size;
  156. #endif
  157. o->read_buffer = calloc(o->block_size, 1);
  158. o->block_buffer = calloc(o->buffer_size, 1);
  159. if (o->block_buffer == NULL || o->read_buffer == NULL)
  160. goto failed;
  161. return 1;
  162. failed:
  163. ziso_running_destroy(running, 0);
  164. return -1;
  165. }
  166. /* --------------------------- Resource accounting ------------------------- */
  167. /* @param mode 0= inquire whether num block pointers would fit
  168. 1= register num block pointers
  169. 2= unregister num block_pointers
  170. 3= return number of accounted block pointers
  171. @return if not mode 3: 0= does not fit , 1= fits
  172. */
  173. static
  174. uint64_t ziso_block_pointer_mgt(uint64_t num, int mode)
  175. {
  176. static uint64_t global_count = 0;
  177. static int underrun = 0;
  178. if (mode == 2) {
  179. if (global_count < num) {
  180. if (underrun < 3)
  181. iso_msg_submit(-1, ISO_ZISOFS_BPT_UNDERRUN, 0,
  182. "Prevented global block pointer counter underrun");
  183. underrun++;
  184. global_count = 0;
  185. } else {
  186. global_count -= num;
  187. }
  188. } else if (mode == 3) {
  189. return global_count;
  190. } else {
  191. if (global_count + num > (uint64_t) ziso_max_total_blocks)
  192. return 0;
  193. if (mode == 1)
  194. global_count += num;
  195. }
  196. return 1;
  197. }
  198. /* ---------------------------- ZisofsFilterStreamData --------------------- */
  199. /* The first 8 bytes of a zisofs compressed data file */
  200. static unsigned char zisofs_magic[9] =
  201. {0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07};
  202. /* The first 8 bytes of a zisofs2 compressed data file */
  203. static unsigned char zisofs2_magic[9] =
  204. {0xEF, 0x22, 0x55, 0xA1, 0xBC, 0x1B, 0x95, 0xA0};
  205. /* Counts the number of active compression filters */
  206. static off_t ziso_ref_count = 0;
  207. /* Counts the number of active uncompression filters */
  208. static off_t ziso_osiz_ref_count = 0;
  209. #ifdef Libisofs_with_zliB
  210. /* Parameter for compress2() , see <zlib.h> */
  211. static int ziso_compression_level = 6;
  212. #endif /* Libisofs_with_zliB */
  213. /*
  214. * The common data payload of an individual Zisofs Filter IsoStream
  215. * IMPORTANT: Any change must be reflected by ziso_clone_stream().
  216. */
  217. typedef struct
  218. {
  219. IsoStream *orig;
  220. off_t size; /* -1 means that the size is unknown yet */
  221. ZisofsFilterRuntime *running; /* is non-NULL when open */
  222. ino_t id;
  223. } ZisofsFilterStreamData;
  224. /*
  225. * The data payload of an individual Zisofs Filter Compressor IsoStream
  226. * IMPORTANT: Any change must be reflected by ziso_clone_stream().
  227. */
  228. typedef struct
  229. {
  230. ZisofsFilterStreamData std;
  231. uint64_t orig_size;
  232. uint64_t *block_pointers; /* Cache for output block addresses. They get
  233. written before the data and so need 2 passes.
  234. This cache avoids surplus passes.
  235. */
  236. uint64_t block_pointer_counter;
  237. uint64_t open_counter;
  238. } ZisofsComprStreamData;
  239. /*
  240. * The data payload of an individual Zisofs Filter Uncompressor IsoStream
  241. * IMPORTANT: Any change must be reflected by ziso_clone_stream().
  242. */
  243. typedef struct
  244. {
  245. ZisofsFilterStreamData std;
  246. uint8_t zisofs_algo_num;
  247. unsigned char header_size_div4;
  248. unsigned char block_size_log2;
  249. } ZisofsUncomprStreamData;
  250. /* Each individual ZisofsFilterStreamData needs a unique id number. */
  251. /* >>> This is very suboptimal:
  252. The counter can rollover.
  253. */
  254. static ino_t ziso_ino_id = 0;
  255. /*
  256. * Methods for the IsoStreamIface of an Zisofs Filter object.
  257. */
  258. static
  259. int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired);
  260. static
  261. int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired);
  262. static
  263. int ziso_decide_v2_usage(off_t orig_size)
  264. {
  265. if (ziso_v2_enabled > 1 ||
  266. (ziso_v2_enabled == 1 && orig_size >= (off_t) ISO_ZISOFS_V1_LIMIT))
  267. return 1;
  268. return 0;
  269. }
  270. /*
  271. * @param flag bit0= original stream is not open
  272. * bit1= do not destroy large
  273. * ZisofsComprStreamData->block_pointers
  274. */
  275. static
  276. int ziso_stream_close_flag(IsoStream *stream, int flag)
  277. {
  278. ZisofsFilterStreamData *data;
  279. ZisofsComprStreamData *cstd = NULL;
  280. if (stream == NULL) {
  281. return ISO_NULL_POINTER;
  282. }
  283. data = stream->data;
  284. if (stream->class->read == &ziso_stream_compress)
  285. cstd = (ZisofsComprStreamData *) data;
  286. #ifdef Not_yeT
  287. /* >>> zisofs2:
  288. research whether zisofs streams get opened and closed often */
  289. if (cstd != NULL) {
  290. int block_size;
  291. block_size = ziso_block_size;
  292. if (ziso_decide_v2_usage(cstd->orig_size))
  293. block_size = ziso_v2_block_size;
  294. if ((!(flag & 2)) && cstd->open_counter == 1 &&
  295. cstd->orig_size / block_size >= ISO_ZISOFS_MANY_BLOCKS) {
  296. if (cstd->block_pointers != NULL) {
  297. ziso_block_pointer_mgt(cstd->block_pointer_counter, 2);
  298. free((char *) cstd->block_pointers);
  299. }
  300. cstd->block_pointers = NULL;
  301. data->size = -1;
  302. }
  303. }
  304. #endif /* Not_yeT */
  305. if (data->running == NULL) {
  306. return 1;
  307. }
  308. ziso_running_destroy(&(data->running), 0);
  309. if (flag & 1)
  310. return 1;
  311. if (cstd != NULL)
  312. if (cstd->open_counter > 0)
  313. cstd->open_counter--;
  314. return iso_stream_close(data->orig);
  315. }
  316. static
  317. int ziso_stream_close(IsoStream *stream)
  318. {
  319. return ziso_stream_close_flag(stream, 0);
  320. }
  321. /*
  322. * @param flag bit0= do not run .get_size() if size is < 0
  323. */
  324. static
  325. int ziso_stream_open_flag(IsoStream *stream, int flag)
  326. {
  327. ZisofsFilterStreamData *data;
  328. ZisofsComprStreamData *cstd;
  329. ZisofsFilterRuntime *running = NULL;
  330. int ret, use_v2 = 0;
  331. if (stream == NULL) {
  332. return ISO_NULL_POINTER;
  333. }
  334. data = (ZisofsFilterStreamData*) stream->data;
  335. if (data->running != NULL) {
  336. return ISO_FILE_ALREADY_OPENED;
  337. }
  338. if (data->size < 0 && !(flag & 1)) {
  339. /* Do the size determination run now, so that the size gets cached
  340. and .get_size() will not fail on an opened stream.
  341. */
  342. stream->class->get_size(stream);
  343. }
  344. if (stream->class->read == &ziso_stream_compress) {
  345. cstd = (ZisofsComprStreamData *) data;
  346. cstd->open_counter++;
  347. use_v2 = ziso_decide_v2_usage((off_t) cstd->orig_size);
  348. }
  349. ret = ziso_running_new(&running,
  350. (stream->class->read == &ziso_stream_uncompress) |
  351. ((!!use_v2) << 1));
  352. if (ret < 0) {
  353. return ret;
  354. }
  355. data->running = running;
  356. ret = iso_stream_open(data->orig);
  357. if (ret < 0) {
  358. return ret;
  359. }
  360. return 1;
  361. }
  362. static
  363. int ziso_stream_open(IsoStream *stream)
  364. {
  365. return ziso_stream_open_flag(stream, 0);
  366. }
  367. static
  368. int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
  369. {
  370. #ifdef Libisofs_with_zliB
  371. int ret, todo, i;
  372. ZisofsComprStreamData *data;
  373. ZisofsFilterRuntime *rng;
  374. size_t fill = 0;
  375. off_t orig_size, next_pt;
  376. char *cbuf = buf;
  377. uLongf buf_len;
  378. uint64_t *copy_base, num_blocks = 0;
  379. if (stream == NULL) {
  380. return ISO_NULL_POINTER;
  381. }
  382. data = stream->data;
  383. rng= data->std.running;
  384. if (rng == NULL) {
  385. return ISO_FILE_NOT_OPENED;
  386. }
  387. if (rng->error_ret < 0) {
  388. return rng->error_ret;
  389. }
  390. while (1) {
  391. if (rng->state == 0) {
  392. /* Delivering file header */
  393. if (rng->buffer_fill == 0) {
  394. orig_size = iso_stream_get_size(data->std.orig);
  395. num_blocks = orig_size / rng->block_size +
  396. 1 + !!(orig_size % rng->block_size);
  397. if (num_blocks > (uint64_t) ziso_max_file_blocks)
  398. return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
  399. if (ziso_block_pointer_mgt((uint64_t) num_blocks, 0) == 0)
  400. return (rng->error_ret = ISO_ZISOFS_TOO_MANY_PTR);
  401. if (orig_size != (off_t) data->orig_size)
  402. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  403. if (ziso_decide_v2_usage(orig_size)) {
  404. rng->zisofs_version = 2;
  405. memcpy(rng->block_buffer, zisofs2_magic, 8);
  406. rng->block_buffer[8] = 0; /* @hdr_version */
  407. rng->block_buffer[9] = 6; /* @hdr_size */
  408. rng->block_buffer[10] = 1; /* @alg_id */
  409. rng->block_buffer[11] = ziso_v2_block_size_log2;
  410. iso_lsb64((uint8_t *) (rng->block_buffer + 12),
  411. (uint64_t) orig_size);
  412. memset(rng->block_buffer + 20, 0, 4);
  413. rng->buffer_fill = 24;
  414. } else {
  415. if (orig_size >= (off_t) ISO_ZISOFS_V1_LIMIT) {
  416. return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
  417. }
  418. rng->zisofs_version = 1;
  419. memcpy(rng->block_buffer, zisofs_magic, 8);
  420. iso_lsb((unsigned char *) (rng->block_buffer + 8),
  421. (uint32_t) orig_size, 4);
  422. rng->block_buffer[12] = 4;
  423. rng->block_buffer[13] = ziso_block_size_log2;
  424. rng->block_buffer[14] = rng->block_buffer[15] = 0;
  425. rng->buffer_fill = 16;
  426. }
  427. rng->buffer_rpos = 0;
  428. } else if (rng->buffer_rpos >= rng->buffer_fill) {
  429. rng->buffer_fill = rng->buffer_rpos = 0;
  430. rng->state = 1; /* header is delivered */
  431. }
  432. }
  433. if (rng->state == 1) {
  434. /* Delivering block pointers */;
  435. if (rng->block_pointer_fill == 0) {
  436. /* Initialize block pointer writing */
  437. rng->block_pointer_rpos = 0;
  438. num_blocks = data->orig_size / rng->block_size
  439. + 1 + !!(data->orig_size % rng->block_size);
  440. rng->block_pointer_fill = num_blocks;
  441. if (data->block_pointers == NULL) {
  442. /* On the first pass, create pointer array with all 0s */
  443. if (ziso_block_pointer_mgt(num_blocks, 1) == 0) {
  444. rng->block_pointer_fill = 0;
  445. return (rng->error_ret = ISO_ZISOFS_TOO_MANY_PTR);
  446. }
  447. data->block_pointers = calloc(rng->block_pointer_fill, 8);
  448. if (data->block_pointers == NULL) {
  449. ziso_block_pointer_mgt(num_blocks, 2);
  450. rng->block_pointer_fill = 0;
  451. return (rng->error_ret = ISO_OUT_OF_MEM);
  452. }
  453. data->block_pointer_counter = rng->block_pointer_fill;
  454. }
  455. }
  456. if (rng->buffer_rpos >= rng->buffer_fill) {
  457. if (rng->block_pointer_rpos >= rng->block_pointer_fill) {
  458. rng->buffer_fill = rng->buffer_rpos = 0;
  459. rng->block_counter = 0;
  460. if (rng->zisofs_version == 1)
  461. data->block_pointers[0] = 16 +
  462. rng->block_pointer_fill * 4;
  463. else
  464. data->block_pointers[0] = 24 +
  465. rng->block_pointer_fill * 8;
  466. rng->state = 2; /* block pointers are delivered */
  467. } else {
  468. /* Provide a buffer full of block pointers */
  469. /* data->block_pointers was filled by ziso_stream_open() */
  470. todo = rng->block_pointer_fill - rng->block_pointer_rpos;
  471. copy_base = data->block_pointers + rng->block_pointer_rpos;
  472. if (rng->zisofs_version == 1) {
  473. if (todo * 4 > rng->buffer_size)
  474. todo = rng->buffer_size / 4;
  475. for (i = 0; i < todo; i++)
  476. iso_lsb((unsigned char *) (rng->block_buffer +
  477. 4 * i),
  478. (uint32_t) (copy_base[i] & 0xffffffff), 4);
  479. rng->buffer_fill = todo * 4;
  480. } else {
  481. if (todo * 8 > rng->buffer_size)
  482. todo = rng->buffer_size / 8;
  483. for (i = 0; i < todo; i++)
  484. iso_lsb64((uint8_t *) rng->block_buffer + 8 * i,
  485. copy_base[i]);
  486. rng->buffer_fill = todo * 8;
  487. }
  488. rng->buffer_rpos = 0;
  489. rng->block_pointer_rpos += todo;
  490. }
  491. }
  492. }
  493. if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) {
  494. /* Delivering data blocks */;
  495. ret = iso_stream_read(data->std.orig, rng->read_buffer,
  496. rng->block_size);
  497. if (ret > 0) {
  498. rng->in_counter += ret;
  499. if ((uint64_t) rng->in_counter > data->orig_size) {
  500. /* Input size became larger */
  501. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  502. }
  503. /* Check whether all 0 : represent as 0-length block */;
  504. for (i = 0; i < ret; i++)
  505. if (rng->read_buffer[i])
  506. break;
  507. if (i >= ret) { /* All 0-bytes. Bypass compression. */
  508. buf_len = 0;
  509. } else {
  510. buf_len = rng->buffer_size;
  511. ret = compress2((Bytef *) rng->block_buffer, &buf_len,
  512. (Bytef *) rng->read_buffer, (uLong) ret,
  513. ziso_compression_level);
  514. if (ret != Z_OK) {
  515. return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
  516. }
  517. }
  518. rng->buffer_fill = buf_len;
  519. rng->buffer_rpos = 0;
  520. next_pt = data->block_pointers[rng->block_counter] + buf_len;
  521. if (data->std.size >= 0 && next_pt > data->std.size) {
  522. /* Compression yields more bytes than on first run */
  523. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  524. }
  525. /* Check or record check block pointer */
  526. rng->block_counter++;
  527. if (data->block_pointers[rng->block_counter] > 0) {
  528. if ((uint64_t) next_pt !=
  529. data->block_pointers[rng->block_counter]) {
  530. /* block pointers mismatch , content has changed */
  531. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  532. }
  533. } else {
  534. data->block_pointers[rng->block_counter] = next_pt;
  535. }
  536. } else if (ret == 0) {
  537. rng->state = 3;
  538. if ((uint64_t) rng->in_counter != data->orig_size) {
  539. /* Input size shrunk */
  540. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  541. }
  542. return fill;
  543. } else
  544. return (rng->error_ret = ret);
  545. if (rng->buffer_fill == 0) {
  546. continue;
  547. }
  548. }
  549. if (rng->state == 3 && rng->buffer_rpos >= rng->buffer_fill) {
  550. return 0; /* EOF */
  551. }
  552. /* Transfer from rng->block_buffer to buf */
  553. todo = desired - fill;
  554. if (todo > rng->buffer_fill - rng->buffer_rpos)
  555. todo = rng->buffer_fill - rng->buffer_rpos;
  556. memcpy(cbuf + fill, rng->block_buffer + rng->buffer_rpos, todo);
  557. fill += todo;
  558. rng->buffer_rpos += todo;
  559. rng->out_counter += todo;
  560. if (fill >= desired) {
  561. return fill;
  562. }
  563. }
  564. return ISO_FILE_READ_ERROR; /* should never be hit */
  565. #else
  566. return ISO_ZLIB_NOT_ENABLED;
  567. #endif
  568. }
  569. static
  570. int ziso_algo_to_num(uint8_t zisofs_algo[2])
  571. {
  572. if (zisofs_algo[0] == 'p' && zisofs_algo[1] == 'z')
  573. return 0;
  574. if (zisofs_algo[0] == 'P' && zisofs_algo[1] == 'Z')
  575. return 1;
  576. return -1;
  577. }
  578. static
  579. int ziso_num_to_algo(uint8_t num, uint8_t zisofs_algo[2])
  580. {
  581. if (num == 0) {
  582. zisofs_algo[0] = 'p';
  583. zisofs_algo[1] = 'z';
  584. return 1;
  585. } else if (num == 1) {
  586. zisofs_algo[0] = 'P';
  587. zisofs_algo[1] = 'Z';
  588. return 2;
  589. }
  590. return -1;
  591. }
  592. /* @param flag bit0= recognize zisofs2 only if ziso_v2_enabled
  593. */
  594. static
  595. int ziso_parse_zisofs_head(IsoStream *stream, uint8_t *ziso_algo_num,
  596. int *header_size_div4, int *block_size_log2,
  597. uint64_t *uncompressed_size, int flag)
  598. {
  599. int ret, consumed = 0, i;
  600. char zisofs_head[24];
  601. char waste_word[4];
  602. ret = iso_stream_read(stream, zisofs_head, 8);
  603. if (ret < 0)
  604. return ret;
  605. if (ret != 8)
  606. return ISO_ZISOFS_WRONG_INPUT;
  607. consumed = 8;
  608. if (memcmp(zisofs_head, zisofs_magic, 8) == 0) {
  609. *ziso_algo_num = 0;
  610. ret = iso_stream_read(stream, zisofs_head + 8, 8);
  611. if (ret < 0)
  612. return ret;
  613. if (ret != 8)
  614. return ISO_ZISOFS_WRONG_INPUT;
  615. consumed += 8;
  616. *header_size_div4 = ((unsigned char *) zisofs_head)[12];
  617. *block_size_log2 = ((unsigned char *) zisofs_head)[13];
  618. *uncompressed_size = iso_read_lsb(((uint8_t *) zisofs_head) + 8, 4);
  619. if (*header_size_div4 < 4 ||
  620. *block_size_log2 < ISO_ZISOFS_V1_MIN_LOG2 ||
  621. *block_size_log2 > ISO_ZISOFS_V1_MAX_LOG2)
  622. return ISO_ZISOFS_WRONG_INPUT;
  623. } else if (memcmp(zisofs_head, zisofs2_magic, 8) == 0 &&
  624. !(ziso_v2_enabled == 0 && (flag & 1))) {
  625. ret = iso_stream_read(stream, zisofs_head + 8, 16);
  626. if (ret < 0)
  627. return ret;
  628. if (ret != 16)
  629. return ISO_ZISOFS_WRONG_INPUT;
  630. consumed += 16;
  631. *ziso_algo_num = zisofs_head[10];
  632. *header_size_div4 = ((unsigned char *) zisofs_head)[9];
  633. *block_size_log2 = ((unsigned char *) zisofs_head)[11];
  634. *uncompressed_size = iso_read_lsb64(((uint8_t *) zisofs_head) + 12);
  635. if (*header_size_div4 < 4 ||
  636. *block_size_log2 < ISO_ZISOFS_V2_MIN_LOG2 ||
  637. *block_size_log2 > ISO_ZISOFS_V2_MAX_LOG2 || *ziso_algo_num != 1)
  638. return ISO_ZISOFS_WRONG_INPUT;
  639. } else {
  640. return ISO_ZISOFS_WRONG_INPUT;
  641. }
  642. for (i = consumed; i < *header_size_div4; i++) {
  643. /* Skip surplus header words */
  644. ret = iso_stream_read(stream, waste_word, 4);
  645. if (ret < 0)
  646. return ret;
  647. if (ret != 4)
  648. return ISO_ZISOFS_WRONG_INPUT;
  649. }
  650. return 1;
  651. }
  652. /* Note: A call with desired==0 directly after .open() only checks the file
  653. head and loads the uncompressed size from that head.
  654. */
  655. static
  656. int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
  657. {
  658. #ifdef Libisofs_with_zliB
  659. int ret, todo, header_size, bs_log2, block_max = 1, blpt_size;
  660. ZisofsFilterStreamData *data;
  661. ZisofsFilterRuntime *rng;
  662. ZisofsUncomprStreamData *nstd;
  663. size_t fill = 0;
  664. char *cbuf = buf;
  665. uLongf buf_len;
  666. uint64_t uncompressed_size;
  667. int64_t i;
  668. uint8_t algo_num, *rpt, *wpt;
  669. if (stream == NULL) {
  670. return ISO_NULL_POINTER;
  671. }
  672. data = stream->data;
  673. nstd = stream->data;
  674. rng= data->running;
  675. if (rng == NULL) {
  676. return ISO_FILE_NOT_OPENED;
  677. }
  678. if (rng->error_ret < 0) {
  679. return rng->error_ret;
  680. }
  681. while (1) {
  682. if (rng->state == 0) {
  683. /* Reading file header */
  684. ret = ziso_parse_zisofs_head(data->orig, &algo_num, &header_size,
  685. &bs_log2, &uncompressed_size, 0);
  686. if (ret < 0)
  687. return (rng->error_ret = ret);
  688. if (algo_num == 0)
  689. blpt_size = 4;
  690. else
  691. blpt_size = 8;
  692. nstd->header_size_div4 = header_size;
  693. header_size *= 4;
  694. data->size = uncompressed_size;
  695. nstd->block_size_log2 = bs_log2;
  696. rng->block_size = 1 << bs_log2;
  697. if (desired == 0)
  698. return 0;
  699. /* Create and read pointer array */
  700. rng->block_pointer_rpos = 0;
  701. rng->block_pointer_fill = data->size / rng->block_size
  702. + 1 + !!(data->size % rng->block_size);
  703. if (rng->block_pointer_fill > ziso_max_file_blocks) {
  704. rng->block_pointer_fill = 0;
  705. return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
  706. }
  707. if (ziso_block_pointer_mgt((uint64_t) rng->block_pointer_fill, 1)
  708. == 0)
  709. return ISO_ZISOFS_TOO_MANY_PTR;
  710. rng->block_pointers = calloc(rng->block_pointer_fill, 8);
  711. if (rng->block_pointers == NULL) {
  712. ziso_block_pointer_mgt((uint64_t) rng->block_pointer_fill, 2);
  713. rng->block_pointer_fill = 0;
  714. return (rng->error_ret = ISO_OUT_OF_MEM);
  715. }
  716. ret = iso_stream_read(data->orig, rng->block_pointers,
  717. rng->block_pointer_fill * blpt_size);
  718. if (ret < 0)
  719. return (rng->error_ret = ret);
  720. if (algo_num == 0) {
  721. /* Spread 4 byte little-endian pointer values over 8 byte */
  722. rpt = ((uint8_t *) rng->block_pointers)
  723. + rng->block_pointer_fill * 4;
  724. wpt = ((uint8_t *) rng->block_pointers)
  725. + rng->block_pointer_fill * 8;
  726. while (rpt > ((uint8_t *) rng->block_pointers) + 4) {
  727. rpt -= 4;
  728. wpt -= 8;
  729. memcpy(wpt, rpt, 4);
  730. memset(wpt + 4, 0, 4);
  731. }
  732. memset(((uint8_t *) rng->block_pointers) + 4, 0, 4);
  733. }
  734. if (ret != rng->block_pointer_fill * blpt_size)
  735. return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
  736. for (i = 0; i < rng->block_pointer_fill; i++) {
  737. rng->block_pointers[i] =
  738. iso_read_lsb64((uint8_t *) (rng->block_pointers + i));
  739. if (i > 0)
  740. if ((int) (rng->block_pointers[i] -
  741. rng->block_pointers[i - 1])
  742. > block_max)
  743. block_max = rng->block_pointers[i]
  744. - rng->block_pointers[i - 1];
  745. }
  746. rng->read_buffer = calloc(block_max, 1);
  747. rng->block_buffer = calloc(rng->block_size, 1);
  748. if (rng->read_buffer == NULL || rng->block_buffer == NULL)
  749. return (rng->error_ret = ISO_OUT_OF_MEM);
  750. rng->state = 2; /* block pointers are read */
  751. rng->buffer_fill = rng->buffer_rpos = 0;
  752. }
  753. if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) {
  754. /* Delivering data blocks */;
  755. i = ++(rng->block_pointer_rpos);
  756. if (i >= rng->block_pointer_fill) {
  757. if (rng->out_counter == data->size) {
  758. rng->state = 3;
  759. rng->block_pointer_rpos--;
  760. return fill;
  761. }
  762. /* More data blocks needed than announced */
  763. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  764. }
  765. todo = rng->block_pointers[i] - rng->block_pointers[i- 1];
  766. if (todo == 0) {
  767. memset(rng->block_buffer, 0, rng->block_size);
  768. rng->buffer_fill = rng->block_size;
  769. if (rng->out_counter + rng->buffer_fill > data->size &&
  770. i == rng->block_pointer_fill - 1)
  771. rng->buffer_fill = data->size - rng->out_counter;
  772. } else {
  773. ret = iso_stream_read(data->orig, rng->read_buffer, todo);
  774. if (ret > 0) {
  775. rng->in_counter += ret;
  776. buf_len = rng->block_size;
  777. ret = uncompress((Bytef *) rng->block_buffer, &buf_len,
  778. (Bytef *) rng->read_buffer, (uLong) ret);
  779. if (ret != Z_OK)
  780. return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
  781. rng->buffer_fill = buf_len;
  782. if ((int) buf_len < rng->block_size &&
  783. i != rng->block_pointer_fill - 1)
  784. return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
  785. } else if(ret == 0) {
  786. rng->state = 3;
  787. if (rng->out_counter != data->size) {
  788. /* Input size shrunk */
  789. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  790. }
  791. return fill;
  792. } else
  793. return (rng->error_ret = ret);
  794. }
  795. rng->buffer_rpos = 0;
  796. if (rng->out_counter + rng->buffer_fill > data->size) {
  797. /* Uncompression yields more bytes than announced by header */
  798. return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
  799. }
  800. }
  801. if (rng->state == 3 && rng->buffer_rpos >= rng->buffer_fill) {
  802. return 0; /* EOF */
  803. }
  804. /* Transfer from rng->block_buffer to buf */
  805. todo = desired - fill;
  806. if (todo > rng->buffer_fill - rng->buffer_rpos)
  807. todo = rng->buffer_fill - rng->buffer_rpos;
  808. memcpy(cbuf + fill, rng->block_buffer + rng->buffer_rpos, todo);
  809. fill += todo;
  810. rng->buffer_rpos += todo;
  811. rng->out_counter += todo;
  812. if (fill >= desired) {
  813. return fill;
  814. }
  815. }
  816. return (rng->error_ret = ISO_FILE_READ_ERROR); /* should never be hit */
  817. #else
  818. return ISO_ZLIB_NOT_ENABLED;
  819. #endif
  820. }
  821. static
  822. off_t ziso_stream_get_size(IsoStream *stream)
  823. {
  824. int ret, ret_close;
  825. off_t count = 0;
  826. ZisofsFilterStreamData *data;
  827. char buf[64 * 1024];
  828. size_t bufsize = 64 * 1024;
  829. if (stream == NULL) {
  830. return ISO_NULL_POINTER;
  831. }
  832. data = stream->data;
  833. if (data->size >= 0) {
  834. return data->size;
  835. }
  836. /* Run filter command and count output bytes */
  837. ret = ziso_stream_open_flag(stream, 1);
  838. if (ret < 0) {
  839. return ret;
  840. }
  841. if (stream->class->read == &ziso_stream_uncompress) {
  842. /* It is enough to read the header part of a compressed file */
  843. ret = ziso_stream_uncompress(stream, buf, 0);
  844. count = data->size;
  845. } else {
  846. /* The size of the compression result has to be counted */
  847. while (1) {
  848. ret = stream->class->read(stream, buf, bufsize);
  849. if (ret <= 0)
  850. break;
  851. count += ret;
  852. }
  853. }
  854. ret_close = ziso_stream_close_flag(stream, 2);
  855. if (ret < 0)
  856. return ret;
  857. if (ret_close < 0)
  858. return ret_close;
  859. data->size = count;
  860. return count;
  861. }
  862. static
  863. int ziso_stream_is_repeatable(IsoStream *stream)
  864. {
  865. /* Only repeatable streams are accepted as orig */
  866. return 1;
  867. }
  868. static
  869. void ziso_stream_get_id(IsoStream *stream, unsigned int *fs_id,
  870. dev_t *dev_id, ino_t *ino_id)
  871. {
  872. ZisofsFilterStreamData *data;
  873. data = stream->data;
  874. *fs_id = ISO_FILTER_FS_ID;
  875. *dev_id = ISO_FILTER_ZISOFS_DEV_ID;
  876. *ino_id = data->id;
  877. }
  878. static
  879. void ziso_stream_free(IsoStream *stream)
  880. {
  881. ZisofsFilterStreamData *data;
  882. ZisofsComprStreamData *nstd;
  883. if (stream == NULL) {
  884. return;
  885. }
  886. data = stream->data;
  887. if (data->running != NULL) {
  888. ziso_stream_close(stream);
  889. }
  890. if (stream->class->read == &ziso_stream_uncompress) {
  891. if (--ziso_osiz_ref_count < 0)
  892. ziso_osiz_ref_count = 0;
  893. } else {
  894. nstd = stream->data;
  895. if (nstd->block_pointers != NULL) {
  896. ziso_block_pointer_mgt(nstd->block_pointer_counter, 2);
  897. free((char *) nstd->block_pointers);
  898. }
  899. if (--ziso_ref_count < 0)
  900. ziso_ref_count = 0;
  901. }
  902. iso_stream_unref(data->orig);
  903. free(data);
  904. }
  905. static
  906. int ziso_update_size(IsoStream *stream)
  907. {
  908. /* By principle size is determined only once */
  909. return 1;
  910. }
  911. static
  912. IsoStream *ziso_get_input_stream(IsoStream *stream, int flag)
  913. {
  914. ZisofsFilterStreamData *data;
  915. if (stream == NULL) {
  916. return NULL;
  917. }
  918. data = stream->data;
  919. return data->orig;
  920. }
  921. static
  922. int ziso_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
  923. {
  924. int ret;
  925. IsoStream *new_input_stream = NULL, *stream = NULL;
  926. ZisofsFilterStreamData *stream_data, *old_stream_data;
  927. ZisofsUncomprStreamData *uncompr, *old_uncompr;
  928. ZisofsComprStreamData *compr, *old_compr;
  929. if (flag)
  930. return ISO_STREAM_NO_CLONE; /* unknown option required */
  931. ret = iso_stream_clone_filter_common(old_stream, &stream,
  932. &new_input_stream, 0);
  933. if (ret < 0)
  934. return ret;
  935. if (old_stream->class->read == &ziso_stream_uncompress) {
  936. uncompr = calloc(1, sizeof(ZisofsUncomprStreamData));
  937. if (uncompr == NULL)
  938. goto no_mem;
  939. stream_data = (ZisofsFilterStreamData *) uncompr;
  940. old_uncompr = (ZisofsUncomprStreamData *) old_stream->data;
  941. uncompr->zisofs_algo_num = old_uncompr->zisofs_algo_num;
  942. uncompr->header_size_div4 = old_uncompr->header_size_div4;
  943. uncompr->block_size_log2 = old_uncompr->block_size_log2;
  944. } else {
  945. compr = calloc(1, sizeof(ZisofsComprStreamData));
  946. if (compr == NULL)
  947. goto no_mem;
  948. stream_data = (ZisofsFilterStreamData *) compr;
  949. old_compr = (ZisofsComprStreamData *) old_stream->data;
  950. compr->orig_size = old_compr->orig_size;
  951. compr->block_pointers = NULL;
  952. compr->block_pointer_counter = 0;
  953. compr->open_counter = 0;
  954. }
  955. old_stream_data = (ZisofsFilterStreamData *) old_stream->data;
  956. stream_data->orig = new_input_stream;
  957. stream_data->size = old_stream_data->size;
  958. stream_data->running = NULL;
  959. stream_data->id = ++ziso_ino_id;
  960. stream->data = stream_data;
  961. *new_stream = stream;
  962. return ISO_SUCCESS;
  963. no_mem:
  964. if (new_input_stream != NULL)
  965. iso_stream_unref(new_input_stream);
  966. if (stream != NULL)
  967. iso_stream_unref(stream);
  968. return ISO_OUT_OF_MEM;
  969. }
  970. static
  971. int ziso_cmp_ino(IsoStream *s1, IsoStream *s2);
  972. static
  973. int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
  974. IsoStreamIface ziso_stream_compress_class = {
  975. 4,
  976. "ziso",
  977. ziso_stream_open,
  978. ziso_stream_close,
  979. ziso_stream_get_size,
  980. ziso_stream_compress,
  981. ziso_stream_is_repeatable,
  982. ziso_stream_get_id,
  983. ziso_stream_free,
  984. ziso_update_size,
  985. ziso_get_input_stream,
  986. ziso_cmp_ino,
  987. ziso_clone_stream
  988. };
  989. IsoStreamIface ziso_stream_uncompress_class = {
  990. 4,
  991. "osiz",
  992. ziso_stream_open,
  993. ziso_stream_close,
  994. ziso_stream_get_size,
  995. ziso_stream_uncompress,
  996. ziso_stream_is_repeatable,
  997. ziso_stream_get_id,
  998. ziso_stream_free,
  999. ziso_update_size,
  1000. ziso_get_input_stream,
  1001. ziso_uncompress_cmp_ino,
  1002. ziso_clone_stream
  1003. };
  1004. static
  1005. int ziso_cmp_ino(IsoStream *s1, IsoStream *s2)
  1006. {
  1007. /* This function may rely on being called by iso_stream_cmp_ino()
  1008. only with s1, s2 which both point to it as their .cmp_ino() function.
  1009. It would be a programming error to let any other than
  1010. ziso_stream_compress_class point to ziso_cmp_ino().
  1011. */
  1012. if (s1->class != s2->class || (s1->class != &ziso_stream_compress_class &&
  1013. s2->class != &ziso_stream_uncompress_class))
  1014. iso_stream_cmp_ino(s1, s2, 1);
  1015. /* Both streams apply the same treatment to their input streams */
  1016. return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
  1017. iso_stream_get_input_stream(s2, 0), 0);
  1018. }
  1019. static
  1020. int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
  1021. {
  1022. /* This function may rely on being called by iso_stream_cmp_ino()
  1023. only with s1, s2 which both point to it as their .cmp_ino() function.
  1024. It would be a programming error to let any other than
  1025. ziso_stream_uncompress_class point to ziso_uncompress_cmp_ino().
  1026. This fallback endangers transitivity of iso_stream_cmp_ino().
  1027. */
  1028. if (s1->class != s2->class ||
  1029. (s1->class != &ziso_stream_uncompress_class &&
  1030. s2->class != &ziso_stream_uncompress_class))
  1031. iso_stream_cmp_ino(s1, s2, 1);
  1032. /* Both streams apply the same treatment to their input streams */
  1033. return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
  1034. iso_stream_get_input_stream(s2, 0), 0);
  1035. }
  1036. /* ------------------------------------------------------------------------- */
  1037. #ifdef Libisofs_with_zliB
  1038. static
  1039. void ziso_filter_free(FilterContext *filter)
  1040. {
  1041. /* no data are allocated */;
  1042. }
  1043. /*
  1044. * @param flag bit1= Install a decompression filter
  1045. */
  1046. static
  1047. int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
  1048. IsoStream **filtered, int flag)
  1049. {
  1050. IsoStream *str;
  1051. ZisofsFilterStreamData *data;
  1052. ZisofsComprStreamData *cnstd = NULL;
  1053. ZisofsUncomprStreamData *unstd = NULL;
  1054. if (filter == NULL || original == NULL || filtered == NULL) {
  1055. return ISO_NULL_POINTER;
  1056. }
  1057. str = calloc(sizeof(IsoStream), 1);
  1058. if (str == NULL) {
  1059. return ISO_OUT_OF_MEM;
  1060. }
  1061. if (flag & 2) {
  1062. unstd = calloc(sizeof(ZisofsUncomprStreamData), 1);
  1063. data = (ZisofsFilterStreamData *) unstd;
  1064. } else {
  1065. cnstd = calloc(sizeof(ZisofsComprStreamData), 1);
  1066. data = (ZisofsFilterStreamData *) cnstd;
  1067. }
  1068. if (data == NULL) {
  1069. free(str);
  1070. return ISO_OUT_OF_MEM;
  1071. }
  1072. /* These data items are not owned by this filter object */
  1073. data->id = ++ziso_ino_id;
  1074. data->orig = original;
  1075. data->size = -1;
  1076. data->running = NULL;
  1077. /* get reference to the source */
  1078. iso_stream_ref(data->orig);
  1079. str->refcount = 1;
  1080. str->data = data;
  1081. if (flag & 2) {
  1082. unstd->zisofs_algo_num = 0;
  1083. unstd->header_size_div4 = 0;
  1084. unstd->block_size_log2 = 0;
  1085. str->class = &ziso_stream_uncompress_class;
  1086. ziso_osiz_ref_count++;
  1087. } else {
  1088. cnstd->orig_size = iso_stream_get_size(original);
  1089. cnstd->block_pointers = NULL;
  1090. cnstd->block_pointer_counter = 0;
  1091. cnstd->open_counter = 0;
  1092. str->class = &ziso_stream_compress_class;
  1093. ziso_ref_count++;
  1094. }
  1095. *filtered = str;
  1096. return ISO_SUCCESS;
  1097. }
  1098. /* To be called by iso_file_add_filter().
  1099. * The FilterContext input parameter is not furtherly needed for the
  1100. * emerging IsoStream.
  1101. */
  1102. static
  1103. int ziso_filter_get_compressor(FilterContext *filter, IsoStream *original,
  1104. IsoStream **filtered)
  1105. {
  1106. return ziso_filter_get_filter(filter, original, filtered, 0);
  1107. }
  1108. static
  1109. int ziso_filter_get_uncompressor(FilterContext *filter, IsoStream *original,
  1110. IsoStream **filtered)
  1111. {
  1112. return ziso_filter_get_filter(filter, original, filtered, 2);
  1113. }
  1114. /* Produce a parameter object suitable for iso_file_add_filter().
  1115. * It may be disposed by free() after all those calls are made.
  1116. *
  1117. * This is quite a dummy as it does not carry individual data.
  1118. * @param flag bit1= Install a decompression filter
  1119. */
  1120. static
  1121. int ziso_create_context(FilterContext **filter, int flag)
  1122. {
  1123. FilterContext *f;
  1124. *filter = f = calloc(1, sizeof(FilterContext));
  1125. if (f == NULL) {
  1126. return ISO_OUT_OF_MEM;
  1127. }
  1128. f->refcount = 1;
  1129. f->version = 0;
  1130. f->data = NULL;
  1131. f->free = ziso_filter_free;
  1132. if (flag & 2)
  1133. f->get_filter = ziso_filter_get_uncompressor;
  1134. else
  1135. f->get_filter = ziso_filter_get_compressor;
  1136. return ISO_SUCCESS;
  1137. }
  1138. #endif /* Libisofs_with_zliB */
  1139. /*
  1140. * @param flag bit0= if_block_reduction rather than if_reduction
  1141. * bit1= Install a decompression filter
  1142. * bit2= only inquire availability of zisofs filtering
  1143. * bit3= do not inquire size
  1144. */
  1145. int ziso_add_filter(IsoFile *file, int flag)
  1146. {
  1147. #ifdef Libisofs_with_zliB
  1148. int ret;
  1149. FilterContext *f = NULL;
  1150. IsoStream *stream;
  1151. off_t original_size = 0, filtered_size = 0;
  1152. if (flag & 4)
  1153. return 2;
  1154. original_size = iso_file_get_size(file);
  1155. if (!(flag & 2)) {
  1156. if (original_size <= 0 || ((flag & 1) && original_size <= 2048)) {
  1157. return 2;
  1158. }
  1159. if (original_size >= (off_t) ISO_ZISOFS_V1_LIMIT && !ziso_v2_enabled) {
  1160. return ISO_ZISOFS_TOO_LARGE;
  1161. }
  1162. }
  1163. ret = ziso_create_context(&f, flag & 2);
  1164. if (ret < 0) {
  1165. return ret;
  1166. }
  1167. ret = iso_file_add_filter(file, f, 0);
  1168. free(f);
  1169. if (ret < 0) {
  1170. return ret;
  1171. }
  1172. if (flag & 8) /* size will be filled in by caller */
  1173. return ISO_SUCCESS;
  1174. /* Run a full filter process getsize so that the size is cached */
  1175. stream = iso_file_get_stream(file);
  1176. filtered_size = iso_stream_get_size(stream);
  1177. if (filtered_size < 0) {
  1178. iso_file_remove_filter(file, 0);
  1179. return filtered_size;
  1180. }
  1181. if ((filtered_size >= original_size ||
  1182. ((flag & 1) && filtered_size / 2048 >= original_size / 2048))
  1183. && !(flag & 2)){
  1184. ret = iso_file_remove_filter(file, 0);
  1185. if (ret < 0) {
  1186. return ret;
  1187. }
  1188. return 2;
  1189. }
  1190. return ISO_SUCCESS;
  1191. #else
  1192. return ISO_ZLIB_NOT_ENABLED;
  1193. #endif /* ! Libisofs_with_zliB */
  1194. }
  1195. /* API function */
  1196. int iso_file_add_zisofs_filter(IsoFile *file, int flag)
  1197. {
  1198. return ziso_add_filter(file, flag & ~8);
  1199. }
  1200. /* API function */
  1201. int iso_zisofs_get_refcounts(off_t *ziso_count, off_t *osiz_count, int flag)
  1202. {
  1203. *ziso_count = ziso_ref_count;
  1204. *osiz_count = ziso_osiz_ref_count;
  1205. return ISO_SUCCESS;
  1206. }
  1207. int ziso_add_osiz_filter(IsoFile *file, uint8_t zisofs_algo[2],
  1208. uint8_t header_size_div4, uint8_t block_size_log2,
  1209. uint64_t uncompressed_size, int flag)
  1210. {
  1211. #ifdef Libisofs_with_zliB
  1212. int ret;
  1213. ZisofsUncomprStreamData *unstd;
  1214. ret = ziso_add_filter(file, 2 | 8);
  1215. if (ret < 0)
  1216. return ret;
  1217. unstd = iso_file_get_stream(file)->data;
  1218. ret = ziso_algo_to_num(zisofs_algo);
  1219. if (ret < 0)
  1220. return ISO_ZISOFS_WRONG_INPUT;
  1221. unstd->zisofs_algo_num = ret;
  1222. unstd->header_size_div4 = header_size_div4;
  1223. unstd->block_size_log2 = block_size_log2;
  1224. unstd->std.size = uncompressed_size;
  1225. return ISO_SUCCESS;
  1226. #else
  1227. return ISO_ZLIB_NOT_ENABLED;
  1228. #endif /* ! Libisofs_with_zliB */
  1229. }
  1230. /* Determine stream type : 1=ziso , -1=osiz , 0=other , 2=ziso_by_content
  1231. and eventual ZF field parameters
  1232. @param flag bit0= allow ziso_by_content which is based on content reading
  1233. bit1= do not inquire stream->class for filters
  1234. bit2= recognize zisofs2 by magic only if ziso_v2_enabled
  1235. */
  1236. int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
  1237. uint8_t zisofs_algo[2],
  1238. int *header_size_div4, int *block_size_log2,
  1239. uint64_t *uncompressed_size, int flag)
  1240. {
  1241. int ret, close_ret, algo_ret;
  1242. ZisofsFilterStreamData *data;
  1243. ZisofsComprStreamData *cnstd;
  1244. ZisofsUncomprStreamData *unstd;
  1245. uint8_t algo_num;
  1246. *stream_type = 0;
  1247. if (stream->class == &ziso_stream_compress_class && !(flag & 2)) {
  1248. *stream_type = 1;
  1249. cnstd = stream->data;
  1250. *header_size_div4 = 4;
  1251. *uncompressed_size = cnstd->orig_size;
  1252. if (ziso_decide_v2_usage((off_t) *uncompressed_size)) {
  1253. *block_size_log2 = ziso_v2_block_size_log2;
  1254. zisofs_algo[0] = 'P';
  1255. zisofs_algo[1] = 'Z';
  1256. } else if (*uncompressed_size < (uint64_t) ISO_ZISOFS_V1_LIMIT) {
  1257. *block_size_log2 = ziso_block_size_log2;
  1258. zisofs_algo[0] = 'p';
  1259. zisofs_algo[1] = 'z';
  1260. } else {
  1261. return 0;
  1262. }
  1263. return 1;
  1264. } else if(stream->class == &ziso_stream_uncompress_class && !(flag & 2)) {
  1265. *stream_type = -1;
  1266. data = stream->data;
  1267. unstd = stream->data;
  1268. ret = ziso_num_to_algo(unstd->zisofs_algo_num, zisofs_algo);
  1269. if (ret < 0)
  1270. return ISO_ZISOFS_WRONG_INPUT;
  1271. *header_size_div4 = unstd->header_size_div4;
  1272. *block_size_log2 = unstd->block_size_log2;
  1273. *uncompressed_size = data->size;
  1274. return 1;
  1275. }
  1276. if (!(flag & 1))
  1277. return 0;
  1278. ret = iso_stream_open(stream);
  1279. if (ret < 0)
  1280. return ret;
  1281. ret = ziso_parse_zisofs_head(stream, &algo_num, header_size_div4,
  1282. block_size_log2, uncompressed_size,
  1283. (flag >> 2) & 1);
  1284. if (ret == 1) {
  1285. *stream_type = 2;
  1286. algo_ret = ziso_num_to_algo(algo_num, zisofs_algo);
  1287. } else {
  1288. ret = 0;
  1289. algo_ret = 1;
  1290. }
  1291. close_ret = iso_stream_close(stream);
  1292. if (algo_ret < 0)
  1293. return ISO_ZISOFS_WRONG_INPUT;
  1294. if (close_ret < 0)
  1295. return close_ret;
  1296. return ret;
  1297. }
  1298. /* API */
  1299. int iso_zisofs_set_params(struct iso_zisofs_ctrl *params, int flag)
  1300. {
  1301. #ifdef Libisofs_with_zliB
  1302. if (params->version < 0 || params->version > 1)
  1303. return ISO_WRONG_ARG_VALUE;
  1304. if (params->compression_level < 0 || params->compression_level > 9 ||
  1305. params->block_size_log2 < ISO_ZISOFS_V1_MIN_LOG2 ||
  1306. params->block_size_log2 > ISO_ZISOFS_V1_MAX_LOG2) {
  1307. return ISO_WRONG_ARG_VALUE;
  1308. }
  1309. if (params->version >= 1)
  1310. if (params->v2_enabled < 0 || params->v2_enabled > 2 ||
  1311. (params->v2_block_size_log2 != 0 &&
  1312. (params->v2_block_size_log2 < ISO_ZISOFS_V2_MIN_LOG2 ||
  1313. params->v2_block_size_log2 > ISO_ZISOFS_V2_MAX_LOG2)))
  1314. return ISO_WRONG_ARG_VALUE;
  1315. if (ziso_ref_count > 0) {
  1316. return ISO_ZISOFS_PARAM_LOCK;
  1317. }
  1318. ziso_compression_level = params->compression_level;
  1319. ziso_block_size_log2 = params->block_size_log2;
  1320. ziso_block_size = 1 << ziso_block_size_log2;
  1321. if (params->version == 0)
  1322. return 1;
  1323. ziso_v2_enabled = params->v2_enabled;
  1324. if (params->v2_block_size_log2 > 0)
  1325. ziso_v2_block_size_log2 = params->v2_block_size_log2;
  1326. ziso_v2_block_size = 1 << ziso_v2_block_size_log2;
  1327. if (params->max_total_blocks > 0)
  1328. ziso_max_total_blocks = params->max_total_blocks;
  1329. if (params->max_file_blocks > 0)
  1330. ziso_max_file_blocks = params->max_file_blocks;
  1331. /* >>> zisofs2: more parameters */
  1332. return 1;
  1333. #else
  1334. return ISO_ZLIB_NOT_ENABLED;
  1335. #endif /* ! Libisofs_with_zliB */
  1336. }
  1337. /* API */
  1338. int iso_zisofs_get_params(struct iso_zisofs_ctrl *params, int flag)
  1339. {
  1340. #ifdef Libisofs_with_zliB
  1341. if (params->version < 0 || params->version > 1)
  1342. return ISO_WRONG_ARG_VALUE;
  1343. params->compression_level = ziso_compression_level;
  1344. params->block_size_log2 = ziso_block_size_log2;
  1345. if (params->version == 1) {
  1346. params->v2_enabled = ziso_v2_enabled;
  1347. params->v2_block_size_log2 = ziso_v2_block_size_log2;
  1348. params->max_total_blocks = ziso_max_total_blocks;
  1349. params->current_total_blocks = ziso_block_pointer_mgt((uint64_t) 0, 3);
  1350. params->max_file_blocks = ziso_max_file_blocks;
  1351. }
  1352. return 1;
  1353. #else
  1354. return ISO_ZLIB_NOT_ENABLED;
  1355. #endif /* ! Libisofs_with_zliB */
  1356. }
  1357. /* API */
  1358. int iso_stream_get_zisofs_par(IsoStream *stream, int *stream_type,
  1359. uint8_t zisofs_algo[2], uint8_t* algo_num,
  1360. int *block_size_log2, int flag)
  1361. {
  1362. uint64_t uncompressed_size;
  1363. int header_size_div4, ret;
  1364. ret = ziso_is_zisofs_stream(stream, stream_type, zisofs_algo,
  1365. &header_size_div4, block_size_log2,
  1366. &uncompressed_size, 0);
  1367. if (ret <= 0 || (*stream_type != -1 && *stream_type != 1))
  1368. return 0;
  1369. *algo_num = ziso_algo_to_num(zisofs_algo);
  1370. return 1;
  1371. }