"Fossies" - the Fresh Open Source Software Archive 
Member "libisofs-1.5.4/libisofs/filters/zisofs.c" (29 Oct 2020, 56026 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "zisofs.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
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
17 #ifdef HAVE_CONFIG_H
18 #include "../config.h"
19 #endif
20
21 #include "../libisofs.h"
22 #include "../filter.h"
23 #include "../fsource.h"
24 #include "../util.h"
25 #include "../stream.h"
26 #include "../messages.h"
27
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35
36 #ifdef Libisofs_with_zliB
37 #include <zlib.h>
38 #else
39 /* If zlib is not available then this code is a dummy */
40 #endif
41
42
43 /*
44 * A filter that encodes or decodes the content of zisofs compressed files.
45 */
46
47
48 /* The lowest size of a file which shall not be represented by zisofs v1 */
49 #define ISO_ZISOFS_V1_LIMIT 4294967296
50
51 /* zisofs2: Test value for small mixed-version ISOs: 1 million
52 ISO_ZISOFS_V1_LIMIT 1000000
53 */
54
55 /* Minimum and maximum blocks sizes for version 1 and 2 */
56 #define ISO_ZISOFS_V1_MIN_LOG2 15
57 #define ISO_ZISOFS_V1_MAX_LOG2 17
58 #define ISO_ZISOFS_V2_MIN_LOG2 15
59 #define ISO_ZISOFS_V2_MAX_LOG2 20
60
61
62 /* ------------------- Defaults of runtime parameters ------------------ */
63
64 /* Limit for overall count of allocated block pointers:
65 2 exp 25 = 256 MiB blocklist buffer = 4 TiB uncompressed at 128 KiB
66 */
67 #define ISO_ZISOFS_MAX_BLOCKS_T 0x2000000
68
69 /* Function to account for global block pointers */
70 static uint64_t ziso_block_pointer_mgt(uint64_t num, int mode);
71
72 /* Limit for single files:
73 2 exp 25 = 256 MiB blocklist buffer = 4 TiB uncompressed at 128 KiB
74 */
75 #define ISO_ZISOFS_MAX_BLOCKS_F 0x2000000
76
77 /* The number of blocks from which on the block pointer list shall be discarded
78 * on iso_stream_close() of a compressing stream. This means that the pointers
79 * have to be determined again on next ziso_stream_compress(), so that adding
80 * a zisofs compression filter and writing the compressed stream needs in the
81 * sum three read runs of the input stream.
82 * <= 0 disables this file size based discarding.
83 */
84 #define ISO_ZISOFS_MANY_BLOCKS 0
85
86 /* A ratio describing the part of the maximum number of block pointers which
87 * shall be kept free by intermediate discarding of block pointers. See above
88 * ISO_ZISOFS_MANY_BLOCKS. -1.0 disables this feature.
89 */
90 #define ISO_ZISOFS_KBF_RATIO -1.0
91
92
93 /* --------------------------- Runtime parameters ------------------------- */
94
95 /* Sizes to be used for compression. Decompression learns from input header. */
96 static uint8_t ziso_block_size_log2 = 15;
97
98 static int ziso_v2_enabled = 0;
99 static int ziso_v2_block_size_log2 = 17;
100
101 static int64_t ziso_block_number_target = -1;
102
103 static int64_t ziso_max_total_blocks = ISO_ZISOFS_MAX_BLOCKS_T;
104 static int64_t ziso_max_file_blocks = ISO_ZISOFS_MAX_BLOCKS_F;
105
106 static int64_t ziso_many_block_limit = ISO_ZISOFS_MANY_BLOCKS;
107 static double ziso_keep_blocks_free_ratio = ISO_ZISOFS_KBF_RATIO;
108
109 /* Discard block pointers on last stream close even if the size constraints
110 * are not met. To be set to 1 at block pointer overflow. To be set to 0
111 * when all compression filters are deleted.
112 */
113 static int ziso_early_bpt_discard = 0;
114
115 /* 1 = produce Z2 entries for zisofs2 , 0 = produce ZF for zisofs2
116 * This is used as extern variable in rockridge.c
117 */
118 int iso_zisofs2_enable_susp_z2 = 0;
119
120
121 static
122 int ziso_decide_v2_usage(off_t orig_size)
123 {
124 if (ziso_v2_enabled > 1 ||
125 (ziso_v2_enabled == 1 && orig_size >= (off_t) ISO_ZISOFS_V1_LIMIT))
126 return 1;
127 return 0;
128 }
129
130 static
131 int ziso_decide_bs_log2(off_t orig_size)
132 {
133 int bs_log2, bs_log2_min, i;
134 off_t bs;
135
136 if (ziso_decide_v2_usage(orig_size)) {
137 bs_log2 = ziso_v2_block_size_log2;
138 bs_log2_min = ISO_ZISOFS_V2_MIN_LOG2;
139 } else {
140 bs_log2 = ziso_block_size_log2;
141 bs_log2_min = ISO_ZISOFS_V1_MIN_LOG2;
142 }
143 if (ziso_block_number_target <= 0)
144 return bs_log2;
145
146 for (i = bs_log2_min; i < bs_log2; i++) {
147 bs = (1 << i);
148 if (orig_size / bs + !!(orig_size % bs) + 1 <=
149 ziso_block_number_target)
150 return i;
151 }
152 return bs_log2;
153 }
154
155
156 /* --------------------------- ZisofsFilterRuntime ------------------------- */
157
158
159 /* Individual runtime properties exist only as long as the stream is opened.
160 */
161 typedef struct
162 {
163 int state; /* processing: 0= header, 1= block pointers, 2= data blocks */
164
165 int zisofs_version; /* 1 or 2 */
166
167 int block_size;
168 int64_t block_pointer_fill;
169 int64_t block_pointer_rpos;
170 uint64_t *block_pointers; /* These are in use only with uncompression.
171 Compression streams hold the pointer in
172 their persistent data.
173 */
174
175 char *read_buffer;
176 char *block_buffer;
177 int buffer_size;
178 int buffer_fill;
179 int buffer_rpos;
180
181 off_t block_counter;
182 off_t in_counter;
183 off_t out_counter;
184
185 int error_ret;
186
187 } ZisofsFilterRuntime;
188
189
190 static
191 int ziso_running_destroy(ZisofsFilterRuntime **running, int flag)
192 {
193 ZisofsFilterRuntime *o= *running;
194 if (o == NULL)
195 return 0;
196 if (o->block_pointers != NULL) {
197 ziso_block_pointer_mgt((uint64_t) o->block_pointer_fill, 2);
198 free(o->block_pointers);
199 }
200 if (o->read_buffer != NULL)
201 free(o->read_buffer);
202 if (o->block_buffer != NULL)
203 free(o->block_buffer);
204 free((char *) o);
205 *running = NULL;
206 return 1;
207 }
208
209
210 /*
211 * @param flag bit0= do not set block_size, do not allocate buffers
212 */
213 static
214 int ziso_running_new(ZisofsFilterRuntime **running, off_t orig_size,
215 int flag)
216 {
217 ZisofsFilterRuntime *o;
218 *running = o = calloc(sizeof(ZisofsFilterRuntime), 1);
219 if (o == NULL) {
220 return ISO_OUT_OF_MEM;
221 }
222 o->state = 0;
223 o->block_size= 0;
224 o->zisofs_version = 0;
225 o->block_pointer_fill = 0;
226 o->block_pointer_rpos = 0;
227 o->block_pointers = NULL;
228 o->read_buffer = NULL;
229 o->block_buffer = NULL;
230 o->buffer_size = 0;
231 o->buffer_fill = 0;
232 o->buffer_rpos = 0;
233 o->block_counter = 0;
234 o->in_counter = 0;
235 o->out_counter = 0;
236 o->error_ret = 0;
237
238 if (flag & 1)
239 return 1;
240
241 o->block_size = (1 << ziso_decide_bs_log2(orig_size));
242 #ifdef Libisofs_with_zliB
243 o->buffer_size = compressBound((uLong) o->block_size);
244 #else
245 o->buffer_size = 2 * o->block_size;
246 #endif
247 o->read_buffer = calloc(o->block_size, 1);
248 o->block_buffer = calloc(o->buffer_size, 1);
249 if (o->block_buffer == NULL || o->read_buffer == NULL)
250 goto failed;
251 return 1;
252 failed:
253 ziso_running_destroy(running, 0);
254 return -1;
255 }
256
257
258 /* --------------------------- Resource accounting ------------------------- */
259
260 /* @param mode 0= inquire whether num block pointers would fit
261 1= register num block pointers
262 2= unregister num block_pointers
263 3= return number of accounted block pointers
264 @return if not mode 3: 0= does not fit , 1= fits
265 */
266 static
267 uint64_t ziso_block_pointer_mgt(uint64_t num, int mode)
268 {
269 static uint64_t global_count = 0;
270 static int underrun = 0;
271
272 if (mode == 2) {
273 if (global_count < num) {
274 if (underrun < 3)
275 iso_msg_submit(-1, ISO_ZISOFS_BPT_UNDERRUN, 0,
276 "Prevented global block pointer counter underrun");
277 underrun++;
278 global_count = 0;
279 } else {
280 global_count -= num;
281 }
282 } else if (mode == 3) {
283 return global_count;
284 } else {
285 if (global_count + num > (uint64_t) ziso_max_total_blocks)
286 return 0;
287 if (mode == 1)
288 global_count += num;
289 }
290 return 1;
291 }
292
293
294 /* ---------------------------- ZisofsFilterStreamData --------------------- */
295
296 /* The first 8 bytes of a zisofs compressed data file */
297 static unsigned char zisofs_magic[9] =
298 {0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07};
299
300 /* The first 8 bytes of a zisofs2 compressed data file */
301 static unsigned char zisofs2_magic[9] =
302 {0xEF, 0x22, 0x55, 0xA1, 0xBC, 0x1B, 0x95, 0xA0};
303
304 /* Counts the number of active compression filters */
305 static off_t ziso_ref_count = 0;
306
307 /* Counts the number of active uncompression filters */
308 static off_t ziso_osiz_ref_count = 0;
309
310
311 #ifdef Libisofs_with_zliB
312 /* Parameter for compress2() , see <zlib.h> */
313
314 static int ziso_compression_level = 6;
315
316 #endif /* Libisofs_with_zliB */
317
318
319 /*
320 * The common data payload of an individual Zisofs Filter IsoStream
321 * IMPORTANT: Any change must be reflected by ziso_clone_stream().
322 */
323 typedef struct
324 {
325 IsoStream *orig;
326
327 off_t size; /* -1 means that the size is unknown yet */
328
329 ZisofsFilterRuntime *running; /* is non-NULL when open */
330
331 ino_t id;
332
333 } ZisofsFilterStreamData;
334
335
336 /*
337 * The data payload of an individual Zisofs Filter Compressor IsoStream
338 * IMPORTANT: Any change must be reflected by ziso_clone_stream().
339 */
340 typedef struct
341 {
342 ZisofsFilterStreamData std;
343
344 uint64_t orig_size;
345 uint64_t *block_pointers; /* Cache for output block addresses. They get
346 written before the data and so need 2 passes.
347 This cache avoids surplus passes.
348 */
349 uint64_t block_pointer_counter;
350 uint64_t open_counter;
351 int block_pointers_dropped;
352
353 } ZisofsComprStreamData;
354
355
356 /*
357 * The data payload of an individual Zisofs Filter Uncompressor IsoStream
358 * IMPORTANT: Any change must be reflected by ziso_clone_stream().
359 */
360 typedef struct
361 {
362 ZisofsFilterStreamData std;
363
364 uint8_t zisofs_algo_num;
365 unsigned char header_size_div4;
366 unsigned char block_size_log2;
367
368 } ZisofsUncomprStreamData;
369
370
371 /* Each individual ZisofsFilterStreamData needs a unique id number. */
372 /* >>> This is very suboptimal:
373 The counter can rollover.
374 */
375 static ino_t ziso_ino_id = 0;
376
377
378 /*
379 * Methods for the IsoStreamIface of an Zisofs Filter object.
380 */
381
382 static
383 int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired);
384
385 static
386 int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired);
387
388
389 /*
390 * @param flag bit0= discard even if the size conditions are not met
391 bit1= check for open_counter == 1 rather than == 0
392 */
393 static
394 int ziso_discard_bpt(IsoStream *stream, int flag)
395 {
396 ZisofsFilterStreamData *data;
397 ZisofsComprStreamData *cstd = NULL;
398 int block_size;
399 double max_blocks, free_blocks;
400
401 data = stream->data;
402 if (stream->class->read == &ziso_stream_compress)
403 cstd = (ZisofsComprStreamData *) data;
404 if (cstd == NULL)
405 return 0;
406
407 block_size = (1 << ziso_decide_bs_log2(cstd->orig_size));
408 max_blocks = ziso_max_file_blocks;
409 if (max_blocks < 1.0)
410 max_blocks = 1.0;
411 free_blocks = ziso_max_total_blocks -
412 ziso_block_pointer_mgt((uint64_t) 0, 3);
413 if (cstd->block_pointers == NULL) {
414 return 0;
415 } else if (cstd->open_counter != !!(flag & 2)) {
416 return 0;
417 } else if (!((flag & 1) || ziso_early_bpt_discard)) {
418 if (ziso_many_block_limit <= 0 ||
419 cstd->orig_size / block_size + !!(cstd->orig_size % block_size)
420 + 1 < (uint64_t) ziso_many_block_limit)
421 if (ziso_keep_blocks_free_ratio < 0.0 ||
422 free_blocks / max_blocks >= ziso_keep_blocks_free_ratio)
423 return 0;
424 }
425 ziso_block_pointer_mgt(cstd->block_pointer_counter, 2);
426 free((char *) cstd->block_pointers);
427 cstd->block_pointers_dropped = 1;
428 cstd->block_pointers = NULL;
429 cstd->block_pointer_counter = 0;
430 return 1;
431 }
432
433 /*
434 * @param flag bit0= original stream is not open
435 * bit1= do not destroy large
436 * ZisofsComprStreamData->block_pointers
437 */
438 static
439 int ziso_stream_close_flag(IsoStream *stream, int flag)
440 {
441 ZisofsFilterStreamData *data;
442 ZisofsComprStreamData *cstd = NULL;
443
444 if (stream == NULL) {
445 return ISO_NULL_POINTER;
446 }
447 data = stream->data;
448 if (stream->class->read == &ziso_stream_compress)
449 cstd = (ZisofsComprStreamData *) data;
450
451 if (cstd != NULL && !(flag & 2))
452 ziso_discard_bpt(stream, 2);
453
454 if (data->running == NULL) {
455 return 1;
456 }
457 ziso_running_destroy(&(data->running), 0);
458 if (flag & 1)
459 return 1;
460 if (cstd != NULL)
461 if (cstd->open_counter > 0)
462 cstd->open_counter--;
463 return iso_stream_close(data->orig);
464 }
465
466
467 static
468 int ziso_stream_close(IsoStream *stream)
469 {
470 return ziso_stream_close_flag(stream, 0);
471 }
472
473
474 /*
475 * @param flag bit0= do not run .get_size() if size is < 0
476 */
477 static
478 int ziso_stream_open_flag(IsoStream *stream, int flag)
479 {
480 ZisofsFilterStreamData *data;
481 ZisofsComprStreamData *cstd;
482 ZisofsFilterRuntime *running = NULL;
483 int ret;
484 off_t orig_size = 0;
485
486 if (stream == NULL) {
487 return ISO_NULL_POINTER;
488 }
489 data = (ZisofsFilterStreamData*) stream->data;
490 if (data->running != NULL) {
491 return ISO_FILE_ALREADY_OPENED;
492 }
493 if (data->size < 0 && !(flag & 1)) {
494 /* Do the size determination run now, so that the size gets cached
495 and .get_size() will not fail on an opened stream.
496 */
497 stream->class->get_size(stream);
498 }
499 orig_size = data->size;
500 if (stream->class->read == &ziso_stream_compress) {
501 cstd = (ZisofsComprStreamData *) data;
502 cstd->open_counter++;
503 orig_size = cstd->orig_size;
504 }
505 if (orig_size < 0)
506 return ISO_ZISOFS_UNKNOWN_SIZE;
507
508 ret = ziso_running_new(&running, orig_size,
509 (stream->class->read == &ziso_stream_uncompress));
510 if (ret < 0) {
511 return ret;
512 }
513 data->running = running;
514
515 ret = iso_stream_open(data->orig);
516 if (ret < 0) {
517 return ret;
518 }
519 return 1;
520 }
521
522
523 static
524 int ziso_stream_open(IsoStream *stream)
525 {
526 return ziso_stream_open_flag(stream, 0);
527 }
528
529
530 /* @param flag bit0= stream is already open
531 bit1= close stream with flag bit1
532 */
533 static
534 off_t ziso_stream_measure_size(IsoStream *stream, int flag)
535 {
536 int ret, ret_close;
537 off_t count = 0;
538 ZisofsFilterStreamData *data;
539 char buf[64 * 1024];
540 size_t bufsize = 64 * 1024;
541
542 if (stream == NULL)
543 return ISO_NULL_POINTER;
544 data = stream->data;
545
546 /* Run filter command and count output bytes */
547 if (!(flag & 1)) {
548 ret = ziso_stream_open_flag(stream, 1);
549 if (ret < 0)
550 return ret;
551 }
552 if (stream->class->read == &ziso_stream_uncompress) {
553 /* It is enough to read the header part of a compressed file */
554 ret = ziso_stream_uncompress(stream, buf, 0);
555 count = data->size;
556 } else {
557 /* The size of the compression result has to be counted */
558 while (1) {
559 ret = stream->class->read(stream, buf, bufsize);
560 if (ret <= 0)
561 break;
562 count += ret;
563 }
564 }
565 ret_close = ziso_stream_close_flag(stream, flag & 2);
566 if (ret < 0)
567 return ret;
568 if (ret_close < 0)
569 return ret_close;
570
571 data->size = count;
572 return count;
573 }
574
575
576 static
577 int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
578 {
579
580 #ifdef Libisofs_with_zliB
581
582 int ret, todo, i;
583 ZisofsComprStreamData *data;
584 ZisofsFilterRuntime *rng;
585 size_t fill = 0;
586 off_t orig_size, next_pt, measure_ret;
587 char *cbuf = buf;
588 uLongf buf_len;
589 uint64_t *copy_base, num_blocks = 0;
590
591 if (stream == NULL) {
592 return ISO_NULL_POINTER;
593 }
594 data = stream->data;
595 rng= data->std.running;
596 if (rng == NULL) {
597 return ISO_FILE_NOT_OPENED;
598 }
599 if (rng->error_ret < 0) {
600 return rng->error_ret;
601 }
602
603 if (data->block_pointers_dropped) {
604 /* The list was dropped after measurement of compressed size. But this
605 * run of the function expects it as already filled with pointer
606 * values. So now they have to be re-computed by extra runs of this
607 * function in the course of compressed size measurement.
608 */
609 data->block_pointers_dropped = 0;
610 measure_ret = ziso_stream_measure_size(stream, 1 | 2);
611 if (measure_ret < 0)
612 return (rng->error_ret = measure_ret);
613
614 /* Stream was closed. Open it again, without any size determination. */
615 ret = ziso_stream_open_flag(stream, 1);
616 if (ret < 0)
617 return ret;
618 }
619
620 while (1) {
621 if (rng->state == 0) {
622 /* Delivering file header */
623
624 if (rng->buffer_fill == 0) {
625 orig_size = iso_stream_get_size(data->std.orig);
626 num_blocks = orig_size / rng->block_size +
627 1 + !!(orig_size % rng->block_size);
628 if (num_blocks > (uint64_t) ziso_max_file_blocks)
629 return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
630 if (ziso_block_pointer_mgt((uint64_t) num_blocks, 0) == 0) {
631 ziso_early_bpt_discard = 1;
632 return (rng->error_ret = ISO_ZISOFS_TOO_MANY_PTR);
633 }
634 if (orig_size != (off_t) data->orig_size)
635 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
636 if (ziso_decide_v2_usage(orig_size)) {
637 rng->zisofs_version = 2;
638 memcpy(rng->block_buffer, zisofs2_magic, 8);
639 rng->block_buffer[8] = 0; /* @hdr_version */
640 rng->block_buffer[9] = 6; /* @hdr_size */
641 rng->block_buffer[10] = 1; /* @alg_id */
642 rng->block_buffer[11] = ziso_decide_bs_log2(orig_size);
643 iso_lsb64((uint8_t *) (rng->block_buffer + 12),
644 (uint64_t) orig_size);
645 memset(rng->block_buffer + 20, 0, 4);
646 rng->buffer_fill = 24;
647 } else {
648 if (orig_size >= (off_t) ISO_ZISOFS_V1_LIMIT) {
649 return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
650 }
651 rng->zisofs_version = 1;
652 memcpy(rng->block_buffer, zisofs_magic, 8);
653 iso_lsb((unsigned char *) (rng->block_buffer + 8),
654 (uint32_t) orig_size, 4);
655 rng->block_buffer[12] = 4;
656 rng->block_buffer[13] = ziso_decide_bs_log2(orig_size);
657 rng->block_buffer[14] = rng->block_buffer[15] = 0;
658 rng->buffer_fill = 16;
659 }
660 rng->buffer_rpos = 0;
661 } else if (rng->buffer_rpos >= rng->buffer_fill) {
662 rng->buffer_fill = rng->buffer_rpos = 0;
663 rng->state = 1; /* header is delivered */
664 }
665 }
666 if (rng->state == 1) {
667 /* Delivering block pointers */;
668
669 if (rng->block_pointer_fill == 0 || data->block_pointers == NULL) {
670 /* Initialize block pointer writing */
671 rng->block_pointer_rpos = 0;
672 num_blocks = data->orig_size / rng->block_size
673 + 1 + !!(data->orig_size % rng->block_size);
674 if (rng->block_pointer_fill > 0 &&
675 (int64_t) num_blocks != rng->block_pointer_fill)
676 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
677 rng->block_pointer_fill = num_blocks;
678 if (data->block_pointers == NULL) {
679 /* On the first pass, create pointer array with all 0s */
680 if (ziso_block_pointer_mgt(num_blocks, 1) == 0) {
681 rng->block_pointer_fill = 0;
682 ziso_early_bpt_discard = 1;
683 return (rng->error_ret = ISO_ZISOFS_TOO_MANY_PTR);
684 }
685 data->block_pointers = calloc(rng->block_pointer_fill, 8);
686 if (data->block_pointers == NULL) {
687 ziso_block_pointer_mgt(num_blocks, 2);
688 rng->block_pointer_fill = 0;
689 return (rng->error_ret = ISO_OUT_OF_MEM);
690 }
691 data->block_pointer_counter = rng->block_pointer_fill;
692 }
693 }
694
695 if (rng->buffer_rpos >= rng->buffer_fill) {
696 if (rng->block_pointer_rpos >= rng->block_pointer_fill) {
697 rng->buffer_fill = rng->buffer_rpos = 0;
698 rng->block_counter = 0;
699 if (rng->zisofs_version == 1)
700 data->block_pointers[0] = 16 +
701 rng->block_pointer_fill * 4;
702 else
703 data->block_pointers[0] = 24 +
704 rng->block_pointer_fill * 8;
705 rng->state = 2; /* block pointers are delivered */
706 } else {
707 /* Provide a buffer full of block pointers */
708 /* data->block_pointers was filled by ziso_stream_open() */
709 todo = rng->block_pointer_fill - rng->block_pointer_rpos;
710 copy_base = data->block_pointers + rng->block_pointer_rpos;
711 if (rng->zisofs_version == 1) {
712 if (todo * 4 > rng->buffer_size)
713 todo = rng->buffer_size / 4;
714 for (i = 0; i < todo; i++)
715 iso_lsb((unsigned char *) (rng->block_buffer +
716 4 * i),
717 (uint32_t) (copy_base[i] & 0xffffffff), 4);
718 rng->buffer_fill = todo * 4;
719 } else {
720 if (todo * 8 > rng->buffer_size)
721 todo = rng->buffer_size / 8;
722 for (i = 0; i < todo; i++)
723 iso_lsb64((uint8_t *) rng->block_buffer + 8 * i,
724 copy_base[i]);
725 rng->buffer_fill = todo * 8;
726 }
727 rng->buffer_rpos = 0;
728 rng->block_pointer_rpos += todo;
729 }
730 }
731 }
732 if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) {
733 /* Delivering data blocks */;
734
735 ret = iso_stream_read(data->std.orig, rng->read_buffer,
736 rng->block_size);
737 if (ret > 0) {
738 rng->in_counter += ret;
739 if ((uint64_t) rng->in_counter > data->orig_size) {
740 /* Input size became larger */
741 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
742 }
743 /* Check whether all 0 : represent as 0-length block */;
744 for (i = 0; i < ret; i++)
745 if (rng->read_buffer[i])
746 break;
747 if (i >= ret) { /* All 0-bytes. Bypass compression. */
748 buf_len = 0;
749 } else {
750 buf_len = rng->buffer_size;
751 ret = compress2((Bytef *) rng->block_buffer, &buf_len,
752 (Bytef *) rng->read_buffer, (uLong) ret,
753 ziso_compression_level);
754 if (ret != Z_OK) {
755 return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
756 }
757 }
758 rng->buffer_fill = buf_len;
759 rng->buffer_rpos = 0;
760
761 next_pt = data->block_pointers[rng->block_counter] + buf_len;
762
763 if (data->std.size >= 0 && next_pt > data->std.size) {
764 /* Compression yields more bytes than on first run */
765 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
766 }
767
768 /* Check or record check block pointer */
769 rng->block_counter++;
770 if (data->block_pointers[rng->block_counter] > 0) {
771 if ((uint64_t) next_pt !=
772 data->block_pointers[rng->block_counter]) {
773 /* block pointers mismatch , content has changed */
774 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
775 }
776 } else {
777 data->block_pointers[rng->block_counter] = next_pt;
778 }
779
780 } else if (ret == 0) {
781 rng->state = 3;
782 if ((uint64_t) rng->in_counter != data->orig_size) {
783 /* Input size shrunk */
784 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
785 }
786 return fill;
787 } else
788 return (rng->error_ret = ret);
789 if (rng->buffer_fill == 0) {
790 continue;
791 }
792 }
793 if (rng->state == 3 && rng->buffer_rpos >= rng->buffer_fill) {
794 return 0; /* EOF */
795 }
796
797 /* Transfer from rng->block_buffer to buf */
798 todo = desired - fill;
799 if (todo > rng->buffer_fill - rng->buffer_rpos)
800 todo = rng->buffer_fill - rng->buffer_rpos;
801 memcpy(cbuf + fill, rng->block_buffer + rng->buffer_rpos, todo);
802 fill += todo;
803 rng->buffer_rpos += todo;
804 rng->out_counter += todo;
805
806 if (fill >= desired) {
807 return fill;
808 }
809 }
810 return ISO_FILE_READ_ERROR; /* should never be hit */
811
812 #else
813
814 return ISO_ZLIB_NOT_ENABLED;
815
816 #endif
817
818 }
819
820
821 #ifdef Libisofs_with_zliB
822
823 static
824 int ziso_algo_to_num(uint8_t zisofs_algo[2])
825 {
826 if (zisofs_algo[0] == 'p' && zisofs_algo[1] == 'z')
827 return 0;
828 if (zisofs_algo[0] == 'P' && zisofs_algo[1] == 'Z')
829 return 1;
830 if (zisofs_algo[0] == 'X' && zisofs_algo[1] == 'Z')
831 return 2;
832 if (zisofs_algo[0] == 'L' && zisofs_algo[1] == '4')
833 return 3;
834 if (zisofs_algo[0] == 'Z' && zisofs_algo[1] == 'D')
835 return 4;
836 if (zisofs_algo[0] == 'B' && zisofs_algo[1] == '2')
837 return 5;
838 return -1;
839 }
840
841 #endif /* Libisofs_with_zliB */
842
843 static
844 int ziso_num_to_algo(uint8_t num, uint8_t zisofs_algo[2])
845 {
846 if (num == 0) {
847 zisofs_algo[0] = 'p';
848 zisofs_algo[1] = 'z';
849 return 1;
850 } else if (num == 1) {
851 zisofs_algo[0] = 'P';
852 zisofs_algo[1] = 'Z';
853 return 1;
854 } else if (num == 2) {
855 zisofs_algo[0] = 'X';
856 zisofs_algo[1] = 'Z';
857 return 2;
858 } else if (num == 3) {
859 zisofs_algo[0] = 'L';
860 zisofs_algo[1] = '4';
861 return 2;
862 } else if (num == 4) {
863 zisofs_algo[0] = 'Z';
864 zisofs_algo[1] = 'D';
865 return 2;
866 } else if (num == 5) {
867 zisofs_algo[0] = 'B';
868 zisofs_algo[1] = '2';
869 return 2;
870 }
871 return -1;
872 }
873
874
875 /* @param flag bit0= recognize zisofs2 only if ziso_v2_enabled
876 bit1= do not accept algorithms which libisofs does not support
877 */
878 static
879 int ziso_parse_zisofs_head(IsoStream *stream, uint8_t *ziso_algo_num,
880 int *header_size_div4, int *block_size_log2,
881 uint64_t *uncompressed_size, int flag)
882 {
883 int ret, consumed = 0, i;
884 char zisofs_head[24];
885 char waste_word[4];
886
887 ret = iso_stream_read(stream, zisofs_head, 8);
888 if (ret < 0)
889 return ret;
890 if (ret != 8)
891 return ISO_ZISOFS_WRONG_INPUT;
892 consumed = 8;
893 if (memcmp(zisofs_head, zisofs_magic, 8) == 0) {
894 *ziso_algo_num = 0;
895 ret = iso_stream_read(stream, zisofs_head + 8, 8);
896 if (ret < 0)
897 return ret;
898 if (ret != 8)
899 return ISO_ZISOFS_WRONG_INPUT;
900 consumed += 8;
901 *header_size_div4 = ((unsigned char *) zisofs_head)[12];
902 *block_size_log2 = ((unsigned char *) zisofs_head)[13];
903 *uncompressed_size = iso_read_lsb(((uint8_t *) zisofs_head) + 8, 4);
904 if (*header_size_div4 < 4 ||
905 *block_size_log2 < ISO_ZISOFS_V1_MIN_LOG2 ||
906 *block_size_log2 > ISO_ZISOFS_V1_MAX_LOG2)
907 return ISO_ZISOFS_WRONG_INPUT;
908 } else if (memcmp(zisofs_head, zisofs2_magic, 8) == 0 &&
909 !(ziso_v2_enabled == 0 && (flag & 1))) {
910 ret = iso_stream_read(stream, zisofs_head + 8, 16);
911 if (ret < 0)
912 return ret;
913 if (ret != 16)
914 return ISO_ZISOFS_WRONG_INPUT;
915 consumed += 16;
916 *ziso_algo_num = zisofs_head[10];
917 *header_size_div4 = ((unsigned char *) zisofs_head)[9];
918 *block_size_log2 = ((unsigned char *) zisofs_head)[11];
919 *uncompressed_size = iso_read_lsb64(((uint8_t *) zisofs_head) + 12);
920 if (*header_size_div4 < 4 ||
921 *block_size_log2 < ISO_ZISOFS_V2_MIN_LOG2 ||
922 *block_size_log2 > ISO_ZISOFS_V2_MAX_LOG2 ||
923 (*ziso_algo_num != 1 && (flag & 2)))
924 return ISO_ZISOFS_WRONG_INPUT;
925 } else {
926 return ISO_ZISOFS_WRONG_INPUT;
927 }
928 for (i = consumed; i < *header_size_div4; i++) {
929 /* Skip surplus header words */
930 ret = iso_stream_read(stream, waste_word, 4);
931 if (ret < 0)
932 return ret;
933 if (ret != 4)
934 return ISO_ZISOFS_WRONG_INPUT;
935 }
936 return 1;
937 }
938
939
940 /* Note: A call with desired==0 directly after .open() only checks the file
941 head and loads the uncompressed size from that head.
942 */
943 static
944 int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
945 {
946
947 #ifdef Libisofs_with_zliB
948
949 int ret, todo, header_size, bs_log2, block_max = 1, blpt_size;
950 ZisofsFilterStreamData *data;
951 ZisofsFilterRuntime *rng;
952 ZisofsUncomprStreamData *nstd;
953 size_t fill = 0;
954 char *cbuf = buf;
955 uLongf buf_len;
956 uint64_t uncompressed_size;
957 int64_t i;
958 uint8_t algo_num, *rpt, *wpt;
959
960 if (stream == NULL) {
961 return ISO_NULL_POINTER;
962 }
963 data = stream->data;
964 nstd = stream->data;
965 rng= data->running;
966 if (rng == NULL) {
967 return ISO_FILE_NOT_OPENED;
968 }
969 if (rng->error_ret < 0) {
970 return rng->error_ret;
971 }
972
973 while (1) {
974 if (rng->state == 0) {
975 /* Reading file header */
976 ret = ziso_parse_zisofs_head(data->orig, &algo_num, &header_size,
977 &bs_log2, &uncompressed_size, 2);
978 if (ret < 0)
979 return (rng->error_ret = ret);
980 if (algo_num == 0)
981 blpt_size = 4;
982 else
983 blpt_size = 8;
984 nstd->header_size_div4 = header_size;
985 header_size *= 4;
986 data->size = uncompressed_size;
987 nstd->block_size_log2 = bs_log2;
988 rng->block_size = 1 << bs_log2;
989
990 if (desired == 0)
991 return 0;
992
993 /* Create and read pointer array */
994 rng->block_pointer_rpos = 0;
995 rng->block_pointer_fill = data->size / rng->block_size
996 + 1 + !!(data->size % rng->block_size);
997 if (rng->block_pointer_fill > ziso_max_file_blocks) {
998 rng->block_pointer_fill = 0;
999 return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
1000 }
1001 if (ziso_block_pointer_mgt((uint64_t) rng->block_pointer_fill, 1)
1002 == 0)
1003 return ISO_ZISOFS_TOO_MANY_PTR;
1004 rng->block_pointers = calloc(rng->block_pointer_fill, 8);
1005 if (rng->block_pointers == NULL) {
1006 ziso_block_pointer_mgt((uint64_t) rng->block_pointer_fill, 2);
1007 rng->block_pointer_fill = 0;
1008 return (rng->error_ret = ISO_OUT_OF_MEM);
1009 }
1010 ret = iso_stream_read(data->orig, rng->block_pointers,
1011 rng->block_pointer_fill * blpt_size);
1012 if (ret < 0)
1013 return (rng->error_ret = ret);
1014 if (algo_num == 0) {
1015 /* Spread 4 byte little-endian pointer values over 8 byte */
1016 rpt = ((uint8_t *) rng->block_pointers)
1017 + rng->block_pointer_fill * 4;
1018 wpt = ((uint8_t *) rng->block_pointers)
1019 + rng->block_pointer_fill * 8;
1020 while (rpt > ((uint8_t *) rng->block_pointers) + 4) {
1021 rpt -= 4;
1022 wpt -= 8;
1023 memcpy(wpt, rpt, 4);
1024 memset(wpt + 4, 0, 4);
1025 }
1026 memset(((uint8_t *) rng->block_pointers) + 4, 0, 4);
1027 }
1028 if (ret != rng->block_pointer_fill * blpt_size)
1029 return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
1030 for (i = 0; i < rng->block_pointer_fill; i++) {
1031 rng->block_pointers[i] =
1032 iso_read_lsb64((uint8_t *) (rng->block_pointers + i));
1033 if (i > 0)
1034 if ((int) (rng->block_pointers[i] -
1035 rng->block_pointers[i - 1])
1036 > block_max)
1037 block_max = rng->block_pointers[i]
1038 - rng->block_pointers[i - 1];
1039 }
1040
1041 rng->read_buffer = calloc(block_max, 1);
1042 rng->block_buffer = calloc(rng->block_size, 1);
1043 if (rng->read_buffer == NULL || rng->block_buffer == NULL)
1044 return (rng->error_ret = ISO_OUT_OF_MEM);
1045 rng->state = 2; /* block pointers are read */
1046 rng->buffer_fill = rng->buffer_rpos = 0;
1047 }
1048
1049 if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) {
1050 /* Delivering data blocks */;
1051 i = ++(rng->block_pointer_rpos);
1052 if (i >= rng->block_pointer_fill) {
1053 if (rng->out_counter == data->size) {
1054 rng->state = 3;
1055 rng->block_pointer_rpos--;
1056 return fill;
1057 }
1058 /* More data blocks needed than announced */
1059 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
1060 }
1061 todo = rng->block_pointers[i] - rng->block_pointers[i- 1];
1062 if (todo == 0) {
1063 memset(rng->block_buffer, 0, rng->block_size);
1064 rng->buffer_fill = rng->block_size;
1065 if (rng->out_counter + rng->buffer_fill > data->size &&
1066 i == rng->block_pointer_fill - 1)
1067 rng->buffer_fill = data->size - rng->out_counter;
1068 } else {
1069 ret = iso_stream_read(data->orig, rng->read_buffer, todo);
1070 if (ret > 0) {
1071 rng->in_counter += ret;
1072 buf_len = rng->block_size;
1073 ret = uncompress((Bytef *) rng->block_buffer, &buf_len,
1074 (Bytef *) rng->read_buffer, (uLong) ret);
1075 if (ret != Z_OK)
1076 return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
1077 rng->buffer_fill = buf_len;
1078 if ((int) buf_len < rng->block_size &&
1079 i != rng->block_pointer_fill - 1)
1080 return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
1081 } else if(ret == 0) {
1082 rng->state = 3;
1083 if (rng->out_counter != data->size) {
1084 /* Input size shrunk */
1085 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
1086 }
1087 return fill;
1088 } else
1089 return (rng->error_ret = ret);
1090 }
1091 rng->buffer_rpos = 0;
1092
1093 if (rng->out_counter + rng->buffer_fill > data->size) {
1094 /* Uncompression yields more bytes than announced by header */
1095 return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
1096 }
1097 }
1098 if (rng->state == 3 && rng->buffer_rpos >= rng->buffer_fill) {
1099 return 0; /* EOF */
1100 }
1101
1102 /* Transfer from rng->block_buffer to buf */
1103 todo = desired - fill;
1104 if (todo > rng->buffer_fill - rng->buffer_rpos)
1105 todo = rng->buffer_fill - rng->buffer_rpos;
1106 memcpy(cbuf + fill, rng->block_buffer + rng->buffer_rpos, todo);
1107 fill += todo;
1108 rng->buffer_rpos += todo;
1109 rng->out_counter += todo;
1110
1111 if (fill >= desired) {
1112 return fill;
1113 }
1114 }
1115 return (rng->error_ret = ISO_FILE_READ_ERROR); /* should never be hit */
1116
1117 #else
1118
1119 return ISO_ZLIB_NOT_ENABLED;
1120
1121 #endif
1122
1123 }
1124
1125
1126 static
1127 off_t ziso_stream_get_size(IsoStream *stream)
1128 {
1129 off_t ret;
1130 ZisofsFilterStreamData *data;
1131
1132 if (stream == NULL)
1133 return ISO_NULL_POINTER;
1134 data = stream->data;
1135 if (data->size >= 0)
1136 return data->size;
1137 ret = ziso_stream_measure_size(stream, 0);
1138 return ret;
1139 }
1140
1141
1142 static
1143 int ziso_stream_is_repeatable(IsoStream *stream)
1144 {
1145 /* Only repeatable streams are accepted as orig */
1146 return 1;
1147 }
1148
1149
1150 static
1151 void ziso_stream_get_id(IsoStream *stream, unsigned int *fs_id,
1152 dev_t *dev_id, ino_t *ino_id)
1153 {
1154 ZisofsFilterStreamData *data;
1155
1156 data = stream->data;
1157 *fs_id = ISO_FILTER_FS_ID;
1158 *dev_id = ISO_FILTER_ZISOFS_DEV_ID;
1159 *ino_id = data->id;
1160 }
1161
1162
1163 static
1164 void ziso_stream_free(IsoStream *stream)
1165 {
1166 ZisofsFilterStreamData *data;
1167 ZisofsComprStreamData *nstd;
1168
1169 if (stream == NULL) {
1170 return;
1171 }
1172 data = stream->data;
1173 if (data->running != NULL) {
1174 ziso_stream_close(stream);
1175 }
1176 if (stream->class->read == &ziso_stream_uncompress) {
1177 if (--ziso_osiz_ref_count < 0)
1178 ziso_osiz_ref_count = 0;
1179 } else {
1180 nstd = stream->data;
1181 if (nstd->block_pointers != NULL) {
1182 ziso_block_pointer_mgt(nstd->block_pointer_counter, 2);
1183 free((char *) nstd->block_pointers);
1184 }
1185 if (--ziso_ref_count < 0)
1186 ziso_ref_count = 0;
1187 if (ziso_ref_count == 0)
1188 ziso_early_bpt_discard = 0;
1189 }
1190 iso_stream_unref(data->orig);
1191 free(data);
1192 }
1193
1194
1195 static
1196 int ziso_update_size(IsoStream *stream)
1197 {
1198 /* By principle size is determined only once */
1199 return 1;
1200 }
1201
1202
1203 static
1204 IsoStream *ziso_get_input_stream(IsoStream *stream, int flag)
1205 {
1206 ZisofsFilterStreamData *data;
1207
1208 if (stream == NULL) {
1209 return NULL;
1210 }
1211 data = stream->data;
1212 return data->orig;
1213 }
1214
1215 static
1216 int ziso_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
1217 {
1218 int ret;
1219 IsoStream *new_input_stream = NULL, *stream = NULL;
1220 ZisofsFilterStreamData *stream_data, *old_stream_data;
1221 ZisofsUncomprStreamData *uncompr, *old_uncompr;
1222 ZisofsComprStreamData *compr, *old_compr;
1223
1224 if (flag)
1225 return ISO_STREAM_NO_CLONE; /* unknown option required */
1226
1227 ret = iso_stream_clone_filter_common(old_stream, &stream,
1228 &new_input_stream, 0);
1229 if (ret < 0)
1230 return ret;
1231
1232 if (old_stream->class->read == &ziso_stream_uncompress) {
1233 uncompr = calloc(1, sizeof(ZisofsUncomprStreamData));
1234 if (uncompr == NULL)
1235 goto no_mem;
1236 stream_data = (ZisofsFilterStreamData *) uncompr;
1237 old_uncompr = (ZisofsUncomprStreamData *) old_stream->data;
1238 uncompr->zisofs_algo_num = old_uncompr->zisofs_algo_num;
1239 uncompr->header_size_div4 = old_uncompr->header_size_div4;
1240 uncompr->block_size_log2 = old_uncompr->block_size_log2;
1241 } else {
1242 compr = calloc(1, sizeof(ZisofsComprStreamData));
1243 if (compr == NULL)
1244 goto no_mem;
1245 stream_data = (ZisofsFilterStreamData *) compr;
1246 old_compr = (ZisofsComprStreamData *) old_stream->data;
1247 compr->orig_size = old_compr->orig_size;
1248 compr->block_pointers = NULL;
1249 compr->block_pointer_counter = 0;
1250 compr->open_counter = 0;
1251 if (old_compr->block_pointers != NULL ||
1252 old_compr->block_pointers_dropped)
1253 compr->block_pointers_dropped = 1;
1254 else
1255 compr->block_pointers_dropped = 0;
1256 }
1257 old_stream_data = (ZisofsFilterStreamData *) old_stream->data;
1258 stream_data->orig = new_input_stream;
1259 stream_data->size = old_stream_data->size;
1260 stream_data->running = NULL;
1261 stream_data->id = ++ziso_ino_id;
1262 stream->data = stream_data;
1263 *new_stream = stream;
1264 return ISO_SUCCESS;
1265 no_mem:
1266 if (new_input_stream != NULL)
1267 iso_stream_unref(new_input_stream);
1268 if (stream != NULL)
1269 iso_stream_unref(stream);
1270 return ISO_OUT_OF_MEM;
1271 }
1272
1273
1274 static
1275 int ziso_cmp_ino(IsoStream *s1, IsoStream *s2);
1276
1277 static
1278 int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
1279
1280
1281 IsoStreamIface ziso_stream_compress_class = {
1282 4,
1283 "ziso",
1284 ziso_stream_open,
1285 ziso_stream_close,
1286 ziso_stream_get_size,
1287 ziso_stream_compress,
1288 ziso_stream_is_repeatable,
1289 ziso_stream_get_id,
1290 ziso_stream_free,
1291 ziso_update_size,
1292 ziso_get_input_stream,
1293 ziso_cmp_ino,
1294 ziso_clone_stream
1295 };
1296
1297
1298 IsoStreamIface ziso_stream_uncompress_class = {
1299 4,
1300 "osiz",
1301 ziso_stream_open,
1302 ziso_stream_close,
1303 ziso_stream_get_size,
1304 ziso_stream_uncompress,
1305 ziso_stream_is_repeatable,
1306 ziso_stream_get_id,
1307 ziso_stream_free,
1308 ziso_update_size,
1309 ziso_get_input_stream,
1310 ziso_uncompress_cmp_ino,
1311 ziso_clone_stream
1312 };
1313
1314
1315 static
1316 int ziso_cmp_ino(IsoStream *s1, IsoStream *s2)
1317 {
1318 /* This function may rely on being called by iso_stream_cmp_ino()
1319 only with s1, s2 which both point to it as their .cmp_ino() function.
1320 It would be a programming error to let any other than
1321 ziso_stream_compress_class point to ziso_cmp_ino().
1322 */
1323 if (s1->class != s2->class || (s1->class != &ziso_stream_compress_class &&
1324 s2->class != &ziso_stream_uncompress_class))
1325 iso_stream_cmp_ino(s1, s2, 1);
1326
1327 /* Both streams apply the same treatment to their input streams */
1328 return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
1329 iso_stream_get_input_stream(s2, 0), 0);
1330 }
1331
1332
1333 static
1334 int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
1335 {
1336 /* This function may rely on being called by iso_stream_cmp_ino()
1337 only with s1, s2 which both point to it as their .cmp_ino() function.
1338 It would be a programming error to let any other than
1339 ziso_stream_uncompress_class point to ziso_uncompress_cmp_ino().
1340 This fallback endangers transitivity of iso_stream_cmp_ino().
1341 */
1342 if (s1->class != s2->class ||
1343 (s1->class != &ziso_stream_uncompress_class &&
1344 s2->class != &ziso_stream_uncompress_class))
1345 iso_stream_cmp_ino(s1, s2, 1);
1346
1347 /* Both streams apply the same treatment to their input streams */
1348 return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
1349 iso_stream_get_input_stream(s2, 0), 0);
1350 }
1351
1352
1353 /* ------------------------------------------------------------------------- */
1354
1355
1356
1357 #ifdef Libisofs_with_zliB
1358
1359 static
1360 void ziso_filter_free(FilterContext *filter)
1361 {
1362 /* no data are allocated */;
1363 }
1364
1365
1366 /*
1367 * @param flag bit1= Install a decompression filter
1368 */
1369 static
1370 int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
1371 IsoStream **filtered, int flag)
1372 {
1373 IsoStream *str;
1374 ZisofsFilterStreamData *data;
1375 ZisofsComprStreamData *cnstd = NULL;
1376 ZisofsUncomprStreamData *unstd = NULL;
1377
1378 if (filter == NULL || original == NULL || filtered == NULL) {
1379 return ISO_NULL_POINTER;
1380 }
1381
1382 str = calloc(sizeof(IsoStream), 1);
1383 if (str == NULL) {
1384 return ISO_OUT_OF_MEM;
1385 }
1386 if (flag & 2) {
1387 unstd = calloc(sizeof(ZisofsUncomprStreamData), 1);
1388 data = (ZisofsFilterStreamData *) unstd;
1389 } else {
1390 cnstd = calloc(sizeof(ZisofsComprStreamData), 1);
1391 data = (ZisofsFilterStreamData *) cnstd;
1392 }
1393 if (data == NULL) {
1394 free(str);
1395 return ISO_OUT_OF_MEM;
1396 }
1397
1398 /* These data items are not owned by this filter object */
1399 data->id = ++ziso_ino_id;
1400 data->orig = original;
1401 data->size = -1;
1402 data->running = NULL;
1403
1404 /* get reference to the source */
1405 iso_stream_ref(data->orig);
1406
1407 str->refcount = 1;
1408 str->data = data;
1409 if (flag & 2) {
1410 unstd->zisofs_algo_num = 0;
1411 unstd->header_size_div4 = 0;
1412 unstd->block_size_log2 = 0;
1413 str->class = &ziso_stream_uncompress_class;
1414 ziso_osiz_ref_count++;
1415 } else {
1416 cnstd->orig_size = iso_stream_get_size(original);
1417 cnstd->block_pointers = NULL;
1418 cnstd->block_pointer_counter = 0;
1419 cnstd->open_counter = 0;
1420 cnstd->block_pointers_dropped = 0;
1421 str->class = &ziso_stream_compress_class;
1422 ziso_ref_count++;
1423 }
1424
1425 *filtered = str;
1426
1427 return ISO_SUCCESS;
1428 }
1429
1430
1431 /* To be called by iso_file_add_filter().
1432 * The FilterContext input parameter is not furtherly needed for the
1433 * emerging IsoStream.
1434 */
1435 static
1436 int ziso_filter_get_compressor(FilterContext *filter, IsoStream *original,
1437 IsoStream **filtered)
1438 {
1439 return ziso_filter_get_filter(filter, original, filtered, 0);
1440 }
1441
1442 static
1443 int ziso_filter_get_uncompressor(FilterContext *filter, IsoStream *original,
1444 IsoStream **filtered)
1445 {
1446 return ziso_filter_get_filter(filter, original, filtered, 2);
1447 }
1448
1449
1450 /* Produce a parameter object suitable for iso_file_add_filter().
1451 * It may be disposed by free() after all those calls are made.
1452 *
1453 * This is quite a dummy as it does not carry individual data.
1454 * @param flag bit1= Install a decompression filter
1455 */
1456 static
1457 int ziso_create_context(FilterContext **filter, int flag)
1458 {
1459 FilterContext *f;
1460
1461 *filter = f = calloc(1, sizeof(FilterContext));
1462 if (f == NULL) {
1463 return ISO_OUT_OF_MEM;
1464 }
1465 f->refcount = 1;
1466 f->version = 0;
1467 f->data = NULL;
1468 f->free = ziso_filter_free;
1469 if (flag & 2)
1470 f->get_filter = ziso_filter_get_uncompressor;
1471 else
1472 f->get_filter = ziso_filter_get_compressor;
1473 return ISO_SUCCESS;
1474 }
1475
1476 #endif /* Libisofs_with_zliB */
1477
1478 /*
1479 * @param flag bit0= if_block_reduction rather than if_reduction
1480 * bit1= Install a decompression filter
1481 * bit2= only inquire availability of zisofs filtering
1482 * bit3= do not inquire size
1483 */
1484 int ziso_add_filter(IsoFile *file, int flag)
1485 {
1486
1487 #ifdef Libisofs_with_zliB
1488
1489 int ret;
1490 FilterContext *f = NULL;
1491 IsoStream *stream;
1492 off_t original_size = 0, filtered_size = 0;
1493
1494 if (flag & 4)
1495 return 2;
1496
1497 original_size = iso_file_get_size(file);
1498 if (!(flag & 2)) {
1499 if (original_size <= 0 || ((flag & 1) && original_size <= 2048)) {
1500 return 2;
1501 }
1502 if (original_size >= (off_t) ISO_ZISOFS_V1_LIMIT && !ziso_v2_enabled) {
1503 return ISO_ZISOFS_TOO_LARGE;
1504 }
1505 }
1506
1507 ret = ziso_create_context(&f, flag & 2);
1508 if (ret < 0) {
1509 return ret;
1510 }
1511 ret = iso_file_add_filter(file, f, 0);
1512 free(f);
1513 if (ret < 0) {
1514 return ret;
1515 }
1516 if (flag & 8) /* size will be filled in by caller */
1517 return ISO_SUCCESS;
1518
1519 /* Run a full filter process getsize so that the size is cached */
1520 stream = iso_file_get_stream(file);
1521 filtered_size = iso_stream_get_size(stream);
1522 if (filtered_size < 0) {
1523 iso_file_remove_filter(file, 0);
1524 return filtered_size;
1525 }
1526 if ((filtered_size >= original_size ||
1527 ((flag & 1) && filtered_size / 2048 >= original_size / 2048))
1528 && !(flag & 2)){
1529 ret = iso_file_remove_filter(file, 0);
1530 if (ret < 0) {
1531 return ret;
1532 }
1533 return 2;
1534 }
1535 return ISO_SUCCESS;
1536
1537 #else
1538
1539 return ISO_ZLIB_NOT_ENABLED;
1540
1541 #endif /* ! Libisofs_with_zliB */
1542
1543 }
1544
1545
1546 /* API function */
1547 int iso_file_add_zisofs_filter(IsoFile *file, int flag)
1548 {
1549 return ziso_add_filter(file, flag & ~8);
1550 }
1551
1552
1553 /* API function */
1554 int iso_zisofs_get_refcounts(off_t *ziso_count, off_t *osiz_count, int flag)
1555 {
1556 *ziso_count = ziso_ref_count;
1557 *osiz_count = ziso_osiz_ref_count;
1558 return ISO_SUCCESS;
1559 }
1560
1561
1562 int ziso_add_osiz_filter(IsoFile *file, uint8_t zisofs_algo[2],
1563 uint8_t header_size_div4, uint8_t block_size_log2,
1564 uint64_t uncompressed_size, int flag)
1565 {
1566
1567 #ifdef Libisofs_with_zliB
1568
1569 int ret;
1570 ZisofsUncomprStreamData *unstd;
1571
1572 ret = ziso_add_filter(file, 2 | 8);
1573 if (ret < 0)
1574 return ret;
1575 unstd = iso_file_get_stream(file)->data;
1576 ret = ziso_algo_to_num(zisofs_algo);
1577 if (ret < 0)
1578 return ISO_ZISOFS_WRONG_INPUT;
1579 unstd->zisofs_algo_num = ret;
1580 unstd->header_size_div4 = header_size_div4;
1581 unstd->block_size_log2 = block_size_log2;
1582 unstd->std.size = uncompressed_size;
1583 return ISO_SUCCESS;
1584
1585 #else
1586
1587 return ISO_ZLIB_NOT_ENABLED;
1588
1589 #endif /* ! Libisofs_with_zliB */
1590
1591 }
1592
1593
1594
1595 /* Determine stream type : 1=ziso , -1=osiz , 0=other , 2=ziso_by_content
1596 and eventual ZF field parameters
1597 @param flag bit0= allow ziso_by_content which is based on content reading
1598 bit1= do not inquire stream->class for filters
1599 bit2= recognize zisofs2 by magic only if ziso_v2_enabled
1600 */
1601 int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
1602 uint8_t zisofs_algo[2],
1603 int *header_size_div4, int *block_size_log2,
1604 uint64_t *uncompressed_size, int flag)
1605 {
1606 int ret, close_ret, algo_ret;
1607 ZisofsFilterStreamData *data;
1608 ZisofsComprStreamData *cnstd;
1609 ZisofsUncomprStreamData *unstd;
1610 uint8_t algo_num;
1611
1612 *stream_type = 0;
1613 if (stream->class == &ziso_stream_compress_class && !(flag & 2)) {
1614 *stream_type = 1;
1615 cnstd = stream->data;
1616 *uncompressed_size = cnstd->orig_size;
1617 *block_size_log2 = ziso_decide_bs_log2((off_t) *uncompressed_size);
1618 if (ziso_decide_v2_usage((off_t) *uncompressed_size)) {
1619 zisofs_algo[0] = 'P';
1620 zisofs_algo[1] = 'Z';
1621 *header_size_div4 = 6;
1622 } else if (*uncompressed_size < (uint64_t) ISO_ZISOFS_V1_LIMIT) {
1623 zisofs_algo[0] = 'p';
1624 zisofs_algo[1] = 'z';
1625 *header_size_div4 = 4;
1626 } else {
1627 return 0;
1628 }
1629 return 1;
1630 } else if(stream->class == &ziso_stream_uncompress_class && !(flag & 2)) {
1631 *stream_type = -1;
1632 data = stream->data;
1633 unstd = stream->data;
1634 ret = ziso_num_to_algo(unstd->zisofs_algo_num, zisofs_algo);
1635 if (ret < 0)
1636 return ISO_ZISOFS_WRONG_INPUT;
1637 *header_size_div4 = unstd->header_size_div4;
1638 *block_size_log2 = unstd->block_size_log2;
1639 *uncompressed_size = data->size;
1640 return 1;
1641 }
1642 if (!(flag & 1))
1643 return 0;
1644
1645 ret = iso_stream_open(stream);
1646 if (ret < 0)
1647 return ret;
1648 ret = ziso_parse_zisofs_head(stream, &algo_num, header_size_div4,
1649 block_size_log2, uncompressed_size,
1650 (flag >> 2) & 1);
1651 if (ret == 1) {
1652 *stream_type = 2;
1653 algo_ret = ziso_num_to_algo(algo_num, zisofs_algo);
1654 } else {
1655 ret = 0;
1656 algo_ret = 1;
1657 }
1658 close_ret = iso_stream_close(stream);
1659 if (algo_ret < 0)
1660 return ISO_ZISOFS_WRONG_INPUT;
1661 if (close_ret < 0)
1662 return close_ret;
1663
1664 return ret;
1665 }
1666
1667
1668 /* API */
1669 int iso_zisofs_set_params(struct iso_zisofs_ctrl *params, int flag)
1670 {
1671
1672 #ifdef Libisofs_with_zliB
1673
1674 if (params->version < 0 || params->version > 1)
1675 return ISO_WRONG_ARG_VALUE;
1676
1677 if (params->compression_level < 0 || params->compression_level > 9 ||
1678 params->block_size_log2 < ISO_ZISOFS_V1_MIN_LOG2 ||
1679 params->block_size_log2 > ISO_ZISOFS_V1_MAX_LOG2) {
1680 return ISO_WRONG_ARG_VALUE;
1681 }
1682 if (params->version >= 1)
1683 if (params->v2_enabled < 0 || params->v2_enabled > 2 ||
1684 (params->v2_block_size_log2 != 0 &&
1685 (params->v2_block_size_log2 < ISO_ZISOFS_V2_MIN_LOG2 ||
1686 params->v2_block_size_log2 > ISO_ZISOFS_V2_MAX_LOG2)))
1687 return ISO_WRONG_ARG_VALUE;
1688 if (ziso_ref_count > 0) {
1689 return ISO_ZISOFS_PARAM_LOCK;
1690 }
1691 ziso_compression_level = params->compression_level;
1692 ziso_block_size_log2 = params->block_size_log2;
1693
1694 if (params->version == 0)
1695 return 1;
1696
1697 ziso_v2_enabled = params->v2_enabled;
1698 if (params->v2_block_size_log2 > 0)
1699 ziso_v2_block_size_log2 = params->v2_block_size_log2;
1700 if (params->max_total_blocks > 0)
1701 ziso_max_total_blocks = params->max_total_blocks;
1702 if (params->max_file_blocks > 0)
1703 ziso_max_file_blocks = params->max_file_blocks;
1704 if (params->block_number_target != 0)
1705 ziso_block_number_target = params->block_number_target;
1706 if (params->bpt_discard_file_blocks != 0)
1707 ziso_many_block_limit = params->bpt_discard_file_blocks;
1708 if (params->bpt_discard_free_ratio != 0.0)
1709 ziso_keep_blocks_free_ratio = params->bpt_discard_free_ratio;
1710
1711 return 1;
1712
1713 #else
1714
1715 return ISO_ZLIB_NOT_ENABLED;
1716
1717 #endif /* ! Libisofs_with_zliB */
1718
1719 }
1720
1721
1722 /* API */
1723 int iso_zisofs_get_params(struct iso_zisofs_ctrl *params, int flag)
1724 {
1725
1726 #ifdef Libisofs_with_zliB
1727
1728 if (params->version < 0 || params->version > 1)
1729 return ISO_WRONG_ARG_VALUE;
1730
1731 params->compression_level = ziso_compression_level;
1732 params->block_size_log2 = ziso_block_size_log2;
1733 if (params->version == 1) {
1734 params->v2_enabled = ziso_v2_enabled;
1735 params->v2_block_size_log2 = ziso_v2_block_size_log2;
1736 params->max_total_blocks = ziso_max_total_blocks;
1737 params->current_total_blocks = ziso_block_pointer_mgt((uint64_t) 0, 3);
1738 params->max_file_blocks = ziso_max_file_blocks;
1739 params->block_number_target = ziso_block_number_target;
1740 params->bpt_discard_file_blocks = ziso_many_block_limit;
1741 params->bpt_discard_free_ratio = ziso_keep_blocks_free_ratio;
1742 }
1743 return 1;
1744
1745 #else
1746
1747 return ISO_ZLIB_NOT_ENABLED;
1748
1749 #endif /* ! Libisofs_with_zliB */
1750
1751 }
1752
1753
1754 /* API */
1755 int iso_stream_get_zisofs_par(IsoStream *stream, int *stream_type,
1756 uint8_t zisofs_algo[2], uint8_t* algo_num,
1757 int *block_size_log2, int flag)
1758 {
1759
1760 #ifdef Libisofs_with_zliB
1761
1762 uint64_t uncompressed_size;
1763 int header_size_div4, ret;
1764
1765 if (stream == NULL)
1766 return ISO_NULL_POINTER;
1767 ret = ziso_is_zisofs_stream(stream, stream_type, zisofs_algo,
1768 &header_size_div4, block_size_log2,
1769 &uncompressed_size, 0);
1770 if (ret <= 0 || (*stream_type != -1 && *stream_type != 1))
1771 return 0;
1772 *algo_num = ziso_algo_to_num(zisofs_algo);
1773 return 1;
1774
1775 #else
1776
1777 return ISO_ZLIB_NOT_ENABLED;
1778
1779 #endif /* ! Libisofs_with_zliB */
1780
1781 }
1782
1783
1784 /* API */
1785 int iso_stream_zisofs_discard_bpt(IsoStream *stream, int flag)
1786 {
1787
1788 #ifdef Libisofs_with_zliB
1789
1790 int ret;
1791
1792 if (stream == NULL)
1793 return ISO_NULL_POINTER;
1794 ret = ziso_discard_bpt(stream, 1);
1795 return ret;
1796
1797 #else
1798
1799 return ISO_ZLIB_NOT_ENABLED;
1800
1801 #endif /* ! Libisofs_with_zliB */
1802
1803 }
1804
1805
1806 /* API */
1807 int iso_zisofs_ctrl_susp_z2(int enable)
1808 {
1809 if (enable == 0 || enable == 1)
1810 iso_zisofs2_enable_susp_z2 = enable;
1811 return iso_zisofs2_enable_susp_z2;
1812 }