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)  

fs_image.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2009 - 2020 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 /*
12  * Filesystem/FileSource implementation to access an ISO image, using an
13  * IsoDataSource to read image data.
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 #include "../config.h"
18 #endif
19 
20 #include "libisofs.h"
21 #include "ecma119.h"
22 #include "messages.h"
23 #include "rockridge.h"
24 #include "image.h"
25 #include "tree.h"
26 #include "eltorito.h"
27 #include "node.h"
28 #include "aaip_0_2.h"
29 #include "system_area.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <locale.h>
34 #include <langinfo.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 
39 
40 /* Enable this and write the correct absolute path into the include statement
41  below in order to test the pending contribution to syslinux:
42  http://www.syslinux.org/archives/2013-March/019755.html
43 
44  # def ine Libisofs_syslinux_tesT 1
45 
46 */
47 #ifdef Libisofs_syslinux_tesT
48 #define Isolinux_rockridge_in_libisofS 1
49 #include "/reiser/syslinux/core/fs/iso9660/susp_rr.c"
50 /*
51  # inc lude "/home/thomas/projekte/cdrskin_dir/libisoburn-develop/test/susp_rr.c"
52 */
53 #endif /* Libisofs_syslinux_tesT */
54 
55 
56 /**
57  * Options for image reading.
58  * There are four kind of options:
59  * - Related to multisession support.
60  * In most cases, an image begins at LBA 0 of the data source. However,
61  * in multisession discs, the later image begins in the last session on
62  * disc. The block option can be used to specify the start of that last
63  * session.
64  * - Related to the tree that will be read.
65  * As default, when Rock Ridge extensions are present in the image, that
66  * will be used to get the tree. If RR extensions are not present, libisofs
67  * will use the Joliet extensions if available. Finally, the plain ISO-9660
68  * tree is used if neither RR nor Joliet extensions are available. With
69  * norock, nojoliet, and preferjoliet options, you can change this
70  * default behavior.
71  * - Related to default POSIX attributes.
72  * When Rock Ridege extensions are not used, libisofs can't figure out what
73  * are the the permissions, uid or gid for the files. You should supply
74  * default values for that.
75  */
77 {
78  /**
79  * Block where the image begins, usually 0, can be different on a
80  * multisession disc.
81  */
82  uint32_t block;
83 
84  unsigned int norock : 1; /*< Do not read Rock Ridge extensions */
85  unsigned int nojoliet : 1; /*< Do not read Joliet extensions */
86  unsigned int noiso1999 : 1; /*< Do not read ISO 9660:1999 enhanced tree */
87  unsigned int noaaip : 1; /* Do not read AAIP extension for xattr and ACL */
88  unsigned int nomd5 : 2; /* Do not read MD5 array */
89 
90  /**
91  * Hand out new inode numbers and overwrite eventually read PX inode
92  * numbers. This will split apart any hardlinks.
93  */
94  unsigned int make_new_ino : 1 ;
95 
96  /**
97  * When both Joliet and RR extensions are present, the RR tree is used.
98  * If you prefer using Joliet, set this to 1.
99  */
100  unsigned int preferjoliet : 1;
101 
102  /**
103  * If neither Rock Ridge nor Joliet is used, the ECMA-119 names are mapped
104  * according to one of these rules
105  * 0 = unmapped: show name as recorded in ECMA-119 directory record
106  * (not suitable for writing it to a new ISO filesystem)
107  * 1 = stripped: like unmapped, but strip off trailing ";1" or ".;1"
108  * 2 = uppercase: like stripped, but {a-z} mapped to {A-Z}
109  * 3 = lowercase: like stripped, but {A-Z} mapped to {a-z}
110  */
111  unsigned int ecma119_map : 2;
112 
113  /**
114  * If Joliet is used, apply one of these mapping rules:
115  * 0 = unmapped: show name as recorded in Joliet directory record
116  * (not suitable for writing it to a new ISO filesystem)
117  * 1 = stripped: strip off trailing ";1" or ".;1"
118  */
119  unsigned int joliet_map : 1;
120 
121  uid_t uid; /**< Default uid when no RR */
122  gid_t gid; /**< Default uid when no RR */
123  mode_t dir_mode; /**< Default mode when no RR (only permissions) */
124  mode_t file_mode;
125  /* TODO #00024 : option to convert names to lower case for iso reading */
126 
127  /**
128  * Input charset for RR file names. NULL to use default locale charset.
129  */
131 
132  /**
133  * Enable or disable methods to automatically choose an input charset.
134  * This eventually overrides input_charset.
135  *
136  * bit0= allow to set the input character set automatically from
137  * attribute "isofs.cs" of root directory
138  */
140 
141 
142  /**
143  * Enable or disable loading of the first 32768 bytes of the session and
144  * submission by iso_write_opts_set_system_area(data, 0).
145  */
147 
148  /**
149  * Keep data source of imported ISO filesystem in IsoImage.import_src
150  */
152 
153  /**
154  * What to do in case of name longer than truncate_length:
155  * 0= throw FAILURE
156  * 1= truncate to truncate_length with MD5 of whole name at end
157  */
160 
161 };
162 
163 /**
164  * Return information for image.
165  * Both size, hasRR and hasJoliet will be filled by libisofs with suitable
166  * values.
167  */
169 {
170  /**
171  * Will be filled with the size (in 2048 byte block) of the image, as
172  * reported in the PVM.
173  */
174  uint32_t size;
175 
176  /** It will be set to 1 if RR extensions are present, to 0 if not. */
177  unsigned int hasRR :1;
178 
179  /** It will be set to 1 if Joliet extensions are present, to 0 if not. */
180  unsigned int hasJoliet :1;
181 
182  /**
183  * It will be set to 1 if the image is an ISO 9660:1999, i.e. it has
184  * a version 2 Enhanced Volume Descriptor.
185  */
186  unsigned int hasIso1999 :1;
187 
188  /** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/
189  unsigned int hasElTorito :1;
190 
191  /**
192  * Which tree was loaded:
193  * 0= ISO 9660 + Rock Ridge , 1= Joliet , 2= ISO 9660:1999
194  */
196 
197  /** Whether Rock Ridge info was used while loading: 0= no, 1= yes */
199 
200 };
201 
202 static int ifs_fs_open(IsoImageFilesystem *fs);
203 static int ifs_fs_close(IsoImageFilesystem *fs);
205  IsoFileSource *parent, struct ecma119_dir_record *record,
206  IsoFileSource **src, int flag);
207 
208 /** unique identifier for each image */
209 unsigned int fs_dev_id = 0;
210 
211 /**
212  * Should the RR extensions be read?
213  */
215  RR_EXT_NO = 0, /*< Do not use RR extensions */
216  RR_EXT_110 = 1, /*< RR extensions conforming version 1.10 */
217  RR_EXT_112 = 2 /*< RR extensions conforming version 1.12 */
218 };
219 
220 
221 /**
222  * Private data for the image IsoFilesystem
223  */
224 typedef struct
225 {
226  /** DataSource from where data will be read */
228 
229  /** unique id for the each image (filesystem instance) */
230  unsigned int id;
231 
232  /**
233  * Counter of the times the filesystem has been opened still pending of
234  * close. It is used to keep track of when we need to actually open or
235  * close the IsoDataSource.
236  */
237  unsigned int open_count;
238 
239  uid_t uid; /**< Default uid when no RR */
240  gid_t gid; /**< Default uid when no RR */
241  mode_t dir_mode; /**< Default mode when no RR (only permissions) */
242  mode_t file_mode;
243 
244  int msgid;
245 
246  char *input_charset; /**< Input charset for RR names */
247  char *local_charset; /**< For RR names, will be set to the locale one */
248 
249  /**
250  * Enable or disable methods to automatically choose an input charset.
251  * This eventually overrides input_charset.
252  *
253  * bit0= allow to set the input character set automatically from
254  * attribute "isofs.cs" of root directory
255  */
257 
258  /**
259  * Will be filled with the block lba of the extend for the root directory
260  * of the hierarchy that will be read, either from the PVD (ISO, RR) or
261  * from the SVD (Joliet)
262  */
263  uint32_t iso_root_block;
264 
265  /**
266  * Will be filled with the block lba of the extend for the root directory,
267  * as read from the PVM
268  */
269  uint32_t pvd_root_block;
270 
271  /**
272  * Will be filled with the block lba of the extend for the root directory,
273  * as read from the SVD
274  */
275  uint32_t svd_root_block;
276 
277  /**
278  * Will be filled with the block lba of the extend for the root directory,
279  * as read from the enhanced volume descriptor (ISO 9660:1999)
280  */
281  uint32_t evd_root_block;
282 
283  /**
284  * If we need to read RR extensions. i.e., if the image contains RR
285  * extensions, and the user wants to read them.
286  */
287  enum read_rr_ext rr;
288 
289  /**
290  * Bytes skipped within the System Use field of a directory record, before
291  * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3.
292  */
293  uint8_t len_skp;
294 
295  /* Volume attributes */
296  char *volset_id;
297  char *volume_id; /**< Volume identifier. */
298  char *publisher_id; /**< Volume publisher. */
299  char *data_preparer_id; /**< Volume data preparer. */
300  char *system_id; /**< Volume system identifier. */
301  char *application_id; /**< Volume application id */
309 
310  /* extension information */
311 
312  /**
313  * RR version being used in image.
314  * 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12
315  */
316  enum read_rr_ext rr_version;
317 
318  /** If Joliet extensions are available on image */
319  unsigned int joliet : 1;
320 
321  /** If ISO 9660:1999 is available on image */
322  unsigned int iso1999 : 1;
323 
324  /**
325  * See struct iso_read_opts.
326  */
329  unsigned int ecma119_map : 2;
330  unsigned int joliet_map : 1;
331 
332  /** Whether AAIP info shall be loaded if it is present.
333  * 1 = yes , 0 = no
334  */
336 
337  /** Whether the MD5 array shall be read if available.
338  * 2 = yes, but do not check tags , 1 = yes , 0 = no
339  */
340  int md5_load;
341 
342  /** Whether AAIP is present. Version major.minor = major * 100 + minor
343  * Value -1 means that no AAIP ER was detected yet.
344  */
346 
347  /**
348  * Start block of loaded session.
349  */
350  uint32_t session_lba;
351 
352  /**
353  * Number of blocks of the volume, as reported in the PVM.
354  */
355  uint32_t nblocks;
356 
357  /* el-torito information */
358  unsigned int eltorito : 1; /* is el-torito available */
360  unsigned char platform_ids[Libisofs_max_boot_imageS];
361  unsigned char id_strings[Libisofs_max_boot_imageS][28];
362  unsigned char selection_crits[Libisofs_max_boot_imageS][20];
363  unsigned char boot_flags[Libisofs_max_boot_imageS]; /* bit0= bootable */
364  unsigned char media_types[Libisofs_max_boot_imageS];
365  unsigned char partition_types[Libisofs_max_boot_imageS];
366  short load_segs[Libisofs_max_boot_imageS];
367  short load_sizes[Libisofs_max_boot_imageS];
368  /** Block addresses of for El-Torito boot images.
369  Needed to recognize them when the get read from the directory tree.
370  */
371  uint32_t bootblocks[Libisofs_max_boot_imageS];
372 
373  uint32_t catblock; /**< Block for El-Torito catalog */
374  off_t catsize; /* Size of boot catalog in bytes */
375  char *catcontent;
376 
377  /* Whether inode numbers from PX entries shall be discarded */
378  unsigned int make_new_ino : 1 ;
379 
380  /* Inode number generator counter. 32 bit because for Rock Ridge PX. */
381  uint32_t inode_counter;
382 
383  /* PX inode number status
384  bit0= there were nodes with PX inode numbers
385  bit1= there were nodes with PX but without inode numbers
386  bit2= there were nodes without PX
387  bit3= there were nodes with faulty PX
388  */
390 
391  /* Which Rock Ridge error messages already have occurred
392  bit0= Invalid PX entry
393  bit1= Invalid TF entry
394  bit2= New NM entry found without previous CONTINUE flag
395  bit3= Invalid NM entry
396  bit4= New SL entry found without previous CONTINUE flag
397  bit5= Invalid SL entry
398  bit6= Invalid CL entry, no child location / found in CL target
399  bit7= Invalid PN entry
400  bit8= Sparse files not supported
401  bit9= SP entry found in a directory entry other than '.' entry of root
402  bit10= ER entry found in a directory entry other than '.' entry of root
403  bit11= Invalid AA entry
404  bit12= Invalid AL entry
405  bit13= Invalid ZF entry
406  bit14= Rock Ridge PX entry is not present or invalid
407  bit15= Incomplete NM
408  bit16= Incomplete SL
409  bit17= Charset conversion error
410  bit18= Link without destination
411  bit19= SL with a non-link file
412  */
415 
417 
418 } _ImageFsData;
419 
420 typedef struct image_fs_data ImageFileSourceData;
421 
422 /* IMPORTANT: Any change must be reflected by ifs_clone_src */
424 {
425  IsoImageFilesystem *fs; /**< reference to the image it belongs to */
426  IsoFileSource *parent; /**< reference to the parent (NULL if root) */
427 
428  struct stat info; /**< filled struct stat */
429  char *name; /**< name of this file */
430 
431  /**
432  * Location of file extents.
433  */
436 
437  unsigned int opened : 2; /**< 0 not opened, 1 opened file, 2 opened dir */
438 
439 #ifdef Libisofs_with_zliB
440  uint8_t zisofs_algo[2];
441  uint8_t header_size_div4;
442  uint8_t block_size_log2;
443  uint64_t uncompressed_size;
444 #endif
445 
446  /* info for content reading */
447  struct
448  {
449  /**
450  * - For regular files, once opened it points to a temporary data
451  * buffer of 2048 bytes.
452  * - For dirs, once opened it points to a IsoFileSource* array with
453  * its children
454  * - For symlinks, it points to link destination
455  */
456  void *content;
457 
458  /**
459  * - For regular files, number of bytes already read.
460  */
461  off_t offset;
462  } data;
463 
464  /**
465  * malloc() storage for the string of AAIP fields which represent
466  * ACLs and XFS-style Extended Attributes. (Not to be confused with
467  * ECMA-119 Extended Attributes.)
468  */
469  unsigned char *aa_string;
470 
471 };
472 
474 {
476  struct child_list *next;
477 };
478 
479 void child_list_free(struct child_list *list)
480 {
481  struct child_list *temp;
482  struct child_list *next = list;
483  while (next != NULL) {
484  temp = next->next;
486  free(next);
487  next = temp;
488  }
489 }
490 
491 static
493 {
494  ImageFileSourceData *data;
495  data = src->data;
496 
497  if (data->parent == NULL) {
498  return strdup("");
499  } else {
500  char *path, *new_path;
501  int pathlen;
502 
503  if (data->name == NULL)
504  return NULL;
505  path = ifs_get_path(data->parent);
506  if (path == NULL)
507  return NULL;
508  pathlen = strlen(path);
509  new_path = realloc(path, pathlen + strlen(data->name) + 2);
510  if (new_path == NULL) {
511  free(path);
512  return NULL;
513  }
514  path= new_path;
515  path[pathlen] = '/';
516  path[pathlen + 1] = '\0';
517  return strcat(path, data->name);
518  }
519 }
520 
521 static
523 {
524  ImageFileSourceData *data;
525  data = src->data;
526  return data->name == NULL ? NULL : strdup(data->name);
527 }
528 
529 static
530 int ifs_lstat(IsoFileSource *src, struct stat *info)
531 {
532  ImageFileSourceData *data;
533 
534  if (src == NULL || info == NULL) {
535  return ISO_NULL_POINTER;
536  }
537 
538  data = src->data;
539  if (data == NULL)
540  return ISO_NULL_POINTER;
541  *info = data->info;
542  return ISO_SUCCESS;
543 }
544 
545 static
546 int ifs_stat(IsoFileSource *src, struct stat *info)
547 {
548  ImageFileSourceData *data;
549 
550  if (src == NULL || info == NULL || src->data == NULL) {
551  return ISO_NULL_POINTER;
552  }
553 
554  data = (ImageFileSourceData*)src->data;
555 
556  if (S_ISLNK(data->info.st_mode)) {
557  /* TODO #00012 : support follow symlinks on image filesystem */
558  return ISO_FILE_BAD_PATH;
559  }
560  *info = data->info;
561  return ISO_SUCCESS;
562 }
563 
564 static
566 {
567  /* we always have access, it is controlled by DataSource */
568  return ISO_SUCCESS;
569 }
570 
571 /**
572  * Read all directory records in a directory, and creates an IsoFileSource for
573  * each of them, storing them in the data field of the IsoFileSource for the
574  * given dir.
575  */
576 static
578 {
579  int ret;
580  uint32_t size;
581  uint32_t block;
582  IsoImageFilesystem *fs;
583  _ImageFsData *fsdata;
584  struct ecma119_dir_record *record;
585  uint8_t *buffer = NULL;
586  IsoFileSource *child = NULL;
587  uint32_t pos = 0;
588  uint32_t tlen = 0;
589 
590  if (data == NULL) {
591  ret = ISO_NULL_POINTER; goto ex;
592  }
593 
595  fs = data->fs;
596  fsdata = fs->data;
597 
598  /* a dir has always a single extent */
599  block = data->sections[0].block;
600  ret = fsdata->src->read_block(fsdata->src, block, buffer);
601  if (ret < 0) {
602  goto ex;
603  }
604 
605  /* "." entry, get size of the dir and skip */
606  record = (struct ecma119_dir_record *)(buffer + pos);
607  size = iso_read_bb(record->length, 4, NULL);
608  tlen += record->len_dr[0];
609  pos += record->len_dr[0];
610 
611  /* skip ".." */
612  record = (struct ecma119_dir_record *)(buffer + pos);
613  tlen += record->len_dr[0];
614  pos += record->len_dr[0];
615 
616  while (tlen < size) {
617 
618  record = (struct ecma119_dir_record *)(buffer + pos);
619  if (pos == 2048 || record->len_dr[0] == 0) {
620  /*
621  * The directory entries are split in several blocks
622  * read next block
623  */
624  ret = fsdata->src->read_block(fsdata->src, ++block, buffer);
625  if (ret < 0) {
626  goto ex;
627  }
628  tlen += 2048 - pos;
629  pos = 0;
630  continue;
631  }
632 
633  /* (Vreixo:)
634  * What about ignoring files with existence flag?
635  * if (record->flags[0] & 0x01)
636  * continue;
637  * ts B20306 : >>> One should rather record that flag and write it
638  * >>> to the new image.
639  */
640 
641 #ifdef Libisofs_wrongly_skip_rr_moveD
642  /* ts B20306 :
643  This skipping by name is wrong resp. redundant:
644  If no rr reading is enabled, then it is the only access point for
645  the content of relocated directories. So one should not ignore it.
646  If rr reading is enabled, then the RE entry of mkisofs' RR_MOVED
647  will cause it to be skipped.
648  */
649 
650  /* (Vreixo:)
651  * For a extrange reason, mkisofs relocates directories under
652  * a RR_MOVED dir. It seems that it is only used for that purposes,
653  * and thus it should be removed from the iso tree before
654  * generating a new image with libisofs, that don't uses it.
655  */
656 
657  if (data->parent == NULL && record->len_fi[0] == 8
658  && !strncmp((char*)record->file_id, "RR_MOVED", 8)) {
659 
660  iso_msg_debug(fsdata->msgid, "Skipping RR_MOVE entry.");
661 
662  tlen += record->len_dr[0];
663  pos += record->len_dr[0];
664  continue;
665  }
666 
667 #endif /* Libisofs_wrongly_skip_rr_moveD */
668 
669  /*
670  * We pass a NULL parent instead of dir, to prevent the circular
671  * reference from child to parent.
672  */
673  ret = iso_file_source_new_ifs(fs, NULL, record, &child, 0);
674  if (ret < 0) {
675  if (child) {
676  /*
677  * This can only happen with multi-extent files.
678  */
679  ImageFileSourceData *ifsdata = child->data;
680  free(ifsdata->sections);
681  free(ifsdata->name);
682  free(ifsdata);
683  free(child);
684  }
685  goto ex;
686  }
687 
688  /* add to the child list */
689  if (ret == 1) {
690  struct child_list *node;
691  node = malloc(sizeof(struct child_list));
692  if (node == NULL) {
693  iso_file_source_unref(child);
694  {ret = ISO_OUT_OF_MEM; goto ex;}
695  }
696  /*
697  * Note that we insert in reverse order. This leads to faster
698  * addition here, but also when adding to the tree, as insertion
699  * will be done, sorted, in the first position of the list.
700  */
701  node->next = data->data.content;
702  node->file = child;
703  data->data.content = node;
704  child = NULL;
705  }
706 
707  tlen += record->len_dr[0];
708  pos += record->len_dr[0];
709  }
710 
711  ret = ISO_SUCCESS;
712 ex:;
714  return ret;
715 }
716 
717 static
719 {
720  int ret;
721  ImageFileSourceData *data;
722 
723  if (src == NULL || src->data == NULL) {
724  return ISO_NULL_POINTER;
725  }
726  data = (ImageFileSourceData*)src->data;
727 
728  if (data->opened) {
730  }
731 
732  if (S_ISDIR(data->info.st_mode)) {
733  /* ensure fs is opened */
734  ret = data->fs->open(data->fs);
735  if (ret < 0) {
736  return ret;
737  }
738 
739  /*
740  * Cache all directory entries.
741  * This can waste more memory, but improves as disc is read in much more
742  * sequentially way, thus reducing jump between tracks on disc
743  */
744  ret = read_dir(data);
745  data->fs->close(data->fs);
746 
747  if (ret < 0) {
748  /* free probably allocated children */
749  child_list_free((struct child_list*)data->data.content);
750  } else {
751  data->opened = 2;
752  }
753 
754  return ret;
755  } else if (S_ISREG(data->info.st_mode)) {
756  /* ensure fs is opened */
757  ret = data->fs->open(data->fs);
758  if (ret < 0) {
759  return ret;
760  }
761  data->data.content = malloc(BLOCK_SIZE);
762  if (data->data.content == NULL) {
763  return ISO_OUT_OF_MEM;
764  }
765  data->data.offset = 0;
766  data->opened = 1;
767  } else {
768  /* symlinks and special files inside image can't be opened */
769  return ISO_FILE_ERROR;
770  }
771  return ISO_SUCCESS;
772 }
773 
774 static
776 {
777  ImageFileSourceData *data;
778 
779  if (src == NULL || src->data == NULL) {
780  return ISO_NULL_POINTER;
781  }
782  data = (ImageFileSourceData*)src->data;
783 
784  if (!data->opened) {
785  return ISO_FILE_NOT_OPENED;
786  }
787 
788  if (data->opened == 2) {
789  /*
790  * close a dir, free all pending pre-allocated children.
791  * not that we don't need to close the filesystem, it was already
792  * closed
793  */
794  child_list_free((struct child_list*) data->data.content);
795  data->data.content = NULL;
796  data->opened = 0;
797  } else if (data->opened == 1) {
798  /* close regular file */
799  free(data->data.content);
800  data->fs->close(data->fs);
801  data->data.content = NULL;
802  data->opened = 0;
803  } else {
804  /* TODO only dirs and files supported for now */
805  return ISO_ERROR;
806  }
807 
808  return ISO_SUCCESS;
809 }
810 
811 /**
812  * Computes the block where the given offset should start.
813  */
814 static
815 uint32_t block_from_offset(int nsections, struct iso_file_section *sections,
816  off_t offset)
817 {
818  int section = 0;
819  off_t bytes = 0;
820 
821  do {
822  if ( (offset - bytes) < (off_t) sections[section].size ) {
823  return sections[section].block + (offset - bytes) / BLOCK_SIZE;
824  } else {
825  bytes += (off_t) sections[section].size;
826  section++;
827  }
828 
829  } while(section < nsections);
830  return 0; /* should never happen */
831 }
832 
833 /**
834  * Get the size available for reading on the corresponding block
835  */
836 static
837 uint32_t size_available(int nsections, struct iso_file_section *sections,
838  off_t offset)
839 {
840  int section = 0;
841  off_t bytes = 0;
842 
843  do {
844  if ( (offset - bytes) < (off_t) sections[section].size ) {
845  uint32_t curr_section_offset = (uint32_t)(offset - bytes);
846  uint32_t curr_section_left = sections[section].size - curr_section_offset;
847  uint32_t available = BLOCK_SIZE - curr_section_offset % BLOCK_SIZE;
848  return MIN(curr_section_left, available);
849  } else {
850  bytes += (off_t) sections[section].size;
851  section++;
852  }
853 
854  } while(section < nsections);
855  return 0; /* should never happen */
856 }
857 
858 /**
859  * Get the block offset for reading the given file offset
860  */
861 static
862 uint32_t block_offset(int nsections, struct iso_file_section *sections,
863  off_t offset)
864 {
865  int section = 0;
866  off_t bytes = 0;
867 
868 
869  do {
870  if ( (offset - bytes) < (off_t) sections[section].size ) {
871  return (uint32_t)(offset - bytes) % BLOCK_SIZE;
872  } else {
873  bytes += (off_t) sections[section].size;
874  section++;
875  }
876 
877  } while(section < nsections);
878  return 0; /* should never happen */
879 }
880 
881 /**
882  * Attempts to read up to count bytes from the given source into
883  * the buffer starting at buf.
884  *
885  * The file src must be open() before calling this, and close() when no
886  * more needed. Not valid for dirs. On symlinks it reads the destination
887  * file.
888  *
889  * @return
890  * number of bytes read, 0 if EOF, < 0 on error
891  * Error codes:
892  * ISO_FILE_ERROR
893  * ISO_NULL_POINTER
894  * ISO_FILE_NOT_OPENED
895  * ISO_FILE_IS_DIR
896  * ISO_OUT_OF_MEM
897  * ISO_INTERRUPTED
898  */
899 static
900 int ifs_read(IsoFileSource *src, void *buf, size_t count)
901 {
902  int ret;
903  ImageFileSourceData *data;
904  uint32_t read = 0;
905 
906  if (src == NULL || src->data == NULL || buf == NULL) {
907  return ISO_NULL_POINTER;
908  }
909  if (count == 0) {
910  return ISO_WRONG_ARG_VALUE;
911  }
912  data = (ImageFileSourceData*)src->data;
913 
914  if (!data->opened) {
915  return ISO_FILE_NOT_OPENED;
916  } else if (data->opened != 1) {
917  return ISO_FILE_IS_DIR;
918  }
919 
920  while (read < count && data->data.offset < data->info.st_size) {
921  size_t bytes;
922  uint8_t *orig;
923 
924  if (block_offset(data->nsections, data->sections, data->data.offset) == 0) {
925  /* we need to buffer next block */
926  uint32_t block;
927  _ImageFsData *fsdata;
928 
929  if (data->data.offset >= data->info.st_size) {
930  /* EOF */
931  break;
932  }
933  fsdata = data->fs->data;
934  block = block_from_offset(data->nsections, data->sections,
935  data->data.offset);
936  ret = fsdata->src->read_block(fsdata->src, block,
937  data->data.content);
938  if (ret < 0) {
939  return ret;
940  }
941  }
942 
943  /* how much can I read */
944  bytes = MIN(size_available(data->nsections, data->sections, data->data.offset),
945  count - read);
946  if (data->data.offset + (off_t)bytes > data->info.st_size) {
947  bytes = data->info.st_size - data->data.offset;
948  }
949  orig = data->data.content;
950  orig += block_offset(data->nsections, data->sections, data->data.offset);
951  memcpy((uint8_t*)buf + read, orig, bytes);
952  read += bytes;
953  data->data.offset += (off_t)bytes;
954  }
955  return read;
956 }
957 
958 static
959 off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
960 {
961  ImageFileSourceData *data;
962 
963  if (src == NULL) {
964  return (off_t)ISO_NULL_POINTER;
965  }
966  if (offset < (off_t)0) {
967  return (off_t)ISO_WRONG_ARG_VALUE;
968  }
969 
970  data = src->data;
971 
972  if (!data->opened) {
973  return (off_t)ISO_FILE_NOT_OPENED;
974  } else if (data->opened != 1) {
975  return (off_t)ISO_FILE_IS_DIR;
976  }
977 
978  switch (flag) {
979  case 0: /* SEEK_SET */
980  data->data.offset = offset;
981  break;
982  case 1: /* SEEK_CUR */
983  data->data.offset += offset;
984  break;
985  case 2: /* SEEK_END */
986  /* do this make sense? */
987  data->data.offset = data->info.st_size + offset;
988  break;
989  default:
990  return (off_t)ISO_WRONG_ARG_VALUE;
991  }
992 
993  /*
994  * We check for block_offset != 0 because if it is already 0, the block
995  * will be read from image in the read function
996  */
997  if (block_offset(data->nsections, data->sections, data->data.offset) != 0) {
998  /* we need to buffer the block */
999  uint32_t block;
1000  _ImageFsData *fsdata;
1001 
1002  if (data->data.offset < data->info.st_size) {
1003  int ret;
1004  fsdata = data->fs->data;
1005  block = block_from_offset(data->nsections, data->sections,
1006  data->data.offset);
1007  ret = fsdata->src->read_block(fsdata->src, block,
1008  data->data.content);
1009  if (ret < 0) {
1010  return (off_t)ret;
1011  }
1012  }
1013  }
1014  return data->data.offset;
1015 }
1016 
1017 static
1019 {
1020  ImageFileSourceData *data, *cdata;
1021  struct child_list *children;
1022 
1023  if (src == NULL || src->data == NULL || child == NULL) {
1024  return ISO_NULL_POINTER;
1025  }
1026  data = (ImageFileSourceData*)src->data;
1027 
1028  if (!data->opened) {
1029  return ISO_FILE_NOT_OPENED;
1030  } else if (data->opened != 2) {
1031  return ISO_FILE_IS_NOT_DIR;
1032  }
1033 
1034  /* return the first child and free it */
1035  if (data->data.content == NULL) {
1036  return 0; /* EOF */
1037  }
1038 
1039  children = (struct child_list*)data->data.content;
1040  *child = children->file;
1041  cdata = (ImageFileSourceData*)(*child)->data;
1042 
1043  /* set the ref to the parent */
1044  cdata->parent = src;
1045  iso_file_source_ref(src);
1046 
1047  /* free the first element of the list */
1048  data->data.content = children->next;
1049  free(children);
1050 
1051  return ISO_SUCCESS;
1052 }
1053 
1054 /**
1055  * Read the destination of a symlink. You don't need to open the file
1056  * to call this.
1057  *
1058  * @param buf
1059  * allocated buffer of at least bufsiz bytes.
1060  * The dest. will be copied there, and it will be NULL-terminated
1061  * @param bufsiz
1062  * characters to be copied. Destination link will be truncated if
1063  * it is larger than given size. This include the \0 character.
1064  * @return
1065  * 1 on success, < 0 on error
1066  * Error codes:
1067  * ISO_FILE_ERROR
1068  * ISO_NULL_POINTER
1069  * ISO_WRONG_ARG_VALUE -> if bufsiz <= 0
1070  * ISO_FILE_IS_NOT_SYMLINK
1071  * ISO_OUT_OF_MEM
1072  * ISO_FILE_BAD_PATH
1073  * ISO_FILE_DOESNT_EXIST
1074  *
1075  */
1076 static
1077 int ifs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
1078 {
1079  char *dest;
1080  size_t len;
1081  int ret;
1082  ImageFileSourceData *data;
1083 
1084  if (src == NULL || buf == NULL || src->data == NULL) {
1085  return ISO_NULL_POINTER;
1086  }
1087 
1088  if (bufsiz <= 0) {
1089  return ISO_WRONG_ARG_VALUE;
1090  }
1091 
1092  data = (ImageFileSourceData*)src->data;
1093 
1094  if (!S_ISLNK(data->info.st_mode)) {
1095  return ISO_FILE_IS_NOT_SYMLINK;
1096  }
1097 
1098  dest = (char*)data->data.content;
1099  len = strlen(dest);
1100 
1101  ret = ISO_SUCCESS;
1102  if (len >= bufsiz) {
1103  ret = ISO_RR_PATH_TOO_LONG;
1104  len = bufsiz - 1;
1105  }
1106  strncpy(buf, dest, len);
1107  buf[len] = '\0';
1108  return ret;
1109 }
1110 
1111 static
1113 {
1114  ImageFileSourceData *data;
1115 
1116  if (src == NULL) {
1117  return NULL;
1118  }
1119 
1120  data = src->data;
1121  return data->fs;
1122 }
1123 
1124 static
1126 {
1127  ImageFileSourceData *data;
1128 
1129  data = src->data;
1130 
1131  /* close the file if it is already opened */
1132  if (data->opened) {
1133  src->class->close(src);
1134  }
1135 
1136  /* free destination if it is a link */
1137  if (S_ISLNK(data->info.st_mode)) {
1138  free(data->data.content);
1139  }
1140  iso_filesystem_unref(data->fs);
1141  if (data->parent != NULL) {
1143  }
1144 
1145  free(data->sections);
1146  free(data->name);
1147  if (data->aa_string != NULL)
1148  free(data->aa_string);
1149  free(data);
1150 }
1151 
1152 
1153 static
1154 int ifs_get_aa_string(IsoFileSource *src, unsigned char **aa_string, int flag)
1155 {
1156  size_t len;
1157  ImageFileSourceData *data;
1158 
1159  data = src->data;
1160 
1161  if ((flag & 1) || data->aa_string == NULL) {
1162  *aa_string = data->aa_string;
1163  data->aa_string = NULL;
1164  } else {
1165  len = aaip_count_bytes(data->aa_string, 0);
1166  *aa_string = calloc(len, 1);
1167  if (*aa_string == NULL)
1168  return ISO_OUT_OF_MEM;
1169  memcpy(*aa_string, data->aa_string, len);
1170  }
1171  return 1;
1172 }
1173 
1174 static
1176  IsoFileSource **new_source, int flag)
1177 {
1178  IsoFileSource *src = NULL;
1179  ImageFileSourceData *old_data, *new_data = NULL;
1180  char *new_name = NULL;
1181  struct iso_file_section *new_sections = NULL;
1182  void *new_aa_string = NULL;
1183  int i, ret;
1184 
1185  if (flag)
1186  return ISO_STREAM_NO_CLONE; /* unknown option required */
1187 
1188  old_data = (ImageFileSourceData *) old_source->data;
1189  *new_source = NULL;
1190  src = calloc(1, sizeof(IsoFileSource));
1191  if (src == NULL)
1192  goto no_mem;
1193  new_name = strdup(old_data->name);
1194  if (new_name == NULL)
1195  goto no_mem;
1196  new_data = calloc(1, sizeof(ImageFileSourceData));
1197 
1198  if (new_data == NULL)
1199  goto no_mem;
1200  if (old_data->nsections > 0) {
1201  new_sections = calloc(old_data->nsections,
1202  sizeof(struct iso_file_section));
1203  if (new_sections == NULL)
1204  goto no_mem;
1205  }
1206  ret = aaip_xinfo_cloner(old_data->aa_string, &new_aa_string, 0);
1207  if (ret < 0)
1208  goto no_mem;
1209 
1210  new_data->fs = old_data->fs;
1211 
1212  new_data->parent = old_data->parent;
1213 
1214  memcpy(&(new_data->info), &(old_data->info), sizeof(struct stat));
1215  new_data->name = new_name;
1216  new_data->sections = new_sections;
1217  new_data->nsections = old_data->nsections;
1218  for (i = 0; i < new_data->nsections; i++)
1219  memcpy(new_data->sections + i, old_data->sections + i,
1220  sizeof(struct iso_file_section));
1221  new_data->opened = old_data->opened;
1222 #ifdef Libisofs_with_zliB
1223  new_data->header_size_div4 = old_data->header_size_div4;
1224  new_data->block_size_log2 = old_data->block_size_log2;
1225  new_data->uncompressed_size = old_data->uncompressed_size;
1226 #endif
1227  new_data->data.content = NULL;
1228  new_data->aa_string = (unsigned char *) new_aa_string;
1229 
1230  src->class = old_source->class;
1231  src->refcount = 1;
1232  src->data = new_data;
1233  *new_source = src;
1234  iso_file_source_ref(new_data->parent);
1235  iso_filesystem_ref(new_data->fs);
1236  return ISO_SUCCESS;
1237 no_mem:;
1238  if (src != NULL)
1239  free((char *) src);
1240  if (new_data != NULL)
1241  free((char *) new_data);
1242  if (new_name != NULL)
1243  free(new_name);
1244  if (new_sections != NULL)
1245  free((char *) new_sections);
1246  if (new_aa_string != NULL)
1247  aaip_xinfo_func(new_aa_string, 1);
1248  return ISO_OUT_OF_MEM;
1249 }
1250 
1251 
1253 
1254  2, /* version */
1255  ifs_get_path,
1256  ifs_get_name,
1257  ifs_lstat,
1258  ifs_stat,
1259  ifs_access,
1260  ifs_open,
1261  ifs_close,
1262  ifs_read,
1263  ifs_readdir,
1264  ifs_readlink,
1266  ifs_free,
1267  ifs_lseek,
1270 
1271 };
1272 
1273 
1274 /* Used from libisofs/stream.c : iso_stream_get_src_zf() */
1275 int iso_ifs_source_get_zf(IsoFileSource *src, uint8_t zisofs_algo[2],
1276  int *header_size_div4, int *block_size_log2,
1277  uint64_t *uncompressed_size, int flag)
1278 {
1279 
1280 #ifdef Libisofs_with_zliB
1281 
1282  ImageFileSourceData *data;
1283 
1284  if (src->class != &ifs_class)
1285  return 0;
1286  data = src->data;
1287  zisofs_algo[0] = data->zisofs_algo[0];
1288  zisofs_algo[1] = data->zisofs_algo[1];
1289  *header_size_div4 = data->header_size_div4;
1290  *block_size_log2 = data->block_size_log2;
1291  *uncompressed_size = data->uncompressed_size;
1292  return 1;
1293 
1294 #else
1295 
1296  return 0;
1297 
1298 #endif /* ! Libisofs_with_zliB */
1299 }
1300 
1301 
1302 static
1304  char *str, size_t len, char **name)
1305 {
1306  int ret, name_len, i;
1307  char c, *smashed = NULL, md5[16];
1308  void *md5_context = NULL;
1309 
1310  /* Shorten so that 32 characters of MD5 fit.
1311  If shorter than 8, pad up to 8 by '_'.
1312  Smash characters to [0-9A-Za-z_.].
1313  Append MD5 of original str as hex digits.
1314  */
1315  name_len = len > 223 ? 223 : len;
1316  LIBISO_ALLOC_MEM(smashed, char, (name_len >= 8 ? name_len : 8) + 32 + 1);
1317  memcpy(smashed, str, name_len);
1318  for (; name_len < 8; name_len++)
1319  smashed[name_len] = '_';
1320  smashed[name_len] = 0;
1321  for (i = 0; i < name_len; i++) {
1322  c = smashed[i];
1323  if (c == '.' || (c >= '0' && c <= '9') ||
1324  c == '_' || (c >= 'a' && c <= 'z'))
1325  continue;
1326  smashed[i] = '_';
1327  }
1328  ret = iso_md5_start(&md5_context);
1329  if (ret != 1)
1330  goto ex;
1331  ret = iso_md5_compute(md5_context, str, len);
1332  if (ret != 1)
1333  goto ex;
1334  ret = iso_md5_end(&md5_context, md5);
1335  if (ret != 1)
1336  goto ex;
1337  for (i = 0; i < 16; i++)
1338  sprintf(smashed + i * 2 + name_len, "%2.2x",
1339  ((unsigned char *) md5)[i]);
1340  name_len += 32;
1341  smashed[name_len] = 0;
1342  *name = smashed; smashed = NULL;
1343 
1344  ret = ISO_SUCCESS;
1345 ex:
1346  LIBISO_FREE_MEM(smashed);
1347  if (md5_context != NULL)
1348  iso_md5_end(&md5_context, md5);
1349  return ret;
1350 }
1351 
1352 
1353 /**
1354  * Read a file name from a directory record, doing the needed charset
1355  * conversion
1356  */
1357 static
1358 char *get_name(_ImageFsData *fsdata, char *str, size_t len)
1359 {
1360  int ret;
1361  char *name = NULL, *from_ucs = NULL;
1362 
1363  if (strcmp(fsdata->local_charset, fsdata->input_charset)) {
1364  /* charset conversion needed */
1365  ret = strnconv(str, fsdata->input_charset, fsdata->local_charset, len,
1366  &name);
1367  if (ret == 1) {
1368  if (fsdata->iso_root_block == fsdata->svd_root_block) {
1369  /* Reading from Joliet : Check whether UTF-16 was needed */
1370  ret = strnconv(str, "UCS-2BE", fsdata->local_charset,
1371  len, &from_ucs);
1372  if (ret == 1)
1373  ret = (strcmp(name, from_ucs) == 0);
1374  if (ret != 1) {
1375  fsdata->joliet_ucs2_failures++;
1376  if (fsdata->joliet_ucs2_failures <=
1379  "Joliet filename valid only with character set UTF-16 : \"%s\"",
1380  name);
1381 
1382  }
1383  if (from_ucs != NULL)
1384  free(from_ucs);
1385  }
1386  return name;
1387  } else {
1388  ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET, ret,
1389  "Cannot convert from charset %s to %s",
1390  fsdata->input_charset, fsdata->local_charset);
1391  if (ret < 0) {
1392  return NULL; /* aborted */
1393  }
1394  /* fallback */
1395  ret = make_hopefully_unique_name(fsdata, str, len, &name);
1396  if (ret == ISO_SUCCESS)
1397  return name;
1398  return NULL;
1399  }
1400  }
1401 
1402  /* we reach here when the charset conversion is not needed */
1403 
1404  name = malloc(len + 1);
1405  if (name == NULL) {
1406  return NULL;
1407  }
1408  memcpy(name, str, len);
1409  name[len] = '\0';
1410  return name;
1411 }
1412 
1413 
1414 static
1415 int iso_rr_msg_submit(_ImageFsData *fsdata, int rr_err_bit,
1416  int errcode, int causedby, const char *msg)
1417 {
1418  int ret;
1419 
1420  if ((fsdata->rr_err_reported & (1 << rr_err_bit)) &&
1421  (fsdata->rr_err_repeated & (1 << rr_err_bit))) {
1422  if (iso_msg_is_abort(errcode))
1423  return ISO_CANCELED;
1424  return 0;
1425  }
1426  if (fsdata->rr_err_reported & (1 << rr_err_bit)) {
1427  ret = iso_msg_submit(fsdata->msgid, errcode, causedby,
1428  "MORE THAN ONCE : %s", msg);
1429  fsdata->rr_err_repeated |= (1 << rr_err_bit);
1430  } else {
1431  ret = iso_msg_submit(fsdata->msgid, errcode, causedby, "%s", msg);
1432  fsdata->rr_err_reported |= (1 << rr_err_bit);
1433  }
1434  return ret;
1435 }
1436 
1437 
1438 /**
1439  *
1440  * @param src
1441  * if not-NULL, it points to a multi-extent file returned by a previous
1442  * call to this function.
1443  * @param flag
1444  * bit0= this is the root node attribute load call
1445  * (parameter parent is not reliable for this)
1446  * bit1= this is a call caused by CL. Do not obey CL again.
1447  * @return
1448  * 2 node is still incomplete (multi-extent)
1449  * 1 success, 0 record ignored (not an error, can be a relocated dir),
1450  * < 0 error
1451  */
1452 static
1454  struct ecma119_dir_record *record,
1455  IsoFileSource **src, int flag)
1456 {
1457  int ret, ecma119_map, skip_nm = 0;
1458  struct stat atts;
1459  time_t recorded;
1460  _ImageFsData *fsdata;
1461  IsoFileSource *ifsrc = NULL;
1462  ImageFileSourceData *ifsdata = NULL;
1463 
1464  int namecont = 0; /* 1 if found a NM with CONTINUE flag */
1465  char *name = NULL;
1466 
1467  /* 1 if found a SL with CONTINUE flag,
1468  * 2 if found a component with continue flag */
1469  int linkdestcont = 0;
1470  char *linkdest = NULL;
1471 
1472  uint32_t relocated_dir = 0;
1473 
1474  unsigned char *aa_string = NULL;
1475  size_t aa_size = 0, aa_len = 0, prev_field = 0;
1476  int aa_done = 0;
1477  char *msg = NULL;
1478  uint8_t *buffer = NULL;
1479  char *cpt;
1480 
1481  int has_px = 0;
1482 
1483 #ifdef Libisofs_with_zliB
1484  uint8_t zisofs_alg[2], zisofs_hs4 = 0, zisofs_bsl2 = 0;
1485  uint64_t zisofs_usize = 0;
1486 #endif
1487 
1488  if (fs == NULL || fs->data == NULL || record == NULL || src == NULL) {
1489  ret = ISO_NULL_POINTER; goto ex;
1490  }
1491 
1492  fsdata = (_ImageFsData*)fs->data;
1493 
1494  memset(&atts, 0, sizeof(struct stat));
1495  atts.st_nlink = 1;
1496 
1497  /* Set preliminary file type */
1498  if (record->flags[0] & 0x02) {
1499  atts.st_mode = S_IFDIR;
1500  } else {
1501  atts.st_mode = S_IFREG;
1502  }
1503 
1504  /*
1505  * First of all, check for unsupported ECMA-119 features
1506  */
1507 
1508  /* check for unsupported interleaved mode */
1509  if (record->file_unit_size[0] || record->interleave_gap_size[0]) {
1511  "Unsupported image. This image has at least one file recorded "
1512  "in interleaved mode. We do not support this mode, as we think "
1513  "it is not used. If you are reading this, then we are wrong :) "
1514  "Please contact libisofs developers, so we can fix this.");
1515  {ret = ISO_UNSUPPORTED_ECMA119; goto ex;}
1516  }
1517 
1518  /* TODO #00013 : check for unsupported flags when reading a dir record */
1519 
1520  /*
1521  * If src is not-NULL, it refers to more extents of this file. We ensure
1522  * name matches, otherwise it means we are dealing with wrong image
1523  */
1524  if (*src != NULL) {
1525  ImageFileSourceData* data = (*src)->data;
1526  char* new_name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1527  if (new_name == NULL) {
1529  "Cannot retrieve file name");
1530  {ret = ISO_WRONG_ECMA119; goto ex;}
1531  }
1532  if (strcmp(new_name, data->name)) {
1534  "Multi-extent file lacks last entry.");
1535  free(new_name);
1536  {ret = ISO_WRONG_ECMA119; goto ex;}
1537  }
1538  free(new_name);
1539  }
1540 
1541  /* check for multi-extent */
1542  if (record->flags[0] & 0x80) {
1543  iso_msg_debug(fsdata->msgid, "Found multi-extent file");
1544 
1545  /*
1546  * Directory entries can only have one section (ECMA-119, 6.8.1)
1547  */
1548  if ((record->flags[0] & 0x02) || (flag & 1)) {
1550  "Directories with more than one section are not allowed.");
1551  {ret = ISO_WRONG_ECMA119; goto ex;}
1552  }
1553 
1554  if (*src == NULL) {
1555  ifsdata = calloc(1, sizeof(ImageFileSourceData));
1556  if (ifsdata == NULL) {
1557  ret = ISO_OUT_OF_MEM;
1558  goto ifs_cleanup;
1559  }
1560  ifsrc = calloc(1, sizeof(IsoFileSource));
1561  if (ifsrc == NULL) {
1562  ret = ISO_OUT_OF_MEM;
1563  goto ifs_cleanup;
1564  }
1565  ifsrc->data = ifsdata;
1566  ifsdata->name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1567  if (ifsdata->name == NULL) {
1569  "Cannot retrieve file name");
1570  ret = ISO_WRONG_ECMA119;
1571  goto ifs_cleanup;
1572  }
1573 
1574  *src = ifsrc;
1575  } else {
1576  ifsdata = (*src)->data;
1577  }
1578 
1579  /* store current extent */
1580  ifsdata->sections = realloc(ifsdata->sections,
1581  (1 + ifsdata->nsections) * sizeof(struct iso_file_section));
1582  if (ifsdata->sections == NULL) {
1583  free(ifsdata->name);
1584  ret = ISO_OUT_OF_MEM;
1585  goto ifs_cleanup;
1586  }
1587  ifsdata->sections[ifsdata->nsections].block =
1588  iso_read_bb(record->block, 4, NULL) + record->len_xa[0];
1589  ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
1590 
1591  ifsdata->info.st_size += (off_t) ifsdata->sections[ifsdata->nsections].size;
1592  ifsdata->nsections++;
1593  {ret = 2; goto ex;}
1594  }
1595 
1596  /*
1597  * The idea is to read all the RR entries (if we want to do that and RR
1598  * extensions exist on image), storing the info we want from that.
1599  * Then, we need some sanity checks.
1600  * Finally, we select what kind of node it is, and set values properly.
1601  */
1602 
1603  if (fsdata->rr) {
1604  struct susp_sys_user_entry *sue;
1605  SuspIterator *iter;
1606 
1607 
1608  iter = susp_iter_new(fsdata->src, record,
1609  fsdata->session_lba + fsdata->nblocks,
1610  fsdata->len_skp, fsdata->msgid);
1611  if (iter == NULL) {
1612  {ret = ISO_OUT_OF_MEM; goto ex;}
1613  }
1614 
1615  while ((ret = susp_iter_next(iter, &sue, 0)) > 0) {
1616 
1617  /* ignore entries from different version */
1618  if (sue->version[0] != 1 &&
1619  !(SUSP_SIG(sue, 'Z', 'F') || SUSP_SIG(sue, 'Z', '2')))
1620  continue;
1621 
1622  if (SUSP_SIG(sue, 'P', 'X')) {
1623  has_px = 1;
1624  ret = read_rr_PX(sue, &atts);
1625  if (ret < 0) {
1626  /* notify and continue */
1627  ret = iso_rr_msg_submit(fsdata, 0, ISO_WRONG_RR_WARN, ret,
1628  "Invalid PX entry");
1629  fsdata->px_ino_status |= 8;
1630  } if (ret == 2) {
1631  if (fsdata->inode_counter < atts.st_ino)
1632  fsdata->inode_counter = atts.st_ino;
1633  fsdata->px_ino_status |= 1;
1634 
1635  } else {
1636  fsdata->px_ino_status |= 2;
1637  }
1638 
1639  } else if (SUSP_SIG(sue, 'T', 'F')) {
1640  ret = read_rr_TF(sue, &atts);
1641  if (ret < 0) {
1642  /* notify and continue */
1643  ret = iso_rr_msg_submit(fsdata, 1, ISO_WRONG_RR_WARN, ret,
1644  "Invalid TF entry");
1645  }
1646  } else if (SUSP_SIG(sue, 'N', 'M')) {
1647  if (skip_nm)
1648  continue; /* in NM error bailout mode */
1649 
1650  if (name != NULL && namecont == 0) {
1651  /* ups, RR standard violation */
1652  ret = iso_rr_msg_submit(fsdata, 2, ISO_WRONG_RR_WARN, 0,
1653  "New NM entry found without previous"
1654  "CONTINUE flag. Ignored");
1655  skip_nm = 1;
1656  continue;
1657  }
1658  ret = read_rr_NM(sue, &name, &namecont);
1659  if (ret < 0) {
1660  /* notify and continue */
1661  ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret,
1662  "Invalid NM entry");
1663  continue;
1664  }
1665  if (name != NULL) if (strlen(name) > 4095) {
1666  /* Preliminarily truncate totally oversized name */
1667  ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret,
1668  "Totally oversized NM list");
1669  skip_nm = 1;
1670  continue;
1671  }
1672 
1673 #ifdef Libisofs_syslinux_tesT
1674 
1675 if (name != NULL && !namecont) {
1676  struct device syslinux_dev;
1677  struct iso_sb_info syslinux_sbi;
1678  struct fs_info syslinux_fsi;
1679  char *syslinux_name = NULL;
1680  int syslinux_name_len;
1681 
1682  syslinux_dev.src = fsdata->src;
1683  memset(&(syslinux_sbi.root), 0, 256);
1684  syslinux_sbi.do_rr = 1;
1685  syslinux_sbi.susp_skip = 0;
1686  syslinux_fsi.fs_dev = &syslinux_dev;
1687  syslinux_fsi.fs_info = &syslinux_sbi;
1688  ret = susp_rr_get_nm(&syslinux_fsi, (char *) record,
1689  &syslinux_name, &syslinux_name_len);
1690  if (ret == 1) {
1691  if (name == NULL || syslinux_name == NULL)
1692  fprintf(stderr, "################ Hoppla. NULL\n");
1693  else if(strcmp(syslinux_name, name) != 0)
1694  fprintf(stderr,
1695  "################ libisofs '%s' != '%s' susp_rr_get_nm()\n",
1696  name, syslinux_name);
1697  } else if (ret == 0) {
1698  fprintf(stderr,
1699  "################ '%s' not found by susp_rr_get_nm()\n", name);
1700  } else {
1701  fprintf(stderr, "################ 'susp_rr_get_nm() returned error\n");
1702  }
1703  if (syslinux_name != NULL)
1704  free(syslinux_name);
1705 
1706 }
1707 
1708 #endif /* Libisofs_syslinux_tesT */
1709 
1710 
1711  } else if (SUSP_SIG(sue, 'S', 'L')) {
1712  if (linkdest != NULL && linkdestcont == 0) {
1713  /* ups, RR standard violation */
1714  ret = iso_rr_msg_submit(fsdata, 4, ISO_WRONG_RR_WARN, 0,
1715  "New SL entry found without previous"
1716  "CONTINUE flag. Ignored");
1717  continue;
1718  }
1719  ret = read_rr_SL(sue, &linkdest, &linkdestcont);
1720  if (ret < 0) {
1721  /* notify and continue */
1722  ret = iso_rr_msg_submit(fsdata, 5, ISO_WRONG_RR_WARN, ret,
1723  "Invalid SL entry");
1724  }
1725  } else if (SUSP_SIG(sue, 'R', 'E')) {
1726  /*
1727  * this directory entry refers to a relocated directory.
1728  * We simply ignore it, as it will be correctly handled
1729  * when found the CL
1730  */
1731  susp_iter_free(iter);
1732  free(name);
1733  if (flag & 1) {
1734  ret = iso_rr_msg_submit(fsdata, 3, ISO_NO_ROOT_DIR, 0,
1735  "Root directory is marked by RRIP RE as relocated");
1736  ret= ISO_NO_ROOT_DIR;
1737  goto ex;
1738  }
1739  {ret = 0; goto ex;} /* it's not an error */
1740  } else if (SUSP_SIG(sue, 'C', 'L') && (flag & 2)) {
1741  ret = iso_rr_msg_submit(fsdata, 6, ISO_WRONG_RR, 0,
1742  "Invalid CL entry, found in CL target");
1743 
1744  } else if (SUSP_SIG(sue, 'C', 'L')) {
1745  /*
1746  * This entry is a placeholder for a relocated dir.
1747  * We need to ignore other entries, with the exception of NM.
1748  * Then we create a directory node that represents the
1749  * relocated dir, and iterate over its children.
1750  */
1751  relocated_dir = iso_read_bb(sue->data.CL.child_loc, 4, NULL);
1752  if (relocated_dir == 0) {
1753  ret = iso_rr_msg_submit(fsdata, 6, ISO_WRONG_RR, 0,
1754  "Invalid CL entry, no child location");
1755  break;
1756  }
1757  } else if (SUSP_SIG(sue, 'P', 'N')) {
1758  ret = read_rr_PN(sue, &atts);
1759  if (ret < 0) {
1760  /* notify and continue */
1761  ret = iso_rr_msg_submit(fsdata, 7, ISO_WRONG_RR_WARN, ret,
1762  "Invalid PN entry");
1763  }
1764  } else if (SUSP_SIG(sue, 'S', 'F')) {
1765  ret = iso_rr_msg_submit(fsdata, 8, ISO_UNSUPPORTED_RR, 0,
1766  "Sparse files not supported.");
1767  break;
1768  } else if (SUSP_SIG(sue, 'R', 'R')) {
1769  /* This was an optional flag byte in RRIP 1.09 which told the
1770  reader what other RRIP fields to expect.
1771  mkisofs emits it. We don't.
1772  */
1773  continue;
1774  } else if (SUSP_SIG(sue, 'S', 'P')) {
1775  /*
1776  * Ignore this, to prevent the hint message, if we are dealing
1777  * with root node (SP is only valid in "." of root node)
1778  */
1779  if (!(flag & 1)) {
1780  /* notify and continue */
1781  ret = iso_rr_msg_submit(fsdata, 9, ISO_WRONG_RR, 0,
1782  "SP entry found in a directory entry other "
1783  "than '.' entry of root node");
1784  }
1785  continue;
1786  } else if (SUSP_SIG(sue, 'E', 'R')) {
1787  /*
1788  * Ignore this, to prevent the hint message, if we are dealing
1789  * with root node (ER is only valid in "." of root node)
1790  */
1791  if (!(flag & 1)) {
1792  /* notify and continue */
1793  ret = iso_rr_msg_submit(fsdata, 10, ISO_WRONG_RR, 0,
1794  "ER entry found in a directory entry other "
1795  "than '.' entry of root node");
1796  }
1797  continue;
1798 
1799  /* Need to read AA resp. AL in any case so it is available for
1800  S_IRWXG mapping in case that fsdata->aaip_load != 1
1801  */
1802  } else if (SUSP_SIG(sue, 'A', 'A')) {
1803 
1804  ret = read_aaip_AA(sue, &aa_string, &aa_size, &aa_len,
1805  &prev_field, &aa_done, 0);
1806  if (ret < 0) {
1807  /* notify and continue */
1808  ret = iso_rr_msg_submit(fsdata, 11, ISO_WRONG_RR_WARN, ret,
1809  "Invalid AA entry");
1810  continue;
1811  }
1812 
1813  } else if (SUSP_SIG(sue, 'A', 'L')) {
1814 
1815  ret = read_aaip_AL(sue, &aa_string, &aa_size, &aa_len,
1816  &prev_field, &aa_done, 0);
1817  if (ret < 0) {
1818  /* notify and continue */
1819  ret = iso_rr_msg_submit(fsdata, 12, ISO_WRONG_RR_WARN, ret,
1820  "Invalid AL entry");
1821  continue;
1822  }
1823 
1824 #ifdef Libisofs_with_zliB
1825 
1826  } else if (SUSP_SIG(sue, 'Z', 'F') || SUSP_SIG(sue, 'Z', '2')) {
1827 
1828  ret = read_zisofs_ZF(sue, zisofs_alg, &zisofs_hs4,
1829  &zisofs_bsl2, &zisofs_usize, 0);
1830  if (ret < 0) {
1831 invalid_zf:
1832  /* notify and continue */
1833  ret = iso_rr_msg_submit(fsdata, 13, ISO_WRONG_RR_WARN, ret,
1834  SUSP_SIG(sue, 'Z', 'F') ?
1835  "Invalid ZF entry" :
1836  "Invalid Z2 entry");
1837  zisofs_hs4 = 0;
1838  continue;
1839  }
1840  if (zisofs_alg[0] == 'p' || zisofs_alg[1] == 'z') {
1841  if (sue->version[0] != 1)
1842  goto invalid_zf;
1843  } else if (zisofs_alg[0] == 'P' || zisofs_alg[1] == 'Z') {
1844  if (sue->version[0] != 2)
1845  goto invalid_zf;
1846  } else {
1847  ret = 0;
1848  goto invalid_zf;
1849  }
1850 
1851 #endif /* Libisofs_with_zliB */
1852 
1853 /* This message is inflationary */
1854 /*
1855  } else {
1856  ret = iso_msg_submit(fsdata->msgid, ISO_SUSP_UNHANDLED, 0,
1857  "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]);
1858 */
1859 
1860  }
1861  }
1862 
1863  susp_iter_free(iter);
1864 
1865  /* check for RR problems */
1866 
1867  if (ret < 0) {
1868  /* error was already submitted above */
1869  iso_msg_debug(fsdata->msgid, "Error parsing RR entries");
1870  } else if (!relocated_dir && atts.st_mode == (mode_t) 0 ) {
1871  ret = iso_rr_msg_submit(fsdata, 14, ISO_WRONG_RR, 0, "Mandatory "
1872  "Rock Ridge PX entry is not present or it "
1873  "contains invalid values.");
1874  } else {
1875  /* ensure both name and link dest are finished */
1876  if (namecont != 0) {
1877  ret = iso_rr_msg_submit(fsdata, 15, ISO_WRONG_RR, 0,
1878  "Incomplete Rock Ridge name, last NM entry continues");
1879  }
1880  if (linkdestcont != 0) {
1881  ret = iso_rr_msg_submit(fsdata, 16, ISO_WRONG_RR, 0,
1882  "Incomplete link destination, last SL entry continues");
1883  }
1884  }
1885 
1886  if (ret < 0) {
1887  free(name);
1888  goto ex;
1889  }
1890 
1891  /* convert name to needed charset */
1892  if (strcmp(fsdata->input_charset, fsdata->local_charset) && name) {
1893  /* we need to convert name charset */
1894  char *newname = NULL;
1895  ret = strconv(name, fsdata->input_charset, fsdata->local_charset,
1896  &newname);
1897  if (ret < 0) {
1898  /* its just a hint message */
1899  LIBISO_FREE_MEM(msg);
1900  LIBISO_ALLOC_MEM(msg, char, 160);
1901  sprintf(msg,
1902  "Cannot convert from charset %.40s to %.40s",
1903  fsdata->input_charset, fsdata->local_charset);
1905  ret, msg);
1906  free(newname);
1907  if (ret < 0) {
1908  free(name);
1909  goto ex;
1910  }
1911  } else {
1912  free(name);
1913  name = newname;
1914  }
1915  }
1916 
1917  /* convert link destination to needed charset */
1918  if (strcmp(fsdata->input_charset, fsdata->local_charset) && linkdest) {
1919  /* we need to convert name charset */
1920  char *newlinkdest = NULL;
1921  ret = strconv(linkdest, fsdata->input_charset,
1922  fsdata->local_charset, &newlinkdest);
1923  if (ret < 0) {
1924  LIBISO_FREE_MEM(msg);
1925  LIBISO_ALLOC_MEM(msg, char, 160);
1926  sprintf(msg,
1927  "Charset conversion error. Cannot convert from %.40s to %.40s",
1928  fsdata->input_charset, fsdata->local_charset);
1930  ret, msg);
1931  free(newlinkdest);
1932  if (ret < 0) {
1933  free(name);
1934  goto ex;
1935  }
1936  } else {
1937  free(linkdest);
1938  linkdest = newlinkdest;
1939  }
1940  }
1941 
1942  } else {
1943  /* RR extensions are not read / used */
1944  atts.st_gid = fsdata->gid;
1945  atts.st_uid = fsdata->uid;
1946  if (record->flags[0] & 0x02) {
1947  atts.st_mode = S_IFDIR | fsdata->dir_mode;
1948  } else {
1949  atts.st_mode = S_IFREG | fsdata->file_mode;
1950  }
1951  }
1952 
1953  if (!has_px) {
1954  fsdata->px_ino_status |= 4;
1955  }
1956 
1957  /*
1958  * if we haven't RR extensions, or no NM entry is present,
1959  * we use the name in directory record
1960  */
1961  if (!name) {
1962  size_t len;
1963 
1964  if (record->len_fi[0] == 1 && record->file_id[0] == 0) {
1965  /* "." entry, we can call this for root node, so... */
1966  if (!(atts.st_mode & S_IFDIR)) {
1967  ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1968  "Wrong ISO file name. \".\" not dir");
1969  goto ex;
1970  }
1971  } else {
1972 
1973  name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
1974  if (name == NULL) {
1975  ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1976  "Cannot retrieve file name");
1977  goto ex;
1978  }
1979 
1980  /* remove trailing version number */
1981  len = strlen(name);
1982  if (fsdata->iso_root_block == fsdata->svd_root_block)
1983  ecma119_map = fsdata->joliet_map;
1984  else
1985  ecma119_map = fsdata->ecma119_map;
1986  if (ecma119_map >= 1 && ecma119_map <= 3 &&
1987  len > 2 && name[len-2] == ';' && name[len-1] == '1') {
1988  if (len > 3 && name[len-3] == '.') {
1989  /*
1990  * the "." is mandatory, so in most cases is included only
1991  * for standard compliance
1992  */
1993  name[len-3] = '\0';
1994  } else {
1995  name[len-2] = '\0';
1996  }
1997  }
1998 
1999  if (ecma119_map == 2 || ecma119_map == 3) {
2000  for (cpt = name; *cpt != 0; cpt++) {
2001  if (ecma119_map == 2) {
2002  if (islower(*cpt))
2003  *cpt = toupper(*cpt);
2004  } else {
2005  if (isupper(*cpt))
2006  *cpt = tolower(*cpt);
2007  }
2008  }
2009  }
2010 
2011  }
2012  }
2013 
2014  if (name != NULL) {
2015  if ((int) strlen(name) > fsdata->truncate_length) {
2016  ret = iso_truncate_rr_name(fsdata->truncate_mode,
2017  fsdata->truncate_length, name, 0);
2018  if (ret < 0)
2019  goto ex;
2020  }
2021  }
2022 
2023  if (relocated_dir) {
2024 
2025  /*
2026  * We are dealing with a placeholder for a relocated dir.
2027  * Thus, we need to read attributes for this directory from the "."
2028  * entry of the relocated dir.
2029  */
2030 
2031  LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2032  ret = fsdata->src->read_block(fsdata->src, relocated_dir, buffer);
2033  if (ret < 0) {
2034  goto ex;
2035  }
2036 
2037  /* Call with flag bit1 to prevent further CL relocation */
2038  ret = iso_file_source_new_ifs(fs, parent, (struct ecma119_dir_record*)
2039  buffer, src, flag | 2);
2040  if (ret <= 0) {
2041  goto ex;
2042  }
2043 
2044  /* but the real name is the name of the placeholder */
2045  ifsdata = (ImageFileSourceData*) (*src)->data;
2046  if (ifsdata->name != NULL)
2047  free(ifsdata->name);
2048  ifsdata->name = name;
2049 
2050  {ret = ISO_SUCCESS; goto ex;}
2051  }
2052 
2053  /* Production of missing inode numbers is delayed until the image is
2054  complete. Then all nodes which shall get a new inode number will
2055  be served.
2056  */
2057 
2058  /*
2059  * if we haven't RR extensions, or a needed TF time stamp is not present,
2060  * we use plain iso recording time
2061  */
2062  recorded = iso_datetime_read_7(record->recording_time);
2063  if (atts.st_atime == (time_t) 0) {
2064  atts.st_atime = recorded;
2065  }
2066  if (atts.st_ctime == (time_t) 0) {
2067  atts.st_ctime = recorded;
2068  }
2069  if (atts.st_mtime == (time_t) 0) {
2070  atts.st_mtime = recorded;
2071  }
2072 
2073  /* the size is read from iso directory record */
2074  atts.st_size = iso_read_bb(record->length, 4, NULL);
2075 
2076  /* Fill last entries */
2077  atts.st_dev = fsdata->id;
2078  atts.st_blksize = BLOCK_SIZE;
2079  atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
2080 
2081  /* TODO #00014 : more sanity checks to ensure dir record info is valid */
2082  if (S_ISLNK(atts.st_mode) && (linkdest == NULL)) {
2083  ret = iso_rr_msg_submit(fsdata, 18, ISO_WRONG_RR, 0,
2084  "Link without destination.");
2085  free(name);
2086  goto ex;
2087  }
2088 
2089  /* ok, we can now create the file source */
2090  if (*src == NULL) {
2091  ifsdata = calloc(1, sizeof(ImageFileSourceData));
2092  if (ifsdata == NULL) {
2093  ret = ISO_OUT_OF_MEM;
2094  goto ifs_cleanup;
2095  }
2096  ifsrc = calloc(1, sizeof(IsoFileSource));
2097  if (ifsrc == NULL) {
2098  ret = ISO_OUT_OF_MEM;
2099  goto ifs_cleanup;
2100  }
2101  } else {
2102  ifsdata = (*src)->data;
2103  ifsrc = (*src);
2104  free(ifsdata->name); /* we will assign a new one */
2105  ifsdata->name = NULL;
2106  atts.st_size += (off_t)ifsdata->info.st_size;
2107  if (ifsdata->aa_string != NULL)
2108  free(ifsdata->aa_string);
2109  ifsdata->aa_string = NULL;
2110  }
2111 
2112  /* fill data */
2113  ifsdata->fs = fs;
2114  iso_filesystem_ref(fs);
2115  if (parent != NULL) {
2116  ifsdata->parent = parent;
2117  iso_file_source_ref(parent);
2118  }
2119  ifsdata->info = atts;
2120  ifsdata->name = name;
2121  ifsdata->aa_string = aa_string;
2122 
2123 #ifdef Libisofs_with_zliB
2124  if (zisofs_hs4 > 0) {
2125  ifsdata->zisofs_algo[0] = zisofs_alg[0];
2126  ifsdata->zisofs_algo[1] = zisofs_alg[1];
2127  ifsdata->header_size_div4 = zisofs_hs4;
2128  ifsdata->block_size_log2 = zisofs_bsl2;
2129  ifsdata->uncompressed_size = zisofs_usize;
2130  } else {
2131  ifsdata->header_size_div4 = 0;
2132  }
2133 #endif
2134 
2135  /* save extents */
2136  ifsdata->sections = realloc(ifsdata->sections,
2137  (1 + ifsdata->nsections) * sizeof(struct iso_file_section));
2138  if (ifsdata->sections == NULL) {
2139  free(ifsdata->name);
2140  ret = ISO_OUT_OF_MEM;
2141  goto ifs_cleanup;
2142  }
2143  ifsdata->sections[ifsdata->nsections].block =
2144  iso_read_bb(record->block, 4, NULL) + record->len_xa[0];
2145  ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
2146  ifsdata->nsections++;
2147 
2148  if (S_ISLNK(atts.st_mode)) {
2149  ifsdata->data.content = linkdest;
2150  } else if (linkdest != NULL) {
2151  ret = iso_rr_msg_submit(fsdata, 19, ISO_WRONG_RR_WARN, 0,
2152  "RRIP SL link destination with file that is not a link.");
2153  free(linkdest);
2154  linkdest = NULL;
2155  }
2156 
2157  ifsrc->class = &ifs_class;
2158  ifsrc->data = ifsdata;
2159  ifsrc->refcount = 1;
2160 
2161  *src = ifsrc;
2162  {ret = ISO_SUCCESS; goto ex;}
2163 
2164 ifs_cleanup: ;
2165  free(name);
2166  free(linkdest);
2167  free(ifsdata);
2168  free(ifsrc);
2169 
2170 ex:;
2171  LIBISO_FREE_MEM(msg);
2173  return ret;
2174 }
2175 
2176 static
2178 {
2179  int ret;
2180  _ImageFsData *data;
2181  uint8_t *buffer = NULL;
2182 
2183  if (fs == NULL || fs->data == NULL || root == NULL) {
2184  ret = ISO_NULL_POINTER; goto ex;
2185  }
2186 
2187  LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2188  data = (_ImageFsData*)fs->data;
2189 
2190  /* open the filesystem */
2191  ret = ifs_fs_open((IsoImageFilesystem*)fs);
2192  if (ret < 0) {
2193  goto ex;
2194  }
2195 
2196  /* read extend for root record */
2197  ret = data->src->read_block(data->src, data->iso_root_block, buffer);
2198  if (ret < 0) {
2200  goto ex;
2201  }
2202 
2203  /* get root attributes from "." entry */
2204  *root = NULL;
2206  (struct ecma119_dir_record*) buffer, root, 1);
2207 
2209 ex:;
2211  return ret;
2212 }
2213 
2214 /**
2215  * Find a file inside a node.
2216  *
2217  * @param file
2218  * it is not modified if requested file is not found
2219  * @return
2220  * 1 success, 0 not found, < 0 error
2221  */
2222 static
2223 int ifs_get_file(IsoFileSource *dir, const char *name, IsoFileSource **file)
2224 {
2225  int ret;
2226  IsoFileSource *src;
2227 
2228  ret = iso_file_source_open(dir);
2229  if (ret < 0) {
2230  return ret;
2231  }
2232  while ((ret = iso_file_source_readdir(dir, &src)) == 1) {
2233  char *fname = iso_file_source_get_name(src);
2234  if (!strcmp(name, fname)) {
2235  free(fname);
2236  *file = src;
2237  ret = ISO_SUCCESS;
2238  break;
2239  }
2240  free(fname);
2241  iso_file_source_unref(src);
2242  }
2243  iso_file_source_close(dir);
2244  return ret;
2245 }
2246 
2247 static
2248 int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
2249 {
2250  int ret;
2251  IsoFileSource *src = NULL;
2252  char *ptr, *brk_info, *component;
2253 
2254  if (fs == NULL || fs->data == NULL || path == NULL || file == NULL) {
2255  return ISO_NULL_POINTER;
2256  }
2257 
2258  if (path[0] != '/') {
2259  /* only absolute paths supported */
2260  return ISO_FILE_BAD_PATH;
2261  }
2262 
2263  /* open the filesystem */
2264  ret = ifs_fs_open((IsoImageFilesystem*)fs);
2265  if (ret < 0) {
2266  return ret;
2267  }
2268 
2269  ret = ifs_get_root(fs, &src);
2270  if (ret < 0) {
2271  return ret;
2272  }
2273  if (!strcmp(path, "/")) {
2274  /* we are looking for root */
2275  *file = src;
2276  ret = ISO_SUCCESS;
2277  goto get_path_exit;
2278  }
2279 
2280  ptr = strdup(path);
2281  if (ptr == NULL) {
2282  iso_file_source_unref(src);
2283  ret = ISO_OUT_OF_MEM;
2284  goto get_path_exit;
2285  }
2286 
2287  component = strtok_r(ptr, "/", &brk_info);
2288  while (component) {
2289  IsoFileSource *child = NULL;
2290 
2291  ImageFileSourceData *fdata;
2292  fdata = src->data;
2293  if (!S_ISDIR(fdata->info.st_mode)) {
2294  ret = ISO_FILE_BAD_PATH;
2295  break;
2296  }
2297 
2298  ret = ifs_get_file(src, component, &child);
2299  iso_file_source_unref(src);
2300  src = NULL;
2301  if (ret <= 0) {
2302  break;
2303  }
2304 
2305  src = child;
2306  component = strtok_r(NULL, "/", &brk_info);
2307  }
2308 
2309  free(ptr);
2310  if (ret < 0) {
2311  if (src != NULL)
2312  iso_file_source_unref(src);
2313  } else if (ret == 0) {
2314  ret = ISO_FILE_DOESNT_EXIST;
2315  } else {
2316  *file = src;
2317  }
2318 
2319  get_path_exit:;
2321  return ret;
2322 }
2323 
2324 unsigned int ifs_get_id(IsoFilesystem *fs)
2325 {
2326  return ISO_IMAGE_FS_ID;
2327 }
2328 
2329 static
2331 {
2332  _ImageFsData *data;
2333 
2334  if (fs == NULL || fs->data == NULL) {
2335  return ISO_NULL_POINTER;
2336  }
2337 
2338  data = (_ImageFsData*)fs->data;
2339 
2340  if (data->open_count == 0) {
2341  /* we need to actually open the data source */
2342  int res = data->src->open(data->src);
2343  if (res < 0) {
2344  return res;
2345  }
2346  }
2347  ++data->open_count;
2348  return ISO_SUCCESS;
2349 }
2350 
2351 static
2353 {
2354  _ImageFsData *data;
2355 
2356  if (fs == NULL || fs->data == NULL) {
2357  return ISO_NULL_POINTER;
2358  }
2359 
2360  data = (_ImageFsData*)fs->data;
2361 
2362  if (--data->open_count == 0) {
2363  /* we need to actually close the data source */
2364  return data->src->close(data->src);
2365  }
2366  return ISO_SUCCESS;
2367 }
2368 
2369 static
2371 {
2372  _ImageFsData *data;
2373 
2374  data = (_ImageFsData*) fs->data;
2375 
2376  /* close data source if already opened */
2377  if (data->open_count > 0) {
2378  data->src->close(data->src);
2379  }
2380 
2381  /* free our ref to datasource */
2382  iso_data_source_unref(data->src);
2383 
2384  /* free volume atts */
2385  free(data->volset_id);
2386  free(data->volume_id);
2387  free(data->publisher_id);
2388  free(data->data_preparer_id);
2389  free(data->system_id);
2390  free(data->application_id);
2391  free(data->copyright_file_id);
2392  free(data->abstract_file_id);
2393  free(data->biblio_file_id);
2394  free(data->creation_time);
2395  free(data->modification_time);
2396  free(data->expiration_time);
2397  free(data->effective_time);
2398  free(data->input_charset);
2399  free(data->local_charset);
2400 
2401  if(data->catcontent != NULL)
2402  free(data->catcontent);
2403 
2404  free(data);
2405 }
2406 
2407 /**
2408  * Read the SUSP system user entries of the "." entry of the root directory,
2409  * identifying when Rock Ridge extensions are being used.
2410  *
2411  * @return
2412  * 1 success, 0 ignored, < 0 error
2413  */
2414 static
2415 int read_root_susp_entries(_ImageFsData *data, uint32_t block)
2416 {
2417  int ret;
2418  unsigned char *buffer = NULL;
2419  struct ecma119_dir_record *record;
2420  struct susp_sys_user_entry *sue;
2421  SuspIterator *iter;
2422 
2423  LIBISO_ALLOC_MEM(buffer, unsigned char, 2048);
2424  ret = data->src->read_block(data->src, block, buffer);
2425  if (ret < 0) {
2426  goto ex;
2427  }
2428 
2429  /* record will be the "." directory entry for the root record */
2430  record = (struct ecma119_dir_record *)buffer;
2431 
2432 #ifdef Libisofs_syslinux_tesT
2433 
2434 {
2435  struct device syslinux_dev;
2436  struct iso_sb_info syslinux_sbi;
2437  struct fs_info syslinux_fsi;
2438 
2439  syslinux_dev.src = data->src;
2440  memcpy(&(syslinux_sbi.root), (char *) record, 256);
2441  syslinux_sbi.do_rr = 1;
2442  syslinux_sbi.susp_skip = 0;
2443  syslinux_fsi.fs_dev = &syslinux_dev;
2444  syslinux_fsi.fs_info = &syslinux_sbi;
2445 
2446  ret = susp_rr_check_signatures(&syslinux_fsi, 1);
2447  fprintf(stderr, "--------- susp_rr_check_signatures == %d , syslinux_sbi.do_rr == %d\n", ret, syslinux_sbi.do_rr);
2448 }
2449 
2450 #endif /* Libisofs_syslinux_tesT */
2451 
2452 
2453  /*
2454  * TODO #00015 : take care of CD-ROM XA discs when reading SP entry
2455  * SUSP specification claims that for CD-ROM XA the SP entry
2456  * is not at position BP 1, but at BP 15. Is that used?
2457  * In that case, we need to set info->len_skp to 15!!
2458  */
2459 
2460  iter = susp_iter_new(data->src, record, data->session_lba + data->nblocks,
2461  data->len_skp, data->msgid);
2462  if (iter == NULL) {
2463  ret = ISO_OUT_OF_MEM; goto ex;
2464  }
2465 
2466  /* first entry must be an SP system use entry */
2467  ret = susp_iter_next(iter, &sue, 1);
2468  if (ret < 0) {
2469  /* error */
2470  susp_iter_free(iter);
2471  goto ex;
2472  } else if (ret == 0 || !SUSP_SIG(sue, 'S', 'P') ) {
2473  iso_msg_debug(data->msgid, "SUSP/RR is not being used.");
2474  susp_iter_free(iter);
2475  {ret = ISO_SUCCESS; goto ex;}
2476  }
2477 
2478  /* it is a SP system use entry */
2479  if (sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
2480  || sue->data.SP.ef[0] != 0xEF) {
2481 
2482  susp_iter_free(iter);
2483  ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_SUSP, 0,
2484  "SUSP SP system use entry seems to be wrong. "
2485  "Ignoring Rock Ridge Extensions.");
2486  goto ex;
2487  }
2488 
2489  iso_msg_debug(data->msgid, "SUSP/RR is being used.");
2490 
2491  /*
2492  * The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the
2493  * number of bytes to be skipped within each System Use field.
2494  * I think this will be always 0, but given that support this standard
2495  * feature is easy...
2496  */
2497  data->len_skp = sue->data.SP.len_skp[0];
2498 
2499  /*
2500  * Ok, now search for ER entry.
2501  * Just notice that the attributes for root dir are read elsewhere.
2502  *
2503  * TODO #00016 : handle non RR ER entries
2504  *
2505  * if several ER are present, we need to identify the position of
2506  * what refers to RR, and then look for corresponding ES entry in
2507  * each directory record. I have not implemented this (it's not used,
2508  * no?), but if we finally need it, it can be easily implemented in
2509  * the iterator, transparently for the rest of the code.
2510  */
2511  while ((ret = susp_iter_next(iter, &sue, 0)) > 0) {
2512 
2513  /* ignore entries from different version */
2514  if (sue->version[0] != 1)
2515  continue;
2516 
2517  if (SUSP_SIG(sue, 'E', 'R')) {
2518  /*
2519  * it seems that Rock Ridge can be identified with any
2520  * of the following
2521  */
2522  if ( sue->data.ER.len_id[0] == 10 &&
2523  !strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) {
2524 
2525  iso_msg_debug(data->msgid,
2526  "Suitable Rock Ridge ER found. Version 1.10.");
2527  data->rr_version = RR_EXT_110;
2528 
2529  } else if ( (sue->data.ER.len_id[0] == 10 &&
2530  !strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10))
2531  || (sue->data.ER.len_id[0] == 9 &&
2532  !strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9)) ) {
2533 
2534  iso_msg_debug(data->msgid,
2535  "Suitable Rock Ridge ER found. Version 1.12.");
2536  data->rr_version = RR_EXT_112;
2537 
2538  } else if (sue->data.ER.len_id[0] == 9 &&
2539  (strncmp((char*)sue->data.ER.ext_id, "AAIP_0002", 9) == 0 ||
2540  strncmp((char*)sue->data.ER.ext_id, "AAIP_0100", 9) == 0 ||
2541  strncmp((char*)sue->data.ER.ext_id, "AAIP_0200", 9) == 0)) {
2542 
2543  /* Tolerate AAIP ER even if not supported */
2544  iso_msg_debug(data->msgid, "Suitable AAIP ER found.");
2545 
2546  if (strncmp((char*)sue->data.ER.ext_id, "AAIP_0200", 9) == 0)
2547  data->aaip_version = 200;
2548  else if (((char*)sue->data.ER.ext_id)[6] == '1')
2549  data->aaip_version = 100;
2550  else
2551  data->aaip_version = 2;
2552  if (!data->aaip_load)
2554  "Identifier for extension AAIP found, but loading is not enabled.");
2555 
2556  } else {
2557  ret = iso_msg_submit(data->msgid, ISO_SUSP_MULTIPLE_ER, 0,
2558  "Unknown Extension Signature found in ER.\n"
2559  "It will be ignored, but can cause problems in "
2560  "image reading. Please notify us about this.");
2561  if (ret < 0) {
2562  break;
2563  }
2564  }
2565  }
2566  }
2567 
2568  susp_iter_free(iter);
2569 
2570  if (ret < 0) {
2571  goto ex;
2572  }
2573 
2574  ret = ISO_SUCCESS;
2575 ex:
2577  return ret;
2578 }
2579 
2580 static
2581 int read_pvd_block(IsoDataSource *src, uint32_t block, uint8_t *buffer,
2582  uint32_t *image_size)
2583 {
2584  int ret;
2585  struct ecma119_pri_vol_desc *pvm;
2586 
2587  ret = src->read_block(src, block, buffer);
2588  if (ret < 0)
2589  return ret;
2590  pvm = (struct ecma119_pri_vol_desc *)buffer;
2591 
2592  /* sanity checks */
2593  if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
2594  || strncmp((char*)pvm->std_identifier, "CD001", 5)
2595  || pvm->file_structure_version[0] != 1) {
2596 
2597  return ISO_WRONG_PVD;
2598  }
2599  if (image_size != NULL)
2600  *image_size = iso_read_bb(pvm->vol_space_size, 4, NULL);
2601  return ISO_SUCCESS;
2602 }
2603 
2604 static
2605 int read_pvm(_ImageFsData *data, uint32_t block)
2606 {
2607  int ret;
2608  struct ecma119_pri_vol_desc *pvm;
2609  struct ecma119_dir_record *rootdr;
2610  uint8_t *buffer = NULL;
2611 
2612  LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2613  ret = read_pvd_block(data->src, block, buffer, NULL);
2614  if (ret < 0)
2615  goto ex;
2616  /* ok, it is a valid PVD */
2617  pvm = (struct ecma119_pri_vol_desc *)buffer;
2618 
2619  /* fill volume attributes */
2620  /* TODO take care of input charset */
2621  data->volset_id = iso_util_strcopy_untail((char*)pvm->vol_set_id, 128);
2622  data->volume_id = iso_util_strcopy_untail((char*)pvm->volume_id, 32);
2623  data->publisher_id =
2624  iso_util_strcopy_untail((char*)pvm->publisher_id, 128);
2625  data->data_preparer_id =
2626  iso_util_strcopy_untail((char*)pvm->data_prep_id, 128);
2627  data->system_id = iso_util_strcopy_untail((char*)pvm->system_id, 32);
2628  data->application_id =
2629  iso_util_strcopy_untail((char*)pvm->application_id, 128);
2630  data->copyright_file_id =
2631  iso_util_strcopy_untail((char*) pvm->copyright_file_id, 37);
2632  data->abstract_file_id =
2633  iso_util_strcopy_untail((char*) pvm->abstract_file_id, 37);
2634  data->biblio_file_id =
2636  if (data->copyright_file_id[0] == '_' && data->copyright_file_id[1] == 0 &&
2637  data->abstract_file_id[0] == '_' && data->abstract_file_id[1] == 0 &&
2638  data->biblio_file_id[0] == '_' && data->biblio_file_id[1] == 0) {
2639  /* This is bug output from libisofs <= 0.6.23 . The texts mean file
2640  names and should have been empty to indicate that there are no such
2641  files. It is obvious that not all three roles can be fulfilled by
2642  one file "_" so that one cannot spoil anything by assuming them
2643  empty now.
2644  */
2645  data->copyright_file_id[0] = 0;
2646  data->abstract_file_id[0] = 0;
2647  data->biblio_file_id[0] = 0;
2648  }
2649  data->creation_time =
2650  iso_util_strcopy_untail((char*) pvm->vol_creation_time, 17);
2651  data->modification_time =
2653  data->expiration_time =
2654  iso_util_strcopy_untail((char*) pvm->vol_expiration_time, 17);
2655  data->effective_time =
2656  iso_util_strcopy_untail((char*) pvm->vol_effective_time, 17);
2657 
2658  data->session_lba = 0;
2659  if (block >= 16) /* The session begins 16 blocks before the PVD */
2660  data->session_lba = block - 16;
2661  data->nblocks = iso_read_bb(pvm->vol_space_size, 4, NULL);
2662 
2663  rootdr = (struct ecma119_dir_record*) pvm->root_dir_record;
2664  data->pvd_root_block = iso_read_bb(rootdr->block, 4, NULL) +
2665  rootdr->len_xa[0];
2666 
2667  /*
2668  * TODO #00017 : take advantage of other atts of PVD
2669  * PVD has other things that could be interesting, but that don't have a
2670  * member in IsoImage, such as creation date. In a multisession disc, we
2671  * could keep the creation date and update the modification date, for
2672  * example.
2673  */
2674 
2675  ret = ISO_SUCCESS;
2676 ex:;
2678  return ret;
2679 }
2680 
2681 /**
2682  * @return
2683  * 1 success, 0 ignored, < 0 error
2684  */
2685 static
2687 {
2688  int ret, i, rx, last_done, idx, bufsize;
2689  struct el_torito_validation_entry *ve;
2690  struct el_torito_section_header *sh;
2691  struct el_torito_section_entry *entry; /* also usable as default_entry */
2692  unsigned char *buffer = NULL, *rpt;
2693 
2694  LIBISO_ALLOC_MEM(buffer, unsigned char, BLOCK_SIZE);
2695  data->num_bootimgs = 0;
2696  data->catsize = 0;
2697  ret = data->src->read_block(data->src, block, buffer);
2698  if (ret < 0) {
2699  goto ex;
2700  }
2701 
2702  ve = (struct el_torito_validation_entry*)buffer;
2703 
2704  /* check if it is a valid catalog (TODO: check also the checksum)*/
2705  if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55)
2706  || (ve->key_byte2[0] != 0xAA) ) {
2708  "Wrong or damaged El-Torito Catalog. El-Torito info "
2709  "will be ignored.");
2710  {ret = ISO_WRONG_EL_TORITO; goto ex;}
2711  }
2712 
2713  /* ok, once we are here we assume it is a valid catalog */
2714 
2715  /* parse the default entry */
2716  entry = (struct el_torito_section_entry *)(buffer + 32);
2717 
2718  data->eltorito = 1;
2719  /* The Default Entry is declared mandatory */
2720  data->catsize = 64;
2721  data->num_bootimgs = 1;
2722  data->platform_ids[0] = ve->platform_id[0];
2723  memcpy(data->id_strings[0], ve->id_string, 24);
2724  memset(data->id_strings[0] + 24, 0, 4);
2725  data->boot_flags[0] = entry->boot_indicator[0] ? 1 : 0;
2726  data->media_types[0] = entry->boot_media_type[0];
2727  data->partition_types[0] = entry->system_type[0];
2728  data->load_segs[0] = iso_read_lsb(entry->load_seg, 2);
2729  data->load_sizes[0] = iso_read_lsb(entry->sec_count, 2);
2730  data->bootblocks[0] = iso_read_lsb(entry->block, 4);
2731  /* The Default Entry has no selection criterion */
2732  memset(data->selection_crits[0], 0, 20);
2733 
2734  /* Read eventual more entries from the boot catalog */
2735  last_done = 0;
2736  for (rx = 64; (buffer[rx] & 0xfe) == 0x90 && !last_done; rx += 32) {
2737  last_done = buffer[rx] & 1;
2738  /* Read Section Header */
2739 
2740  /* >>> ts B10703 : load a new buffer if needed */;
2741 
2742  sh = (struct el_torito_section_header *) (buffer + rx);
2743  data->catsize += 32;
2744  for (i = 0; i < sh->num_entries[0]; i++) {
2745  rx += 32;
2746  data->catsize += 32;
2747 
2748  /* >>> ts B10703 : load a new buffer if needed */;
2749 
2750  if (data->num_bootimgs >= Libisofs_max_boot_imageS) {
2751 
2752  /* >>> ts B10703 : need to continue rather than abort */;
2753 
2755  "Too many boot images found. List truncated.");
2756  goto after_bootblocks;
2757  }
2758  /* Read bootblock from section entry */
2759  entry = (struct el_torito_section_entry *)(buffer + rx);
2760  idx = data->num_bootimgs;
2761  data->platform_ids[idx] = sh->platform_id[0];
2762  memcpy(data->id_strings[idx], sh->id_string, 28);
2763  data->boot_flags[idx] = entry->boot_indicator[0] ? 1 : 0;
2764  data->media_types[idx] = entry->boot_media_type[0];
2765  data->partition_types[idx] = entry->system_type[0];
2766  data->load_segs[idx] = iso_read_lsb(entry->load_seg, 2);
2767  data->load_sizes[idx] = iso_read_lsb(entry->sec_count, 2);
2768  data->bootblocks[idx] = iso_read_lsb(entry->block, 4);
2769  data->selection_crits[idx][0] = entry->selec_criteria[0];
2770  memcpy(data->selection_crits[idx] + 1, entry->vendor_sc, 19);
2771  data->num_bootimgs++;
2772  }
2773  }
2774 after_bootblocks:;
2775  if(data->catsize > 0) {
2776  if(data->catcontent != NULL)
2777  free(data->catcontent);
2778  if(data->catsize > 10 * BLOCK_SIZE)
2779  data->catsize = 10 * BLOCK_SIZE;
2780  bufsize = data->catsize;
2781  if (bufsize % BLOCK_SIZE)
2782  bufsize += BLOCK_SIZE - (bufsize % BLOCK_SIZE);
2783  data->catcontent = calloc(bufsize , 1);
2784  if(data->catcontent == NULL) {
2785  data->catsize = 0;
2786  ret = ISO_OUT_OF_MEM;
2787  goto ex;
2788  }
2789  for(rx = 0; rx < bufsize; rx += BLOCK_SIZE) {
2790  rpt = (unsigned char *) (data->catcontent + rx);
2791  ret = data->src->read_block(data->src, block + rx / BLOCK_SIZE, rpt);
2792  if (ret < 0)
2793  goto ex;
2794  }
2795  }
2796  ret = ISO_SUCCESS;
2797 ex:;
2799  return ret;
2800 }
2801 
2802 
2803 /*
2804  @return 1= ok, checked, go on with loading
2805  2= no checksum tags found, go on with loading
2806  <0= libisofs error
2807  especially ISO_SB_TREE_CORRUPTED
2808 */
2809 static
2810 int iso_src_check_sb_tree(IsoDataSource *src, uint32_t start_lba, int flag)
2811 {
2812  int tag_type, ret;
2813  char *block = NULL, md5[16];
2814  int desired = (1 << 2);
2815  void *ctx = NULL;
2816  uint32_t next_tag = 0, i;
2817 
2818  LIBISO_ALLOC_MEM(block, char, 2048);
2819  ret = iso_md5_start(&ctx);
2820  if (ret < 0)
2821  goto ex;
2822  if (start_lba == 0)
2823  desired |= (1 << 4);
2824  for (i = 0; i < 32; i++) {
2825  ret = src->read_block(src, start_lba + i, (uint8_t *) block);
2826  if (ret < 0)
2827  goto ex;
2828  ret = 0;
2829  if (i >= 16)
2830  ret = iso_util_eval_md5_tag(block, desired, start_lba + i,
2831  ctx, start_lba, &tag_type, &next_tag, 0);
2832  iso_md5_compute(ctx, block, 2048);
2833  if (ret == (int) ISO_MD5_TAG_COPIED) {/* growing without emulated TOC */
2834  ret = 2;
2835  goto ex;
2836  }
2837  if (ret == (int) ISO_MD5_AREA_CORRUPTED ||
2838  ret == (int) ISO_MD5_TAG_MISMATCH)
2839  ret = ISO_SB_TREE_CORRUPTED;
2840  if (ret < 0)
2841  goto ex;
2842  if (ret == 1)
2843  break;
2844  }
2845  if (i >= 32) {
2846  ret = 2;
2847  goto ex;
2848  }
2849  if (tag_type == 4) {
2850  /* Relocated Superblock: restart checking at real session start */
2851  if (next_tag < 32) {
2852  /* Non plausible session_start address */
2853  ret = ISO_SB_TREE_CORRUPTED;
2854  iso_msg_submit(-1, ret, 0, NULL);
2855  goto ex;
2856  }
2857  /* Check real session */
2858  ret = iso_src_check_sb_tree(src, next_tag, 0);
2859  goto ex;
2860  }
2861 
2862  /* Go on with tree */
2863  for (i++; start_lba + i <= next_tag; i++) {
2864  ret = src->read_block(src, start_lba + i, (uint8_t *) block);
2865  if (ret < 0)
2866  goto ex;
2867  if (start_lba + i < next_tag)
2868  iso_md5_compute(ctx, block, 2048);
2869  }
2870  ret = iso_util_eval_md5_tag(block, (1 << 3), start_lba + i - 1,
2871  ctx, start_lba, &tag_type, &next_tag, 0);
2872  if (ret == (int) ISO_MD5_AREA_CORRUPTED ||
2873  ret == (int) ISO_MD5_TAG_MISMATCH)
2874  ret = ISO_SB_TREE_CORRUPTED;
2875  if (ret < 0)
2876  goto ex;
2877 
2878  ret = 1;
2879 ex:
2880  if (ctx != NULL)
2881  iso_md5_end(&ctx, md5);
2883  return ret;
2884 }
2885 
2886 
2888  int msgid, IsoImageFilesystem **fs)
2889 {
2890  int ret, i;
2891  uint32_t block;
2892  IsoImageFilesystem *ifs;
2893  _ImageFsData *data;
2894  uint8_t *buffer = NULL;
2895 
2896  if (src == NULL || opts == NULL || fs == NULL) {
2897  ret = ISO_NULL_POINTER; goto ex;
2898  }
2899 
2900  LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
2901  data = calloc(1, sizeof(_ImageFsData));
2902  if (data == NULL) {
2903  ret = ISO_OUT_OF_MEM; goto ex;
2904  }
2905 
2906  ifs = calloc(1, sizeof(IsoImageFilesystem));
2907  if (ifs == NULL) {
2908  free(data);
2909  {ret = ISO_OUT_OF_MEM; goto ex;}
2910  }
2911  data->rr = RR_EXT_NO;
2912 
2913  /* get our ref to IsoDataSource */
2914  data->src = src;
2915  iso_data_source_ref(src);
2916  data->open_count = 0;
2917 
2918  data->catcontent = NULL;
2919 
2920  /* get an id for the filesystem */
2921  data->id = ++fs_dev_id;
2922 
2923  /* fill data from opts */
2924  data->gid = opts->gid;
2925  data->uid = opts->uid;
2926  data->file_mode = opts->file_mode & ~S_IFMT;
2927  data->dir_mode = opts->dir_mode & ~S_IFMT;
2928  data->msgid = msgid;
2929  data->aaip_load = !opts->noaaip;
2930  if (opts->nomd5 == 0)
2931  data->md5_load = 1;
2932  else if (opts->nomd5 == 2)
2933  data->md5_load = 2;
2934  else
2935  data->md5_load = 0;
2936  data->aaip_version = -1;
2937  data->make_new_ino = opts->make_new_ino;
2938  data->num_bootimgs = 0;
2939  for (i = 0; i < Libisofs_max_boot_imageS; i++)
2940  data->bootblocks[i] = 0;
2941  data->inode_counter = 0;
2942  data->px_ino_status = 0;
2943  data->rr_err_reported = 0;
2944  data->rr_err_repeated = 0;
2945  data->joliet_ucs2_failures = 0;
2946 
2947 
2948  data->local_charset = strdup(iso_get_local_charset(0));
2949  if (data->local_charset == NULL) {
2950  ret = ISO_OUT_OF_MEM;
2951  LIBISO_FREE_MEM(data);
2952  data = NULL;
2953  goto fs_cleanup;
2954  }
2955 
2956  memcpy(ifs->type, "iso ", 4);
2957  ifs->data = data;
2958  ifs->refcount = 1;
2959  ifs->version = 0;
2960  ifs->get_root = ifs_get_root;
2962  ifs->get_id = ifs_get_id;
2963  ifs->open = ifs_fs_open;
2964  ifs->close = ifs_fs_close;
2965  ifs->free = ifs_fs_free;
2966 
2967  /* read Volume Descriptors and ensure it is a valid image */
2968  if (data->md5_load == 1) {
2969  /* From opts->block on : check for superblock and tree tags */;
2970  ret = iso_src_check_sb_tree(src, opts->block, 0);
2971  if (ret < 0) {
2972  iso_msgs_submit(0,
2973  "Image loading aborted due to MD5 mismatch of image tree data",
2974  0, "FAILURE", 0);
2975  iso_msgs_submit(0,
2976  "You may override this refusal by disabling MD5 checking",
2977  0, "HINT", 0);
2978  goto fs_cleanup;
2979  }
2980  }
2981 
2982  /* 1. first, open the filesystem */
2983  ifs_fs_open(ifs);
2984 
2985  /* 2. read primary volume description */
2986  ret = read_pvm(data, opts->block + 16);
2987  if (ret < 0) {
2988  goto fs_cleanup;
2989  }
2990 
2991  /* 3. read next volume descriptors */
2992  block = opts->block + 17;
2993  do {
2994  ret = src->read_block(src, block, buffer);
2995  if (ret < 0) {
2996  /* cleanup and exit */
2997  goto fs_cleanup;
2998  }
2999  switch (buffer[0]) {
3000  case 0:
3001  /* boot record */
3002  {
3003  struct ecma119_boot_rec_vol_desc *vol;
3004  vol = (struct ecma119_boot_rec_vol_desc*)buffer;
3005 
3006  /* some sanity checks */
3007  if (strncmp((char*)vol->std_identifier, "CD001", 5)
3008  || vol->vol_desc_version[0] != 1
3009  || strncmp((char*)vol->boot_sys_id,
3010  "EL TORITO SPECIFICATION", 23)) {
3011  iso_msg_submit(data->msgid,
3013  "Unsupported Boot Vol. Desc. Only El-Torito "
3014  "Specification, Version 1.0 Volume "
3015  "Descriptors are supported. Ignoring boot info");
3016  } else {
3017  data->catblock = iso_read_lsb(vol->boot_catalog, 4);
3018  ret = read_el_torito_boot_catalog(data, data->catblock);
3019  if (ret < 0 && ret != (int) ISO_UNSUPPORTED_EL_TORITO &&
3020  ret != (int) ISO_WRONG_EL_TORITO) {
3021  goto fs_cleanup;
3022  }
3023  }
3024  }
3025  break;
3026  case 2:
3027  /* supplementary volume descritor */
3028  {
3029  struct ecma119_sup_vol_desc *sup;
3030  struct ecma119_dir_record *root;
3031 
3032  sup = (struct ecma119_sup_vol_desc*)buffer;
3033  if (sup->esc_sequences[0] == 0x25 &&
3034  sup->esc_sequences[1] == 0x2F &&
3035  (sup->esc_sequences[2] == 0x40 ||
3036  sup->esc_sequences[2] == 0x43 ||
3037  sup->esc_sequences[2] == 0x45) ) {
3038 
3039  /* it's a Joliet Sup. Vol. Desc. */
3040  iso_msg_debug(data->msgid, "Found Joliet extensions");
3041  data->joliet = 1;
3042  root = (struct ecma119_dir_record*)sup->root_dir_record;
3043  data->svd_root_block = iso_read_bb(root->block, 4, NULL) +
3044  root->len_xa[0];
3045  /* TODO #00019 : set IsoImage attribs from Joliet SVD? */
3046  /* TODO #00020 : handle RR info in Joliet tree */
3047  } else if (sup->vol_desc_version[0] == 2) {
3048  /*
3049  * It is an Enhanced Volume Descriptor, image is an
3050  * ISO 9660:1999
3051  */
3052  iso_msg_debug(data->msgid, "Found ISO 9660:1999");
3053  data->iso1999 = 1;
3054  root = (struct ecma119_dir_record*)sup->root_dir_record;
3055  data->evd_root_block = iso_read_bb(root->block, 4, NULL) +
3056  root->len_xa[0];
3057  /* TODO #00021 : handle RR info in ISO 9660:1999 tree */
3058  } else {
3059  ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
3060  "Unsupported Sup. Vol. Desc found.");
3061  if (ret < 0) {
3062  goto fs_cleanup;
3063  }
3064  }
3065  }
3066  break;
3067  case 255:
3068  /*
3069  * volume set terminator
3070  * ignore, as it's checked in loop end condition
3071  */
3072  break;
3073  default:
3075  "Ignoring Volume descriptor %x.", buffer[0]);
3076  break;
3077  }
3078  block++;
3079  } while (buffer[0] != 255);
3080 
3081  /* 4. check if RR extensions are being used */
3082  ret = read_root_susp_entries(data, data->pvd_root_block);
3083  if (ret < 0)
3084  goto fs_cleanup;
3085  if (!opts->norock)
3086  data->rr = data->rr_version;
3087 
3088  /* select what tree to read */
3089  if (data->rr) {
3090  /* RR extensions are available */
3091  if (!opts->nojoliet && opts->preferjoliet && data->joliet) {
3092  /* if user prefers joliet, that is used */
3093  iso_msg_debug(data->msgid, "Reading Joliet extensions.");
3094  /* Although Joliet prescribes UCS-2BE, interpret names by its
3095  superset UTF-16BE in order to avoid conversion failures.
3096  */
3097  data->input_charset = strdup("UTF-16BE");
3098  data->rr = RR_EXT_NO;
3099  data->iso_root_block = data->svd_root_block;
3100  } else {
3101  /* RR will be used */
3102  iso_msg_debug(data->msgid, "Reading Rock Ridge extensions.");
3103  data->iso_root_block = data->pvd_root_block;
3104  }
3105  } else {
3106  /* RR extensions are not available */
3107  if (!opts->nojoliet && data->joliet) {
3108  /* joliet will be used */
3109  iso_msg_debug(data->msgid, "Reading Joliet extensions.");
3110  data->input_charset = strdup("UTF-16BE");
3111  data->iso_root_block = data->svd_root_block;
3112  } else if (!opts->noiso1999 && data->iso1999) {
3113  /* we will read ISO 9660:1999 */
3114  iso_msg_debug(data->msgid, "Reading ISO-9660:1999 tree.");
3115  data->iso_root_block = data->evd_root_block;
3116  } else {
3117  /* default to plain iso */
3118  iso_msg_debug(data->msgid, "Reading plain ISO-9660 tree.");
3119  data->iso_root_block = data->pvd_root_block;
3120  data->input_charset = strdup("ASCII");
3121  }
3122  }
3123  data->truncate_mode = opts->truncate_mode;
3124  data->truncate_length = opts->truncate_length;
3125  data->ecma119_map = opts->ecma119_map;
3126  data->joliet_map = opts->joliet_map;
3127 
3128  if (data->input_charset == NULL) {
3129  if (opts->input_charset != NULL) {
3130  data->input_charset = strdup(opts->input_charset);
3131  } else {
3132  data->input_charset = strdup(data->local_charset);
3133  }
3134  }
3135  if (data->input_charset == NULL) {
3136  ret = ISO_OUT_OF_MEM;
3137  goto fs_cleanup;
3138  }
3139  data->auto_input_charset = opts->auto_input_charset;
3140 
3141  /* and finally return. Note that we keep the DataSource opened */
3142 
3143  *fs = ifs;
3144  {ret = ISO_SUCCESS; goto ex;}
3145 
3146 fs_cleanup: ;
3147  ifs_fs_free(ifs);
3148  free(ifs);
3149 
3150 ex:;
3152  return ret;
3153 }
3154 
3155 
3156 /* Take over aa_string from file source to node or discard it after making
3157  the necessary change in node->mode group permissions.
3158  node->mode must already be set.
3159 */
3160 static
3161 int src_aa_to_node(IsoFileSource *src, IsoNode *node, int flag)
3162 {
3163  int ret;
3164  unsigned char *aa_string;
3165  ImageFileSourceData *data;
3166  _ImageFsData *fsdata;
3167  char *a_text = NULL, *d_text = NULL;
3168 
3169  data = (ImageFileSourceData*)src->data;
3170  fsdata = data->fs->data;
3171 
3172  /* Obtain ownership of eventual AAIP string */
3173  ret = iso_file_source_get_aa_string(src, &aa_string, 1);
3174  if (ret != 1 || aa_string == NULL)
3175  return 1;
3176  if (fsdata->aaip_load == 1) {
3177  /* Attach aa_string to node */
3178  ret = iso_node_add_xinfo(node, aaip_xinfo_func, aa_string);
3179  if (ret < 0)
3180  return ret;
3181  } else {
3182  /* Look for ACL and perform S_IRWXG mapping */
3183  iso_aa_get_acl_text(aa_string, node->mode, &a_text, &d_text, 16);
3184  if (a_text != NULL)
3185  aaip_cleanout_st_mode(a_text, &(node->mode), 4 | 16);
3186  /* Dispose ACL a_text and d_text */
3187  iso_aa_get_acl_text(aa_string, node->mode, &a_text, &d_text, 1 << 15);
3188  /* Dispose aa_string */
3189  aaip_xinfo_func(aa_string, 1);
3190  }
3191  return 1;
3192 }
3193 
3194 
3195 static
3197  IsoFileSource *src, char *in_name,
3198  IsoNode **node)
3199 {
3200  int ret, idx, to_copy;
3201  struct stat info;
3202  IsoNode *new = NULL;
3203  IsoBoot *bootcat;
3204  char *name = NULL;
3205  char *dest = NULL;
3206  ImageFileSourceData *data;
3207  _ImageFsData *fsdata;
3208 
3209 #ifdef Libisofs_with_zliB
3210  /* Intimate friendship with this function in filters/zisofs.c */
3211  int ziso_add_osiz_filter(IsoFile *file, uint8_t zisofs_algo[2],
3212  uint8_t header_size_div4, uint8_t block_size_log2,
3213  uint64_t uncompressed_size, int flag);
3214 #endif /* Libisofs_with_zliB */
3215 
3216 
3217  if (builder == NULL || src == NULL || node == NULL || src->data == NULL) {
3218  ret = ISO_NULL_POINTER; goto ex;
3219  }
3220 
3221  data = (ImageFileSourceData*)src->data;
3222  fsdata = data->fs->data;
3223 
3224  if (in_name == NULL) {
3225  name = iso_file_source_get_name(src);
3226  } else {
3227  name = strdup(in_name);
3228  if (name == NULL) {
3229  ret = ISO_OUT_OF_MEM; goto ex;
3230  }
3231  }
3232 
3233  /* get info about source */
3234  ret = iso_file_source_lstat(src, &info);
3235  if (ret < 0) {
3236  goto ex;
3237  }
3238 
3239  switch (info.st_mode & S_IFMT) {
3240  case S_IFREG:
3241  {
3242  /* source is a regular file */
3243 
3244  /* El-Torito images have only one section */
3245  if (fsdata->eltorito && data->sections[0].block == fsdata->catblock) {
3246 
3247  if (image->bootcat->node != NULL) {
3248  ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
3249  "More than one catalog node has been found. "
3250  "We can continue, but that could lead to "
3251  "problems");
3252  if (ret < 0)
3253  goto ex;
3254  iso_node_unref((IsoNode*)image->bootcat->node);
3255  }
3256 
3257  /* we create a placeholder for the catalog instead of
3258  * a regular file */
3259  new = calloc(1, sizeof(IsoBoot));
3260  if (new == NULL) {
3261  ret = ISO_OUT_OF_MEM; goto ex;
3262  }
3263  bootcat = (IsoBoot *) new;
3264  bootcat->lba = data->sections[0].block;
3265  bootcat->size = info.st_size;
3266  if (bootcat->size > 10 * BLOCK_SIZE)
3267  bootcat->size = 10 * BLOCK_SIZE;
3268  bootcat->content = NULL;
3269  if (bootcat->size > 0) {
3270  bootcat->content = calloc(1, bootcat->size);
3271  if (bootcat->content == NULL) {
3272  ret = ISO_OUT_OF_MEM; goto ex;
3273  }
3274  to_copy = bootcat->size;
3275  if (bootcat->size > fsdata->catsize)
3276  to_copy = fsdata->catsize;
3277  memcpy(bootcat->content, fsdata->catcontent, to_copy);
3278  }
3279 
3280  /* and set the image node */
3281  image->bootcat->node = bootcat;
3282  new->type = LIBISO_BOOT;
3283  new->refcount = 1;
3284  } else {
3285  IsoStream *stream;
3286  IsoFile *file;
3287 
3288  ret = iso_file_source_stream_new(src, &stream);
3289  if (ret < 0)
3290  goto ex;
3291 
3292  /* take a ref to the src, as stream has taken our ref */
3293  iso_file_source_ref(src);
3294 
3295  file = calloc(1, sizeof(IsoFile));
3296  if (file == NULL) {
3297  iso_stream_unref(stream);
3298  {ret = ISO_OUT_OF_MEM; goto ex;}
3299  }
3300 
3301  /* mark file as from old session */
3302  file->from_old_session = 1;
3303 
3304  /*
3305  * and we set the sort weight based on the block on image, to
3306  * improve performance on image modifying.
3307  *
3308  * This was too obtrusive because it occupied the highest
3309  * possible weight ranks:
3310  * file->sort_weight = INT_MAX - data->sections[0].block;
3311  *
3312  * So a try to be more nice and rely on caching with tiles
3313  * of at least 16 blocks. This occupies a range within
3314  * the interval of 1 to 2 exp 28 = 268,435,456.
3315  * (Dividing each number separately saves from integer
3316  * rollover problems.)
3317  */
3318  file->sort_weight =
3319  fsdata->nblocks / 16 - data->sections[0].block / 16 + 1;
3320 
3321  file->stream = stream;
3322  file->node.type = LIBISO_FILE;
3323 
3324 #ifdef Libisofs_with_zliB
3325 
3326  if (data->header_size_div4 > 0) {
3327  ret = ziso_add_osiz_filter(file, data->zisofs_algo,
3328  data->header_size_div4,
3329  data->block_size_log2,
3330  data->uncompressed_size, 0);
3331  if (ret < 0) {
3332  iso_stream_unref(stream);
3333  goto ex;
3334  }
3335  }
3336 
3337 #endif /* Libisofs_with_zliB */
3338 
3339  new = (IsoNode*) file;
3340  new->refcount = 0;
3341 
3342  if (data->sections[0].size > 0) {
3343  for (idx = 0; idx < fsdata->num_bootimgs; idx++)
3344  if (fsdata->eltorito && data->sections[0].block ==
3345  fsdata->bootblocks[idx])
3346  break;
3347  } else {
3348  idx = fsdata->num_bootimgs;
3349  }
3350  if (idx < fsdata->num_bootimgs) {
3351  /* it is boot image node */
3352  if (image->bootcat->bootimages[idx]->image != NULL) {
3353  /* idx is already occupied, try to find unoccupied one
3354  which has the same block address.
3355  */
3356  for (; idx < fsdata->num_bootimgs; idx++)
3357  if (fsdata->eltorito && data->sections[0].block ==
3358  fsdata->bootblocks[idx] &&
3359  image->bootcat->bootimages[idx]->image == NULL)
3360  break;
3361  }
3362  if (idx >= fsdata->num_bootimgs) {
3363  ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
3364  "More than one ISO node has been found for the same boot image.");
3365  if (ret < 0) {
3366  iso_stream_unref(stream);
3367  goto ex;
3368  }
3369  } else {
3370  /* and set the image node */
3371  image->bootcat->bootimages[idx]->image = file;
3372  new->refcount++;
3373  }
3374  }
3375  }
3376  }
3377  break;
3378  case S_IFDIR:
3379  {
3380  /* source is a directory */
3381  new = calloc(1, sizeof(IsoDir));
3382  if (new == NULL) {
3383  {ret = ISO_OUT_OF_MEM; goto ex;}
3384  }
3385  new->type = LIBISO_DIR;
3386  new->refcount = 0;
3387  }
3388  break;
3389  case S_IFLNK:
3390  {
3391  /* source is a symbolic link */
3392  IsoSymlink *link;
3393 
3395 
3397  if (ret < 0) {
3398  goto ex;
3399  }
3400  link = calloc(1, sizeof(IsoSymlink));
3401  if (link == NULL) {
3402  {ret = ISO_OUT_OF_MEM; goto ex;}
3403  }
3404  link->dest = strdup(dest);
3405  link->node.type = LIBISO_SYMLINK;
3406  link->fs_id = ISO_IMAGE_FS_ID;
3407  link->st_dev = info.st_dev;
3408  link->st_ino = info.st_ino;
3409  new = (IsoNode*) link;
3410  new->refcount = 0;
3411  }
3412  break;
3413  case S_IFSOCK:
3414  case S_IFBLK:
3415  case S_IFCHR:
3416  case S_IFIFO:
3417  {
3418  /* source is an special file */
3419  IsoSpecial *special;
3420  special = calloc(1, sizeof(IsoSpecial));
3421  if (special == NULL) {
3422  ret = ISO_OUT_OF_MEM; goto ex;
3423  }
3424  special->dev = info.st_rdev;
3425  special->node.type = LIBISO_SPECIAL;
3426  special->fs_id = ISO_IMAGE_FS_ID;
3427  special->st_dev = info.st_dev;
3428  special->st_ino = info.st_ino;
3429  new = (IsoNode*) special;
3430  new->refcount = 0;
3431  }
3432  break;
3433  default:
3434  ret = ISO_BAD_ISO_FILETYPE; goto ex;
3435  }
3436  /* fill fields */
3437  new->refcount++;
3438  new->name = name; name = NULL;
3439  new->mode = info.st_mode;
3440  new->uid = info.st_uid;
3441  new->gid = info.st_gid;
3442  new->atime = info.st_atime;
3443  new->mtime = info.st_mtime;
3444  new->ctime = info.st_ctime;
3445 
3446  new->hidden = 0;
3447 
3448  new->parent = NULL;
3449  new->next = NULL;
3450 
3451  ret = src_aa_to_node(src, new, 0);
3452  if (ret < 0) {
3453  goto ex;
3454  }
3455 
3456  /* Attach ino as xinfo if valid and no IsoStream is involved */
3457  if (info.st_ino != 0 && (info.st_mode & S_IFMT) != S_IFREG &&
3458  !fsdata->make_new_ino) {
3459  ret = iso_node_set_ino(new, info.st_ino, 0);
3460  if (ret < 0)
3461  goto ex;
3462  }
3463 
3464  *node = new; new = NULL;
3465  {ret = ISO_SUCCESS; goto ex;}
3466 
3467 ex:;
3468  if (name != NULL)
3469  free(name);
3470  if (new != NULL)
3471  iso_node_unref(new);
3472  LIBISO_FREE_MEM(dest);
3473  return ret;
3474 }
3475 
3476 /**
3477  * Create a new builder, that is exactly a copy of an old builder, but where
3478  * create_node() function has been replaced by image_builder_create_node.
3479  */
3480 static
3482 {
3483  IsoNodeBuilder *b;
3484 
3485  if (builder == NULL) {
3486  return ISO_NULL_POINTER;
3487  }
3488 
3489  b = malloc(sizeof(IsoNodeBuilder));
3490  if (b == NULL) {
3491  return ISO_OUT_OF_MEM;
3492  }
3493 
3494  b->refcount = 1;
3497  b->create_file = old->create_file;
3499  b->free = old->free;
3500 
3501  *builder = b;
3502  return ISO_SUCCESS;
3503 }
3504 
3505 /**
3506  * Create a file source to access the El-Torito boot image, when it is not
3507  * accessible from the ISO filesystem.
3508  */
3509 static
3511  IsoFileSource **src)
3512 {
3513  int ret;
3514  struct stat atts;
3515  _ImageFsData *fsdata;
3516  IsoFileSource *ifsrc = NULL;
3517  ImageFileSourceData *ifsdata = NULL;
3518 
3519  if (fs == NULL || fs->data == NULL || src == NULL) {
3520  return ISO_NULL_POINTER;
3521  }
3522 
3523  fsdata = (_ImageFsData*)fs->data;
3524 
3525  memset(&atts, 0, sizeof(struct stat));
3526  atts.st_mode = S_IFREG;
3527  atts.st_ino = img_give_ino_number(image, 0);
3528  atts.st_nlink = 1;
3529 
3530  /*
3531  * this is the greater problem. We don't know the size. For now, we
3532  * just use a single block of data. In a future, maybe we could figure out
3533  * a better idea. Another alternative is to use several blocks, that way
3534  * is less probable that we throw out valid data.
3535  */
3536  atts.st_size = (off_t)BLOCK_SIZE;
3537 
3538  /* Fill last entries */
3539  atts.st_dev = fsdata->id;
3540  atts.st_blksize = BLOCK_SIZE;
3541  atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
3542 
3543  /* ok, we can now create the file source */
3544  ifsdata = calloc(1, sizeof(ImageFileSourceData));
3545  if (ifsdata == NULL) {
3546  ret = ISO_OUT_OF_MEM;
3547  goto boot_fs_cleanup;
3548  }
3549  ifsrc = calloc(1, sizeof(IsoFileSource));
3550  if (ifsrc == NULL) {
3551  ret = ISO_OUT_OF_MEM;
3552  goto boot_fs_cleanup;
3553  }
3554 
3555  ifsdata->sections = malloc(sizeof(struct iso_file_section));
3556  if (ifsdata->sections == NULL) {
3557  ret = ISO_OUT_OF_MEM;
3558  goto boot_fs_cleanup;
3559  }
3560 
3561  /* fill data */
3562  ifsdata->fs = fs;
3563  iso_filesystem_ref(fs);
3564  ifsdata->parent = NULL;
3565  ifsdata->info = atts;
3566  ifsdata->name = NULL;
3567  ifsdata->sections[0].block = fsdata->bootblocks[idx];
3568  ifsdata->sections[0].size = BLOCK_SIZE;
3569  ifsdata->nsections = 1;
3570 
3571  ifsrc->class = &ifs_class;
3572  ifsrc->data = ifsdata;
3573  ifsrc->refcount = 1;
3574 
3575  *src = ifsrc;
3576  return ISO_SUCCESS;
3577 
3578 boot_fs_cleanup: ;
3579  free(ifsdata);
3580  free(ifsrc);
3581  return ret;
3582 }
3583 
3584 /** ??? >>> ts B00428 : should the max size become public ? */
3585 #define Libisofs_boot_image_max_sizE (4096*1024)
3586 
3587 /** Guess which of the loaded boot images contain boot information tables.
3588  Set boot->seems_boot_info_table accordingly.
3589 */
3590 static
3592  IsoDataSource *src, uint32_t iso_image_size, int flag)
3593 {
3594  int i, j, ret, section_count, todo, chunk;
3595  uint32_t img_lba, img_size, boot_pvd_found, image_pvd, alleged_size;
3596  struct iso_file_section *sections = NULL;
3597  struct el_torito_boot_image *boot;
3598  uint8_t *boot_image_buf = NULL, boot_info_found[16], *buf = NULL;
3599  IsoStream *stream = NULL;
3600  IsoFile *boot_file;
3601  uint64_t blk;
3602 
3603  if (image->bootcat == NULL)
3604  {ret = ISO_SUCCESS; goto ex;}
3605  LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
3606  for (i = 0; i < image->bootcat->num_bootimages; i++) {
3607  boot = image->bootcat->bootimages[i];
3608  boot_file = boot->image;
3609  boot->seems_boot_info_table = 0;
3610  boot->seems_grub2_boot_info = 0;
3611  boot->seems_isohybrid_capable = 0;
3612  img_size = iso_file_get_size(boot_file);
3613  if (img_size > Libisofs_boot_image_max_sizE || img_size < 64)
3614  continue;
3615  img_lba = 0;
3616  sections = NULL;
3617  ret = iso_file_get_old_image_sections(boot_file,
3618  &section_count, &sections, 0);
3619  if (ret == 1 && section_count > 0)
3620  img_lba = sections[0].block;
3621  if (sections != NULL) {
3622  free(sections);
3623  sections = NULL;
3624  }
3625  if(img_lba == 0)
3626  continue;
3627 
3628  boot_image_buf = calloc(1, img_size);
3629  if (boot_image_buf == NULL) {
3630  ret = ISO_OUT_OF_MEM;
3631  goto ex;
3632  }
3633  stream = iso_file_get_stream(boot_file);
3634  ret = iso_stream_open(stream);
3635  if (ret < 0) {
3636  stream = NULL;
3637  goto ex;
3638  }
3639  for (todo = img_size; todo > 0; ) {
3640  if (todo > BLOCK_SIZE)
3641  chunk = BLOCK_SIZE;
3642  else
3643  chunk = todo;
3644  ret = iso_stream_read(stream, boot_image_buf + (img_size - todo),
3645  chunk);
3646  if (ret != chunk) {
3647  ret = (ret < 0) ? ret : (int) ISO_FILE_READ_ERROR;
3648  goto ex;
3649  }
3650  todo -= chunk;
3651  }
3652  iso_stream_close(stream);
3653  stream = NULL;
3654 
3655  memcpy(boot_info_found, boot_image_buf + 8, 16);
3656  boot_pvd_found = iso_read_lsb(boot_info_found, 4);
3657  image_pvd = (uint32_t) (opts->block + 16);
3658 
3659  /* Accommodate to eventually relocated superblock */
3660  if (image_pvd != boot_pvd_found &&
3661  image_pvd == 16 && boot_pvd_found < iso_image_size) {
3662  /* Check whether there is a PVD at boot_pvd_found
3663  and whether it bears the same image size
3664  */
3665  ret = read_pvd_block(src, boot_pvd_found, buf, &alleged_size);
3666  if (ret == 1 &&
3667  alleged_size + boot_pvd_found == iso_image_size + image_pvd)
3668  image_pvd = boot_pvd_found;
3669  }
3670 
3671  ret = make_boot_info_table(boot_image_buf, image_pvd,
3672  img_lba, img_size);
3673  if (ret < 0)
3674  goto ex;
3675  if (memcmp(boot_image_buf + 8, boot_info_found, 16) == 0)
3676  boot->seems_boot_info_table = 1;
3677 
3678  if (img_size >= Libisofs_grub2_elto_patch_poS + 8) {
3679  blk = 0;
3680  for (j = Libisofs_grub2_elto_patch_poS + 7;
3682  blk = (blk << 8) | boot_image_buf[j];
3683  if (blk == img_lba * 4 + Libisofs_grub2_elto_patch_offsT)
3684  boot->seems_grub2_boot_info = 1;
3685  }
3686  if (img_size >= 68 && boot->seems_boot_info_table)
3687  if (boot_image_buf[64] == 0xfb && boot_image_buf[65] == 0xc0 &&
3688  boot_image_buf[66] == 0x78 && boot_image_buf[67] == 0x70)
3689  boot->seems_isohybrid_capable = 1;
3690 
3691  free(boot_image_buf);
3692  boot_image_buf = NULL;
3693  }
3694  ret = 1;
3695 ex:;
3696  if (boot_image_buf != NULL)
3697  free(boot_image_buf);
3698  if (stream != NULL)
3699  iso_stream_close(stream);
3700  LIBISO_FREE_MEM(buf);
3701  return ret;
3702 }
3703 
3704 
3705 static
3706 void issue_collision_warning_summary(size_t failures)
3707 {
3708  if (failures > ISO_IMPORT_COLL_WARN_MAX) {
3710  "More file name collisions had to be resolved");
3711  }
3712  if (failures > 0) {
3714  "Sum of resolved file name collisions: %.f",
3715  (double) failures);
3716  }
3717 }
3718 
3719 /* Mark all non-matching combinations of head_per_cyl and sectors_per_head
3720  in the matches bitmap. This is a brute force approach to find the common
3721  intersections of up to 8 hyperbolas additionally intersected with the grid
3722  of integer coordinates {1..255}x{1..63}.
3723  Given the solution space size of only 14 bits, it seems inappropriate to
3724  employ any algebra.
3725 */
3726 static
3727 void iso_scan_hc_sh(uint32_t lba, int c, int h, int s, uint8_t *matches)
3728 {
3729  int i, j;
3730  uint32_t res;
3731 
3732 /*
3733  fprintf(stderr, "iso_scan_hc_sh :%d = %4d/%3d/%2d :\n", lba, c, h, s);
3734 */
3735  if (lba == ((uint32_t) s) - 1 && c == 0 && h == 0) /* trivial solutions */
3736  return;
3737  if (c == 1023 && h >= 254 && s == 63) /* Indicators for invalid CHS */
3738  return;
3739 
3740  /* matches(i=0,j=1) == 0 indicates presence of non-trivial equations */
3741  matches[0] &= ~1;
3742 
3743  for (i = 1; i <= 255; i++) {
3744  for (j = 1; j <= 63; j++) {
3745  res = ((c * i) + h) * j + (s - 1);
3746  if (res != lba) {
3747  matches[(i / 8) * 32 + (j - 1)] &= ~(1 << (i % 8));
3748 /*
3749  } else {
3750  if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8)))
3751  fprintf(stderr,
3752  "iso_scan_hc_sh :%d = %4d/%3d/%2d : H/C= %3d S/H= %2d\n",
3753  lba, c, h, s, i, j);
3754 */
3755  }
3756  }
3757  }
3758 }
3759 
3760 /* Pick a good remaining solution from the matches bitmap.
3761 */
3762 static
3763 void iso_get_hc_sh(uint8_t *matches, uint32_t iso_image_size,
3764  int *hc, int *sh, int flag)
3765 {
3766  int i, j, k;
3767  static int pref[][2] = {{64, 32}, {255, 63}}, prefs = 2;
3768 
3769  *hc = *sh = 0;
3770 
3771  if (matches[0] & 1)
3772  return; /* Only trivial equations seen */
3773 
3774  /* Look for preferred layouts */
3775  for (k = 0; k < prefs; k++) {
3776  i = pref[k][0];
3777  j = pref[k][1];
3778  if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
3779  continue;
3780  if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
3781  *hc = i;
3782  *sh = j;
3783  return;
3784  }
3785  }
3786 
3787  /* Look for largest possible cylinder */
3788  for (i = 1; i <= 255; i++) {
3789  for (j = 1; j <= 63; j++) {
3790  if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
3791  continue;
3792  if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
3793  if( i * j < *hc * *sh)
3794  continue;
3795  *hc = i;
3796  *sh = j;
3797  }
3798  }
3799  }
3800 }
3801 
3802 static
3804 {
3805  int i, j, ret, cyl_align_mode, part_after_image = 0;
3806  uint32_t start_h, start_s, start_c, end_h, end_s, end_c, sph = 0, hpc = 0;
3807  uint32_t start_lba, num_blocks, end_chs_lba, image_size, lba, cyl_size;
3808  uint8_t *data, pstatus, ptype, *hc_sh = NULL;
3809  struct iso_imported_sys_area *sai;
3810 
3811  /* Bitmap for finding head_per_cyl and sectors_per_head. */
3812  LIBISO_ALLOC_MEM(hc_sh, uint8_t, 32 * 63);
3813  memset(hc_sh, 0xff, 32 * 63);
3814 
3815  sai = image->imported_sa_info;
3816  image_size = sai->image_size;
3817  for (i = 0; i < 4; i++) {
3818  data = (uint8_t *) (image->system_area_data + 446 + 16 * i);
3819  for (j = 0; j < 16; j++)
3820  if (data[j])
3821  break;
3822  if (j == 16)
3823  continue;
3824  pstatus = data[0];
3825  ptype = data[4];
3826  start_c = ((data[2] & 0xc0) << 2) | data[3];
3827  start_h = data[1];
3828  start_s = data[2] & 63;
3829  end_c = ((data[6] & 0xc0) << 2) | data[7];
3830  end_h = data[5];
3831  end_s = data[6] & 63;
3832  start_lba = iso_read_lsb(data + 8, 4);
3833  num_blocks = iso_read_lsb(data + 12, 4);
3834  if (num_blocks <= 0)
3835  continue;
3836  if (sph > 0) {
3837  if (end_s != sph)
3838  sph = 0xffffffff;
3839  } else if (sph == 0) {
3840  sph = end_s;
3841  }
3842  if (hpc > 0) {
3843  if (end_h + 1 != hpc)
3844  hpc = 0xffffffff;
3845  } else if (hpc == 0) {
3846  hpc = end_h + 1;
3847  }
3848  /* Check whether start_lba + num_blocks - 1 matches chs,hpc,spc */
3849  end_chs_lba = ((end_c * hpc) + end_h) * sph + end_s;
3850  if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff)
3851  if (end_chs_lba != start_lba + num_blocks)
3852  hpc = sph = 0xffffffff;
3853  /* In case that end CHS does not give cylinder layout */
3854  iso_scan_hc_sh(start_lba, start_c, start_h, start_s, hc_sh);
3855  iso_scan_hc_sh(start_lba + num_blocks - 1, end_c, end_h, end_s, hc_sh);
3856 
3857  /* Register partition as iso_mbr_partition_request */
3858  if (sai->mbr_req == NULL) {
3859  sai->mbr_req = calloc(ISO_MBR_ENTRIES_MAX,
3860  sizeof(struct iso_mbr_partition_request *));
3861  if (sai->mbr_req == NULL)
3862  {ret = ISO_OUT_OF_MEM; goto ex;}
3863  }
3864  ret = iso_quick_mbr_entry(sai->mbr_req, &(sai->mbr_req_count),
3865  (uint64_t) start_lba, (uint64_t) num_blocks,
3866  ptype, pstatus, i + 1);
3867  if (ret < 0)
3868  goto ex;
3869  if ((start_lba + num_blocks + 3) / 4 > image_size)
3870  image_size = (start_lba + num_blocks + 3) / 4;
3871  }
3872 
3873  if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff) {
3874  sai->partition_secs_per_head = sph;
3875  sai->partition_heads_per_cyl = hpc;
3876  } else {
3877  /* Look for the best C/H/S parameters caught in scan */
3879  &(sai->partition_secs_per_head), 0);
3880  }
3881 
3882  cyl_align_mode = 2; /* off */
3883  if (sai->partition_secs_per_head >0 && sai->partition_heads_per_cyl > 0 &&
3884  sai->mbr_req_count > 0) {
3885  /* Check for cylinder alignment */
3886  for (i = 0; i < sai->mbr_req_count; i++) {
3887  cyl_size = sai->partition_secs_per_head *
3889  lba = sai->mbr_req[i]->start_block + sai->mbr_req[i]->block_count;
3890  if (sai->mbr_req[i]->start_block >= sai->image_size)
3891  part_after_image = 1;
3892  end_c = lba / cyl_size;
3893  if (end_c * cyl_size != lba)
3894  break;
3895  }
3896  if (i == sai->mbr_req_count && part_after_image)
3897  cyl_align_mode = 3; /* all */
3898  else if (i >= 1)
3899  cyl_align_mode = 1; /* on */
3900  }
3901  sai->system_area_options &= ~(3 << 8);
3902  sai->system_area_options |= (cyl_align_mode << 8);
3903  ret = 1;
3904 ex:
3905  LIBISO_FREE_MEM(hc_sh);
3906  return ret;
3907 
3908 }
3909 
3910 /* @return 0= no hybrid detected
3911  1= ISOLINUX isohybrid (options & 2)
3912  2= GRUB2 MBR patching (options & (1 << 14))
3913 */
3914 static
3915 int iso_analyze_isohybrid(IsoImage *image, int flag)
3916 {
3917  uint8_t *sad;
3918  uint32_t eltorito_lba = 0;
3919  uint64_t mbr_lba;
3920  int i, section_count, ret;
3921  ElToritoBootImage *boot;
3922  struct iso_file_section *sections;
3923 
3924  sad = (uint8_t *) image->system_area_data;
3925 
3926  /* Learn LBA of boot image */;
3927  if (image->bootcat == NULL)
3928  return 0;
3929  if (image->bootcat->num_bootimages < 1)
3930  return 0;
3931  boot = image->bootcat->bootimages[0];
3932  if (boot == NULL)
3933  return 0;
3934  ret = iso_file_get_old_image_sections(boot->image, &section_count,
3935  &sections, 0);
3936  if (ret < 0)
3937  return ret;
3938  if (ret > 0 && section_count > 0)
3939  eltorito_lba = sections[0].block;
3940  free(sections);
3941 
3942  /* Check MBR whether it is ISOLINUX and learn LBA to which it points */
3943  if (!boot->seems_isohybrid_capable)
3944  goto try_grub2_mbr;
3945  for (i= 0; i < 426; i++)
3946  if(strncmp((char *) (sad + i), "isolinux", 8) == 0)
3947  break;
3948  if (i < 426) { /* search text was found */
3949  mbr_lba = iso_read_lsb(sad + 432, 4);
3950  mbr_lba /= 4;
3951  if (mbr_lba == eltorito_lba)
3952  return 1;
3953  goto try_grub2_mbr;
3954  }
3955 
3956 try_grub2_mbr:;
3957  /* Check for GRUB2 MBR patching */
3958  mbr_lba = iso_read_lsb64(sad + 0x1b0);
3959  if (mbr_lba / 4 - 1 == eltorito_lba)
3960  return 2;
3961 
3962  return 0;
3963 }
3964 
3965 static
3967  uint64_t start_block, uint64_t block_count,
3968  int flag)
3969 {
3970  int ret;
3971  uint8_t *buf = NULL;
3972  uint32_t iso_size;
3973  off_t p_offset;
3974  struct ecma119_pri_vol_desc *pvm;
3975  struct iso_imported_sys_area *sai;
3976 
3977  sai = image->imported_sa_info;
3978 
3979  /* Check for PVD at partition start with same end */
3980  LIBISO_ALLOC_MEM(buf, uint8_t, 2048);
3981  p_offset = start_block / 4;
3982  ret = src->read_block(src, p_offset + 16, buf);
3983  if (ret > 0) {
3984  pvm = (struct ecma119_pri_vol_desc *) buf;
3985  iso_size = iso_read_lsb(pvm->vol_space_size, 4);
3986  if (strncmp((char*) pvm->std_identifier, "CD001", 5) == 0 &&
3987  pvm->vol_desc_type[0] == 1 &&
3988  pvm->vol_desc_version[0] == 1 &&
3989  pvm->file_structure_version[0] == 1 &&
3990  (iso_size + p_offset == sai->image_size ||
3991  iso_size == block_count / 4))
3992 
3993  sai->partition_offset = p_offset;
3994  }
3995  ret = 1;
3996 ex:;
3997  LIBISO_FREE_MEM(buf);
3998  return ret;
3999 }
4000 
4001 static
4002 int iso_analyze_mbr(IsoImage *image, IsoDataSource *src, int flag)
4003 {
4004  int sub_type = 2, ret, is_isohybrid = 0, is_grub2_mbr = 0;
4005  int is_protective_label = 0;
4006  uint64_t part2_start;
4007  char *sad;
4008  struct iso_imported_sys_area *sai;
4009  struct iso_mbr_partition_request *part;
4010 
4011  sad = image->system_area_data;
4012  sai = image->imported_sa_info;
4013 
4014  /* Is it an MBR ? */
4015  if (((unsigned char *) sad)[510] != 0x55 ||
4016  ((unsigned char *) sad)[511] != 0xaa)
4017  {ret = 0; goto ex;}
4018 
4019  ret = iso_analyze_mbr_ptable(image, 0);
4020  if (ret <= 0)
4021  goto ex;
4022 
4023  ret = iso_analyze_isohybrid(image, 0);
4024  if (ret < 0)
4025  goto ex;
4026  if (ret == 1) {
4027  sub_type = 0;
4028  is_isohybrid = 1;
4029  } else if(ret == 2) {
4030  /* will become sub_type 0 if protective_label */
4031  is_grub2_mbr = 1;
4032  }
4033 
4034  if (sai->mbr_req_count == 3 && !is_isohybrid) {
4035  /* Check for libisofs PReP partitions :
4036  0xee or 0xcd from 0 to a-1
4037  0x41 from a to b
4038  0x0c or 0xcd from b+1 to end
4039  */
4040  if ((sai->mbr_req[0]->start_block == 0 &&
4041  (sai->mbr_req[0]->type_byte == 0xee ||
4042  sai->mbr_req[0]->type_byte == 0xcd)) &&
4043  sai->mbr_req[0]->block_count == sai->mbr_req[1]->start_block &&
4044  sai->mbr_req[1]->type_byte == 0x41 &&
4045  (sai->mbr_req[1]->start_block % 4) == 0 &&
4046  sai->mbr_req[1]->start_block + sai->mbr_req[1]->block_count ==
4047  sai->mbr_req[2]->start_block &&
4048  (sai->mbr_req[2]->type_byte == 0x0c ||
4049  sai->mbr_req[2]->type_byte == 0xcd) &&
4050  (sai->mbr_req[2]->start_block + sai->mbr_req[2]->block_count) / 4
4051  == sai->image_size) {
4052  sai->prep_part_start = sai->mbr_req[1]->start_block / 4;
4053  sai->prep_part_size = (sai->mbr_req[1]->block_count + 3) / 4;
4054  sub_type = 0;
4055  }
4056  }
4057  if (sai->mbr_req_count >= 1 &&
4058  (sai->mbr_req[0]->type_byte == 0xee || !is_isohybrid) &&
4059  !(sai->prep_part_start > 0)) {
4060  part = sai->mbr_req[0];
4061  part2_start = 0;
4062  if (sai->mbr_req_count >= 2)
4063  part2_start = sai->mbr_req[1]->start_block;
4064  if (part->start_block == 1 &&
4065  (part->block_count + 1 == ((uint64_t) sai->image_size) * 4 ||
4066  (part->type_byte == 0xee &&
4067  part->block_count + 1 >= ((uint64_t) sai->image_size) * 4 &&
4068  (sai->mbr_req_count == 1 ||
4069  (sai->mbr_req_count == 2 &&
4070  sai->mbr_req[1]->type_byte == 0x00))) ||
4071  part->block_count + 1 == part2_start)) {
4072  /* libisofs protective msdos label for GRUB2 */
4073  is_protective_label = 1;
4074  sub_type = 0;
4075  } else if (sai->mbr_req_count == 1 && part->start_block == 0 &&
4076  part->block_count <= ((uint64_t) sai->image_size) * 4 &&
4077  part->block_count + 600 >= ((uint64_t) sai->image_size) * 4 &&
4078  part->type_byte == 0x96) {
4079  /* CHRP (possibly without padding) */
4080  sub_type = 1;
4081  } else if (sai->mbr_req_count == 1 &&
4082  sai->mbr_req[0]->start_block > 0 &&
4083  (sai->mbr_req[0]->start_block % 4) == 0 &&
4084  (sai->mbr_req[0]->start_block +
4085  sai->mbr_req[0]->block_count) / 4 <= sai->image_size &&
4086  part->type_byte == 0x41) {
4087  /* mkisofs PReP partition */
4088  sai->prep_part_start = sai->mbr_req[0]->start_block / 4;
4089  sai->prep_part_size = (sai->mbr_req[0]->block_count + 3) / 4;
4090  sub_type = 0;
4091  }
4092  }
4093 
4094  /* Check for partition offset with extra set of meta data */
4095  if (sai->mbr_req_count > 0) {
4096  part = sai->mbr_req[0];
4097  if ((part->status_byte == 0x80 || part->status_byte == 0) &&
4098  part->start_block >= 64 && part->block_count >= 72 &&
4099  part->start_block <= 2048 &&
4100  part->start_block % 4 == 0 && part->block_count % 4 == 0 &&
4101  (part->start_block + part->block_count) / 4 <= sai->image_size) {
4102 
4103  ret = iso_analyze_partition_offset(image, src, part->start_block,
4104  part->block_count, 0);
4105  if (ret < 0)
4106  goto ex;
4107  }
4108  }
4109 
4110  /* Set sa type 0, sub type as chosen */
4111  sai->system_area_options = (sai->system_area_options & 0xffff8300) |
4112  is_protective_label |
4113  (is_isohybrid << 1) |
4114  (sub_type << 10) |
4115  (is_grub2_mbr << 14);
4116  ret = 1;
4117 ex:;
4118  return ret;
4119 }
4120 
4121 static
4122 int iso_seems_usable_gpt_head(uint8_t *head, int flag)
4123 {
4124  uint32_t head_size, entry_size;
4125 
4126  if (strncmp((char *) head, "EFI PART", 8) != 0) /* signature */
4127  return 0;
4128  if (head[8] || head[9] || head[10] != 1 || head[11]) /* revision */
4129  return 0;
4130  head_size = iso_read_lsb(head + 12, 4);
4131  if (head_size < 92)
4132  return 0;
4133  entry_size = iso_read_lsb(head + 84, 4);
4134  if (entry_size != 128)
4135  return 0;
4136  return 1;
4137 }
4138 
4139 static
4140 int iso_analyze_gpt_backup(IsoImage *image, IsoDataSource *src, int flag)
4141 {
4142  struct iso_imported_sys_area *sai;
4143  uint64_t part_start;
4144  uint32_t iso_block, found_crc, crc, entry_count, array_crc;
4145  uint8_t *head, *part_array, *b_part, *m_part;
4146  int ret, i, num_iso_blocks, l, j, entries_diff;
4147  unsigned char *buf = NULL;
4148  char *comments = NULL;
4149 
4150  sai = image->imported_sa_info;
4151  LIBISO_ALLOC_MEM(buf, unsigned char, 34 * 1024);
4152  LIBISO_ALLOC_MEM(comments, char, 4096);
4153 
4154  /* Read ISO block with backup head */
4155  if (sai->gpt_backup_lba >= ((uint64_t) sai->image_size) * 4 &&
4156  (sai->mbr_req_count < 1 ||
4157  sai->mbr_req[0]->start_block + sai->mbr_req[0]->block_count
4158  > sai->gpt_backup_lba + 1))
4159  sprintf(comments + strlen(comments), "Implausible header LBA %.f, ",
4160  (double) sai->gpt_backup_lba);
4161  iso_block = sai->gpt_backup_lba / 4;
4162  ret = src->read_block(src, iso_block, buf);
4163  if (ret < 0) {
4164  sprintf(comments + strlen(comments),
4165  "Cannot read header block at 2k LBA %.f, ",
4166  (double) iso_block);
4167  ret = 0; goto ex;
4168  }
4169  head = buf + (sai->gpt_backup_lba % 4) * 512;
4170  ret = iso_seems_usable_gpt_head(head, 0);
4171  if (ret == 0)
4172  strcat(comments,
4173  "Not a GPT 1.0 header of 92 bytes for 128 bytes per entry, ");
4174  if (ret <= 0) {
4175  ret = 0; goto ex;
4176  }
4177 
4178  /* Check head CRC */
4179  found_crc = iso_read_lsb(head + 16, 4);
4180  memset(head + 16, 0, 4);
4181  crc = iso_crc32_gpt((unsigned char *) head, 92, 0);
4182  if (found_crc != crc) {
4183  sprintf(comments + strlen(comments),
4184  "Head CRC 0x%8x wrong. Should be 0x%8x",
4185  found_crc, crc);
4186  crc = iso_crc32_gpt((unsigned char *) head, 512, 0);
4187  if (found_crc == crc) {
4188  strcat(comments, ". Matches all 512 block bytes, ");
4189  } else {
4190  strcat(comments, ", ");
4191  ret = 0; goto ex;
4192  }
4193  }
4194  for (i = 0; i < 16; i ++)
4195  if (head[i + 56] != sai->gpt_disk_guid[i])
4196  break;
4197  if (i < 16) {
4198  sprintf(comments + strlen(comments), "Disk GUID differs (");
4199  iso_util_bin_to_hex(comments + strlen(comments), head + 56, 16, 0);
4200  sprintf(comments + strlen(comments), "), ");
4201  }
4202 
4203  /* Header content will possibly be overwritten now */
4204  array_crc = iso_read_lsb(head + 88, 4);
4205  part_start = iso_read_lsb64(head + 72);
4206  entry_count = iso_read_lsb(head + 80, 4);
4207  head = NULL;
4208 
4209  /* Read backup array */
4210  if (entry_count != sai->gpt_max_entries) {
4211  sprintf(comments + strlen(comments),
4212  "Number of array entries %u differs from main GPT %u, ",
4213  entry_count, sai->gpt_max_entries);
4214  ret = 0; goto ex;
4215  }
4216  if (part_start + (entry_count + 3) / 4 != sai->gpt_backup_lba)
4217  sprintf(comments + strlen(comments), "Implausible array LBA %.f, ",
4218  (double) part_start);
4219  iso_block = part_start / 4;
4220  num_iso_blocks = (part_start + (entry_count + 3) / 4) / 4 - iso_block + 1;
4221  for (i = 0; i < num_iso_blocks; i++) {
4222  ret = src->read_block(src, iso_block + (uint32_t) i, buf + i * 2048);
4223  if (ret < 0) {
4224  sprintf(comments + strlen(comments),
4225  "Cannot read array block at 2k LBA %.f, ",
4226  (double) iso_block);
4227  ret = 0; goto ex;
4228  }
4229  }
4230  part_array = buf + (part_start % 4) * 512;
4231 
4232  crc = iso_crc32_gpt((unsigned char *) part_array, 128 * entry_count, 0);
4233  if (crc != array_crc)
4234  sprintf(comments + strlen(comments),
4235  "Array CRC 0x%8x wrong. Should be 0x%8x, ", array_crc, crc);
4236 
4237  /* Compare entries */
4238  entries_diff = 0;
4239  for (i = 0; i < (int) entry_count; i++) {
4240  b_part = part_array + 128 * i;
4241  m_part = ((uint8_t *) image->system_area_data) +
4242  sai->gpt_part_start * 512 + 128 * i;
4243  for (j = 0; j < 128; j++)
4244  if (b_part[j] != m_part[j])
4245  break;
4246  if (j < 128) {
4247  if (!entries_diff) {
4248  strcat(comments, "Entries differ for partitions");
4249  entries_diff = 1;
4250  }
4251  sprintf(comments + strlen(comments), " %d", i + 1);
4252  }
4253  }
4254  if (entries_diff) {
4255  strcat(comments, ", ");
4256  ret = 0; goto ex;
4257  }
4258 
4259  ret = 1;
4260 ex:;
4261  if (comments != NULL) {
4262  l = strlen(comments);
4263  if (l > 2)
4264  if (comments[l - 2] == ',' && comments[l - 1] == ' ')
4265  comments[l - 2] = 0;
4266  sai->gpt_backup_comments = strdup(comments);
4267  if (sai->gpt_backup_comments == NULL)
4268  ret = ISO_OUT_OF_MEM;
4269  }
4270  LIBISO_FREE_MEM(comments);
4271  LIBISO_FREE_MEM(buf);
4272  return ret;
4273 }
4274 
4275 static
4276 int iso_analyze_gpt_head(IsoImage *image, IsoDataSource *src, int flag)
4277 {
4278  struct iso_imported_sys_area *sai;
4279  uint8_t *head;
4280  uint32_t crc;
4281  uint64_t part_start;
4282  int ret;
4283  unsigned char *crc_buf = NULL;
4284 
4285  sai = image->imported_sa_info;
4286  head = ((uint8_t *) image->system_area_data) + 512;
4287  LIBISO_ALLOC_MEM(crc_buf, unsigned char, 512);
4288 
4289  /* Is this a GPT header with digestible parameters ? */
4290  ret = iso_seems_usable_gpt_head(head, 0);
4291  if (ret <= 0)
4292  goto ex;
4293  memcpy(crc_buf, head, 512);
4294  memset(crc_buf + 16, 0, 4); /* CRC is computed when head_crc is 0 */
4295  sai->gpt_head_crc_found = iso_read_lsb(head + 16, 4);
4296  sai->gpt_head_crc_should = iso_crc32_gpt((unsigned char *) crc_buf, 92, 0);
4297  if (sai->gpt_head_crc_found != sai->gpt_head_crc_should) {
4298  /* There was a bug during libisofs-1.2.4 to libisofs-1.2.8
4299  (fixed in rev 1071). So accept the buggy CRC if it matches the
4300  whole GPT header block. */
4301  crc = iso_crc32_gpt((unsigned char *) crc_buf, 512, 0);
4302  if (sai->gpt_head_crc_found != crc)
4303  {ret = 0; goto ex;}
4304  }
4305  part_start = iso_read_lsb64(head + 72);
4306  sai->gpt_max_entries = iso_read_lsb(head + 80, 4);
4307  if (part_start + (sai->gpt_max_entries + 3) / 4 > 64)
4308  {ret = 0; goto ex;}
4309 
4310  /* Fetch desired information */
4311  memcpy(sai->gpt_disk_guid, head + 56, 16);
4312  sai->gpt_part_start = part_start;
4313  sai->gpt_backup_lba = iso_read_lsb64(head + 32);
4314  sai->gpt_first_lba = iso_read_lsb64(head + 40);
4315  sai->gpt_last_lba = iso_read_lsb64(head + 48);
4316  sai->gpt_array_crc_found = iso_read_lsb(head + 88, 4);
4317  sai->gpt_array_crc_should =
4318  iso_crc32_gpt((unsigned char *) image->system_area_data +
4319  sai->gpt_part_start * 512,
4320  sai->gpt_max_entries * 128, 0);
4321 
4322  ret = iso_analyze_gpt_backup(image, src, 0);
4323  if (ret < 0)
4324  goto ex;
4325 
4326  ret = 1;
4327 ex:
4328  LIBISO_FREE_MEM(crc_buf);
4329  return ret;
4330 }
4331 
4332 static
4333 int iso_analyze_gpt(IsoImage *image, IsoDataSource *src, int flag)
4334 {
4335  int ret, i, j;
4336  uint64_t start_block, block_count, flags, end_block, j_end, j_start;
4337  uint8_t *part;
4338  struct iso_imported_sys_area *sai;
4339 
4340  sai = image->imported_sa_info;
4341 
4342  ret = iso_analyze_gpt_head(image, src, 0);
4343  if (ret <= 0)
4344  return ret;
4345 
4346  for (i = 0; i < (int) sai->gpt_max_entries; i++) {
4347  part = ((uint8_t *) image->system_area_data) +
4348  sai->gpt_part_start * 512 + 128 * i;
4349  for (j = 0; j < 128; j++)
4350  if (part[j])
4351  break;
4352  if (j >= 128) /* all zero, invalid entry */
4353  continue;
4354  start_block = iso_read_lsb64(part + 32);
4355  block_count = iso_read_lsb64(part + 40);
4356  flags = iso_read_lsb64(part + 48);
4357  if ((start_block == 0 && block_count == 0) ||
4358  block_count + 1 < start_block)
4359  continue;
4360  block_count = block_count + 1 - start_block;
4361  if (sai->gpt_req == NULL) {
4362  sai->gpt_req = calloc(ISO_GPT_ENTRIES_MAX,
4363  sizeof(struct iso_gpt_partition_request *));
4364  if (sai->gpt_req == NULL)
4365  return ISO_OUT_OF_MEM;
4366  }
4367  ret = iso_quick_gpt_entry(sai->gpt_req, &(sai->gpt_req_count),
4368  start_block, block_count,
4369  part, part + 16, flags, part + 56);
4370  if (ret < 0)
4371  return ret;
4372  sai->gpt_req[sai->gpt_req_count - 1]->idx = i + 1;
4373  }
4374 
4375  /* sai->gpt_req_flags :
4376  bit0= GPT partitions may overlap
4377  >>> bit1= with bit0: neatly nested partitions
4378  without : neatly divided disk
4379  */
4380  for (i = 0; i < (int) sai->gpt_req_count && !(sai->gpt_req_flags & 1);
4381  i++) {
4382  if (sai->gpt_req[i]->block_count == 0)
4383  continue;
4384  start_block = sai->gpt_req[i]->start_block;
4385  end_block = start_block + sai->gpt_req[i]->block_count;
4386  for (j = i + 1; j < (int) sai->gpt_req_count; j++) {
4387  if (sai->gpt_req[j]->block_count == 0)
4388  continue;
4389  j_start = sai->gpt_req[j]->start_block;
4390  j_end = j_start + sai->gpt_req[j]->block_count;
4391  if ((start_block <= j_start && j_start < end_block) ||
4392  (start_block <= j_end && j_end < end_block) ||
4393  (j_start <= start_block && start_block < j_end)) {
4394  sai->gpt_req_flags |= 1;
4395  break;
4396  }
4397  }
4398  }
4399 
4400  /* Check first GPT partition for ISO partition offset */
4401  if (sai->partition_offset == 0 && sai->mbr_req_count > 0 &&
4402  sai->gpt_req_count > 0) {
4403  if (sai->mbr_req[0]->type_byte == 0xee &&
4404  sai->mbr_req[0]->start_block == 1) { /* protective MBR */
4405  start_block = sai->gpt_req[0]->start_block;
4406  block_count = sai->gpt_req[0]->block_count;
4407  if (start_block >= 64 && block_count >= 72 &&
4408  start_block <= 2048 && start_block % 4 == 0 &&
4409  block_count % 4 == 0) {
4410 
4411  ret = iso_analyze_partition_offset(image, src, start_block,
4412  block_count, 0);
4413  if (ret < 0)
4414  return ret;
4415  }
4416  }
4417  }
4418 
4419  return 1;
4420 }
4421 
4422 
4423 static
4424 int iso_analyze_apm_head(IsoImage *image, IsoDataSource *src, int flag)
4425 {
4426  struct iso_imported_sys_area *sai;
4427  char *sad;
4428  uint32_t block_size;
4429 
4430  sai = image->imported_sa_info;
4431  sad = image->system_area_data;
4432 
4433  if (sad[0] != 'E' || sad[1] != 'R')
4434  return 0;
4435  block_size = iso_read_msb(((uint8_t *) sad) + 2, 2);
4436  if (block_size != 2048 && block_size != 512)
4437  return 0;
4438  sai->apm_block_size = block_size;
4439  sai->apm_req_flags |= 4 | 2; /* start_block and block_count are in
4440  block_size units, do not fill gaps */
4441  return 1;
4442 }
4443 
4444 static
4445 int iso_analyze_apm(IsoImage *image, IsoDataSource *src, int flag)
4446 {
4447  int ret, i;
4448  uint32_t map_entries, start_block, block_count, flags;
4449  char *sad, *part, name[33], type_string[33];
4450  struct iso_imported_sys_area *sai;
4451 
4452  sai = image->imported_sa_info;
4453  sad = image->system_area_data;
4454 
4455  ret = iso_analyze_apm_head(image, src, 0);
4456  if (ret <= 0)
4457  return ret;
4458 
4459  part = sad + sai->apm_block_size;
4460  map_entries = iso_read_msb(((uint8_t *) part) + 4, 4);
4461  for (i = 0; i < (int) map_entries; i++) {
4462  part = sad + (i + 1) * sai->apm_block_size;
4463  if (part[0] != 'P' || part[1] != 'M')
4464  break;
4465  flags = iso_read_msb(((uint8_t *) part) + 88, 4);
4466  if (!(flags & 3))
4467  continue;
4468  memcpy(type_string, part + 48, 32);
4469  type_string[32] = 0;
4470  if(strcmp(type_string, "Apple_partition_map") == 0)
4471  continue;
4472  start_block = iso_read_msb(((uint8_t *) part) + 8, 4);
4473  block_count = iso_read_msb(((uint8_t *) part + 12), 4);
4474  memcpy(name, part + 16, 32);
4475  name[32] = 0;
4476  if (sai->apm_req == NULL) {
4477  sai->apm_req = calloc(ISO_APM_ENTRIES_MAX,
4478  sizeof(struct iso_apm_partition_request *));
4479  if (sai->apm_req == NULL)
4480  return ISO_OUT_OF_MEM;
4481  }
4482  ret = iso_quick_apm_entry(sai->apm_req, &(sai->apm_req_count),
4483  start_block, block_count, name, type_string);
4484  if (ret <= 0)
4485  return ret;
4486  if (strncmp(name, "Gap", 3) == 0 &&
4487  strcmp(type_string, "ISO9660_data") == 0) {
4488  if ('0' <= name[3] && name[3] <= '9' && (name[4] == 0 ||
4489  ('0' <= name[4] && name[4] <= '9' && name[5] == 0))) {
4490  sai->apm_gap_count++;
4491  sai->apm_req_flags &= ~2;
4492  }
4493  }
4494  }
4495  return 1;
4496 }
4497 
4498 static
4499 int iso_analyze_mips(IsoImage *image, IsoDataSource *src, int flag)
4500 {
4501  int ret = 0, spt, bps, i, j, idx;
4502  uint32_t magic, chk, head_chk;
4503  char *sad;
4504  uint8_t *usad, *upart;
4505  struct iso_imported_sys_area *sai;
4506  IsoNode *node;
4507 
4508  sai = image->imported_sa_info;
4509  sad = image->system_area_data;
4510  usad = (uint8_t *) sad;
4511 
4512  magic = iso_read_msb(usad, 4);
4513  if (magic != 0x0be5a941)
4514  return 0;
4515  spt = iso_read_msb(usad + 38, 2);
4516  bps = iso_read_msb(usad + 40, 2);
4517  if (spt != 32 || bps != 512)
4518  return 0;
4519  chk = 0;
4520  for (i = 0; i < 504; i += 4)
4521  chk -= iso_read_msb(usad + i, 4);
4522  head_chk = iso_read_msb(usad + 504, 4);
4523  if (chk != head_chk)
4524  return 0;
4525 
4526  /* Verify that partitions 1 to 8 are empty */
4527  for (j = 312; j < 408; j++)
4528  if (sad[j])
4529  return 0;
4530 
4531  /* >>> verify that partitions 9 and 10 match the image size */;
4532 
4533  for (i = 0; i < 15; i++) {
4534  upart = usad + 72 + 16 * i;
4535  for (j = 0; j < 16; j++)
4536  if (upart[j])
4537  break;
4538  if (j == 16)
4539  continue;
4540  if (sai->mips_vd_entries == NULL) {
4541  sai->mips_boot_file_paths = calloc(15, sizeof(char *));
4542  sai->mips_vd_entries = calloc(15,
4543  sizeof(struct iso_mips_voldir_entry *));
4544  if (sai->mips_vd_entries == NULL ||
4545  sai->mips_boot_file_paths == NULL)
4546  return ISO_OUT_OF_MEM;
4547  sai->num_mips_boot_files = 0;
4548  for (j = 0; j < 15; j++) {
4549  sai->mips_boot_file_paths[j] = NULL;
4550  sai->mips_vd_entries[j] = NULL;
4551  }
4552  }
4553 
4554  /* Assess boot file entry */
4555  if (sai->num_mips_boot_files >= 15)
4556  return ISO_BOOT_TOO_MANY_MIPS;
4557  idx = sai->num_mips_boot_files;
4558  sai->mips_vd_entries[idx] =
4559  calloc(1, sizeof(struct iso_mips_voldir_entry));
4560  if (sai->mips_vd_entries[idx] == NULL)
4561  return ISO_OUT_OF_MEM;
4562  memcpy(sai->mips_vd_entries[idx]->name, upart, 8);
4563  sai->mips_vd_entries[idx]->name[8] = 0;
4564  sai->mips_vd_entries[idx]->boot_block = iso_read_msb(upart + 8, 4);
4565  sai->mips_vd_entries[idx]->boot_bytes = iso_read_msb(upart + 12, 4);
4566  ret = iso_tree_get_node_of_block(image, NULL,
4567  sai->mips_vd_entries[idx]->boot_block / 4,
4568  &node, NULL, 0);
4569  if (ret > 0)
4570  sai->mips_boot_file_paths[idx] = iso_tree_get_node_path(node);
4571  sai->num_mips_boot_files++;
4572  }
4573  if (sai->num_mips_boot_files > 0)
4574  sai->system_area_options = (1 << 2);/* MIPS Big Endian Volume Header */
4575 
4576  return ret;
4577 }
4578 
4579 static
4580 int iso_analyze_mipsel(IsoImage *image, IsoDataSource *src, int flag)
4581 {
4582  int ret = 0, i, section_count;
4583  char *sad;
4584  uint8_t *usad;
4585  uint32_t magic;
4586  struct iso_imported_sys_area *sai;
4587  IsoNode *node;
4588  IsoFile *file;
4589  struct iso_file_section *sections = NULL;
4590 
4591  sai = image->imported_sa_info;
4592  sad = image->system_area_data;
4593  usad = (uint8_t *) sad;
4594 
4595  for (i = 0; i < 8; i++)
4596  if (sad[i])
4597  return 0;
4598  magic = iso_read_lsb(usad + 8, 4);
4599  if (magic != 0x0002757a)
4600  return 0;
4601 
4602  sai->mipsel_p_vaddr = iso_read_lsb(usad + 16, 4);
4603  sai->mipsel_e_entry = iso_read_lsb(usad + 20, 4);
4604  sai->mipsel_p_filesz = iso_read_lsb(usad + 24, 4) * 512;
4605  sai->mipsel_seg_start = iso_read_lsb(usad + 28, 4);
4606  ret = iso_tree_get_node_of_block(image, NULL, sai->mipsel_seg_start / 4,
4607  &node, NULL, 0);
4608  if (ret > 0) {
4610  file = (IsoFile *) node;
4611  ret = iso_file_get_old_image_sections(file, &section_count,
4612  &sections, 0);
4613  if (ret > 0 && section_count > 0) {
4614  if (sections[0].block < (1 << 30) &&
4615  sections[0].block * 4 < sai->mipsel_seg_start)
4616  sai->mipsel_p_offset = sai->mipsel_seg_start -
4617  sections[0].block * 4;
4618  free(sections);
4619  }
4620  }
4621  /* DEC Boot Block for MIPS Little Endian */
4622  sai->system_area_options = (2 << 2);
4623 
4624  return 1;
4625 }
4626 
4627 static
4628 int iso_analyze_sun(IsoImage *image, IsoDataSource *src, int flag)
4629 {
4630  int ret = 0, i, idx;
4631  char *sad;
4632  uint8_t *usad, checksum[2];
4633  uint16_t perms;
4634  uint64_t last_core_block;
4635  struct iso_imported_sys_area *sai;
4636  IsoNode *node;
4637 
4638  sai = image->imported_sa_info;
4639  sad = image->system_area_data;
4640  usad = (uint8_t *) sad;
4641 
4642  if (iso_read_msb(usad + 128, 4) != 1 ||
4643  iso_read_msb(usad + 140, 2) != 8 ||
4644  iso_read_msb(usad + 188, 4) != 0x600ddeee ||
4645  iso_read_msb(usad + 430, 2) != 1 ||
4646  iso_read_msb(usad + 508, 2) != 0xdabe)
4647  return 0;
4648  if (iso_read_msb(usad + 142, 2) != 4 ||
4649  iso_read_msb(usad + 144, 2) != 0x10 ||
4650  iso_read_msb(usad + 444, 4) != 0 ||
4651  sai->image_size > 0x3fffffff ||
4652  iso_read_msb(usad + 448, 4) < ((int64_t) sai->image_size * 4) - 600 ||
4653  iso_read_msb(usad + 448, 4) > sai->image_size * 4)
4654  return 0;
4655  checksum[0] = checksum[1] = 0;
4656  for (i = 0; i < 510; i += 2) {
4657  checksum[0] ^= usad[i];
4658  checksum[1] ^= usad[i + 1];
4659  }
4660  if (checksum[0] != usad[510] || checksum[1] != usad[511])
4661  return 0;
4662 
4663  sai->sparc_disc_label = calloc(1, 129);
4664  if (sai->sparc_disc_label == NULL)
4665  return ISO_OUT_OF_MEM;
4666  memcpy(sai->sparc_disc_label, sad, 128);
4667  sai->sparc_disc_label[128] = 0;
4668  sai->sparc_heads_per_cyl = iso_read_msb(usad + 436, 2);
4669  sai->sparc_secs_per_head = iso_read_msb(usad + 438, 2);
4670 
4671  for (i = 0; i < 8; i++) {
4672  perms = iso_read_msb(usad + 144 + 4 * i, 2);
4673  if (perms == 0)
4674  continue;
4675  if (sai->sparc_entries == NULL) {
4676  sai->sparc_entries = calloc(8,
4677  sizeof(struct iso_sun_disk_label_entry));
4678  if (sai->sparc_entries == NULL)
4679  return ISO_OUT_OF_MEM;
4680  }
4681  idx = sai->sparc_entry_count;
4682  sai->sparc_entries[idx].idx = i + 1;
4683  sai->sparc_entries[idx].id_tag = iso_read_msb(usad + 142 + 4 * i, 2);
4684  sai->sparc_entries[idx].permissions = perms;
4685  sai->sparc_entries[idx].start_cyl =
4686  iso_read_msb(usad + 444 + 8 * i, 4);
4687  sai->sparc_entries[idx].num_blocks =
4688  iso_read_msb(usad + 448 + 8 * i, 4);
4689  sai->sparc_entry_count++;
4690  }
4691 
4692  /* GRUB2 SUN SPARC Core File Address */
4693  sai->sparc_grub2_core_adr = iso_read_msb64(usad + 552);
4694  sai->sparc_grub2_core_size = iso_read_msb(usad + 560, 4);
4695  last_core_block = (sai->sparc_grub2_core_adr +
4696  sai->sparc_grub2_core_size + 2047) / 2048;
4697  if (last_core_block > 0)
4698  last_core_block--;
4699  if (last_core_block > 17 && last_core_block < sai->image_size) {
4700  ret = iso_tree_get_node_of_block(image, NULL,
4701  (uint32_t) last_core_block, &node,
4702  NULL, 0);
4703  if (ret > 0) {
4704  iso_node_ref(node);
4705  sai->sparc_core_node = (IsoFile *) node;
4706  }
4707  } else {
4708  sai->sparc_grub2_core_adr = 0;
4709  sai->sparc_grub2_core_size = 0;
4710  }
4711 
4712  /* SUN Disk Label for SUN SPARC */
4713  sai->system_area_options = (3 << 2);
4714 
4715  return 1;
4716 }
4717 
4718 static
4719 int iso_analyze_hppa(IsoImage *image, IsoDataSource *src, int flag)
4720 {
4721  int ret = 0, i, cmd_adr, cmd_len;
4722  char *sad, *paths[4];
4723  uint8_t *usad;
4724  uint16_t magic;
4725  uint32_t adrs[4];
4726  struct iso_imported_sys_area *sai;
4727  IsoNode *node;
4728 
4729  sai = image->imported_sa_info;
4730  sad = image->system_area_data;
4731  usad = (uint8_t *) sad;
4732 
4733  magic = iso_read_msb(usad, 2);
4734  if (magic != 0x8000 || strncmp(sad + 2, "PALO", 5) != 0 ||
4735  sad[7] < 4 || sad[7] > 5)
4736  return 0;
4737 
4738  sai->hppa_hdrversion = sad[7];
4739  if (sai->hppa_hdrversion == 4) {
4740  cmd_len = 127;
4741  cmd_adr = 24;
4742  } else {
4743  cmd_len = 1023;
4744  cmd_adr = 1024;
4745  }
4746  sai->hppa_cmdline = calloc(1, cmd_len + 1);
4747  if (sai->hppa_cmdline == NULL)
4748  return ISO_OUT_OF_MEM;
4749  memcpy(sai->hppa_cmdline, sad + cmd_adr, cmd_len);
4750  sai->hppa_cmdline[cmd_len] = 0;
4751  adrs[0] = sai->hppa_kern32_adr = iso_read_msb(usad + 8, 4);
4752  sai->hppa_kern32_len = iso_read_msb(usad + 12, 4);
4753  adrs[1] = sai->hppa_kern64_adr = iso_read_msb(usad + 232, 4);
4754  sai->hppa_kern64_len = iso_read_msb(usad + 236, 4);
4755  adrs[2] = sai->hppa_ramdisk_adr = iso_read_msb(usad + 16, 4);
4756  sai->hppa_ramdisk_len = iso_read_msb(usad + 20, 4);
4757  adrs[3] = sai->hppa_bootloader_adr = iso_read_msb(usad + 240, 4);
4758  sai->hppa_bootloader_len = iso_read_msb(usad + 244, 4);
4759  for (i = 0; i < 4; i++) {
4760  paths[i] = NULL;
4761  ret = iso_tree_get_node_of_block(image, NULL, adrs[i] / 2048,
4762  &node, NULL, 0);
4763  if (ret > 0)
4764  paths[i] = iso_tree_get_node_path(node);
4765  }
4766  sai->hppa_kernel_32 = paths[0];
4767  sai->hppa_kernel_64 = paths[1];
4768  sai->hppa_ramdisk = paths[2];
4769  sai->hppa_bootloader = paths[3];
4770 
4771  if (sai->hppa_hdrversion == 5)
4772  sai->hppa_ipl_entry = iso_read_msb(usad + 248, 4);
4773 
4774  /* HP-PA PALO boot sector version 4 or 5 for HP PA-RISC */
4775  sai->system_area_options = (sai->hppa_hdrversion << 2);
4776 
4777  return 1;
4778 }
4779 
4780 static
4781 int iso_analyze_alpha_boot(IsoImage *image, IsoDataSource *src, int flag)
4782 {
4783  int ret = 0, i, section_count;
4784  char *sad;
4785  uint8_t *usad;
4786  struct iso_imported_sys_area *sai;
4787  IsoNode *node;
4788  IsoFile *file;
4789  uint64_t checksum_found, checksum_should = 0, size;
4790  struct iso_file_section *sections = NULL;
4791 
4792  sai = image->imported_sa_info;
4793  sad = image->system_area_data;
4794  usad = (uint8_t *) sad;
4795 
4796  checksum_found = iso_read_lsb64(usad + 504);
4797  for (i = 0; i < 63; i++)
4798  checksum_should += iso_read_lsb64(usad + 8 * i);
4799  if (checksum_found != checksum_should)
4800  return 0;
4801  sai->alpha_boot_image = NULL;
4802  sai->alpha_boot_image_size = (uint64_t) iso_read_lsb64(usad + 480);
4803  sai->alpha_boot_image_adr = (uint64_t) iso_read_lsb64(usad + 488);
4804  ret = iso_tree_get_node_of_block(image, NULL,
4805  (uint32_t) (sai->alpha_boot_image_adr / 4),
4806  &node, NULL, 0);
4807  if (ret > 0) {
4808  if (iso_node_get_type(node) != LIBISO_FILE)
4809  return 0;
4810  file = (IsoFile *) node;
4811  ret = iso_file_get_old_image_sections(file, &section_count,
4812  &sections, 0);
4813  if (ret > 0 && section_count > 0) {
4814  size = sections[0].size / 512 + !!(sections[0].size % 512);
4815  free(sections);
4816  if (size != sai->alpha_boot_image_size)
4817  return 0;
4818  }
4820  } else if (strncmp(sad, "Linux/Alpha aboot for ISO filesystem.", 37) != 0
4821  || sad[37] != 0) {
4822  return 0; /* Want to see either boot file or genisoimage string */
4823  }
4824  sai->system_area_options = (6 << 2);
4825  return 1;
4826 }
4827 
4828 
4830  char *buf;
4832  char **lines;
4834 };
4835 
4836 static
4838 {
4839  int ret;
4840 
4841  LIBISO_ALLOC_MEM(*r, struct iso_impsysa_result, 1);
4842  (*r)->buf = NULL;
4843  (*r)->lines = NULL;
4844  ret = 1;
4845 ex:
4846  if (ret <= 0) {
4847  LIBISO_FREE_MEM(*r);
4848  *r = NULL;
4849  }
4850  return ret;
4851 }
4852 
4853 static
4855 {
4856  if (*r == NULL)
4857  return;
4858  if ((*r)->buf != NULL)
4859  free((*r)->buf);
4860  if ((*r)->lines != NULL)
4861  free((*r)->lines);
4862  free(*r);
4863  *r = NULL;
4864 }
4865 
4866 static
4867 void iso_impsysa_line(struct iso_impsysa_result *target, char *msg)
4868 {
4869  if (target->buf != NULL)
4870  strcpy(target->buf + target->byte_count, msg);
4871  if (target->lines != NULL)
4872  target->lines[target->line_count] = target->buf + target->byte_count;
4873  target->byte_count += strlen(msg) + 1;
4874  target->line_count++;
4875 }
4876 
4877 static
4879  char *msg, char *path, int flag)
4880 {
4881  if (strlen(msg) + strlen(path) >= ISO_MAX_SYSAREA_LINE_LENGTH)
4882  sprintf(msg + strlen(msg), "(too long to show here)");
4883  else
4884  strcat(msg, path);
4885  iso_impsysa_line(target, msg);
4886 }
4887 
4888 static
4889 void iso_impsysa_reduce_na(uint32_t block, uint32_t *na, uint32_t claim)
4890 {
4891  if ((*na == 0 || *na > claim) && block < claim)
4892  *na = claim;
4893 }
4894 
4895 static
4896 int iso_impsysa_reduce_next_above(IsoImage *image, uint32_t block,
4897  uint32_t *next_above, int flag)
4898 {
4899  int i, section_count, ret;
4900  struct iso_imported_sys_area *sai;
4901  struct el_torito_boot_image *img;
4902  struct iso_file_section *sections = NULL;
4903 
4904  sai = image->imported_sa_info;
4905 
4906  /* PVD, path table, root directory of active and of first session */
4907  for (i = 0; i < sai->num_meta_struct_blocks; i++)
4908  iso_impsysa_reduce_na(block, next_above, sai->meta_struct_blocks[i]);
4909 
4910  /* Partition tables */
4911  for (i = 0; i < sai->mbr_req_count; i++) {
4912  iso_impsysa_reduce_na(block, next_above,
4913  (uint32_t) (sai->mbr_req[i]->start_block / 4));
4914  iso_impsysa_reduce_na(block, next_above,
4915  (uint32_t) ((sai->mbr_req[i]->start_block +
4916  sai->mbr_req[i]->block_count) / 4));
4917  }
4918  for (i = 0; i < sai->gpt_req_count; i++) {
4919  iso_impsysa_reduce_na(block, next_above,
4920  (uint32_t) (sai->gpt_req[i]->start_block / 4));
4921  iso_impsysa_reduce_na(block, next_above,
4922  (uint32_t) ((sai->gpt_req[i]->start_block +
4923  sai->gpt_req[i]->block_count) / 4));
4924  }
4925  for (i = 0; i < sai->apm_req_count; i++) {
4926  iso_impsysa_reduce_na(block, next_above,
4927  (uint32_t) (sai->apm_req[i]->start_block /
4928  (2048 / sai->apm_block_size)));
4929  iso_impsysa_reduce_na(block, next_above,
4930  (uint32_t) ((sai->apm_req[i]->start_block +
4931  sai->apm_req[i]->block_count) /
4932  (2048 / sai->apm_block_size)));
4933  }
4934  if (image->bootcat != NULL) {
4935  if (image->bootcat->node != NULL)
4936  iso_impsysa_reduce_na(block, next_above,
4937  image->bootcat->node->lba);
4938  for (i= 0; i < image->bootcat->num_bootimages; i++) {
4939  img = image->bootcat->bootimages[i];
4940  ret = iso_file_get_old_image_sections(img->image, &section_count,
4941  &sections, 0);
4942  if (ret > 0 && section_count > 0)
4943  if (block != sections[0].block)
4944  iso_impsysa_reduce_na(block, next_above,
4945  sections[0].block);
4946  if (sections != NULL) {
4947  free(sections);
4948  sections = NULL;
4949  }
4950  }
4951  }
4952 
4953  iso_impsysa_reduce_na(block, next_above, sai->image_size);
4954 
4955  return ISO_SUCCESS;
4956 }
4957 
4958 /* @param flag bit0= try to estimate the size if no path is found
4959 */
4960 static
4962  struct iso_impsysa_result *target, char *msg,
4963  uint32_t start_block, int flag)
4964 {
4965  int ret;
4966  char *path = NULL, *cpt;
4967  IsoNode *node;
4968  uint32_t next_above = 0;
4969  uint32_t size;
4970 
4971  ret = iso_tree_get_node_of_block(image, NULL, start_block,
4972  &node, &next_above, 0);
4973  if (ret <= 0) {
4974  if (!(flag & 1))
4975  return;
4976  /* Look for next claimed block for estimating file size.
4977  next_above already holds the best data file candidate.
4978  */
4979  ret = iso_impsysa_reduce_next_above(image, start_block, &next_above, 0);
4980  if (ret < 0)
4981  return;
4982  if (next_above == 0)
4983  return;
4984  size = next_above - start_block;
4985 
4986  /* Replace in msg "path" by "blks", report number in blocks of 2048 */
4987  cpt = strstr(msg, "path");
4988  if (cpt == NULL)
4989  return;
4990  path = iso_alloc_mem(strlen(msg) + 20, 1, 0);
4991  if (path == NULL)
4992  return;
4993  strcpy(path, msg);
4994  memcpy(path + (cpt - msg), "blks", 4);
4995  sprintf(path + strlen(path), "%u", (unsigned int) size);
4996  iso_impsysa_report_text(target, path, "", 0);
4997  free(path);
4998  return;
4999  }
5000  path = iso_tree_get_node_path(node);
5001  if (path != NULL) {
5002  iso_impsysa_report_text(target, msg, path, 0);
5003  free(path);
5004  }
5005 }
5006 
5007 static
5009  int flag)
5010 {
5011  char *msg = NULL, *local_name = NULL, *path;
5012  int i, j, sa_type, sao, sa_sub, ret, idx;
5013  size_t local_len;
5014  struct iso_imported_sys_area *sai;
5015  struct iso_mbr_partition_request *part;
5016  struct iso_gpt_partition_request *gpt_entry;
5017  struct iso_apm_partition_request *apm_entry;
5018  static char *alignments[4] = {"auto", "on", "off", "all"};
5019  IsoWriteOpts *opts = NULL;
5020  struct iso_sun_disk_label_entry *sparc_entry;
5021 
5022  sai = image->imported_sa_info;
5023 
5025 
5026  if (sai == NULL)
5027  {ret = 0; goto ex;}
5028  if (!sai->is_not_zero)
5029  {ret = 0; goto ex;}
5030  sao = sai->system_area_options;
5031  sprintf(msg, "System area options: 0x%-8.8x", (unsigned int) sao);
5032  iso_impsysa_line(target, msg);
5033 
5034  /* Human readable form of system_area_options */
5035  sa_type = (sao >> 2) & 63;
5036  sa_sub = (sao >> 10) & 15;
5037  strcpy(msg, "System area summary:");
5038  if (sa_type == 0) {
5039  if ((sao & 3) || sa_sub == 1 || sa_sub == 2) {
5040  strcat(msg, " MBR");
5041  if (sao & 2)
5042  strcat(msg, " isohybrid");
5043  else if (sao & 1)
5044  strcat(msg, " protective-msdos-label");
5045  else if (sa_sub == 1) {
5046  strcat(msg, " CHRP");
5047  }
5048  if ((sao & (1 << 14)) && !(sao & 2))
5049  strcat(msg, " grub2-mbr");
5050  sprintf(msg + strlen(msg), " cyl-align-%s",
5051  alignments[(sao >> 8) & 3]);
5052  } else if (sai->prep_part_start > 0 && sai->prep_part_size > 0) {
5053  strcat(msg, " PReP");
5054  } else if (sai->mbr_req_count > 0) {
5055  strcat(msg, " MBR");
5056  } else {
5057  strcat(msg, " not-recognized");
5058  }
5059  } else if (sa_type == 1) {
5060  strcat(msg, " MIPS-Big-Endian");
5061  } else if (sa_type == 2) {
5062  strcat(msg, " MIPS-Little-Endian");
5063  } else if (sa_type == 3) {
5064  strcat(msg, " SUN-SPARC-Disk-Label");
5065  } else if (sa_type == 4 || sa_type == 5) {
5066  sprintf(msg + strlen(msg), " HP-PA-PALO");
5067  } else if (sa_type == 6) {
5068  sprintf(msg + strlen(msg), " DEC-Alpha");
5069  } else {
5070  sprintf(msg + strlen(msg), " unkown-system-area-type-%d", sa_type);
5071  }
5072  if (sai->gpt_req_count > 0)
5073  strcat(msg, " GPT");
5074  if (sai->apm_req_count > 0)
5075  strcat(msg, " APM");
5076 
5077  iso_impsysa_line(target, msg); /* System area summary */
5078 
5079  sprintf(msg, "ISO image size/512 : %.f",
5080  ((double) sai->image_size) * 4.0);
5081  iso_impsysa_line(target, msg);
5082  if (sai->mbr_req_count > 0 && sa_type == 0) {
5083  sprintf(msg, "Partition offset : %d", sai->partition_offset);
5084  iso_impsysa_line(target, msg);
5085  }
5086  if (sa_type >= 4 && sa_type <= 5) {
5087  sprintf(msg, "PALO header version: %d", sai->hppa_hdrversion);
5088  iso_impsysa_line(target, msg);
5089  sprintf(msg, "HP-PA cmdline : ");
5090  iso_impsysa_report_text(target, msg, sai->hppa_cmdline, 0);
5091  sprintf(msg, "HP-PA boot files : ByteAddr ByteSize Path");
5092  iso_impsysa_line(target, msg);
5093  sprintf(msg, "HP-PA 32-bit kernel: %10u %10u ",
5094  sai->hppa_kern32_adr, sai->hppa_kern32_len);
5095  iso_impsysa_report_text(target, msg,
5096  sai->hppa_kernel_32 != NULL ?
5097  sai->hppa_kernel_32 : "(not found in ISO)", 0);
5098  sprintf(msg, "HP-PA 64-bit kernel: %10u %10u ",
5099  sai->hppa_kern64_adr, sai->hppa_kern64_len);
5100  iso_impsysa_report_text(target, msg,
5101  sai->hppa_kernel_64 != NULL ?
5102  sai->hppa_kernel_64 : "(not found in ISO)", 0);
5103  sprintf(msg, "HP-PA ramdisk : %10u %10u ",
5104  sai->hppa_ramdisk_adr, sai->hppa_ramdisk_len);
5105  iso_impsysa_report_text(target, msg,
5106  sai->hppa_ramdisk != NULL ?
5107  sai->hppa_ramdisk : "(not found in ISO)", 0);
5108  sprintf(msg, "HP-PA bootloader : %10u %10u ",
5110  iso_impsysa_report_text(target, msg,
5111  sai->hppa_bootloader != NULL ?
5112  sai->hppa_bootloader : "(not found in ISO)", 0);
5113  } else if (sa_type == 6) {
5114  sprintf(msg, "DEC Alpha ldr size : %.f",
5115  (double) sai->alpha_boot_image_size);
5116  iso_impsysa_line(target, msg);
5117  sprintf(msg, "DEC Alpha ldr adr : %.f",
5118  (double) sai->alpha_boot_image_adr);
5119  iso_impsysa_line(target, msg);
5120  if (sai->alpha_boot_image != NULL) {
5121  sprintf(msg, "DEC Alpha ldr path : %s", sai->alpha_boot_image);
5122  iso_impsysa_line(target, msg);
5123  }
5124  }
5125  if (sai->mbr_req_count > 0) {
5126  sprintf(msg, "MBR heads per cyl : %d", sai->partition_heads_per_cyl);
5127  iso_impsysa_line(target, msg);
5128  sprintf(msg, "MBR secs per head : %d", sai->partition_secs_per_head);
5129  iso_impsysa_line(target, msg);
5130  sprintf(msg,
5131  "MBR partition table: N Status Type Start Blocks");
5132  iso_impsysa_line(target, msg);
5133  }
5134  for (i = 0; i < sai->mbr_req_count; i++) {
5135  part = sai->mbr_req[i];
5136  sprintf(msg,
5137  "MBR partition : %3d 0x%2.2x 0x%2.2x %11.f %11.f",
5138  part->desired_slot,
5139  (unsigned int) part->status_byte,
5140  (unsigned int) part->type_byte,
5141  (double) part->start_block, (double) part->block_count);
5142  iso_impsysa_line(target, msg);
5143  }
5144  for (i = 0; i < sai->mbr_req_count; i++) {
5145  part = sai->mbr_req[i];
5146  if (part->block_count == 0)
5147  continue;
5148  sprintf(msg, "MBR partition path : %3d ", part->desired_slot);
5149  iso_impsysa_report_blockpath(image, target, msg,
5150  (uint32_t) (part->start_block / 4), 0);
5151  }
5152  if (sai->prep_part_start > 0 && sai->prep_part_size > 0) {
5153  sprintf(msg, "PReP boot partition: %u %u",
5154  sai->prep_part_start, sai->prep_part_size);
5155  iso_impsysa_line(target, msg);
5156  }
5157 
5158  if (sa_type == 1) {
5159  sprintf(msg,
5160  "MIPS-BE volume dir : N Name Block Bytes");
5161  iso_impsysa_line(target, msg);
5162  for (i = 0; i < sai->num_mips_boot_files; i++) {
5163  sprintf(msg,
5164  "MIPS-BE boot entry : %3d %8s %10u %10u",
5165  i + 1, sai->mips_vd_entries[i]->name,
5166  sai->mips_vd_entries[i]->boot_block,
5167  sai->mips_vd_entries[i]->boot_bytes);
5168  iso_impsysa_line(target, msg);
5169  if (sai->mips_boot_file_paths[i] != NULL) {
5170  sprintf(msg, "MIPS-BE boot path : %3d ", i + 1);
5171  iso_impsysa_report_text(target, msg,
5172  sai->mips_boot_file_paths[i], 0);
5173  }
5174  }
5175  } else if (sa_type == 2) {
5176  sprintf(msg,
5177  "MIPS-LE boot map : LoadAddr ExecAddr SegmentSize SegmentStart");
5178  iso_impsysa_line(target, msg);
5179  sprintf(msg, "MIPS-LE boot params: %10u %10u %10u %10u",
5181  sai->mipsel_seg_start);
5182  iso_impsysa_line(target, msg);
5183  if (sai->mipsel_boot_file_path != NULL) {
5184  sprintf(msg, "MIPS-LE boot path : ");
5185  iso_impsysa_report_text(target, msg,
5186  sai->mipsel_boot_file_path, 0);
5187  sprintf(msg, "MIPS-LE elf offset : %u", sai->mipsel_p_offset);
5188  iso_impsysa_line(target, msg);
5189  }
5190  } else if (sa_type == 3) {
5191  sprintf(msg, "SUN SPARC disklabel: %s", sai->sparc_disc_label);
5192  iso_impsysa_line(target, msg);
5193  sprintf(msg, "SUN SPARC secs/head: %d", sai->sparc_secs_per_head);
5194  iso_impsysa_line(target, msg);
5195  sprintf(msg, "SUN SPARC heads/cyl: %d", sai->sparc_heads_per_cyl);
5196  iso_impsysa_line(target, msg);
5197  sprintf(msg,
5198  "SUN SPARC partmap : N IdTag Perms StartCyl NumBlocks");
5199  iso_impsysa_line(target, msg);
5200  for (i = 0; i < sai->sparc_entry_count; i++) {
5201  sparc_entry = sai->sparc_entries + i;
5202  sprintf(msg,
5203  "SUN SPARC partition: %3d 0x%4.4x 0x%4.4x %10u %10u",
5204  sparc_entry->idx,
5205  sparc_entry->id_tag, sparc_entry->permissions,
5206  sparc_entry->start_cyl, sparc_entry->num_blocks);
5207  iso_impsysa_line(target, msg);
5208  }
5209  if (sai->sparc_grub2_core_adr > 0) {
5210  sprintf(msg, "SPARC GRUB2 core : %.f %u",
5211  (double) sai->sparc_grub2_core_adr,
5212  sai->sparc_grub2_core_size);
5213  iso_impsysa_line(target, msg);
5214  if (sai->sparc_core_node != NULL) {
5216  if (path != NULL) {
5217  sprintf(msg, "SPARC GRUB2 path : ");
5218  iso_impsysa_report_text(target, msg, path, 0);
5219  free(path);
5220  }
5221  }
5222  }
5223  }
5224 
5225  if (sai->gpt_req_count > 0) {
5226  sprintf(msg, "GPT : N Info");
5227  iso_impsysa_line(target, msg);
5228  if (sai->gpt_head_crc_should != sai->gpt_head_crc_found) {
5229  sprintf(msg,
5230  "GPT CRC should be : 0x%8.8x to match first 92 GPT header block bytes",
5231  sai->gpt_head_crc_should);
5232  iso_impsysa_line(target, msg);
5233  sprintf(msg,
5234  "GPT CRC found : 0x%8.8x matches all 512 bytes of GPT header block",
5235  sai->gpt_head_crc_found);
5236  iso_impsysa_line(target, msg);
5237  }
5238  if (sai->gpt_array_crc_should != sai->gpt_array_crc_found) {
5239  sprintf(msg,
5240  "GPT array CRC wrong: should be 0x%8.8x , found 0x%8.8x",
5242  iso_impsysa_line(target, msg);
5243  }
5244  if (sai->gpt_backup_comments != NULL) {
5245  if (sai->gpt_backup_comments[0]) {
5246  sprintf(msg, "GPT backup problems: ");
5247  iso_impsysa_report_text(target, msg,
5248  sai->gpt_backup_comments, 0);
5249  }
5250  }
5251  sprintf(msg, "GPT disk GUID : ");
5252  iso_util_bin_to_hex(msg + 26, sai->gpt_disk_guid, 16, 0);
5253  iso_impsysa_line(target, msg);
5254  sprintf(msg, "GPT entry array : %u %u %s",
5255  (unsigned int) sai->gpt_part_start,
5256  (unsigned int) sai->gpt_max_entries,
5257  sai->gpt_req_flags & 1 ? "overlapping" : "separated");
5258  iso_impsysa_line(target, msg);
5259  sprintf(msg, "GPT lba range : %.f %.f %.f",
5260  (double) sai->gpt_first_lba, (double) sai->gpt_last_lba,
5261  (double) sai->gpt_backup_lba);
5262  iso_impsysa_line(target, msg);
5263  ret = iso_write_opts_new(&opts, 0);
5264  if (ret < 0)
5265  goto ex;
5266  ret = iso_write_opts_set_output_charset(opts, "UTF-16LE");
5267  if (ret < 0)
5268  goto ex;
5269  }
5270  for (i = 0; i < sai->gpt_req_count; i++) {
5271  gpt_entry = sai->gpt_req[i];
5272  idx = gpt_entry->idx;
5273 
5274  sprintf(msg, "GPT partition name : %3d ", idx);
5275  for (j = 72; j >= 2; j -= 2)
5276  if (gpt_entry->name[j - 2] || gpt_entry->name[j - 1])
5277  break;
5278  iso_util_bin_to_hex(msg + 26, gpt_entry->name, j, 0);
5279  iso_impsysa_line(target, msg);
5280  if (j > 0)
5281  ret = iso_conv_name_chars(opts, (char *) gpt_entry->name, j,
5282  &local_name, &local_len, 0 | 512 | (1 << 15));
5283  else
5284  ret = 0;
5285  if (ret == 1 && local_len <= 228) {
5286  sprintf(msg, "GPT partname local : %3d ", idx);
5287  memcpy(msg + 26, local_name, local_len);
5288  LIBISO_FREE_MEM(local_name); local_name = NULL;
5289  msg[26 + local_len] = 0;
5290  iso_impsysa_line(target, msg);
5291  }
5292  sprintf(msg, "GPT partition GUID : %3d ", idx);
5293  iso_util_bin_to_hex(msg + 26, gpt_entry->partition_guid, 16, 0);
5294  iso_impsysa_line(target, msg);
5295  sprintf(msg, "GPT type GUID : %3d ", idx);
5296  iso_util_bin_to_hex(msg + 26, gpt_entry->type_guid, 16, 0);
5297  iso_impsysa_line(target, msg);
5298  sprintf(msg, "GPT partition flags: %3d 0x%8.8x%8.8x", idx,
5299  (unsigned int) ((gpt_entry->flags >> 32) & 0xffffffff),
5300  (unsigned int) (gpt_entry->flags & 0xffffffff));
5301  iso_impsysa_line(target, msg);
5302  sprintf(msg, "GPT start and size : %3d %.f %.f", idx,
5303  (double) gpt_entry->start_block,
5304  (double) gpt_entry->block_count);
5305  iso_impsysa_line(target, msg);
5306  if (gpt_entry->block_count == 0)
5307  continue;
5308  sprintf(msg, "GPT partition path : %3d ", idx);
5309  iso_impsysa_report_blockpath(image, target, msg,
5310  (uint32_t) (gpt_entry->start_block / 4), 0);
5311  }
5312 
5313  if (sai->apm_req_count > 0) {
5314  sprintf(msg, "APM : N Info");
5315  iso_impsysa_line(target, msg);
5316  sprintf(msg, "APM block size : %u", sai->apm_block_size);
5317  iso_impsysa_line(target, msg);
5318  sprintf(msg, "APM gap fillers : %d", sai->apm_gap_count);
5319  iso_impsysa_line(target, msg);
5320  }
5321  for (i = 0; i < sai->apm_req_count; i++) {
5322  apm_entry = sai->apm_req[i];
5323  idx = i + 1;
5324  sprintf(msg, "APM partition name : %3d %s", idx, apm_entry->name);
5325  iso_impsysa_line(target, msg);
5326  sprintf(msg, "APM partition type : %3d %s", idx, apm_entry->type);
5327  iso_impsysa_line(target, msg);
5328  sprintf(msg, "APM start and size : %3d %.f %.f", idx,
5329  (double) apm_entry->start_block,
5330  (double) apm_entry->block_count);
5331  iso_impsysa_line(target, msg);
5332  if (apm_entry->block_count == 0)
5333  continue;
5334  sprintf(msg, "APM partition path : %3d ", idx);
5335  iso_impsysa_report_blockpath(image, target, msg,
5336  (uint32_t) (apm_entry->start_block /
5337  (2048 / sai->apm_block_size)),
5338  0);
5339  }
5340 
5341  ret = 1;
5342 ex:
5343  LIBISO_FREE_MEM(local_name);
5344  if (opts != NULL)
5345  iso_write_opts_free(opts);
5346  LIBISO_FREE_MEM(msg);
5347  return ret;
5348 }
5349 
5350 static
5351 int iso_report_result_destroy(char ***result, int flag)
5352 {
5353  if (*result == NULL)
5354  return ISO_SUCCESS;
5355  if ((*result)[0] != NULL) /* points to the whole multi-line buffer */
5356  free((*result)[0]);
5357  free(*result);
5358  *result = NULL;
5359  return ISO_SUCCESS;
5360 }
5361 
5362 static
5363 int iso_report_help(char **doc, char ***result, int *line_count, int flag)
5364 {
5365  int i, count = 0;
5366  char *buf = NULL;
5367 
5368  *line_count = 0;
5369  for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++)
5370  count += strlen(doc[i]) + 1;
5371  if (i == 0)
5372  return ISO_SUCCESS;
5373  *result = calloc(i, sizeof(char *));
5374  if (*result == NULL)
5375  return ISO_OUT_OF_MEM;
5376  buf = calloc(1, count);
5377  if (buf == NULL) {
5378  free(*result);
5379  *result = NULL;
5380  return ISO_OUT_OF_MEM;
5381  }
5382  *line_count = i;
5383  count = 0;
5384  for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++) {
5385  strcpy(buf + count, doc[i]);
5386  (*result)[i] = buf + count;
5387  count += strlen(doc[i]) + 1;
5388  }
5389  return ISO_SUCCESS;
5390 }
5391 
5392 static
5394  uint32_t lba, int flag)
5395 {
5396  uint32_t max_size = 0, start_lba, num_blocks;
5397  int i, ret;
5398  uint8_t *buffer = NULL;
5399 
5400  /* Obtain first block of image */
5401  LIBISO_ALLOC_MEM(buffer, uint8_t, 2048);
5402  ret = src->read_block(src, lba, buffer);
5403  if (ret < 0)
5404  goto ex;
5405 
5406  /* Check for magic number of MBR */
5407  if (buffer[510] != 0x55 || buffer[511] != 0xaa)
5408  goto ex;
5409 
5410  for (i = 0; i < 4; i++) {
5411  start_lba = iso_read_lsb(buffer + 454 + 16 * i, 4);
5412  num_blocks = iso_read_lsb(buffer + 458 + 16 * i, 4);
5413  if (start_lba + num_blocks > max_size)
5414  max_size = start_lba + num_blocks;
5415  }
5416 ex:;
5418  return max_size;
5419 }
5420 
5421 static
5423  int flag)
5424 {
5425  char *msg = NULL, emul_code[6], pltf[5], *path;
5426  int i, j, ret, section_count;
5427  uint32_t lba, *lba_mem = NULL;
5428  struct el_torito_boot_catalog *bootcat;
5429  IsoBoot *bootnode;
5430  struct el_torito_boot_image *img;
5431  struct iso_file_section *sections = NULL;
5432  static char emul_names[5][6] = {"none", "fd1.2", "fd1.4", "fd2.8", "hd"};
5433  static char pltf_names[3][5] = {"BIOS", "PPC", "Mac"};
5434  static int num_emuls = 5, num_pltf = 3;
5435 
5436  bootcat = image->bootcat;
5437 
5439 
5440  if (bootcat == NULL)
5441  {ret= 0; goto ex;}
5442  bootnode = image->bootcat->node;
5443  if (bootnode == NULL)
5444  {ret= 0; goto ex;}
5445 
5446  sprintf(msg, "El Torito catalog : %u %u",
5447  (unsigned int) bootnode->lba,
5448  (unsigned int) (bootnode->size + 2047) / 2048);
5449  iso_impsysa_line(target, msg);
5450  path = iso_tree_get_node_path((IsoNode *) bootnode);
5451  if (path != NULL) {
5452  sprintf(msg, "El Torito cat path : ");
5453  iso_impsysa_report_text(target, msg, path, 0);
5454  free(path);
5455  }
5456  if (bootcat->num_bootimages > 0) {
5457  sprintf(msg,
5458 "El Torito images : N Pltf B Emul Ld_seg Hdpt Ldsiz LBA");
5459  iso_impsysa_line(target, msg);
5460  LIBISO_ALLOC_MEM(lba_mem, uint32_t, bootcat->num_bootimages);
5461  }
5462  for (i= 0; i < bootcat->num_bootimages; i++) {
5463  img = bootcat->bootimages[i];
5464  if (img->type < num_emuls)
5465  strcpy(emul_code, emul_names[img->type]);
5466  else
5467  sprintf(emul_code, "0x%2.2x", (unsigned int) img->type);
5468  if (img->platform_id < num_pltf)
5469  strcpy(pltf, pltf_names[img->platform_id]);
5470  else if(img->platform_id == 0xef)
5471  strcpy(pltf, "UEFI");
5472  else
5473  sprintf(pltf, "0x%2.2x", (unsigned int) img->platform_id);
5474  lba = 0xffffffff;
5475  ret = iso_file_get_old_image_sections(img->image, &section_count,
5476  &sections, 0);
5477  if (ret > 0 && section_count > 0)
5478  lba = sections[0].block;
5479  lba_mem[i]= lba;
5480  if (sections != NULL) {
5481  free(sections);
5482  sections = NULL;
5483  }
5484  sprintf(msg,
5485  "El Torito boot img : %3d %4s %c %5s 0x%4.4x 0x%2.2x %5u %10u",
5486  i + 1, pltf, img->bootable ? 'y' : 'n', emul_code,
5487  (unsigned int) img->load_seg, (unsigned int) img->partition_type,
5488  (unsigned int) img->load_size,
5489  (unsigned int) lba);
5490  iso_impsysa_line(target, msg);
5491  }
5492  for (i= 0; i < bootcat->num_bootimages; i++) {
5493  img = bootcat->bootimages[i];
5494  if (lba_mem[i] != 0xffffffff) {
5495  sprintf(msg, "El Torito img path : %3d ", i + 1);
5496  iso_impsysa_report_blockpath(image, target, msg, lba_mem[i], 1);
5497  if (img->type == 4 && img->emul_hdd_size > 0) {
5498  sprintf(msg, "El Torito hdsiz/512: %3d %u",
5499  i + 1, (unsigned int) img->emul_hdd_size);
5500  iso_impsysa_line(target, msg);
5501  }
5502  }
5503  sprintf(msg, "El Torito img opts : %3d ", i + 1);
5504  if (img->seems_boot_info_table)
5505  strcat(msg, "boot-info-table ");
5506  if (img->seems_isohybrid_capable)
5507  strcat(msg, "isohybrid-suitable ");
5508  if (img->seems_grub2_boot_info)
5509  strcat(msg, "grub2-boot-info ");
5510  if (strlen(msg) > 27) {
5511  msg[strlen(msg) - 1] = 0;
5512  iso_impsysa_line(target, msg);
5513  }
5514  for (j = 0; j < (int) sizeof(img->id_string); j++)
5515  if (img->id_string[j])
5516  break;
5517  if (j < (int) sizeof(img->id_string)) {
5518  sprintf(msg, "El Torito id string: %3d ", i + 1);
5519  iso_util_bin_to_hex(msg + strlen(msg),
5520  img->id_string, 24 + 4 * (i > 0), 0);
5521  }
5522  for (j = 0; j < (int) sizeof(img->selection_crit); j++)
5523  if (img->selection_crit[j])
5524  break;
5525  if (j < (int) sizeof(img->selection_crit) && i > 0) {
5526  sprintf(msg, "El Torito sel crit : %3d ", i + 1);
5527  iso_util_bin_to_hex(msg + strlen(msg),
5528  img->selection_crit, 20, 0);
5529  }
5530  }
5531 
5532  ret = ISO_SUCCESS;
5533 ex:;
5534  LIBISO_FREE_MEM(msg);
5535  LIBISO_FREE_MEM(lba_mem);
5536  return ret;
5537 }
5538 
5539 
5540 /* API */
5541 /* @param flag bit1= do not report system area but rather reply help text
5542  bit15= dispose result from previous call
5543 */
5544 static
5546  char ***result, int *line_count, int flag)
5547 {
5548  int ret;
5549  char **doc;
5550  struct iso_impsysa_result *target = NULL;
5551  static char *sysarea_doc[] = { ISO_SYSAREA_REPORT_DOC ,
5560  "@END_OF_DOC@" };
5561  static char *eltorito_doc[] = { ISO_ELTORITO_REPORT_DOC ,
5562  "@END_OF_DOC@" };
5563 
5564  if (flag & (1 << 15))
5565  return iso_report_result_destroy(result, 0);
5566  if (flag & 1) {
5567  if (what == 0)
5568  doc = sysarea_doc;
5569  else
5570  doc = eltorito_doc;
5571  return iso_report_help(doc, result, line_count, 0);
5572  }
5573 
5574  *result = NULL;
5575  *line_count = 0;
5576  ret = iso_impsysa_result_new(&target, 0);
5577  if (ret < 0)
5578  goto ex;
5579  if (what == 0)
5580  ret = iso_impsysa_report(image, target, 0);
5581  else
5582  ret = iso_eltorito_report(image, target, 0);
5583  if (ret <= 0)
5584  goto ex;
5585  target->buf = calloc(1, target->byte_count + 1);
5586  target->lines = calloc(target->line_count + 1, sizeof(char *));
5587  if (target->buf == NULL || target->lines == NULL)
5588  {ret = ISO_OUT_OF_MEM; goto ex;}
5589  target->lines[0] = target->buf; /* even if no lines get reported */
5590  target->byte_count = 0;
5591  target->line_count = 0;
5592  if (what == 0)
5593  ret = iso_impsysa_report(image, target, 0);
5594  else
5595  ret = iso_eltorito_report(image, target, 0);
5596  if (ret <= 0)
5597  goto ex;
5598 
5599  /* target to result */
5600  *result = target->lines;
5601  target->lines = NULL;
5602  target->buf = NULL;
5603  *line_count = target->line_count;
5604 
5605  ret = ISO_SUCCESS;
5606 ex:
5607  iso_impsysa_result_destroy(&target, 0);
5608  return ret;
5609 }
5610 
5611 /* API */
5612 /* @param flag bit1= do not report system area but rather reply help text
5613  bit15= dispose result from previous call
5614 */
5616  char ***result, int *line_count, int flag)
5617 {
5618  return iso_image_report_boot_eqp(image, 0, result, line_count, flag);
5619 }
5620 
5621 static
5622 int iso_record_pvd_blocks(IsoImage *image, IsoDataSource *src, uint32_t block,
5623  int flag)
5624 {
5625  int ret;
5626  uint8_t *buffer = NULL;
5627  struct iso_imported_sys_area *sai;
5628 
5629  LIBISO_ALLOC_MEM(buffer, uint8_t, 2048);
5630 
5631  sai = image->imported_sa_info;
5632  sai->meta_struct_blocks[sai->num_meta_struct_blocks++] = block;
5633 
5634  ret = src->read_block(src, block, buffer);
5635  if (ret < 0)
5636  goto ex;
5637 
5638  /* Verify that it is a PVD of a volume not larger than sai->image_size */
5639  if (buffer[0] != 1 || strncmp((char *) buffer + 1, "CD001", 5) != 0)
5640  {ret = 0; goto ex;}
5641  if (iso_read_lsb(buffer + 80, 4) > sai->image_size)
5642  {ret = 0; goto ex;}
5643 
5644  /* L pathtable, Opt L, M pathtable , Opt M, Root directory extent*/
5646  iso_read_lsb(buffer + 140, 4);
5648  iso_read_lsb(buffer + 144, 4);
5650  iso_read_lsb(buffer + 148, 4);
5652  iso_read_lsb(buffer + 152, 4);
5654  iso_read_lsb(buffer + 158, 4);
5655 
5656  ret = ISO_SUCCESS;
5657 ex:;
5659  return ret;
5660 }
5661 
5662 static
5664  int flag)
5665 {
5666  int ret;
5667  struct iso_imported_sys_area *sai;
5668 
5669  sai = image->imported_sa_info;
5670  ret = iso_record_pvd_blocks(image, src, sai->pvd_block, 0);
5671  if (ret < 0)
5672  goto ex;
5673  /* Try block 32 as first session PVD */
5674  ret = iso_record_pvd_blocks(image, src, 16, 0);
5675  if (ret < 0)
5676  goto ex;
5677  if (ret == 0 && sai->pvd_block > 16) {
5678  /* No emulated multi-session: Try block 16 as first session PVD */
5679  ret = iso_record_pvd_blocks(image, src, 16, 0);
5680  if (ret < 0)
5681  goto ex;
5682  }
5683  ret = ISO_SUCCESS;
5684 ex:
5685  return ret;
5686 }
5687 
5688 static
5690  struct iso_read_opts *opts, uint32_t image_size,
5691  int flag)
5692 {
5693  int ret, i, sao, sa_type, sa_sub;
5694 
5696  ret = iso_imported_sa_new(&(image->imported_sa_info), 0);
5697  if (ret < 0)
5698  goto ex;
5699 
5700  for (i = 0; i < 32768; i++)
5701  if (image->system_area_data[i] != 0)
5702  break;
5703  if (i < 32768)
5704  image->imported_sa_info->is_not_zero = 1;
5705 
5707  image->imported_sa_info->pvd_block = opts->block + 16;
5708 
5709  ret = iso_analyze_mbr(image, src, 0);
5710  if (ret < 0)
5711  goto ex;
5712  ret = iso_analyze_gpt(image, src, 0);
5713  if (ret < 0)
5714  goto ex;
5715  ret = iso_analyze_apm(image, src, 0);
5716  if (ret < 0)
5717  goto ex;
5718  sao = image->imported_sa_info->system_area_options;
5719  sa_type = (sao >> 2) & 0x3f;
5720  sa_sub = (sao >> 10) & 0xf;
5721  if (sa_type == 0 && !((sao & 3) || sa_sub == 1 || sa_sub == 2)) {
5722  ret = iso_analyze_mips(image, src, 0);
5723  if (ret < 0)
5724  goto ex;
5725  if (ret == 0) {
5726  ret = iso_analyze_mipsel(image, src, 0);
5727  if (ret < 0)
5728  goto ex;
5729  }
5730  if (ret == 0) {
5731  ret =