xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

zisofs.c
Go to the documentation of this file.
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 
105 
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  */
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 <=
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 
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;
180 
182  off_t in_counter;
183  off_t out_counter;
184 
186 
188 
189 
190 static
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 {
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)
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 {
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 
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 {
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  */
350  uint64_t open_counter;
352 
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 {
363 
365  unsigned char header_size_div4;
366  unsigned char block_size_log2;
367 
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 {
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  }
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 {
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
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 {
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) {
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)
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
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;
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) {
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;
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  }
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;
951  ZisofsFilterRuntime *rng;
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);
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
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
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
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) {
1183  free((char *) nstd->block_pointers);
1184  }
1185  if (--ziso_ref_count < 0)
1186  ziso_ref_count = 0;
1187  if (ziso_ref_count == 0)
1189  }
1190  iso_stream_unref(data->orig);
1191  free(data);
1192 }
1193 
1194 
1195 static
1197 {
1198  /* By principle size is determined only once */
1199  return 1;
1200 }
1201 
1202 
1203 static
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
1279 
1280 
1282  4,
1283  "ziso",
1293  ziso_cmp_ino,
1295 };
1296 
1297 
1299  4,
1300  "osiz",
1312 };
1313 
1314 
1315 static
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 &&
1325  iso_stream_cmp_ino(s1, s2, 1);
1326 
1327  /* Both streams apply the same treatment to their input streams */
1329  iso_stream_get_input_stream(s2, 0), 0);
1330 }
1331 
1332 
1333 static
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 ||
1345  iso_stream_cmp_ino(s1, s2, 1);
1346 
1347  /* Both streams apply the same treatment to their input streams */
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;
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;
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 */
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 */
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 */
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 */
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 */
1808 {
1809  if (enable == 0 || enable == 1)
1810  iso_zisofs2_enable_susp_z2 = enable;
1812 }
int iso_file_remove_filter(IsoFile *file, int flag)
Definition: filter.c:58
int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
Definition: filter.c:33
#define ISO_FILTER_ZISOFS_DEV_ID
Definition: filter.h:26
#define ISO_FILTER_FS_ID
Definition: fsource.h:25
static uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
Definition: isofs_wrap.c:78
uint64_t iso_read_lsb64(const uint8_t *buf)
Definition: util.c:1554
void iso_lsb64(uint8_t *buf, uint64_t num)
Definition: util.c:1486
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
Definition: util.c:1478
IsoStream * iso_file_get_stream(IsoFile *file)
Definition: node.c:1161
#define ISO_ZLIB_NOT_ENABLED
Definition: libisofs.h:8956
#define ISO_ZISOFS_BPT_UNDERRUN
Definition: libisofs.h:9252
#define ISO_ZISOFS_TOO_MANY_PTR
Definition: libisofs.h:9249
#define ISO_ZISOFS_PARAM_LOCK
Definition: libisofs.h:8972
#define ISO_SUCCESS
Definition: libisofs.h:8719
#define ISO_STREAM_NO_CLONE
Definition: libisofs.h:9089
off_t iso_file_get_size(IsoFile *file)
Definition: node.c:1144
IsoStream * iso_stream_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:867
int iso_stream_open(IsoStream *stream)
Definition: stream.c:798
#define ISO_FILE_NOT_OPENED
Definition: libisofs.h:8811
#define ISO_OUT_OF_MEM
Definition: libisofs.h:8745
off_t iso_stream_get_size(IsoStream *stream)
Definition: stream.c:810
#define ISO_ZISOFS_TOO_LARGE
Definition: libisofs.h:8959
#define ISO_FILE_READ_ERROR
Definition: libisofs.h:8820
#define ISO_WRONG_ARG_VALUE
Definition: libisofs.h:8751
int iso_stream_read(IsoStream *stream, void *buf, size_t count)
Definition: stream.c:816
#define ISO_ZISOFS_UNKNOWN_SIZE
Definition: libisofs.h:9255
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
Definition: stream.c:1042
void iso_stream_unref(IsoStream *stream)
Definition: stream.c:789
#define ISO_ZISOFS_WRONG_INPUT
Definition: libisofs.h:8968
int iso_stream_close(IsoStream *stream)
Definition: stream.c:804
#define ISO_FILTER_WRONG_INPUT
Definition: libisofs.h:8962
#define ISO_FILE_ALREADY_OPENED
Definition: libisofs.h:8796
#define ISO_ZLIB_COMPR_ERR
Definition: libisofs.h:8965
void iso_stream_ref(IsoStream *stream)
Definition: stream.c:784
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt,...)
Definition: messages.c:579
int iso_stream_clone_filter_common(IsoStream *old_stream, IsoStream **new_stream, IsoStream **new_input, int flag)
Definition: stream.c:1292
off_t(* get_size)(IsoStream *stream)
Definition: libisofs.h:1039
int(* read)(IsoStream *stream, void *buf, size_t count)
Definition: libisofs.h:1055
Definition: node.h:149
int block_pointers_dropped
Definition: zisofs.c:351
uint64_t * block_pointers
Definition: zisofs.c:345
uint64_t open_counter
Definition: zisofs.c:350
uint64_t orig_size
Definition: zisofs.c:344
uint64_t block_pointer_counter
Definition: zisofs.c:349
ZisofsFilterStreamData std
Definition: zisofs.c:342
char * read_buffer
Definition: zisofs.c:175
off_t block_counter
Definition: zisofs.c:181
char * block_buffer
Definition: zisofs.c:176
int64_t block_pointer_rpos
Definition: zisofs.c:169
uint64_t * block_pointers
Definition: zisofs.c:170
int64_t block_pointer_fill
Definition: zisofs.c:168
ZisofsFilterRuntime * running
Definition: zisofs.c:329
IsoStream * orig
Definition: zisofs.c:325
uint8_t zisofs_algo_num
Definition: zisofs.c:364
unsigned char block_size_log2
Definition: zisofs.c:366
ZisofsFilterStreamData std
Definition: zisofs.c:362
unsigned char header_size_div4
Definition: zisofs.c:365
void(* free)(FilterContext *filter)
Definition: filter.h:60
int refcount
Definition: filter.h:36
int version
Definition: filter.h:35
int(* get_filter)(FilterContext *filter, IsoStream *original, IsoStream **filtered)
Definition: filter.h:53
void * data
Definition: filter.h:39
int refcount
Definition: libisofs.h:1186
void * data
Definition: libisofs.h:1187
IsoStreamIface * class
Definition: libisofs.h:1185
IsoStreamIface ziso_stream_compress_class
Definition: zisofs.c:1281
#define ISO_ZISOFS_V2_MAX_LOG2
Definition: zisofs.c:59
static int ziso_discard_bpt(IsoStream *stream, int flag)
Definition: zisofs.c:394
#define ISO_ZISOFS_V1_LIMIT
Definition: zisofs.c:49
static IsoStream * ziso_get_input_stream(IsoStream *stream, int flag)
Definition: zisofs.c:1204
static int ziso_parse_zisofs_head(IsoStream *stream, uint8_t *ziso_algo_num, int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: zisofs.c:879
static int ziso_stream_open_flag(IsoStream *stream, int flag)
Definition: zisofs.c:478
static int ziso_decide_v2_usage(off_t orig_size)
Definition: zisofs.c:122
static off_t ziso_stream_measure_size(IsoStream *stream, int flag)
Definition: zisofs.c:534
static int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
Definition: zisofs.c:1334
#define ISO_ZISOFS_KBF_RATIO
Definition: zisofs.c:90
int iso_zisofs_set_params(struct iso_zisofs_ctrl *params, int flag)
Definition: zisofs.c:1669
static int ziso_running_new(ZisofsFilterRuntime **running, off_t orig_size, int flag)
Definition: zisofs.c:214
static void ziso_stream_free(IsoStream *stream)
Definition: zisofs.c:1164
static int ziso_stream_open(IsoStream *stream)
Definition: zisofs.c:524
static double ziso_keep_blocks_free_ratio
Definition: zisofs.c:107
#define ISO_ZISOFS_MAX_BLOCKS_F
Definition: zisofs.c:75
static int ziso_stream_close_flag(IsoStream *stream, int flag)
Definition: zisofs.c:439
IsoStreamIface ziso_stream_uncompress_class
Definition: zisofs.c:1298
static int ziso_decide_bs_log2(off_t orig_size)
Definition: zisofs.c:131
int ziso_add_filter(IsoFile *file, int flag)
Definition: zisofs.c:1484
int iso_zisofs_ctrl_susp_z2(int enable)
Definition: zisofs.c:1807
#define ISO_ZISOFS_V2_MIN_LOG2
Definition: zisofs.c:58
#define ISO_ZISOFS_MANY_BLOCKS
Definition: zisofs.c:84
static int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
Definition: zisofs.c:944
static int ziso_num_to_algo(uint8_t num, uint8_t zisofs_algo[2])
Definition: zisofs.c:844
static int64_t ziso_max_file_blocks
Definition: zisofs.c:104
int iso_zisofs_get_refcounts(off_t *ziso_count, off_t *osiz_count, int flag)
Definition: zisofs.c:1554
static int ziso_v2_block_size_log2
Definition: zisofs.c:99
static uint64_t ziso_block_pointer_mgt(uint64_t num, int mode)
Definition: zisofs.c:267
int iso_stream_get_zisofs_par(IsoStream *stream, int *stream_type, uint8_t zisofs_algo[2], uint8_t *algo_num, int *block_size_log2, int flag)
Definition: zisofs.c:1755
static int ziso_v2_enabled
Definition: zisofs.c:98
static int ziso_stream_is_repeatable(IsoStream *stream)
Definition: zisofs.c:1143
#define ISO_ZISOFS_V1_MAX_LOG2
Definition: zisofs.c:57
static int ziso_update_size(IsoStream *stream)
Definition: zisofs.c:1196
static int ziso_stream_close(IsoStream *stream)
Definition: zisofs.c:468
int iso_zisofs_get_params(struct iso_zisofs_ctrl *params, int flag)
Definition: zisofs.c:1723
static int ziso_early_bpt_discard
Definition: zisofs.c:113
int ziso_add_osiz_filter(IsoFile *file, uint8_t zisofs_algo[2], uint8_t header_size_div4, uint8_t block_size_log2, uint64_t uncompressed_size, int flag)
Definition: zisofs.c:1562
static uint8_t ziso_block_size_log2
Definition: zisofs.c:96
#define ISO_ZISOFS_V1_MIN_LOG2
Definition: zisofs.c:56
static off_t ziso_ref_count
Definition: zisofs.c:305
static unsigned char zisofs_magic[9]
Definition: zisofs.c:297
#define ISO_ZISOFS_MAX_BLOCKS_T
Definition: zisofs.c:67
static unsigned char zisofs2_magic[9]
Definition: zisofs.c:301
static int64_t ziso_max_total_blocks
Definition: zisofs.c:103
int iso_zisofs2_enable_susp_z2
Definition: zisofs.c:118
static int64_t ziso_many_block_limit
Definition: zisofs.c:106
int iso_file_add_zisofs_filter(IsoFile *file, int flag)
Definition: zisofs.c:1547
static int ziso_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: zisofs.c:1216
static off_t ziso_osiz_ref_count
Definition: zisofs.c:308
int iso_stream_zisofs_discard_bpt(IsoStream *stream, int flag)
Definition: zisofs.c:1785
static int64_t ziso_block_number_target
Definition: zisofs.c:101
static void ziso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: zisofs.c:1151
static ino_t ziso_ino_id
Definition: zisofs.c:375
static int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
Definition: zisofs.c:577
static int ziso_cmp_ino(IsoStream *s1, IsoStream *s2)
Definition: zisofs.c:1316
static off_t ziso_stream_get_size(IsoStream *stream)
Definition: zisofs.c:1127
static int ziso_running_destroy(ZisofsFilterRuntime **running, int flag)
Definition: zisofs.c:191
int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type, uint8_t zisofs_algo[2], int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: zisofs.c:1601