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)  

stream.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2009 - 2015 Thomas Schmitt
4  *
5  * This file is part of the libisofs project; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * or later as published by the Free Software Foundation.
8  * See COPYING file for details.
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #include "libisofs.h"
16 #include "stream.h"
17 #include "fsource.h"
18 #include "util.h"
19 #include "node.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <stdio.h>
25 
26 
27 #ifndef PATH_MAX
28 #define PATH_MAX Libisofs_default_path_maX
29 #endif
30 
31 
32 ino_t serial_id = (ino_t)1;
33 ino_t mem_serial_id = (ino_t)1;
34 ino_t cut_out_serial_id = (ino_t)1;
35 
36 static
37 int fsrc_open(IsoStream *stream)
38 {
39  int ret;
40  struct stat info;
41  off_t esize;
42  IsoFileSource *src;
43  if (stream == NULL) {
44  return ISO_NULL_POINTER;
45  }
46  src = ((FSrcStreamData*)stream->data)->src;
47  ret = iso_file_source_stat(src, &info);
48  if (ret < 0) {
49  return ret;
50  }
51  ret = iso_file_source_open(src);
52  if (ret < 0) {
53  return ret;
54  }
55  esize = ((FSrcStreamData*)stream->data)->size;
56  if (info.st_size == esize) {
57  return ISO_SUCCESS;
58  } else {
59  return (esize > info.st_size) ? 3 : 2;
60  }
61 }
62 
63 static
64 int fsrc_close(IsoStream *stream)
65 {
66  IsoFileSource *src;
67  if (stream == NULL) {
68  return ISO_NULL_POINTER;
69  }
70  src = ((FSrcStreamData*)stream->data)->src;
71  return iso_file_source_close(src);
72 }
73 
74 static
75 off_t fsrc_get_size(IsoStream *stream)
76 {
77  FSrcStreamData *data;
78  data = (FSrcStreamData*)stream->data;
79 
80  return data->size;
81 }
82 
83 static
84 int fsrc_read(IsoStream *stream, void *buf, size_t count)
85 {
86  IsoFileSource *src;
87  if (stream == NULL) {
88  return ISO_NULL_POINTER;
89  }
90  src = ((FSrcStreamData*)stream->data)->src;
91  return iso_file_source_read(src, buf, count);
92 }
93 
94 static
96 {
97  int ret;
98  struct stat info;
99  FSrcStreamData *data;
100  if (stream == NULL) {
101  return ISO_NULL_POINTER;
102  }
103  data = (FSrcStreamData*)stream->data;
104 
105  /* mode is not cached, this function is only useful for filters */
106  ret = iso_file_source_stat(data->src, &info);
107  if (ret < 0) {
108  return ret;
109  }
110  if (S_ISREG(info.st_mode) || S_ISBLK(info.st_mode)) {
111  return 1;
112  } else {
113  return 0;
114  }
115 }
116 
117 static
118 void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
119  ino_t *ino_id)
120 {
121  FSrcStreamData *data;
122  IsoFilesystem *fs;
123 
124  data = (FSrcStreamData*)stream->data;
126 
127  *fs_id = fs->get_id(fs);
128  *dev_id = data->dev_id;
129  *ino_id = data->ino_id;
130 }
131 
132 static
133 void fsrc_free(IsoStream *stream)
134 {
135  FSrcStreamData *data;
136  data = (FSrcStreamData*)stream->data;
137  iso_file_source_unref(data->src);
138  free(data);
139 }
140 
141 static
143 {
144  int ret;
145  struct stat info;
146  IsoFileSource *src;
147 
148  if (stream == NULL) {
149  return ISO_NULL_POINTER;
150  }
151  src = ((FSrcStreamData*)stream->data)->src;
152  ret = iso_file_source_stat(src, &info);
153  if (ret < 0) {
154  return ret;
155  }
156 
157  ((FSrcStreamData*)stream->data)->size = info.st_size;
158  return ISO_SUCCESS;
159 }
160 
161 static
163 {
164  return NULL;
165 }
166 
167 int fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
168  int flag)
169 {
170  FSrcStreamData *data, *new_data;
171  IsoStream *stream;
172  int ret;
173 
174  if (flag)
175  return ISO_STREAM_NO_CLONE; /* unknown option required */
176 
177  data = (FSrcStreamData*) old_stream->data;
178  if (data->src->class->version < 2)
179  return ISO_STREAM_NO_CLONE; /* No clone_src() method available */
180 
181  *new_stream = NULL;
182  stream = calloc(1, sizeof(IsoStream));
183  if (stream == NULL)
184  return ISO_OUT_OF_MEM;
185  new_data = calloc(1, sizeof(FSrcStreamData));
186  if (new_data == NULL) {
187  free((char *) stream);
188  return ISO_OUT_OF_MEM;
189  }
190  *new_stream = stream;
191  stream->class = old_stream->class;
192  stream->refcount = 1;
193  stream->data = new_data;
194 
195  ret = data->src->class->clone_src(data->src, &(new_data->src), 0);
196  if (ret < 0) {
197  free((char *) stream);
198  free((char *) new_data);
199  return ret;
200  }
201  new_data->dev_id = data->dev_id;
202  new_data->ino_id = data->ino_id;
203  new_data->size = data->size;
204 
205  return ISO_SUCCESS;
206 }
207 
208 static
210  4, /* version */
211  "fsrc",
212  fsrc_open,
213  fsrc_close,
215  fsrc_read,
217  fsrc_get_id,
218  fsrc_free,
221  NULL,
223 };
224 
226 {
227  int r;
228  struct stat info;
229  IsoStream *str;
230  FSrcStreamData *data;
231 
232  if (src == NULL || stream == NULL) {
233  return ISO_NULL_POINTER;
234  }
235 
236  r = iso_file_source_stat(src, &info);
237  if (r < 0) {
238  return r;
239  }
240  if (S_ISDIR(info.st_mode)) {
241  return ISO_FILE_IS_DIR;
242  }
243 
244  /* check for read access to contents */
245  r = iso_file_source_access(src);
246  if (r < 0) {
247  return r;
248  }
249 
250  str = malloc(sizeof(IsoStream));
251  if (str == NULL) {
252  return ISO_OUT_OF_MEM;
253  }
254  data = malloc(sizeof(FSrcStreamData));
255  if (data == NULL) {
256  free(str);
257  return ISO_OUT_OF_MEM;
258  }
259 
260  /* take the ref to IsoFileSource */
261  data->src = src;
262  data->size = info.st_size;
263 
264  /* get the id numbers */
265  {
266  IsoFilesystem *fs;
267  unsigned int fs_id;
269 
270  fs_id = fs->get_id(fs);
271  if (fs_id == 0) {
272  /*
273  * the filesystem implementation is unable to provide valid
274  * st_dev and st_ino fields. Use serial_id.
275  */
276  data->dev_id = (dev_t) 0;
277  data->ino_id = serial_id++;
278  } else {
279  data->dev_id = info.st_dev;
280  data->ino_id = info.st_ino;
281  }
282  }
283 
284  str->refcount = 1;
285  str->data = data;
286  str->class = &fsrc_stream_class;
287 
288  *stream = str;
289  return ISO_SUCCESS;
290 }
291 
292 
293 int iso_stream_get_src_zf(IsoStream *stream, uint8_t zisofs_algo[2],
294  int *header_size_div4, int *block_size_log2,
295  uint64_t *uncompressed_size, int flag)
296 {
297  int ret;
298  FSrcStreamData *data;
299  IsoFileSource *src;
300 
301  /* Intimate friendship with libisofs/fs_image.c */
302  int iso_ifs_source_get_zf(IsoFileSource *src, uint8_t zisofs_algo[2],
303  int *header_size_div4, int *block_size_log2,
304  uint64_t *uncompressed_size, int flag);
305 
306  if (stream->class != &fsrc_stream_class)
307  return 0;
308  data = stream->data;
309  src = data->src;
310  ret = iso_ifs_source_get_zf(src, zisofs_algo, header_size_div4,
311  block_size_log2, uncompressed_size, 0);
312  return ret;
313 }
314 
315 
317 {
319 
320  /* key for file identification inside filesystem */
321  dev_t dev_id;
322  ino_t ino_id;
323  off_t offset; /**< offset where read begins */
324  off_t size; /**< size of this file */
325  off_t pos; /* position on the file for read */
326 };
327 
328 static
330 {
331  int ret;
332  struct stat info;
333  IsoFileSource *src;
334  struct cut_out_stream *data;
335 
336  if (stream == NULL) {
337  return ISO_NULL_POINTER;
338  }
339 
340  data = stream->data;
341  src = data->src;
342  ret = iso_file_source_stat(data->src, &info);
343  if (ret < 0) {
344  return ret;
345  }
346  ret = iso_file_source_open(src);
347  if (ret < 0) {
348  return ret;
349  }
350 
351  {
352  off_t ret;
353  if (data->offset > info.st_size) {
354  /* file is smaller than expected */
355  ret = iso_file_source_lseek(src, info.st_size, 0);
356  } else {
357  ret = iso_file_source_lseek(src, data->offset, 0);
358  }
359  if (ret < 0) {
360  return (int) ret;
361  }
362  }
363  data->pos = 0;
364  if (data->offset + data->size > info.st_size) {
365  return 3; /* file smaller than expected */
366  } else {
367  return ISO_SUCCESS;
368  }
369 }
370 
371 static
373 {
375  if (stream == NULL) {
376  return ISO_NULL_POINTER;
377  }
378  src = ((struct cut_out_stream*)stream->data)->src;
379  return iso_file_source_close(src);
380 }
381 
382 static
384 {
385  struct cut_out_stream *data = stream->data;
386  return data->size;
387 }
388 
389 static
390 int cut_out_read(IsoStream *stream, void *buf, size_t count)
391 {
392  struct cut_out_stream *data = stream->data;
393  count = (size_t) MIN((size_t) (data->size - data->pos), count);
394  if (count == 0) {
395  return 0;
396  }
397  return iso_file_source_read(data->src, buf, count);
398 }
399 
400 static
402 {
403  /* reg files are always repeatable */
404  return 1;
405 }
406 
407 static
408 void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
409  ino_t *ino_id)
410 {
411  FSrcStreamData *data;
412  IsoFilesystem *fs;
413 
414  data = (FSrcStreamData*)stream->data;
416 
417  *fs_id = fs->get_id(fs);
418  *dev_id = data->dev_id;
419  *ino_id = data->ino_id;
420 }
421 
422 static
423 void cut_out_free(IsoStream *stream)
424 {
425  struct cut_out_stream *data = stream->data;
426  iso_file_source_unref(data->src);
427  free(data);
428 }
429 
430 static
432 {
433  return ISO_SUCCESS;
434 }
435 
436 static
438 {
439  return NULL;
440 }
441 
442 static
443 int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
444  int flag)
445 {
446  struct cut_out_stream *data, *new_data;
447  IsoStream *stream;
448  int ret;
449 
450  if (flag)
451  return ISO_STREAM_NO_CLONE; /* unknown option required */
452 
453  data = (struct cut_out_stream *) old_stream->data;
454  if (data->src->class->version < 2)
455  return ISO_STREAM_NO_CLONE; /* No clone_src() method available */
456 
457  *new_stream = NULL;
458  stream = calloc(1, sizeof(IsoStream));
459  if (stream == NULL)
460  return ISO_OUT_OF_MEM;
461  stream->refcount = 1;
462  stream->class = old_stream->class;
463  new_data = calloc(1, sizeof(struct cut_out_stream));
464  if (new_data == NULL) {
465  free((char *) stream);
466  return ISO_OUT_OF_MEM;
467  }
468  ret = data->src->class->clone_src(data->src, &(new_data->src), 0);
469  if (ret < 0) {
470  free((char *) stream);
471  free((char *) new_data);
472  return ret;
473  }
474 
475  new_data->dev_id = (dev_t) 0;
476  new_data->ino_id = cut_out_serial_id++;
477  new_data->offset = data->offset;
478  new_data->size = data->size;
479  new_data->pos = 0;
480 
481  stream->data = new_data;
482  *new_stream = stream;
483  return ISO_SUCCESS;
484 }
485 
486 /*
487  * TODO update cut out streams to deal with update_size(). Seems hard.
488  */
489 static
491  4, /* version */
492  "cout",
493  cut_out_open,
496  cut_out_read,
499  cut_out_free,
502  NULL,
504 
505 };
506 
508  IsoStream **stream)
509 {
510  int r;
511  struct stat info;
512  IsoStream *str;
513  struct cut_out_stream *data;
514 
515  if (src == NULL || stream == NULL) {
516  return ISO_NULL_POINTER;
517  }
518  if (size == 0) {
519  return ISO_WRONG_ARG_VALUE;
520  }
521 
522  r = iso_file_source_stat(src, &info);
523  if (r < 0) {
524  return r;
525  }
526  if (!S_ISREG(info.st_mode)) {
527  return ISO_WRONG_ARG_VALUE;
528  }
529  if (offset > info.st_size) {
531  }
532 
533  /* check for read access to contents */
535  if (r < 0) {
536  return r;
537  }
538 
539  str = malloc(sizeof(IsoStream));
540  if (str == NULL) {
541  return ISO_OUT_OF_MEM;
542  }
543  data = malloc(sizeof(struct cut_out_stream));
544  if (data == NULL) {
545  free(str);
546  return ISO_OUT_OF_MEM;
547  }
548 
549  /* take a new ref to IsoFileSource */
550  data->src = src;
552 
553  data->offset = offset;
554  data->size = MIN(info.st_size - offset, size);
555 
556  /* get the id numbers */
557  data->dev_id = (dev_t) 0;
558  data->ino_id = cut_out_serial_id++;
559 
560  str->refcount = 1;
561  str->data = data;
562  str->class = &cut_out_stream_class;
563 
564  *stream = str;
565  return ISO_SUCCESS;
566 }
567 
568 
569 
570 typedef struct
571 {
572  uint8_t *buf;
573  ssize_t offset; /* -1 if stream closed */
574  ino_t ino_id;
575  size_t size;
576 } MemStreamData;
577 
578 static
579 int mem_open(IsoStream *stream)
580 {
581  MemStreamData *data;
582  if (stream == NULL) {
583  return ISO_NULL_POINTER;
584  }
585  data = (MemStreamData*)stream->data;
586  if (data->offset != -1) {
588  }
589  data->offset = 0;
590  return ISO_SUCCESS;
591 }
592 
593 static
594 int mem_close(IsoStream *stream)
595 {
596  MemStreamData *data;
597  if (stream == NULL) {
598  return ISO_NULL_POINTER;
599  }
600  data = (MemStreamData*)stream->data;
601  if (data->offset == -1) {
602  return ISO_FILE_NOT_OPENED;
603  }
604  data->offset = -1;
605  return ISO_SUCCESS;
606 }
607 
608 static
609 off_t mem_get_size(IsoStream *stream)
610 {
611  MemStreamData *data;
612  data = (MemStreamData*)stream->data;
613 
614  return (off_t)data->size;
615 }
616 
617 static
618 int mem_read(IsoStream *stream, void *buf, size_t count)
619 {
620  size_t len;
621  MemStreamData *data;
622  if (stream == NULL || buf == NULL) {
623  return ISO_NULL_POINTER;
624  }
625  if (count == 0) {
626  return ISO_WRONG_ARG_VALUE;
627  }
628  data = stream->data;
629 
630  if (data->offset == -1) {
631  return ISO_FILE_NOT_OPENED;
632  }
633 
634  if (data->offset >= (ssize_t) data->size) {
635  return 0; /* EOF */
636  }
637 
638  len = MIN(count, data->size - data->offset);
639  memcpy(buf, data->buf + data->offset, len);
640  data->offset += len;
641  return len;
642 }
643 
644 static
646 {
647  return 1;
648 }
649 
650 static
651 void mem_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
652  ino_t *ino_id)
653 {
654  MemStreamData *data;
655  data = (MemStreamData*)stream->data;
656  *fs_id = ISO_MEM_FS_ID;
657  *dev_id = 0;
658  *ino_id = data->ino_id;
659 }
660 
661 static
662 void mem_free(IsoStream *stream)
663 {
664  MemStreamData *data;
665  data = (MemStreamData*)stream->data;
666  if (data->buf != NULL)
667  free(data->buf);
668  free(data);
669 }
670 
671 static
673 {
674  return ISO_SUCCESS;
675 }
676 
677 static
679 {
680  return NULL;
681 }
682 
683 static
684 int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
685  int flag)
686 {
687  MemStreamData *data, *new_data;
688  IsoStream *stream;
689  uint8_t *new_buf = NULL;
690 
691  if (flag)
692  return ISO_STREAM_NO_CLONE; /* unknown option required */
693 
694  *new_stream = NULL;
695  stream = calloc(1, sizeof(IsoStream));
696  if (stream == NULL)
697  return ISO_OUT_OF_MEM;
698  stream->refcount = 1;
699  stream->class = old_stream->class;
700  new_data = calloc(1, sizeof(MemStreamData));
701  if (new_data == NULL) {
702  free((char *) stream);
703  return ISO_OUT_OF_MEM;
704  }
705  data = (MemStreamData *) old_stream->data;
706  if (data->size > 0) {
707  new_buf = calloc(1, data->size);
708  if (new_buf == NULL) {
709  free((char *) stream);
710  free((char *) new_data);
711  return ISO_OUT_OF_MEM;
712  }
713  memcpy(new_buf, data->buf, data->size);
714  }
715  new_data->buf = new_buf;
716  new_data->offset = -1;
717  new_data->ino_id = mem_serial_id++;
718  new_data->size = data->size;
719 
720  stream->data = new_data;
721  *new_stream = stream;
722  return ISO_SUCCESS;
723 }
724 
725 
726 static
728  4, /* version */
729  "mem ",
730  mem_open,
731  mem_close,
732  mem_get_size,
733  mem_read,
735  mem_get_id,
736  mem_free,
739  NULL,
741 
742 };
743 
744 /**
745  * Create a stream for reading from a arbitrary memory buffer.
746  * When the Stream refcount reach 0, the buffer is free(3).
747  *
748  * @return
749  * 1 success, < 0 error
750  */
751 int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream)
752 {
753  IsoStream *str;
754  MemStreamData *data;
755 
756  if (buf == NULL || stream == NULL) {
757  return ISO_NULL_POINTER;
758  }
759 
760  str = malloc(sizeof(IsoStream));
761  if (str == NULL) {
762  return ISO_OUT_OF_MEM;
763  }
764  data = malloc(sizeof(MemStreamData));
765  if (data == NULL) {
766  free(str);
767  return ISO_OUT_OF_MEM;
768  }
769 
770  /* fill data */
771  data->buf = buf;
772  data->size = size;
773  data->offset = -1;
774  data->ino_id = mem_serial_id++;
775 
776  str->refcount = 1;
777  str->data = data;
778  str->class = &mem_stream_class;
779 
780  *stream = str;
781  return ISO_SUCCESS;
782 }
783 
785 {
786  ++stream->refcount;
787 }
788 
790 {
791  if (--stream->refcount == 0) {
792  stream->class->free(stream);
793  free(stream);
794  }
795 }
796 
797 inline
799 {
800  return stream->class->open(stream);
801 }
802 
803 inline
805 {
806  return stream->class->close(stream);
807 }
808 
809 inline
811 {
812  return stream->class->get_size(stream);
813 }
814 
815 inline
816 int iso_stream_read(IsoStream *stream, void *buf, size_t count)
817 {
818  return stream->class->read(stream, buf, count);
819 }
820 
821 inline
823 {
824  return stream->class->is_repeatable(stream);
825 }
826 
827 inline
829 {
830  IsoStreamIface* class = stream->class;
831  return (class->version >= 1) ? class->update_size(stream) : 0;
832 }
833 
834 inline
835 void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
836  ino_t *ino_id)
837 {
838  stream->class->get_id(stream, fs_id, dev_id, ino_id);
839 }
840 
841 void iso_stream_get_file_name(IsoStream *stream, char *name)
842 {
843  char *type = stream->class->type;
844 
845  if (!strncmp(type, "fsrc", 4)) {
846  FSrcStreamData *data = stream->data;
847  char *path = iso_file_source_get_path(data->src);
848  if (path == NULL) {
849  name[0] = 0;
850  return;
851  }
852  strncpy(name, path, PATH_MAX - 1);
853  name[PATH_MAX - 1] = 0;
854  free(path);
855  } else if (!strncmp(type, "boot", 4)) {
856  strcpy(name, "BOOT CATALOG");
857  } else if (!strncmp(type, "mem ", 4)) {
858  strcpy(name, "MEM SOURCE");
859  } else if (!strncmp(type, "extf", 4)) {
860  strcpy(name, "EXTERNAL FILTER");
861  } else {
862  strcpy(name, "UNKNOWN SOURCE");
863  }
864 }
865 
866 /* @param flag bit0= Obtain most fundamental stream */
868 {
869  IsoStreamIface* class;
870  IsoStream *result = NULL, *next;
871 
872  if (stream == NULL) {
873  return NULL;
874  }
875  while (1) {
876  class = stream->class;
877  if (class->version < 2)
878  return result;
879  next = class->get_input_stream(stream, 0);
880  if (next == NULL)
881  return result;
882  result = next;
883  if (!(flag & 1))
884  return result;
885  stream = result;
886  }
887 }
888 
889 char *iso_stream_get_source_path(IsoStream *stream, int flag)
890 {
891  char *path = NULL, ivd[80], *raw_path = NULL;
892 
893  if (stream == NULL) {
894  return NULL;
895  }
896  if (stream->class == &fsrc_stream_class) {
897  FSrcStreamData *fsrc_data = stream->data;
898 
899  path = iso_file_source_get_path(fsrc_data->src);
900  } else if (stream->class == &cut_out_stream_class) {
901  struct cut_out_stream *cout_data = stream->data;
902 
903  raw_path = iso_file_source_get_path(cout_data->src);
904  sprintf(ivd, " %.f %.f",
905  (double) cout_data->offset, (double) cout_data->size);
906  path= calloc(strlen(raw_path) + strlen(ivd) + 1, 1);
907  if (path == NULL) {
908  goto ex;
909  }
910  strcpy(path, raw_path);
911  strcat(path, ivd);
912  }
913 ex:;
914  if (raw_path != NULL)
915  free(raw_path);
916  return path;
917 }
918 
919 /*
920  @param flag bit0= in case of filter stream do not dig for base stream
921  @return 1 = ok , 0 = not an ISO image stream , <0 = error
922 */
923 int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag)
924 {
925  IsoStream *base_stream;
926 
927  if (stream == NULL) {
928  return ISO_NULL_POINTER;
929  }
930  if (!(flag & 1)) {
931  base_stream = iso_stream_get_input_stream(stream, 1);
932  if (base_stream != NULL)
933  stream = base_stream;
934  }
935  if (stream->class == &fsrc_stream_class) {
936  FSrcStreamData *fsrc_data = stream->data;
937  fsrc_data->ino_id = ino;
938  return 1;
939  }
940  return 0;
941 }
942 
944  int flag)
945 {
946  int ret;
947  FSrcStreamData *fssd1, *fssd2;
948  IsoFileSource *src1, *src2;
949 
950  /* Must keep any suspect in the game to preserve transitivity of the
951  calling function by ranking applicable streams lower than
952  non-applicable. ones.
953  */
954  if (s1->class != &fsrc_stream_class && s2->class != &fsrc_stream_class)
955  return 0;
956 
957  /* Compare eventual image data section LBA and sizes */
958  if (s1->class == &fsrc_stream_class) {
959  fssd1= (FSrcStreamData *) s1->data;
960  src1 = fssd1->src;
961  } else {
962  src1 = NULL;
963  }
964  if (s2->class == &fsrc_stream_class) {
965  fssd2= (FSrcStreamData *) s2->data;
966  src2 = fssd2->src;
967  } else {
968  src2 = NULL;
969  }
970  ret = iso_ifs_sections_cmp(src1, src2, cmp_ret, 1);
971  if (ret <= 0)
972  return 0;
973  return 1;
974 }
975 
976 
977 /* Maintain and exploit a list of stream compare functions seen by
978  iso_stream_cmp_ino(). This is needed to separate stream comparison
979  families in order to keep iso_stream_cmp_ino() transitive while
980  alternative stream->class->cmp_ino() decide inside the families.
981 */
983  int (*cmp_func)(IsoStream *s1, IsoStream *s2);
985 };
986 
987 static struct iso_streamcmprank *streamcmpranks = NULL;
988 
989 static
991  int flag)
992 {
993  int idx;
994  struct iso_streamcmprank *cpr, *last_cpr = NULL;
995 
996  idx = 0;
997  for (cpr = streamcmpranks; cpr != NULL; cpr = cpr->next) {
998  if (cpr->cmp_func == cmp_func)
999  break;
1000  idx++;
1001  last_cpr = cpr;
1002  }
1003  if (cpr != NULL)
1004  return idx;
1005  LIBISO_ALLOC_MEM_VOID(cpr, struct iso_streamcmprank, 1);
1006  cpr->cmp_func = cmp_func;
1007  cpr->next = NULL;
1008  if (last_cpr != NULL)
1009  last_cpr->next = cpr;
1010  if (streamcmpranks == NULL)
1011  streamcmpranks = cpr;
1012  return idx;
1013 ex:;
1014  return -1;
1015 }
1016 
1017 static
1018 int iso_cmp_streamcmpranks(int (*cf1)(IsoStream *s1, IsoStream *s2),
1019  int (*cf2)(IsoStream *s1, IsoStream *s2))
1020 {
1021  int rank1, rank2;
1022 
1023  rank1 = iso_get_streamcmprank(cf1, 0);
1024  rank2 = iso_get_streamcmprank(cf2, 0);
1025  return rank1 < rank2 ? -1 : 1;
1026 }
1027 
1029 {
1030  struct iso_streamcmprank *cpr, *next;
1031 
1032  for (cpr = streamcmpranks; cpr != NULL; cpr = next) {
1033  next = cpr->next;
1034  LIBISO_FREE_MEM(cpr);
1035  }
1036  streamcmpranks = NULL;
1037  return ISO_SUCCESS;
1038 }
1039 
1040 
1041 /* API */
1042 int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
1043 {
1044  int ret;
1045  unsigned int fs_id1, fs_id2;
1046  dev_t dev_id1, dev_id2;
1047  ino_t ino_id1, ino_id2;
1048  off_t size1, size2;
1049 
1050 /*
1051  #define Libisofs_stream_cmp_ino_debuG 1
1052 */
1053 #ifdef Libisofs_stream_cmp_ino_debuG
1054  static int report_counter = 0;
1055  static int debug = 1;
1056 #endif /* Libisofs_stream_cmp_ino_debuG */
1057 
1058  if (s1 == s2)
1059  return 0;
1060  if (s1 == NULL)
1061  return -1;
1062  if (s2 == NULL)
1063  return 1;
1064 
1065  /* This stays transitive by the fact that
1066  iso_stream_cmp_ifs_sections() is transitive,
1067  returns > 0 if s1 or s2 are applicable,
1068  ret is -1 if s1 is applicable but s2 is not,
1069  ret is 1 if s1 is not applicable but s2 is.
1070 
1071  Proof:
1072  Be A the set of applicable streams, S and G transitive and
1073  antisymmetric relations in respect to outcome {-1, 0, 1}.
1074  The combined relation R shall be defined by
1075  I. R(a,b) = S(a,b) if a in A or b in A, else G(a,b)
1076  Further S shall have the property
1077  II. S(a,b) = -1 if a in A and b not in A
1078  Then R can be proven to be transitive:
1079  By enumerating the 8 combinations of a,b,c being in A or not, we get
1080  5 cases of pure S or pure G. Three cases are mixed:
1081  a,b not in A, c in A : G(a,b) == -1, S(b,c) == -1 -> S(a,c) == -1
1082  Impossible because S(b,c) == -1 contradicts II.
1083  a,c not in A, b in A : S(a,b) == -1, S(b,c) == -1 -> G(a,c) == -1
1084  Impossible because S(a,b) == -1 contradicts II.
1085  b,c not in A, a in A : S(a,b) == -1, G(b,c) == -1 -> S(a,c) == -1
1086  Always true because S(a,c) == -1 by definition II.
1087  */
1088  if (iso_stream_cmp_ifs_sections(s1, s2, &ret, 0) > 0)
1089  return ret; /* Both are unfiltered from loaded ISO filesystem */
1090 
1091  if (!(flag & 1)) {
1092  /* Filters may have smarter methods to compare themselves with others.
1093  Transitivity is ensured by ranking mixed pairs by the rank of their
1094  comparison functions, and by ranking streams with .cmp_ino lower
1095  than streams without.
1096  (One could merge (class->version < 3) and (cmp_ino == NULL).)
1097 
1098  Here we define S for "and" rather than "or"
1099  I. R(a,b) = S(a,b) if a in A and b in A, else G(a,b)
1100  and the function ranking in case of "exor" makes sure that
1101  II. G(a,b) = -1 if a in A and b not in A
1102  Again we get three mixed cases:
1103  a not in A, b,c in A : G(a,b) == -1, S(b,c) == -1 -> G(a,c) == -1
1104  Impossible because G(a,b) == -1 contradicts II.
1105  b not in A, a,c in A : G(a,b) == -1, G(b,c) == -1 -> S(a,c) == -1
1106  Impossible because G(b,c) == -1 contradicts II.
1107  c not in A, a,b in A : S(a,b) == -1, G(b,c) == -1 -> G(a,c) == -1
1108  Always true because G(a,c) == -1 by definition II.
1109  */
1110  if ((s1->class->version >= 3) ^ (s2->class->version >= 3)) {
1111  /* One of both has no own com_ino function. Rank it as larger. */
1112  return s1->class->version >= 3 ? -1 : 1;
1113  } else if (s1->class->version >= 3) {
1114  if (s1->class->cmp_ino == s2->class->cmp_ino) {
1115  if (s1->class->cmp_ino == NULL) {
1116  /* Both are NULL. No decision by .cmp_ino(). */;
1117  } else {
1118  /* Both are compared by the same function */
1119  ret = s1->class->cmp_ino(s1, s2);
1120  return ret;
1121  }
1122  } else {
1123  /* Not the same cmp_ino() function. Decide by list rank of
1124  function while building the list on the fly.
1125  */
1127  s2->class->cmp_ino);
1128  return ret;
1129  }
1130  }
1131  }
1132 
1133  iso_stream_get_id(s1, &fs_id1, &dev_id1, &ino_id1);
1134  iso_stream_get_id(s2, &fs_id2, &dev_id2, &ino_id2);
1135  if (fs_id1 < fs_id2) {
1136  return -1;
1137  } else if (fs_id1 > fs_id2) {
1138  return 1;
1139  }
1140  /* files belong to the same fs */
1141  if (dev_id1 > dev_id2) {
1142  return -1;
1143  } else if (dev_id1 < dev_id2) {
1144  return 1;
1145  } else if (ino_id1 < ino_id2) {
1146  return -1;
1147  } else if (ino_id1 > ino_id2) {
1148  return 1;
1149  }
1150  size1 = iso_stream_get_size(s1);
1151  size2 = iso_stream_get_size(s2);
1152  if (size1 < size2) {
1153 
1154 #ifdef Libisofs_stream_cmp_ino_debuG
1155  if (debug) {
1156  if (report_counter < 5)
1157  fprintf(stderr,
1158  "\n\nlibisofs_DEBUG : Program error: same ino but differing size\n\n\n");
1159  else if (report_counter == 5)
1160  fprintf(stderr,
1161  "\n\nlibisofs_DEBUG : Inode error: more of same ino but differing size\n\n\n");
1162  report_counter++;
1163  }
1164 #endif /* Libisofs_stream_cmp_ino_debuG */
1165 
1166  return -1;
1167  } else if (size1 > size2) {
1168 
1169 #ifdef Libisofs_stream_cmp_ino_debuG
1170  if (debug) {
1171  if (report_counter < 5)
1172  fprintf(stderr,
1173  "\n\nlibisofs_DEBUG : Inode error: same ino but differing size\n\n\n");
1174  else if (report_counter == 5)
1175  fprintf(stderr,
1176  "\n\nlibisofs_DEBUG : Program error: more of same ino but differing size\n\n\n");
1177  report_counter++;
1178  }
1179 #endif /* Libisofs_stream_cmp_ino_debuG */
1180 
1181  return 1;
1182  }
1183 
1184  if (s1->class != s2->class)
1185  return (s1->class < s2->class ? -1 : 1);
1186  if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) {
1187  return (s1 < s2 ? -1 : 1);
1188  }
1189  return 0;
1190 }
1191 
1192 
1193 /**
1194  * @return
1195  * 1 ok, 0 EOF, < 0 error
1196  */
1197 int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count,
1198  size_t *got)
1199 {
1200  ssize_t result;
1201 
1202  *got = 0;
1203  do {
1204  result = iso_stream_read(stream, buf + *got, count - *got);
1205  if (result < 0) {
1206  memset(buf + *got, 0, count - *got);
1207  return result;
1208  }
1209  if (result == 0)
1210  break;
1211  *got += result;
1212  } while (*got < count);
1213 
1214  if (*got < count) {
1215  /* eof */
1216  memset(buf + *got, 0, count - *got);
1217  return 0;
1218  }
1219  return 1;
1220 }
1221 
1222 /* @param flag bit0= dig out most original stream (e.g. because from old image)
1223  @return 1=ok, md5 is valid,
1224  0= not ok,
1225  <0 fatal error, abort
1226 */
1227 int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag)
1228 {
1229  int ret, is_open = 0;
1230  char * buffer = NULL;
1231  void *ctx= NULL;
1232  off_t file_size;
1233  uint32_t b, nblocks;
1234  size_t got_bytes;
1235  IsoStream *input_stream;
1236 
1237  LIBISO_ALLOC_MEM(buffer, char, 2048);
1238  if (flag & 1) {
1239  while(1) {
1240  input_stream = iso_stream_get_input_stream(stream, 0);
1241  if (input_stream == NULL)
1242  break;
1243  stream = input_stream;
1244  }
1245  }
1246 
1247  if (! iso_stream_is_repeatable(stream))
1248  {ret = 0; goto ex;}
1249  ret = iso_md5_start(&ctx);
1250  if (ret < 0)
1251  goto ex;
1252  ret = iso_stream_open(stream);
1253  if (ret < 0)
1254  goto ex;
1255  is_open = 1;
1256  file_size = iso_stream_get_size(stream);
1257  nblocks = DIV_UP(file_size, 2048);
1258  for (b = 0; b < nblocks; ++b) {
1259  ret = iso_stream_read_buffer(stream, buffer, 2048, &got_bytes);
1260  if (ret < 0) {
1261  ret = 0;
1262  goto ex;
1263  }
1264  /* Do not use got_bytes to stay closer to IsoFileSrc processing */
1265  if (file_size - b * 2048 > 2048)
1266  ret = 2048;
1267  else
1268  ret = file_size - b * 2048;
1269  iso_md5_compute(ctx, buffer, ret);
1270  }
1271  ret = 1;
1272 ex:;
1273  if (is_open)
1274  iso_stream_close(stream);
1275  if (ctx != NULL)
1276  iso_md5_end(&ctx, md5);
1278  return ret;
1279 }
1280 
1281 /* API */
1282 int iso_stream_clone(IsoStream *old_stream, IsoStream **new_stream, int flag)
1283 {
1284  int ret;
1285 
1286  if (old_stream->class->version < 4)
1287  return ISO_STREAM_NO_CLONE;
1288  ret = old_stream->class->clone_stream(old_stream, new_stream, 0);
1289  return ret;
1290 }
1291 
1293  IsoStream **new_stream,
1294  IsoStream **new_input, int flag)
1295 {
1296  IsoStream *stream, *input_stream;
1297  int ret;
1298 
1299  *new_stream = NULL;
1300  *new_input = NULL;
1301  input_stream = iso_stream_get_input_stream(old_stream, 0);
1302  if (input_stream == NULL)
1303  return ISO_STREAM_NO_CLONE;
1304  stream = calloc(1, sizeof(IsoStream));
1305  if (stream == NULL)
1306  return ISO_OUT_OF_MEM;
1307  ret = iso_stream_clone(input_stream, new_input, 0);
1308  if (ret < 0) {
1309  free((char *) stream);
1310  return ret;
1311  }
1312  stream->class = old_stream->class;
1313  stream->refcount = 1;
1314  stream->data = NULL;
1315  *new_stream = stream;
1316  return ISO_SUCCESS;
1317 }
1318 
static off_t file_size(struct burn_source *source)
Definition: file.c:96
int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret, int flag)
Definition: fs_image.c:6633
int iso_ifs_source_get_zf(IsoFileSource *src, uint8_t zisofs_algo[2], int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: fs_image.c:1275
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
Definition: fsource.c:101
int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
Definition: fsource.c:95
void iso_file_source_unref(IsoFileSource *src)
Definition: fsource.c:27
int iso_file_source_access(IsoFileSource *src)
Definition: fsource.c:71
int iso_file_source_close(IsoFileSource *src)
Definition: fsource.c:89
int iso_file_source_stat(IsoFileSource *src, struct stat *info)
Definition: fsource.c:77
void iso_file_source_ref(IsoFileSource *src)
Definition: fsource.c:22
IsoFilesystem * iso_file_source_get_filesystem(IsoFileSource *src)
Definition: fsource.c:119
int iso_file_source_open(IsoFileSource *src)
Definition: fsource.c:83
char * iso_file_source_get_path(IsoFileSource *src)
Definition: fsource.c:53
#define ISO_MEM_FS_ID
Definition: fsource.h:24
#define MIN(a, b)
Definition: util.h:35
#define LIBISO_FREE_MEM(pt)
Definition: util.h:627
#define DIV_UP(n, div)
Definition: util.h:38
#define LIBISO_ALLOC_MEM_VOID(pt, typ, count)
Definition: util.h:621
#define LIBISO_ALLOC_MEM(pt, typ, count)
Definition: util.h:615
int iso_md5_end(void **md5_context, char result[16])
Definition: md5.c:391
#define ISO_SUCCESS
Definition: libisofs.h:8719
#define ISO_STREAM_NO_CLONE
Definition: libisofs.h:9089
#define ISO_FILE_NOT_OPENED
Definition: libisofs.h:8811
#define ISO_OUT_OF_MEM
Definition: libisofs.h:8745
#define ISO_FILE_OFFSET_TOO_BIG
Definition: libisofs.h:8858
#define ISO_FILE_IS_DIR
Definition: libisofs.h:8817
#define ISO_WRONG_ARG_VALUE
Definition: libisofs.h:8751
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
int iso_md5_start(void **md5_context)
Definition: md5.c:353
int iso_md5_compute(void *md5_context, char *data, int datalen)
Definition: md5.c:365
#define ISO_FILE_ALREADY_OPENED
Definition: libisofs.h:8796
static IsoStreamIface fsrc_stream_class
Definition: stream.c:209
static int cut_out_is_repeatable(IsoStream *stream)
Definition: stream.c:401
int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count, size_t *got)
Definition: stream.c:1197
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
Definition: stream.c:225
static IsoStreamIface mem_stream_class
Definition: stream.c:727
static int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: stream.c:684
static IsoStream * fsrc_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:162
ino_t cut_out_serial_id
Definition: stream.c:34
static void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: stream.c:408
static int fsrc_is_repeatable(IsoStream *stream)
Definition: stream.c:95
static void cut_out_free(IsoStream *stream)
Definition: stream.c:423
char * iso_stream_get_source_path(IsoStream *stream, int flag)
Definition: stream.c:889
static off_t cut_out_get_size(IsoStream *stream)
Definition: stream.c:383
static int fsrc_open(IsoStream *stream)
Definition: stream.c:37
void iso_stream_get_file_name(IsoStream *stream, char *name)
Definition: stream.c:841
static int iso_get_streamcmprank(int(*cmp_func)(IsoStream *s1, IsoStream *s2), int flag)
Definition: stream.c:990
int iso_stream_update_size(IsoStream *stream)
Definition: stream.c:828
int iso_stream_clone(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: stream.c:1282
IsoStream * iso_stream_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:867
static int mem_read(IsoStream *stream, void *buf, size_t count)
Definition: stream.c:618
int iso_stream_get_src_zf(IsoStream *stream, uint8_t zisofs_algo[2], int *header_size_div4, int *block_size_log2, uint64_t *uncompressed_size, int flag)
Definition: stream.c:293
int iso_stream_open(IsoStream *stream)
Definition: stream.c:798
static int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: stream.c:443
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream)
Definition: stream.c:751
static int iso_cmp_streamcmpranks(int(*cf1)(IsoStream *s1, IsoStream *s2), int(*cf2)(IsoStream *s1, IsoStream *s2))
Definition: stream.c:1018
static struct iso_streamcmprank * streamcmpranks
Definition: stream.c:987
off_t iso_stream_get_size(IsoStream *stream)
Definition: stream.c:810
static IsoStreamIface cut_out_stream_class
Definition: stream.c:490
static int cut_out_read(IsoStream *stream, void *buf, size_t count)
Definition: stream.c:390
static int fsrc_close(IsoStream *stream)
Definition: stream.c:64
static int mem_is_repeatable(IsoStream *stream)
Definition: stream.c:645
static off_t fsrc_get_size(IsoStream *stream)
Definition: stream.c:75
int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag)
Definition: stream.c:1227
ino_t mem_serial_id
Definition: stream.c:33
static int cut_out_close(IsoStream *stream)
Definition: stream.c:372
static int cut_out_open(IsoStream *stream)
Definition: stream.c:329
static int mem_open(IsoStream *stream)
Definition: stream.c:579
int iso_stream_cmp_ifs_sections(IsoStream *s1, IsoStream *s2, int *cmp_ret, int flag)
Definition: stream.c:943
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: stream.c:835
int iso_stream_read(IsoStream *stream, void *buf, size_t count)
Definition: stream.c:816
int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag)
Definition: stream.c:923
static IsoStream * mem_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:678
static void mem_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: stream.c:651
ino_t serial_id
Definition: stream.c:32
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
Definition: stream.c:1042
static off_t mem_get_size(IsoStream *stream)
Definition: stream.c:609
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, IsoStream **stream)
Definition: stream.c:507
static int cut_out_update_size(IsoStream *stream)
Definition: stream.c:431
static void fsrc_free(IsoStream *stream)
Definition: stream.c:133
void iso_stream_unref(IsoStream *stream)
Definition: stream.c:789
static int mem_close(IsoStream *stream)
Definition: stream.c:594
static int mem_update_size(IsoStream *stream)
Definition: stream.c:672
static void mem_free(IsoStream *stream)
Definition: stream.c:662
static IsoStream * cut_out_get_input_stream(IsoStream *stream, int flag)
Definition: stream.c:437
int iso_stream_destroy_cmpranks(int flag)
Definition: stream.c:1028
static int fsrc_read(IsoStream *stream, void *buf, size_t count)
Definition: stream.c:84
static void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: stream.c:118
int iso_stream_close(IsoStream *stream)
Definition: stream.c:804
static int fsrc_update_size(IsoStream *stream)
Definition: stream.c:142
#define PATH_MAX
Definition: stream.c:28
int iso_stream_clone_filter_common(IsoStream *old_stream, IsoStream **new_stream, IsoStream **new_input, int flag)
Definition: stream.c:1292
void iso_stream_ref(IsoStream *stream)
Definition: stream.c:784
int fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: stream.c:167
int iso_stream_is_repeatable(IsoStream *stream)
Definition: stream.c:822
off_t size
Definition: stream.h:26
ino_t ino_id
Definition: stream.h:25
IsoFileSource * src
Definition: stream.h:21
dev_t dev_id
Definition: stream.h:24
int(* clone_src)(IsoFileSource *old_src, IsoFileSource **new_src, int flag)
Definition: libisofs.h:896
void(* get_id)(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, ino_t *ino_id)
Definition: libisofs.h:1071
int(* cmp_ino)(IsoStream *s1, IsoStream *s2)
Definition: libisofs.h:1151
int(* clone_stream)(IsoStream *old_stream, IsoStream **new_stream, int flag)
Definition: libisofs.h:1170
char type[4]
Definition: libisofs.h:1016
int(* is_repeatable)(IsoStream *stream)
Definition: libisofs.h:1066
off_t(* get_size)(IsoStream *stream)
Definition: libisofs.h:1039
int(* close)(IsoStream *stream)
Definition: libisofs.h:1032
void(* free)(IsoStream *stream)
Definition: libisofs.h:1078
int(* open)(IsoStream *stream)
Definition: libisofs.h:1025
int(* read)(IsoStream *stream, void *buf, size_t count)
Definition: libisofs.h:1055
uint8_t * buf
Definition: stream.c:572
ssize_t offset
Definition: stream.c:573
ino_t ino_id
Definition: stream.c:574
size_t size
Definition: stream.c:575
ino_t ino_id
Definition: stream.c:322
dev_t dev_id
Definition: stream.c:321
off_t offset
Definition: stream.c:323
off_t pos
Definition: stream.c:325
off_t size
Definition: stream.c:324
IsoFileSource * src
Definition: stream.c:318
const IsoFileSourceIface * class
Definition: libisofs.h:915
unsigned int(* get_id)(IsoFilesystem *fs)
Definition: libisofs.h:593
int refcount
Definition: libisofs.h:1186
void * data
Definition: libisofs.h:1187
IsoStreamIface * class
Definition: libisofs.h:1185
struct iso_streamcmprank * next
Definition: stream.c:984
int(* cmp_func)(IsoStream *s1, IsoStream *s2)
Definition: stream.c:983