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  */
76 struct iso_read_opts
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      */
130     char *input_charset;
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      */
139     int auto_input_charset;
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      */
146     int load_system_area;
147 
148     /**
149      * Keep data source of imported ISO filesystem in IsoImage.import_src
150      */
151     int keep_import_src;
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      */
158     int truncate_mode;
159     int truncate_length;
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  */
168 struct iso_read_image_features
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      */
195     int tree_loaded;
196 
197     /** Whether Rock Ridge info was used while loading: 0= no, 1= yes */
198     int rr_loaded;
199 
200 };
201 
202 static int ifs_fs_open(IsoImageFilesystem *fs);
203 static int ifs_fs_close(IsoImageFilesystem *fs);
204 static int iso_file_source_new_ifs(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  */
214 enum read_rr_ext {
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 */
227     IsoDataSource *src;
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      */
256     int auto_input_charset;
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 */
302     char *copyright_file_id;
303     char *abstract_file_id;
304     char *biblio_file_id;
305     char *creation_time;
306     char *modification_time;
307     char *expiration_time;
308     char *effective_time;
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      */
327     int truncate_mode;
328     int truncate_length;
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      */
335     int aaip_load;
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      */
345     int aaip_version;
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 */
359     int num_bootimgs;
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      */
389     int px_ino_status;
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     */
413     int rr_err_reported;
414     int rr_err_repeated;
415 
416     size_t joliet_ucs2_failures;
417 
418 } _ImageFsData;
419 
420 typedef struct image_fs_data ImageFileSourceData;
421 
422 /* IMPORTANT: Any change must be reflected by ifs_clone_src */
423 struct image_fs_data
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      */
434     struct iso_file_section *sections;
435     int nsections;
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 
473 struct child_list
474 {
475     IsoFileSource *file;
476     struct child_list *next;
477 };
478 
child_list_free(struct child_list * list)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;
485         iso_file_source_unref(next->file);
486         free(next);
487         next = temp;
488     }
489 }
490 
491 static
ifs_get_path(IsoFileSource * src)492 char* ifs_get_path(IsoFileSource *src)
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
ifs_get_name(IsoFileSource * src)522 char* ifs_get_name(IsoFileSource *src)
523 {
524     ImageFileSourceData *data;
525     data = src->data;
526     return data->name == NULL ? NULL : strdup(data->name);
527 }
528 
529 static
ifs_lstat(IsoFileSource * src,struct stat * info)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
ifs_stat(IsoFileSource * src,struct stat * info)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
ifs_access(IsoFileSource * src)565 int ifs_access(IsoFileSource *src)
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
read_dir(ImageFileSourceData * data)577 int read_dir(ImageFileSourceData *data)
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 
594     LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
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:;
713     LIBISO_FREE_MEM(buffer);
714     return ret;
715 }
716 
717 static
ifs_open(IsoFileSource * src)718 int ifs_open(IsoFileSource *src)
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) {
729         return ISO_FILE_ALREADY_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
ifs_close(IsoFileSource * src)775 int ifs_close(IsoFileSource *src)
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
block_from_offset(int nsections,struct iso_file_section * sections,off_t offset)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
size_available(int nsections,struct iso_file_section * sections,off_t offset)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
block_offset(int nsections,struct iso_file_section * sections,off_t offset)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
ifs_read(IsoFileSource * src,void * buf,size_t count)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
ifs_lseek(IsoFileSource * src,off_t offset,int flag)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
ifs_readdir(IsoFileSource * src,IsoFileSource ** child)1018 int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
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
ifs_readlink(IsoFileSource * src,char * buf,size_t bufsiz)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
ifs_get_filesystem(IsoFileSource * src)1112 IsoFilesystem* ifs_get_filesystem(IsoFileSource *src)
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
ifs_free(IsoFileSource * src)1125 void ifs_free(IsoFileSource *src)
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) {
1142         iso_file_source_unref(data->parent);
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
ifs_get_aa_string(IsoFileSource * src,unsigned char ** aa_string,int flag)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
ifs_clone_src(IsoFileSource * old_source,IsoFileSource ** new_source,int flag)1175 int ifs_clone_src(IsoFileSource *old_source,
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 
1252 IsoFileSourceIface ifs_class = {
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,
1265     ifs_get_filesystem,
1266     ifs_free,
1267     ifs_lseek,
1268     ifs_get_aa_string,
1269     ifs_clone_src
1270 
1271 };
1272 
1273 
1274 /* Used from libisofs/stream.c : iso_stream_get_src_zf() */
iso_ifs_source_get_zf(IsoFileSource * src,uint8_t zisofs_algo[2],int * header_size_div4,int * block_size_log2,uint64_t * uncompressed_size,int flag)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
make_hopefully_unique_name(_ImageFsData * fsdata,char * str,size_t len,char ** name)1303 int make_hopefully_unique_name(_ImageFsData *fsdata,
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
get_name(_ImageFsData * fsdata,char * str,size_t len)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 <=
1377                                                      ISO_JOLIET_UCS2_WARN_MAX)
1378                         iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
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
iso_rr_msg_submit(_ImageFsData * fsdata,int rr_err_bit,int errcode,int causedby,const char * msg)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
iso_file_source_new_ifs(IsoImageFilesystem * fs,IsoFileSource * parent,struct ecma119_dir_record * record,IsoFileSource ** src,int flag)1453 int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
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]) {
1510         iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 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) {
1528             iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
1529                           "Cannot retrieve file name");
1530             {ret = ISO_WRONG_ECMA119; goto ex;}
1531         }
1532         if (strcmp(new_name, data->name)) {
1533             iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
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)) {
1549             iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
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) {
1568                 iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
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);
1904                 ret = iso_rr_msg_submit(fsdata, 17, ISO_FILENAME_WRONG_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);
1929                 ret = iso_rr_msg_submit(fsdata, 17, ISO_FILENAME_WRONG_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);
2172     LIBISO_FREE_MEM(buffer);
2173     return ret;
2174 }
2175 
2176 static
ifs_get_root(IsoFilesystem * fs,IsoFileSource ** root)2177 int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root)
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) {
2199         ifs_fs_close((IsoImageFilesystem*)fs);
2200         goto ex;
2201     }
2202 
2203     /* get root attributes from "." entry */
2204     *root = NULL;
2205     ret = iso_file_source_new_ifs((IsoImageFilesystem*)fs, NULL,
2206                                  (struct ecma119_dir_record*) buffer, root, 1);
2207 
2208     ifs_fs_close((IsoImageFilesystem*)fs);
2209 ex:;
2210     LIBISO_FREE_MEM(buffer);
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
ifs_get_file(IsoFileSource * dir,const char * name,IsoFileSource ** file)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
ifs_get_by_path(IsoFilesystem * fs,const char * path,IsoFileSource ** file)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:;
2320     ifs_fs_close((IsoImageFilesystem*)fs);
2321     return ret;
2322 }
2323 
ifs_get_id(IsoFilesystem * fs)2324 unsigned int ifs_get_id(IsoFilesystem *fs)
2325 {
2326     return ISO_IMAGE_FS_ID;
2327 }
2328 
2329 static
ifs_fs_open(IsoImageFilesystem * fs)2330 int ifs_fs_open(IsoImageFilesystem *fs)
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
ifs_fs_close(IsoImageFilesystem * fs)2352 int ifs_fs_close(IsoImageFilesystem *fs)
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
ifs_fs_free(IsoFilesystem * fs)2370 void ifs_fs_free(IsoFilesystem *fs)
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
read_root_susp_entries(_ImageFsData * data,uint32_t block)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)
2553                     iso_msg_submit(data->msgid, ISO_AAIP_IGNORED, 0,
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:
2576     LIBISO_FREE_MEM(buffer);
2577     return ret;
2578 }
2579 
2580 static
read_pvd_block(IsoDataSource * src,uint32_t block,uint8_t * buffer,uint32_t * image_size)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
read_pvm(_ImageFsData * data,uint32_t block)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 =
2635                iso_util_strcopy_untail((char*) pvm->bibliographic_file_id, 37);
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 =
2652             iso_util_strcopy_untail((char*) pvm->vol_modification_time, 17);
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:;
2677     LIBISO_FREE_MEM(buffer);
2678     return ret;
2679 }
2680 
2681 /**
2682  * @return
2683  *      1 success, 0 ignored, < 0 error
2684  */
2685 static
read_el_torito_boot_catalog(_ImageFsData * data,uint32_t block)2686 int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
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) ) {
2707         iso_msg_submit(data->msgid, ISO_WRONG_EL_TORITO, 0,
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 
2754                 iso_msg_submit(data->msgid, ISO_EL_TORITO_WARN, 0,
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:;
2798     LIBISO_FREE_MEM(buffer);
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
iso_src_check_sb_tree(IsoDataSource * src,uint32_t start_lba,int flag)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);
2882     LIBISO_FREE_MEM(block);
2883     return ret;
2884 }
2885 
2886 
iso_image_filesystem_new(IsoDataSource * src,struct iso_read_opts * opts,int msgid,IsoImageFilesystem ** fs)2887 int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
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;
2961     ifs->get_by_path = ifs_get_by_path;
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,
3012                           ISO_UNSUPPORTED_EL_TORITO, 0,
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:
3074             iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
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:;
3151     LIBISO_FREE_MEM(buffer);
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
src_aa_to_node(IsoFileSource * src,IsoNode * node,int flag)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
image_builder_create_node(IsoNodeBuilder * builder,IsoImage * image,IsoFileSource * src,char * in_name,IsoNode ** node)3196 int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
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 
3394             LIBISO_ALLOC_MEM(dest, char, LIBISOFS_NODE_PATH_MAX);
3395 
3396             ret = iso_file_source_readlink(src, dest, LIBISOFS_NODE_PATH_MAX);
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
iso_image_builder_new(IsoNodeBuilder * old,IsoNodeBuilder ** builder)3481 int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder)
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;
3495     b->create_file_data = old->create_file_data;
3496     b->create_node_data = old->create_node_data;
3497     b->create_file = old->create_file;
3498     b->create_node = image_builder_create_node;
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
create_boot_img_filesrc(IsoImageFilesystem * fs,IsoImage * image,int idx,IsoFileSource ** src)3510 int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, int idx,
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
iso_image_eval_boot_info_table(IsoImage * image,struct iso_read_opts * opts,IsoDataSource * src,uint32_t iso_image_size,int flag)3591 int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts,
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;
3681                  j >= Libisofs_grub2_elto_patch_poS; j--)
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
issue_collision_warning_summary(size_t failures)3706 void issue_collision_warning_summary(size_t failures)
3707 {
3708     if (failures > ISO_IMPORT_COLL_WARN_MAX) {
3709         iso_msg_submit(-1, ISO_IMPORT_COLLISION, 0,
3710                        "More file name collisions had to be resolved");
3711     }
3712     if (failures > 0) {
3713         iso_msg_submit(-1, ISO_IMPORT_COLLISION, 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
iso_scan_hc_sh(uint32_t lba,int c,int h,int s,uint8_t * matches)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
iso_get_hc_sh(uint8_t * matches,uint32_t iso_image_size,int * hc,int * sh,int flag)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
iso_analyze_mbr_ptable(IsoImage * image,int flag)3803 int iso_analyze_mbr_ptable(IsoImage *image, int flag)
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 */
3878         iso_get_hc_sh(hc_sh, image_size, &(sai->partition_heads_per_cyl),
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 *
3888                         sai->partition_heads_per_cyl;
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
iso_analyze_isohybrid(IsoImage * image,int flag)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
iso_analyze_partition_offset(IsoImage * image,IsoDataSource * src,uint64_t start_block,uint64_t block_count,int flag)3966 int iso_analyze_partition_offset(IsoImage *image, IsoDataSource *src,
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
iso_analyze_mbr(IsoImage * image,IsoDataSource * src,int flag)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
iso_seems_usable_gpt_head(uint8_t * head,int flag)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
iso_analyze_gpt_backup(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_gpt_head(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_gpt(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_apm_head(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_apm(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_mips(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_mipsel(IsoImage * image,IsoDataSource * src,int flag)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) {
4609         sai->mipsel_boot_file_path = iso_tree_get_node_path(node);
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
iso_analyze_sun(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_hppa(IsoImage * image,IsoDataSource * src,int flag)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
iso_analyze_alpha_boot(IsoImage * image,IsoDataSource * src,int flag)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        }
4819        sai->alpha_boot_image = iso_tree_get_node_path(node);
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 
4829 struct iso_impsysa_result {
4830     char *buf;
4831     int byte_count;
4832     char **lines;
4833     int line_count;
4834 };
4835 
4836 static
iso_impsysa_result_new(struct iso_impsysa_result ** r,int flag)4837 int iso_impsysa_result_new(struct iso_impsysa_result **r, int flag)
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
iso_impsysa_result_destroy(struct iso_impsysa_result ** r,int flag)4854 void iso_impsysa_result_destroy(struct iso_impsysa_result **r, int flag)
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
iso_impsysa_line(struct iso_impsysa_result * target,char * msg)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
iso_impsysa_report_text(struct iso_impsysa_result * target,char * msg,char * path,int flag)4878 void iso_impsysa_report_text(struct iso_impsysa_result  *target,
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
iso_impsysa_reduce_na(uint32_t block,uint32_t * na,uint32_t claim)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
iso_impsysa_reduce_next_above(IsoImage * image,uint32_t block,uint32_t * next_above,int flag)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
iso_impsysa_report_blockpath(IsoImage * image,struct iso_impsysa_result * target,char * msg,uint32_t start_block,int flag)4961 void iso_impsysa_report_blockpath(IsoImage *image,
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
iso_impsysa_report(IsoImage * image,struct iso_impsysa_result * target,int flag)5008 int iso_impsysa_report(IsoImage *image, struct iso_impsysa_result *target,
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 
5024     LIBISO_ALLOC_MEM(msg, char, ISO_MAX_SYSAREA_LINE_LENGTH);
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  ",
5109                      sai->hppa_bootloader_adr, sai->hppa_bootloader_len);
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",
5180                 sai->mipsel_p_vaddr, sai->mipsel_e_entry, sai->mipsel_p_filesz,
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) {
5215                 path = iso_tree_get_node_path((IsoNode *) sai->sparc_core_node);
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",
5241                  sai->gpt_array_crc_should, sai->gpt_array_crc_found);
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
iso_report_result_destroy(char *** result,int flag)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
iso_report_help(char ** doc,char *** result,int * line_count,int flag)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
iso_impsysa_hdd_emul_size(IsoImage * image,IsoDataSource * src,uint32_t lba,int flag)5393 uint32_t iso_impsysa_hdd_emul_size(IsoImage *image, IsoDataSource *src,
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:;
5417     LIBISO_FREE_MEM(buffer);
5418     return max_size;
5419 }
5420 
5421 static
iso_eltorito_report(IsoImage * image,struct iso_impsysa_result * target,int flag)5422 int iso_eltorito_report(IsoImage *image, struct iso_impsysa_result *target,
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 
5438     LIBISO_ALLOC_MEM(msg, char, ISO_MAX_SYSAREA_LINE_LENGTH);
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
iso_image_report_boot_eqp(IsoImage * image,int what,char *** result,int * line_count,int flag)5545 int iso_image_report_boot_eqp(IsoImage *image, int what,
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 ,
5552                                    ISO_SYSAREA_REPORT_DOC_MBR ,
5553                                    ISO_SYSAREA_REPORT_DOC_GPT1 ,
5554                                    ISO_SYSAREA_REPORT_DOC_GPT2 ,
5555                                    ISO_SYSAREA_REPORT_DOC_APM ,
5556                                    ISO_SYSAREA_REPORT_DOC_MIPS ,
5557                                    ISO_SYSAREA_REPORT_DOC_SUN ,
5558                                    ISO_SYSAREA_REPORT_DOC_HPPA ,
5559                                    ISO_SYSAREA_REPORT_DOC_ALPHA ,
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 */
iso_image_report_system_area(IsoImage * image,char *** result,int * line_count,int flag)5615 int iso_image_report_system_area(IsoImage *image,
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
iso_record_pvd_blocks(IsoImage * image,IsoDataSource * src,uint32_t block,int flag)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*/
5645     sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5646                                                  iso_read_lsb(buffer + 140, 4);
5647     sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5648                                                  iso_read_lsb(buffer + 144, 4);
5649     sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5650                                                  iso_read_lsb(buffer + 148, 4);
5651     sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5652                                                  iso_read_lsb(buffer + 152, 4);
5653     sai->meta_struct_blocks[sai->num_meta_struct_blocks++] =
5654                                                  iso_read_lsb(buffer + 158, 4);
5655 
5656     ret = ISO_SUCCESS;
5657 ex:;
5658     LIBISO_FREE_MEM(buffer);
5659     return ret;
5660 }
5661 
5662 static
iso_record_meta_struct_blocks(IsoImage * image,IsoDataSource * src,int flag)5663 int iso_record_meta_struct_blocks(IsoImage *image, IsoDataSource *src,
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
iso_analyze_system_area(IsoImage * image,IsoDataSource * src,struct iso_read_opts * opts,uint32_t image_size,int flag)5689 int iso_analyze_system_area(IsoImage *image, IsoDataSource *src,
5690                             struct iso_read_opts *opts, uint32_t image_size,
5691                             int flag)
5692 {
5693     int ret, i, sao, sa_type, sa_sub;
5694 
5695     iso_imported_sa_unref(&(image->imported_sa_info), 0);
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 
5706     image->imported_sa_info->image_size = image_size;
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 = iso_analyze_sun(image, src, 0);
5732             if (ret < 0)
5733                 goto ex;
5734         }
5735     }
5736     if (sa_type == 0 && !((sao & 3) || sa_sub == 1)) {
5737         /* HP-PA PALO v5 can look like generic MBR */
5738         ret = iso_analyze_hppa(image, src, 0);
5739         if (ret < 0)
5740             goto ex;
5741         /* DEC Alpha has checksum bytes where MBR has its magic number */
5742         if (ret == 0) {
5743             ret = iso_analyze_alpha_boot(image, src, 0);
5744             if (ret < 0)
5745                 goto ex;
5746         }
5747     }
5748     ret = iso_record_meta_struct_blocks(image, src, 0);
5749     if (ret < 0)
5750         goto ex;
5751 
5752     ret = ISO_SUCCESS;
5753 ex:;
5754     image->imported_sa_info->overall_return = ret;
5755     return ret;
5756 }
5757 
5758 
5759 /* API */
5760 /* @param flag  bit1= do not report system area but rather reply help text
5761                bit15= dispose result from previous call
5762 */
iso_image_report_el_torito(IsoImage * image,char *** reply,int * line_count,int flag)5763 int iso_image_report_el_torito(IsoImage *image,
5764                                char ***reply, int *line_count, int flag)
5765 {
5766     return iso_image_report_boot_eqp(image, 1, reply, line_count, flag);
5767 }
5768 
5769 
iso_image_import(IsoImage * image,IsoDataSource * src,struct iso_read_opts * opts,IsoReadImageFeatures ** features)5770 int iso_image_import(IsoImage *image, IsoDataSource *src,
5771                      struct iso_read_opts *opts,
5772                      IsoReadImageFeatures **features)
5773 {
5774     int ret, hflag, i, idx;
5775     IsoImageFilesystem *fs;
5776     IsoFilesystem *fsback;
5777     IsoNodeBuilder *blback;
5778     IsoDir *oldroot;
5779     IsoFileSource *newroot;
5780     _ImageFsData *data;
5781     struct el_torito_boot_catalog *oldbootcat;
5782     uint8_t *rpt;
5783     IsoFileSource *boot_src;
5784     IsoNode *node;
5785     char *old_checksum_array = NULL;
5786     char checksum_type[81];
5787     uint32_t checksum_size, truncate_mode, truncate_length;
5788     size_t size, attr_value_length;
5789     char *attr_value;
5790     unsigned char *aa_string = NULL;
5791     void *ctx = NULL;
5792     char md5[16];
5793     struct el_torito_boot_catalog *catalog = NULL;
5794     ElToritoBootImage *boot_image = NULL;
5795 
5796     if (image == NULL || src == NULL || opts == NULL) {
5797         return ISO_NULL_POINTER;
5798     }
5799 
5800     opts->truncate_mode = image->truncate_mode;
5801     opts->truncate_length = image->truncate_length;
5802     ret = iso_image_filesystem_new(src, opts, image->id, &fs);
5803     if (ret < 0) {
5804         return ret;
5805     }
5806     data = fs->data;
5807 
5808 
5809     if (opts->keep_import_src) {
5810         iso_data_source_ref(src);
5811         image->import_src = src;
5812     }
5813     if (opts->load_system_area) {
5814         if (image->system_area_data != NULL)
5815             free(image->system_area_data);
5816         image->system_area_data = calloc(32768, 1);
5817         if (image->system_area_data == NULL) {
5818             iso_filesystem_unref(fs);
5819             return ISO_OUT_OF_MEM;
5820         }
5821         image->system_area_options = 0;
5822         /* Read 32768 bytes */
5823         for (i = 0; i < 16; i++) {
5824             rpt = (uint8_t *) (image->system_area_data + i * 2048);
5825             ret = src->read_block(src, opts->block + i, rpt);
5826             if (ret < 0) {
5827                 iso_filesystem_unref(fs);
5828                 return ret;
5829             }
5830         }
5831     }
5832 
5833     /* get root from filesystem */
5834     ret = fs->get_root(fs, &newroot);
5835     if (ret < 0) {
5836         iso_filesystem_unref(fs);
5837         return ret;
5838     }
5839     if (newroot == NULL) {
5840         iso_filesystem_unref(fs);
5841         return ISO_NO_ROOT_DIR;
5842     }
5843 
5844     /* Lookup character set even if no AAIP loading is enabled */
5845     ret = iso_file_source_get_aa_string(newroot, &aa_string, 2);
5846     if (ret == 1 && aa_string != NULL) {
5847         ret = iso_aa_lookup_attr(aa_string, "isofs.cs",
5848                                    &attr_value_length, &attr_value, 0);
5849         free(aa_string);
5850     } else {
5851         ret = 0;
5852     }
5853     if (ret == 1) {
5854         if (data->auto_input_charset & 1) {
5855             if (data->input_charset != NULL)
5856                 free(data->input_charset);
5857             data->input_charset = attr_value;
5858             iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
5859                          "Learned from ISO image: input character set '%.80s'",
5860                           attr_value);
5861         } else {
5862             iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
5863                    "Ignored character set name recorded in ISO image: '%.80s'",
5864                            attr_value);
5865             free(attr_value);
5866         }
5867         attr_value = NULL;
5868     }
5869 
5870     /* backup image filesystem, builder and root */
5871     fsback = image->fs;
5872     blback = image->builder;
5873     oldroot = image->root;
5874     oldbootcat = image->bootcat; /* could be NULL */
5875     image->bootcat = NULL;
5876     old_checksum_array = image->checksum_array;
5877     image->checksum_array = NULL;
5878 
5879     /* create new builder */
5880     ret = iso_image_builder_new(blback, &image->builder);
5881     if (ret < 0) {
5882         goto import_revert;
5883     }
5884 
5885     image->fs = fs;
5886 
5887     /* create new root, and set root attributes from source */
5888     ret = iso_node_new_root(&image->root);
5889     if (ret < 0) {
5890         goto import_revert;
5891     }
5892     {
5893         struct stat info;
5894 
5895         /* I know this will not fail */
5896         iso_file_source_lstat(newroot, &info);
5897         image->root->node.mode = info.st_mode;
5898         image->root->node.uid = info.st_uid;
5899         image->root->node.gid = info.st_gid;
5900         image->root->node.atime = info.st_atime;
5901         image->root->node.mtime = info.st_mtime;
5902         image->root->node.ctime = info.st_ctime;
5903 
5904         /* This might fail in iso_node_add_xinfo() */
5905         ret = src_aa_to_node(newroot, &(image->root->node), 0);
5906         if (ret < 0)
5907             goto import_revert;
5908 
5909         /* Attach ino as xinfo if valid */
5910         if (info.st_ino != 0 && !data->make_new_ino) {
5911             ret = iso_node_set_ino(&(image->root->node), info.st_ino, 0);
5912             if (ret < 0)
5913                 goto import_revert;
5914         }
5915     }
5916 
5917     ret = iso_root_get_isofsnt(&(image->root->node), &truncate_mode,
5918                                &truncate_length, 0);
5919     if (ret == 1 && (int) truncate_mode == image->truncate_mode &&
5920         image->truncate_mode == 1 &&
5921         truncate_length >= 64 && truncate_length <= 255 &&
5922         (int) truncate_length != image->truncate_length) {
5923 
5924         data->truncate_mode = opts->truncate_mode = image->truncate_mode =
5925                                                                  truncate_mode;
5926         data->truncate_length = opts->truncate_length =
5927                                       image->truncate_length = truncate_length;
5928         iso_msg_submit(image->id, ISO_TRUNCATE_ISOFSNT, 0,
5929                 "File name truncation length changed by loaded image info: %d",
5930                 (int) truncate_length);
5931     }
5932 
5933     /* if old image has el-torito, add a new catalog */
5934     if (data->eltorito) {
5935 
5936         catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
5937         if (catalog == NULL) {
5938             ret = ISO_OUT_OF_MEM;
5939             goto import_revert;
5940         }
5941 
5942         catalog->num_bootimages = 0;
5943         for (idx = 0; idx < data->num_bootimgs; idx++) {
5944             boot_image = calloc(1, sizeof(ElToritoBootImage));
5945             if (boot_image == NULL) {
5946                 ret = ISO_OUT_OF_MEM;
5947                 goto import_revert;
5948             }
5949             boot_image->image = NULL;
5950             boot_image->bootable = data->boot_flags[idx] & 1;
5951             boot_image->type = data->media_types[idx];
5952             boot_image->partition_type = data->partition_types[idx];
5953             boot_image->load_seg = data->load_segs[idx];
5954             boot_image->load_size = data->load_sizes[idx];
5955             boot_image->platform_id = data->platform_ids[idx];
5956             memcpy(boot_image->id_string, data->id_strings[idx], 28);
5957             memcpy(boot_image->selection_crit, data->selection_crits, 20);
5958             boot_image->appended_idx = -1;
5959             boot_image->appended_start = data->bootblocks[idx];
5960             if (boot_image->type == 4) {
5961                 boot_image->emul_hdd_size = iso_impsysa_hdd_emul_size(
5962                                                 image, src,
5963                                                 data->bootblocks[idx], 0);
5964             } else {
5965                 boot_image->emul_hdd_size = 0;
5966             }
5967 
5968             catalog->bootimages[catalog->num_bootimages] = boot_image;
5969             boot_image = NULL;
5970             catalog->num_bootimages++;
5971         }
5972         for ( ; idx < Libisofs_max_boot_imageS; idx++)
5973             catalog->bootimages[idx] = NULL;
5974         image->bootcat = catalog;
5975         catalog = NULL; /* So it does not get freed */
5976     }
5977 
5978     /* recursively add image */
5979     ret = iso_add_dir_src_rec(image, image->root, newroot);
5980     if (ret < 0) {
5981         /* error during recursive image addition */
5982         iso_node_builder_unref(image->builder);
5983         goto import_revert;
5984     }
5985     issue_ucs2_warning_summary(data->joliet_ucs2_failures);
5986     issue_collision_warning_summary(image->collision_warnings);
5987 
5988     /* Take over inode management from IsoImageFilesystem.
5989        data->inode_counter is supposed to hold the maximum PX inode number.
5990      */
5991     image->inode_counter = data->inode_counter;
5992 
5993     if ((data->px_ino_status & (2 | 4 | 8)) || opts->make_new_ino) {
5994         /* Attach new inode numbers to any node which does not have one,
5995            resp. to all nodes in case of opts->make_new_ino
5996         */
5997         if (opts->make_new_ino)
5998             hflag = 1; /* Equip all data files with new unique inos */
5999         else
6000             hflag = 2 | 4 | 8; /* Equip any file type if it has ino == 0 */
6001         ret = img_make_inos(image, image->root, hflag);
6002         if (ret < 0) {
6003             iso_node_builder_unref(image->builder);
6004             goto import_revert;
6005         }
6006     }
6007 
6008     if (data->eltorito) {
6009         /* if catalog and boot image nodes were not filled,
6010            we create them here */
6011         for (idx = 0; idx < image->bootcat->num_bootimages; idx++) {
6012             if (image->bootcat->bootimages[idx]->image != NULL)
6013         continue;
6014             ret = create_boot_img_filesrc(fs, image, idx, &boot_src);
6015             if (ret < 0) {
6016                 iso_node_builder_unref(image->builder);
6017                 goto import_revert;
6018             }
6019             ret = image_builder_create_node(image->builder, image, boot_src,
6020                                             NULL, &node);
6021             iso_file_source_unref(boot_src); /* Now owned by node */
6022             if (ret < 0) {
6023                 iso_node_builder_unref(image->builder);
6024                 goto import_revert;
6025             }
6026             if (image->bootcat->bootimages[idx]->image != NULL) {
6027                 /* Already added to bootimages in image_builder_create_node().
6028                  * Now it has one refcount for tree and one for bootimages.
6029                  * But it will not go to tree. So unref.
6030                  */
6031                 iso_node_unref(node);
6032             } else {
6033                 image->bootcat->bootimages[idx]->image = (IsoFile*)node;
6034             }
6035 
6036 
6037             /* warn about hidden images */
6038             if (image->bootcat->bootimages[idx]->platform_id == 0xef) {
6039                 iso_msg_submit(image->id, ISO_ELTO_EFI_HIDDEN, 0,
6040                                "Found hidden El-Torito image for EFI.");
6041                 iso_msg_submit(image->id, ISO_GENERAL_NOTE, 0,
6042                             "EFI image start and size: %lu * 2048 , %lu * 512",
6043                                (unsigned long int)
6044                                image->bootcat->bootimages[idx]->appended_start,
6045                                (unsigned long int)
6046                                image->bootcat->bootimages[idx]->load_size);
6047             } else {
6048                 iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0,
6049                            "Found hidden El-Torito image. Its size could not "
6050                            "be figured out, so image modify or boot image "
6051                            "patching may lead to bad results.");
6052             }
6053         }
6054         if (image->bootcat->node == NULL) {
6055             IsoNode *node;
6056             IsoBoot *bootcat;
6057             node = calloc(1, sizeof(IsoBoot));
6058             if (node == NULL) {
6059                 ret = ISO_OUT_OF_MEM;
6060                 goto import_revert;
6061             }
6062             bootcat = (IsoBoot *) node;
6063             bootcat->lba = data->catblock;
6064             bootcat->size = data->catsize;
6065             bootcat->content = NULL;
6066             if (bootcat->size > 0) {
6067                 bootcat->content = calloc(1, bootcat->size);
6068                 if (bootcat->content == NULL) {
6069                     free(node);
6070                     ret = ISO_OUT_OF_MEM;
6071                     goto import_revert;
6072                 }
6073                 memcpy(bootcat->content, data->catcontent, bootcat->size);
6074             }
6075             node->type = LIBISO_BOOT;
6076             node->mode = S_IFREG;
6077             node->refcount = 1;
6078             image->bootcat->node = (IsoBoot*)node;
6079         }
6080     }
6081 
6082     iso_node_builder_unref(image->builder);
6083 
6084     /* set volume attributes */
6085     iso_image_set_volset_id(image, data->volset_id);
6086     iso_image_set_volume_id(image, data->volume_id);
6087     iso_image_set_publisher_id(image, data->publisher_id);
6088     iso_image_set_data_preparer_id(image, data->data_preparer_id);
6089     iso_image_set_system_id(image, data->system_id);
6090     iso_image_set_application_id(image, data->application_id);
6091     iso_image_set_copyright_file_id(image, data->copyright_file_id);
6092     iso_image_set_abstract_file_id(image, data->abstract_file_id);
6093     iso_image_set_biblio_file_id(image, data->biblio_file_id);
6094     iso_image_set_pvd_times(image, data->creation_time,
6095          data->modification_time, data->expiration_time, data->effective_time);
6096 
6097     if (features != NULL) {
6098         *features = malloc(sizeof(IsoReadImageFeatures));
6099         if (*features == NULL) {
6100             ret = ISO_OUT_OF_MEM;
6101             goto import_revert;
6102         }
6103         (*features)->hasJoliet = data->joliet;
6104         (*features)->hasRR = data->rr_version != 0;
6105         (*features)->hasIso1999 = data->iso1999;
6106         (*features)->hasElTorito = data->eltorito;
6107         (*features)->size = data->nblocks;
6108         (*features)->tree_loaded = 0;
6109         if (data->iso_root_block == data->svd_root_block)
6110             (*features)->tree_loaded = 1;
6111         else if (data->iso_root_block == data->evd_root_block &&
6112                  data->iso_root_block != data->pvd_root_block)
6113             (*features)->tree_loaded = 2;
6114         (*features)->rr_loaded = (data->rr != RR_EXT_NO);
6115     }
6116 
6117     if (data->md5_load) {
6118         /* Read checksum array */
6119         ret = iso_root_get_isofsca((IsoNode *) image->root,
6120                                    &(image->checksum_start_lba),
6121                                    &(image->checksum_end_lba),
6122                                    &(image->checksum_idx_count),
6123                                    &checksum_size, checksum_type, 0);
6124         if (ret > 0)
6125             if (checksum_size != 16 || strcmp(checksum_type, "MD5") != 0)
6126                 ret = 0;
6127         if (ret > 0 && image->checksum_idx_count > 1) {
6128             size = image->checksum_idx_count / 128;
6129             if (size * 128 < image->checksum_idx_count)
6130                 size++;
6131             image->checksum_array = calloc(size, 2048);
6132             if (image->checksum_array == NULL) {
6133                 ret = ISO_OUT_OF_MEM;
6134                 goto import_revert;
6135             }
6136 
6137             /* Load from image->checksum_end_lba */;
6138             for (i = 0; i < (int) size; i++) {
6139                 rpt = (uint8_t *) (image->checksum_array + i * 2048);
6140                 ret = src->read_block(src, image->checksum_end_lba + i, rpt);
6141                 if (ret <= 0)
6142                     goto import_cleanup;
6143             }
6144 
6145             /* Compute MD5 and compare with recorded MD5 */
6146             ret = iso_md5_start(&ctx);
6147             if (ret < 0) {
6148                 ret = ISO_OUT_OF_MEM;
6149                 goto import_revert;
6150             }
6151             for (i = 0; i < (int) image->checksum_idx_count - 1; i++)
6152                 iso_md5_compute(ctx, image->checksum_array + i * 16, 16);
6153             iso_md5_end(&ctx, md5);
6154             for (i = 0; i < 16; i++)
6155                 if (md5[i] != image->checksum_array[
6156                                       (image->checksum_idx_count - 1) * 16 + i]
6157                    )
6158             break;
6159             if (i < 16) {
6160                 iso_msg_submit(image->id, ISO_MD5_AREA_CORRUPTED, 0,
6161   "MD5 checksum array appears damaged and not trustworthy for verifications.");
6162                 free(image->checksum_array);
6163                 image->checksum_array = NULL;
6164                 image->checksum_idx_count = 0;
6165             }
6166         }
6167     }
6168 
6169     ret = iso_image_eval_boot_info_table(image, opts, src, data->nblocks, 0);
6170     if (ret < 0)
6171         goto import_revert;
6172 
6173     if (opts->load_system_area && image->system_area_data != NULL) {
6174         ret = iso_analyze_system_area(image, src, opts, data->nblocks, 0);
6175         if (ret < 0) {
6176             iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0,
6177                       "Problem encountered during inspection of System Area:");
6178             iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0,
6179                            iso_error_to_msg(ret));
6180         }
6181     }
6182 
6183     ret = ISO_SUCCESS;
6184     goto import_cleanup;
6185 
6186     import_revert:;
6187 
6188     iso_node_unref((IsoNode*)image->root);
6189     el_torito_boot_catalog_free(image->bootcat);
6190     image->root = oldroot;
6191     oldroot = NULL;
6192     image->bootcat = oldbootcat;
6193     oldbootcat = NULL;
6194     image->checksum_array = old_checksum_array;
6195     old_checksum_array = NULL;
6196 
6197     import_cleanup:;
6198 
6199     /* recover backed fs and builder */
6200     image->fs = fsback;
6201     image->builder = blback;
6202 
6203     /* free old root */
6204     if (oldroot != NULL)
6205         iso_node_unref((IsoNode*)oldroot);
6206 
6207     /* free old boot catalog */
6208     if (oldbootcat != NULL)
6209         el_torito_boot_catalog_free(oldbootcat);
6210 
6211     if (catalog != NULL)
6212         el_torito_boot_catalog_free(catalog);
6213     if (boot_image != NULL)
6214         free((char *) boot_image);
6215     iso_file_source_unref(newroot);
6216     fs->close(fs);
6217     iso_filesystem_unref(fs);
6218     if (old_checksum_array != NULL)
6219         free(old_checksum_array);
6220     if (ctx != NULL)
6221         iso_md5_end(&ctx, md5);
6222     return ret;
6223 }
6224 
iso_image_fs_get_volset_id(IsoImageFilesystem * fs)6225 const char *iso_image_fs_get_volset_id(IsoImageFilesystem *fs)
6226 {
6227     _ImageFsData *data = (_ImageFsData*) fs->data;
6228     return data->volset_id;
6229 }
6230 
iso_image_fs_get_volume_id(IsoImageFilesystem * fs)6231 const char *iso_image_fs_get_volume_id(IsoImageFilesystem *fs)
6232 {
6233     _ImageFsData *data = (_ImageFsData*) fs->data;
6234     return data->volume_id;
6235 }
6236 
iso_image_fs_get_publisher_id(IsoImageFilesystem * fs)6237 const char *iso_image_fs_get_publisher_id(IsoImageFilesystem *fs)
6238 {
6239     _ImageFsData *data = (_ImageFsData*) fs->data;
6240     return data->publisher_id;
6241 }
6242 
iso_image_fs_get_data_preparer_id(IsoImageFilesystem * fs)6243 const char *iso_image_fs_get_data_preparer_id(IsoImageFilesystem *fs)
6244 {
6245     _ImageFsData *data = (_ImageFsData*) fs->data;
6246     return data->data_preparer_id;
6247 }
6248 
iso_image_fs_get_system_id(IsoImageFilesystem * fs)6249 const char *iso_image_fs_get_system_id(IsoImageFilesystem *fs)
6250 {
6251     _ImageFsData *data = (_ImageFsData*) fs->data;
6252     return data->system_id;
6253 }
6254 
iso_image_fs_get_application_id(IsoImageFilesystem * fs)6255 const char *iso_image_fs_get_application_id(IsoImageFilesystem *fs)
6256 {
6257     _ImageFsData *data = (_ImageFsData*) fs->data;
6258     return data->application_id;
6259 }
6260 
iso_image_fs_get_copyright_file_id(IsoImageFilesystem * fs)6261 const char *iso_image_fs_get_copyright_file_id(IsoImageFilesystem *fs)
6262 {
6263     _ImageFsData *data = (_ImageFsData*) fs->data;
6264     return data->copyright_file_id;
6265 }
6266 
iso_image_fs_get_abstract_file_id(IsoImageFilesystem * fs)6267 const char *iso_image_fs_get_abstract_file_id(IsoImageFilesystem *fs)
6268 {
6269     _ImageFsData *data;
6270     data = (_ImageFsData*) fs->data;
6271     return data->abstract_file_id;
6272 }
6273 
iso_image_fs_get_biblio_file_id(IsoImageFilesystem * fs)6274 const char *iso_image_fs_get_biblio_file_id(IsoImageFilesystem *fs)
6275 {
6276     _ImageFsData *data = (_ImageFsData*) fs->data;
6277     return data->biblio_file_id;
6278 }
6279 
iso_read_opts_new(IsoReadOpts ** opts,int profile)6280 int iso_read_opts_new(IsoReadOpts **opts, int profile)
6281 {
6282     IsoReadOpts *ropts;
6283 
6284     if (opts == NULL) {
6285         return ISO_NULL_POINTER;
6286     }
6287     if (profile != 0) {
6288         return ISO_WRONG_ARG_VALUE;
6289     }
6290 
6291     ropts = calloc(1, sizeof(IsoReadOpts));
6292     if (ropts == NULL) {
6293         return ISO_OUT_OF_MEM;
6294     }
6295 
6296     ropts->file_mode = 0444;
6297     ropts->dir_mode = 0555;
6298     ropts->noaaip = 1;
6299     ropts->ecma119_map = 1;
6300     ropts->joliet_map = 1;
6301     ropts->nomd5 = 1;
6302     ropts->load_system_area = 0;
6303     ropts->keep_import_src = 0;
6304     ropts->truncate_mode = 1;
6305     ropts->truncate_length = LIBISOFS_NODE_NAME_MAX;
6306 
6307     *opts = ropts;
6308     return ISO_SUCCESS;
6309 }
6310 
iso_read_opts_free(IsoReadOpts * opts)6311 void iso_read_opts_free(IsoReadOpts *opts)
6312 {
6313     if (opts == NULL) {
6314         return;
6315     }
6316 
6317     free(opts->input_charset);
6318     free(opts);
6319 }
6320 
iso_read_opts_set_start_block(IsoReadOpts * opts,uint32_t block)6321 int iso_read_opts_set_start_block(IsoReadOpts *opts, uint32_t block)
6322 {
6323     if (opts == NULL) {
6324         return ISO_NULL_POINTER;
6325     }
6326     opts->block = block;
6327     return ISO_SUCCESS;
6328 }
6329 
iso_read_opts_set_no_rockridge(IsoReadOpts * opts,int norr)6330 int iso_read_opts_set_no_rockridge(IsoReadOpts *opts, int norr)
6331 {
6332     if (opts == NULL) {
6333         return ISO_NULL_POINTER;
6334     }
6335     opts->norock = norr ? 1 :0;
6336     return ISO_SUCCESS;
6337 }
6338 
iso_read_opts_set_no_joliet(IsoReadOpts * opts,int nojoliet)6339 int iso_read_opts_set_no_joliet(IsoReadOpts *opts, int nojoliet)
6340 {
6341     if (opts == NULL) {
6342         return ISO_NULL_POINTER;
6343     }
6344     opts->nojoliet = nojoliet ? 1 :0;
6345     return ISO_SUCCESS;
6346 }
6347 
iso_read_opts_set_no_iso1999(IsoReadOpts * opts,int noiso1999)6348 int iso_read_opts_set_no_iso1999(IsoReadOpts *opts, int noiso1999)
6349 {
6350     if (opts == NULL) {
6351         return ISO_NULL_POINTER;
6352     }
6353     opts->noiso1999 = noiso1999 ? 1 :0;
6354     return ISO_SUCCESS;
6355 }
6356 
iso_read_opts_set_no_aaip(IsoReadOpts * opts,int noaaip)6357 int iso_read_opts_set_no_aaip(IsoReadOpts *opts, int noaaip)
6358 {
6359     if (opts == NULL) {
6360         return ISO_NULL_POINTER;
6361     }
6362     opts->noaaip = noaaip ? 1 : 0;
6363     return ISO_SUCCESS;
6364 }
6365 
iso_read_opts_set_no_md5(IsoReadOpts * opts,int no_md5)6366 int iso_read_opts_set_no_md5(IsoReadOpts *opts, int no_md5)
6367 {
6368     if (opts == NULL) {
6369         return ISO_NULL_POINTER;
6370     }
6371     opts->nomd5 = no_md5 == 2 ? 2 : no_md5 == 1 ? 1 : 0;
6372     return ISO_SUCCESS;
6373 }
6374 
6375 
iso_read_opts_set_new_inos(IsoReadOpts * opts,int new_inos)6376 int iso_read_opts_set_new_inos(IsoReadOpts *opts, int new_inos)
6377 {
6378     if (opts == NULL) {
6379         return ISO_NULL_POINTER;
6380     }
6381     opts->make_new_ino = new_inos ? 1 : 0;
6382     return ISO_SUCCESS;
6383 }
6384 
iso_read_opts_set_preferjoliet(IsoReadOpts * opts,int preferjoliet)6385 int iso_read_opts_set_preferjoliet(IsoReadOpts *opts, int preferjoliet)
6386 {
6387     if (opts == NULL) {
6388         return ISO_NULL_POINTER;
6389     }
6390     opts->preferjoliet = preferjoliet ? 1 :0;
6391     return ISO_SUCCESS;
6392 }
6393 
iso_read_opts_set_ecma119_map(IsoReadOpts * opts,int ecma119_map)6394 int iso_read_opts_set_ecma119_map(IsoReadOpts *opts, int ecma119_map)
6395 {
6396     if (opts == NULL) {
6397         return ISO_NULL_POINTER;
6398     }
6399     if (ecma119_map < 0 || ecma119_map > 3)
6400         return 0;
6401     opts->ecma119_map = ecma119_map;
6402     return ISO_SUCCESS;
6403 }
6404 
iso_read_opts_set_joliet_map(IsoReadOpts * opts,int joliet_map)6405 int iso_read_opts_set_joliet_map(IsoReadOpts *opts, int joliet_map)
6406 {
6407     if (opts == NULL)
6408         return ISO_NULL_POINTER;
6409     if (joliet_map < 0 || joliet_map > 1)
6410         return 0;
6411     opts->joliet_map = joliet_map;
6412     return ISO_SUCCESS;
6413 }
6414 
iso_read_opts_set_default_uid(IsoReadOpts * opts,uid_t uid)6415 int iso_read_opts_set_default_uid(IsoReadOpts *opts, uid_t uid)
6416 {
6417     if (opts == NULL) {
6418         return ISO_NULL_POINTER;
6419     }
6420     opts->uid = uid;
6421     return ISO_SUCCESS;
6422 }
6423 
iso_read_opts_set_default_gid(IsoReadOpts * opts,gid_t gid)6424 int iso_read_opts_set_default_gid(IsoReadOpts *opts, gid_t gid)
6425 {
6426     if (opts == NULL) {
6427         return ISO_NULL_POINTER;
6428     }
6429     opts->gid = gid;
6430     return ISO_SUCCESS;
6431 }
6432 
iso_read_opts_set_default_permissions(IsoReadOpts * opts,mode_t file_perm,mode_t dir_perm)6433 int iso_read_opts_set_default_permissions(IsoReadOpts *opts, mode_t file_perm,
6434                                           mode_t dir_perm)
6435 {
6436     if (opts == NULL) {
6437         return ISO_NULL_POINTER;
6438     }
6439     opts->file_mode = file_perm;
6440     opts->dir_mode = dir_perm;
6441     return ISO_SUCCESS;
6442 }
6443 
iso_read_opts_set_input_charset(IsoReadOpts * opts,const char * charset)6444 int iso_read_opts_set_input_charset(IsoReadOpts *opts, const char *charset)
6445 {
6446     if (opts == NULL) {
6447         return ISO_NULL_POINTER;
6448     }
6449     opts->input_charset = charset ? strdup(charset) : NULL;
6450     return ISO_SUCCESS;
6451 }
6452 
iso_read_opts_auto_input_charset(IsoReadOpts * opts,int mode)6453 int iso_read_opts_auto_input_charset(IsoReadOpts *opts, int mode)
6454 {
6455     if (opts == NULL) {
6456         return ISO_NULL_POINTER;
6457     }
6458     opts->auto_input_charset = mode;
6459     return ISO_SUCCESS;
6460 }
6461 
iso_read_opts_load_system_area(IsoReadOpts * opts,int mode)6462 int iso_read_opts_load_system_area(IsoReadOpts *opts, int mode)
6463 {
6464     if (opts == NULL) {
6465         return ISO_NULL_POINTER;
6466     }
6467     opts->load_system_area = mode & 1;
6468     return ISO_SUCCESS;
6469 }
6470 
iso_read_opts_keep_import_src(IsoReadOpts * opts,int mode)6471 int iso_read_opts_keep_import_src(IsoReadOpts *opts, int mode)
6472 {
6473     if (opts == NULL) {
6474         return ISO_NULL_POINTER;
6475     }
6476     opts->keep_import_src = mode & 1;
6477     return ISO_SUCCESS;
6478 }
6479 
6480 /**
6481  * Destroy an IsoReadImageFeatures object obtained with iso_image_import.
6482  */
iso_read_image_features_destroy(IsoReadImageFeatures * f)6483 void iso_read_image_features_destroy(IsoReadImageFeatures *f)
6484 {
6485     if (f) {
6486         free(f);
6487     }
6488 }
6489 
6490 /**
6491  * Get the size (in 2048 byte block) of the image, as reported in the PVM.
6492  */
iso_read_image_features_get_size(IsoReadImageFeatures * f)6493 uint32_t iso_read_image_features_get_size(IsoReadImageFeatures *f)
6494 {
6495     return f->size;
6496 }
6497 
6498 /**
6499  * Whether RockRidge extensions are present in the image imported.
6500  */
iso_read_image_features_has_rockridge(IsoReadImageFeatures * f)6501 int iso_read_image_features_has_rockridge(IsoReadImageFeatures *f)
6502 {
6503     return f->hasRR;
6504 }
6505 
6506 /**
6507  * Whether Joliet extensions are present in the image imported.
6508  */
iso_read_image_features_has_joliet(IsoReadImageFeatures * f)6509 int iso_read_image_features_has_joliet(IsoReadImageFeatures *f)
6510 {
6511     return f->hasJoliet;
6512 }
6513 
6514 /**
6515  * Whether the image is recorded according to ISO 9660:1999, i.e. it has
6516  * a version 2 Enhanced Volume Descriptor.
6517  */
iso_read_image_features_has_iso1999(IsoReadImageFeatures * f)6518 int iso_read_image_features_has_iso1999(IsoReadImageFeatures *f)
6519 {
6520     return f->hasIso1999;
6521 }
6522 
6523 /**
6524  * Whether El-Torito boot record is present present in the image imported.
6525  */
iso_read_image_features_has_eltorito(IsoReadImageFeatures * f)6526 int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f)
6527 {
6528     return f->hasElTorito;
6529 }
6530 
6531 /**
6532  * Tells what directory tree was loaded:
6533  *     0= ISO 9660 , 1 = Joliet , 2 = ISO 9660:1999
6534  */
iso_read_image_features_tree_loaded(IsoReadImageFeatures * f)6535 int iso_read_image_features_tree_loaded(IsoReadImageFeatures *f)
6536 {
6537     return f->tree_loaded;
6538 }
6539 
6540 /**
6541  * Tells whether Rock Ridge information was used while loading the tree.
6542  */
iso_read_image_features_rr_loaded(IsoReadImageFeatures * f)6543 int iso_read_image_features_rr_loaded(IsoReadImageFeatures *f)
6544 {
6545     return f->rr_loaded;
6546 }
6547 
6548 /**
6549  * Get the start addresses and the sizes of the data extents of a file node
6550  * if it was imported from an old image.
6551  *
6552  * @param file
6553  *      The file
6554  * @param section_count
6555  *      Returns the number of extent entries in sections arrays
6556  * @param sections
6557  *      Returns the array of file sections. Apply free() to dispose it.
6558  * @param flag
6559  *      Reserved for future usage, submit 0
6560  * @return
6561  *      1 if there are valid extents (file comes from old image),
6562  *      0 if file was newly added, i.e. it does not come from an old image,
6563  *      < 0 error
6564  */
iso_file_get_old_image_sections(IsoFile * file,int * section_count,struct iso_file_section ** sections,int flag)6565 int iso_file_get_old_image_sections(IsoFile *file, int *section_count,
6566                                    struct iso_file_section **sections,
6567                                    int flag)
6568 {
6569     if (file == NULL || section_count == NULL || sections == NULL) {
6570         return ISO_NULL_POINTER;
6571     }
6572     if (flag != 0) {
6573         return ISO_WRONG_ARG_VALUE;
6574     }
6575     *section_count = 0;
6576     *sections = NULL;
6577     if (file->from_old_session != 0) {
6578 
6579         /*
6580          * When file is from old session, we retrieve the original IsoFileSource
6581          * to get the sections. This break encapsultation, but safes memory as
6582          * we don't need to store the sections in the IsoFile node.
6583          */
6584         IsoStream *stream = file->stream, *input_stream;
6585         FSrcStreamData *data;
6586         ImageFileSourceData *ifsdata;
6587 
6588         /* Get the most original stream */
6589         while (1) {
6590             input_stream = iso_stream_get_input_stream(stream, 0);
6591             if (input_stream == NULL || input_stream == stream)
6592         break;
6593             stream = input_stream;
6594         }
6595 
6596         /* From here on it must be a stream with FSrcStreamData. */
6597         /* ??? Shall one rather check :
6598                 stream->class == extern IsoStreamIface fsrc_stream_class
6599                (its storage location is global in stream.c)
6600          */
6601         if (stream->class->type[0] != 'f' || stream->class->type[1] != 's' ||
6602             stream->class->type[2] != 'r' || stream->class->type[3] != 'c')
6603             return 0;
6604 
6605         data = stream->data;
6606         ifsdata = data->src->data;
6607 
6608         *section_count = ifsdata->nsections;
6609         if (*section_count <= 0)
6610             return 1;
6611         *sections = malloc(ifsdata->nsections *
6612                                 sizeof(struct iso_file_section));
6613         if (*sections == NULL) {
6614             return ISO_OUT_OF_MEM;
6615         }
6616         memcpy(*sections, ifsdata->sections,
6617                ifsdata->nsections * sizeof(struct iso_file_section));
6618         return 1;
6619     }
6620     return 0;
6621 }
6622 
6623 /* Rank two IsoFileSource by their eventual old image LBAs if still non-zero.
6624    Other IsoFileSource classes and zeroized LBAs will be ranked only roughly.
6625    flag bit0 preserves transitivity of the caller by evaluating ifs_class with
6626    non-zero block address as smaller than anything else.
6627    flag bit1 could harm reproducibility of ISO image output.
6628    @param flag bit0= if s1 exor s2 is of applicable class, then enforce
6629                      a valid test result by comparing classes
6630                bit1= if both are applicable but also have sections[].block == 0
6631                      then enforce a valid test result by comparing object                            addresses.
6632 */
iso_ifs_sections_cmp(IsoFileSource * s1,IsoFileSource * s2,int * cmp_ret,int flag)6633 int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
6634                          int flag)
6635 {
6636     int i;
6637     ImageFileSourceData *d1 = NULL, *d2 = NULL;
6638     IsoFileSourceIface *class1 = NULL, *class2 = NULL;
6639 
6640     /* Newly created IsoFileSrc from imported IsoFile (e.g. boot image)
6641        is not an applicable source. It must be kept from causing a decision
6642        with other non-applicables.
6643     */
6644     if (s1 != NULL) {
6645         class1 = (IsoFileSourceIface *) s1->class;
6646         if (class1 == &ifs_class) {
6647             d1 = (ImageFileSourceData *) s1->data;
6648             if (d1->nsections > 0)
6649                 if (d1->sections[0].block == 0)
6650                     class1 = NULL;
6651         }
6652     }
6653     if (s2 != NULL) {
6654         class2 = (IsoFileSourceIface *) s2->class;
6655         if (class2 == &ifs_class) {
6656             d2 = (ImageFileSourceData *) s2->data;
6657             if (d2->nsections > 0)
6658                 if (d2->sections[0].block == 0)
6659                     class2 = NULL;
6660         }
6661     }
6662 
6663     if (class1 != &ifs_class && class2 != &ifs_class) {
6664         *cmp_ret = 0;
6665         return 0;
6666     }
6667     if (class1 != class2) {
6668         *cmp_ret = (class1 == &ifs_class ? -1 : 1);
6669         if (flag & 1)
6670             return 1;
6671         return 0;
6672     }
6673 
6674     if (d1->nsections != d2->nsections) {
6675         *cmp_ret = d1->nsections < d2->nsections ? -1 : 1;
6676         return 1;
6677     }
6678     if (d1->nsections == 0) {
6679        *cmp_ret = 0;
6680        return 1;
6681     }
6682     if (d1->sections[0].size < 1 || d2->sections[0].size < 1) {
6683         if (d1->sections[0].size > d2->sections[0].size)
6684             *cmp_ret = 1;
6685         else if (d1->sections[0].size < d2->sections[0].size)
6686             *cmp_ret = -1;
6687         else
6688             *cmp_ret = 0;
6689         return 1;
6690     }
6691 
6692     for (i = 0; i < d1->nsections; i++) {
6693         if (d1->sections[i].block != d2->sections[i].block) {
6694             *cmp_ret = (d1->sections[i].block < d2->sections[i].block ? -1 : 1);
6695             return 1;
6696         }
6697         if (d1->sections[i].size != d2->sections[i].size) {
6698             *cmp_ret = (d1->sections[i].size < d2->sections[i].size ? -1 : 1);
6699             return 1;
6700         }
6701     }
6702     *cmp_ret = 0;
6703     return 1;
6704 }
6705 
6706