"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/fs_image.c" (7 Dec 2020, 220606 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fs_image.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 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 
  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
  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
  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
  530 int ifs_lstat(IsoFileSource *src, struct stat *info)
  531 {
  532     ImageFileSourceData *data;
  533 
  534     if (src == NULL || info == NULL) {
  535         return ISO_NULL_POINTER;
  536     }
  537 
  538     data = src->data;
  539     if (data == NULL)
  540         return ISO_NULL_POINTER;
  541     *info = data->info;
  542     return ISO_SUCCESS;
  543 }
  544 
  545 static
  546 int ifs_stat(IsoFileSource *src, struct stat *info)
  547 {
  548     ImageFileSourceData *data;
  549 
  550     if (src == NULL || info == NULL || src->data == NULL) {
  551         return ISO_NULL_POINTER;
  552     }
  553 
  554     data = (ImageFileSourceData*)src->data;
  555 
  556     if (S_ISLNK(data->info.st_mode)) {
  557         /* TODO #00012 : support follow symlinks on image filesystem */
  558         return ISO_FILE_BAD_PATH;
  559     }
  560     *info = data->info;
  561     return ISO_SUCCESS;
  562 }
  563 
  564 static
  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
  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
  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
  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
  815 uint32_t block_from_offset(int nsections, struct iso_file_section *sections,
  816                            off_t offset)
  817 {
  818     int section = 0;
  819     off_t bytes = 0;
  820 
  821     do {
  822         if ( (offset - bytes) < (off_t) sections[section].size ) {
  823             return sections[section].block + (offset - bytes) / BLOCK_SIZE;
  824         } else {
  825             bytes += (off_t) sections[section].size;
  826             section++;
  827         }
  828 
  829     } while(section < nsections);
  830     return 0; /* should never happen */
  831 }
  832 
  833 /**
  834  * Get the size available for reading on the corresponding block
  835  */
  836 static
  837 uint32_t size_available(int nsections, struct iso_file_section *sections,
  838                            off_t offset)
  839 {
  840     int section = 0;
  841     off_t bytes = 0;
  842 
  843     do {
  844         if ( (offset - bytes) < (off_t) sections[section].size ) {
  845             uint32_t curr_section_offset = (uint32_t)(offset - bytes);
  846             uint32_t curr_section_left = sections[section].size - curr_section_offset;
  847             uint32_t available = BLOCK_SIZE - curr_section_offset % BLOCK_SIZE;
  848             return MIN(curr_section_left, available);
  849         } else {
  850             bytes += (off_t) sections[section].size;
  851             section++;
  852         }
  853 
  854     } while(section < nsections);
  855     return 0; /* should never happen */
  856 }
  857 
  858 /**
  859  * Get the block offset for reading the given file offset
  860  */
  861 static
  862 uint32_t block_offset(int nsections, struct iso_file_section *sections,
  863                       off_t offset)
  864 {
  865     int section = 0;
  866     off_t bytes = 0;
  867 
  868 
  869     do {
  870         if ( (offset - bytes) < (off_t) sections[section].size ) {
  871             return (uint32_t)(offset - bytes) % BLOCK_SIZE;
  872         } else {
  873             bytes += (off_t) sections[section].size;
  874             section++;
  875         }
  876 
  877     } while(section < nsections);
  878     return 0; /* should never happen */
  879 }
  880 
  881 /**
  882  * Attempts to read up to count bytes from the given source into
  883  * the buffer starting at buf.
  884  *
  885  * The file src must be open() before calling this, and close() when no
  886  * more needed. Not valid for dirs. On symlinks it reads the destination
  887  * file.
  888  *
  889  * @return
  890  *     number of bytes read, 0 if EOF, < 0 on error
  891  *      Error codes:
  892  *         ISO_FILE_ERROR
  893  *         ISO_NULL_POINTER
  894  *         ISO_FILE_NOT_OPENED
  895  *         ISO_FILE_IS_DIR
  896  *         ISO_OUT_OF_MEM
  897  *         ISO_INTERRUPTED
  898  */
  899 static
  900 int ifs_read(IsoFileSource *src, void *buf, size_t count)
  901 {
  902     int ret;
  903     ImageFileSourceData *data;
  904     uint32_t read = 0;
  905 
  906     if (src == NULL || src->data == NULL || buf == NULL) {
  907         return ISO_NULL_POINTER;
  908     }
  909     if (count == 0) {
  910         return ISO_WRONG_ARG_VALUE;
  911     }
  912     data = (ImageFileSourceData*)src->data;
  913 
  914     if (!data->opened) {
  915         return ISO_FILE_NOT_OPENED;
  916     } else if (data->opened != 1) {
  917         return ISO_FILE_IS_DIR;
  918     }
  919 
  920     while (read < count && data->data.offset < data->info.st_size) {
  921         size_t bytes;
  922         uint8_t *orig;
  923 
  924         if (block_offset(data->nsections, data->sections, data->data.offset) == 0) {
  925             /* we need to buffer next block */
  926             uint32_t block;
  927             _ImageFsData *fsdata;
  928 
  929             if (data->data.offset >= data->info.st_size) {
  930                 /* EOF */
  931                 break;
  932             }
  933             fsdata = data->fs->data;
  934             block = block_from_offset(data->nsections, data->sections,
  935                                       data->data.offset);
  936             ret = fsdata->src->read_block(fsdata->src, block,
  937                                           data->data.content);
  938             if (ret < 0) {
  939                 return ret;
  940             }
  941         }
  942 
  943         /* how much can I read */
  944         bytes = MIN(size_available(data->nsections, data->sections, data->data.offset),
  945                     count - read);
  946         if (data->data.offset + (off_t)bytes > data->info.st_size) {
  947              bytes = data->info.st_size - data->data.offset;
  948         }
  949         orig = data->data.content;
  950         orig += block_offset(data->nsections, data->sections, data->data.offset);
  951         memcpy((uint8_t*)buf + read, orig, bytes);
  952         read += bytes;
  953         data->data.offset += (off_t)bytes;
  954     }
  955     return read;
  956 }
  957 
  958 static
  959 off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
  960 {
  961     ImageFileSourceData *data;
  962 
  963     if (src == NULL) {
  964         return (off_t)ISO_NULL_POINTER;
  965     }
  966     if (offset < (off_t)0) {
  967         return (off_t)ISO_WRONG_ARG_VALUE;
  968     }
  969 
  970     data = src->data;
  971 
  972     if (!data->opened) {
  973         return (off_t)ISO_FILE_NOT_OPENED;
  974     } else if (data->opened != 1) {
  975         return (off_t)ISO_FILE_IS_DIR;
  976     }
  977 
  978     switch (flag) {
  979     case 0: /* SEEK_SET */
  980         data->data.offset = offset;
  981         break;
  982     case 1: /* SEEK_CUR */
  983         data->data.offset += offset;
  984         break;
  985     case 2: /* SEEK_END */
  986         /* do this make sense? */
  987         data->data.offset = data->info.st_size + offset;
  988         break;
  989     default:
  990         return (off_t)ISO_WRONG_ARG_VALUE;
  991     }
  992 
  993     /*
  994      * We check for block_offset != 0 because if it is already 0, the block
  995      * will be read from image in the read function
  996      */
  997     if (block_offset(data->nsections, data->sections, data->data.offset) != 0) {
  998         /* we need to buffer the block */
  999         uint32_t block;
 1000         _ImageFsData *fsdata;
 1001 
 1002         if (data->data.offset < data->info.st_size) {
 1003             int ret;
 1004             fsdata = data->fs->data;
 1005             block = block_from_offset(data->nsections, data->sections,
 1006                                       data->data.offset);
 1007             ret = fsdata->src->read_block(fsdata->src, block,
 1008                                           data->data.content);
 1009             if (ret < 0) {
 1010                 return (off_t)ret;
 1011             }
 1012         }
 1013     }
 1014     return data->data.offset;
 1015 }
 1016 
 1017 static
 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
 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
 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
 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
 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
 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() */
 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
 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
 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
 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
 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
 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
 2223 int ifs_get_file(IsoFileSource *dir, const char *name, IsoFileSource **file)
 2224 {
 2225     int ret;
 2226     IsoFileSource *src;
 2227 
 2228     ret = iso_file_source_open(dir);
 2229     if (ret < 0) {
 2230         return ret;
 2231     }
 2232     while ((ret = iso_file_source_readdir(dir, &src)) == 1) {
 2233         char *fname = iso_file_source_get_name(src);
 2234         if (!strcmp(name, fname)) {
 2235             free(fname);
 2236             *file = src;
 2237             ret = ISO_SUCCESS;
 2238             break;
 2239         }
 2240         free(fname);
 2241         iso_file_source_unref(src);
 2242     }
 2243     iso_file_source_close(dir);
 2244     return ret;
 2245 }
 2246 
 2247 static
 2248 int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
 2249 {
 2250     int ret;
 2251     IsoFileSource *src = NULL;
 2252     char *ptr, *brk_info, *component;
 2253 
 2254     if (fs == NULL || fs->data == NULL || path == NULL || file == NULL) {
 2255         return ISO_NULL_POINTER;
 2256     }
 2257 
 2258     if (path[0] != '/') {
 2259         /* only absolute paths supported */
 2260         return ISO_FILE_BAD_PATH;
 2261     }
 2262 
 2263     /* open the filesystem */
 2264     ret = ifs_fs_open((IsoImageFilesystem*)fs);
 2265     if (ret < 0) {
 2266         return ret;
 2267     }
 2268 
 2269     ret = ifs_get_root(fs, &src);
 2270     if (ret < 0) {
 2271         return ret;
 2272     }
 2273     if (!strcmp(path, "/")) {
 2274         /* we are looking for root */
 2275         *file = src;
 2276         ret = ISO_SUCCESS;
 2277         goto get_path_exit;
 2278     }
 2279 
 2280     ptr = strdup(path);
 2281     if (ptr == NULL) {
 2282         iso_file_source_unref(src);
 2283         ret = ISO_OUT_OF_MEM;
 2284         goto get_path_exit;
 2285     }
 2286 
 2287     component = strtok_r(ptr, "/", &brk_info);
 2288     while (component) {
 2289         IsoFileSource *child = NULL;
 2290 
 2291         ImageFileSourceData *fdata;
 2292         fdata = src->data;
 2293         if (!S_ISDIR(fdata->info.st_mode)) {
 2294             ret = ISO_FILE_BAD_PATH;
 2295             break;
 2296         }
 2297 
 2298         ret = ifs_get_file(src, component, &child);
 2299         iso_file_source_unref(src);
 2300         src = NULL;
 2301         if (ret <= 0) {
 2302             break;
 2303         }
 2304 
 2305         src = child;
 2306         component = strtok_r(NULL, "/", &brk_info);
 2307     }
 2308 
 2309     free(ptr);
 2310     if (ret < 0) {
 2311         if (src != NULL)
 2312             iso_file_source_unref(src);
 2313     } else if (ret == 0) {
 2314         ret = ISO_FILE_DOESNT_EXIST;
 2315     } else {
 2316         *file = src;
 2317     }
 2318 
 2319     get_path_exit:;
 2320     ifs_fs_close((IsoImageFilesystem*)fs);
 2321     return ret;
 2322 }
 2323 
 2324 unsigned int ifs_get_id(IsoFilesystem *fs)
 2325 {
 2326     return ISO_IMAGE_FS_ID;
 2327 }
 2328 
 2329 static
 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
 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
 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
 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
 2581 int read_pvd_block(IsoDataSource *src, uint32_t block, uint8_t *buffer,
 2582                    uint32_t *image_size)
 2583 {
 2584     int ret;
 2585     struct ecma119_pri_vol_desc *pvm;
 2586 
 2587     ret = src->read_block(src, block, buffer);
 2588     if (ret < 0)
 2589         return ret;
 2590     pvm = (struct ecma119_pri_vol_desc *)buffer;
 2591 
 2592     /* sanity checks */
 2593     if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
 2594             || strncmp((char*)pvm->std_identifier, "CD001", 5)
 2595             || pvm->file_structure_version[0] != 1) {
 2596 
 2597         return ISO_WRONG_PVD;
 2598     }
 2599     if (image_size != NULL)
 2600         *image_size = iso_read_bb(pvm->vol_space_size, 4, NULL);
 2601     return ISO_SUCCESS;
 2602 }
 2603 
 2604 static
 2605 int read_pvm(_ImageFsData *data, uint32_t block)
 2606 {
 2607     int ret;
 2608     struct ecma119_pri_vol_desc *pvm;
 2609     struct ecma119_dir_record *rootdr;
 2610     uint8_t *buffer = NULL;
 2611 
 2612     LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
 2613     ret = read_pvd_block(data->src, block, buffer, NULL);
 2614     if (ret < 0)
 2615         goto ex;
 2616     /* ok, it is a valid PVD */
 2617     pvm = (struct ecma119_pri_vol_desc *)buffer;
 2618 
 2619     /* fill volume attributes  */
 2620     /* TODO take care of input charset */
 2621     data->volset_id = iso_util_strcopy_untail((char*)pvm->vol_set_id, 128);
 2622     data->volume_id = iso_util_strcopy_untail((char*)pvm->volume_id, 32);
 2623     data->publisher_id =
 2624                iso_util_strcopy_untail((char*)pvm->publisher_id, 128);
 2625     data->data_preparer_id =
 2626                iso_util_strcopy_untail((char*)pvm->data_prep_id, 128);
 2627     data->system_id = iso_util_strcopy_untail((char*)pvm->system_id, 32);
 2628     data->application_id =
 2629                iso_util_strcopy_untail((char*)pvm->application_id, 128);
 2630     data->copyright_file_id =
 2631                iso_util_strcopy_untail((char*) pvm->copyright_file_id, 37);
 2632     data->abstract_file_id =
 2633                iso_util_strcopy_untail((char*) pvm->abstract_file_id, 37);
 2634     data->biblio_file_id =
 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
 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
 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 
 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
 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
 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
 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
 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
 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
 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
 3727 void iso_scan_hc_sh(uint32_t lba, int c, int h, int s, uint8_t *matches)
 3728 {
 3729     int i, j;
 3730     uint32_t res;
 3731 
 3732 /*
 3733     fprintf(stderr, "iso_scan_hc_sh :%d = %4d/%3d/%2d :\n", lba, c, h, s);
 3734 */
 3735     if (lba == ((uint32_t) s) - 1 && c == 0 && h == 0) /* trivial solutions */
 3736         return;
 3737     if (c == 1023 && h >= 254 && s == 63) /* Indicators for invalid CHS */
 3738         return;
 3739 
 3740     /* matches(i=0,j=1) == 0 indicates presence of non-trivial equations */
 3741     matches[0] &= ~1;
 3742 
 3743     for (i = 1; i <= 255; i++) {
 3744         for (j = 1; j <= 63; j++) {
 3745             res = ((c * i) + h) * j + (s - 1);
 3746             if (res != lba) {
 3747                 matches[(i / 8) * 32 + (j - 1)] &= ~(1 << (i % 8));
 3748 /*
 3749             } else {    
 3750                  if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8)))
 3751                      fprintf(stderr,
 3752                     "iso_scan_hc_sh :%d = %4d/%3d/%2d :  H/C= %3d  S/H= %2d\n",
 3753                             lba, c, h, s, i, j);
 3754 */
 3755             }
 3756         }
 3757     }
 3758 }
 3759 
 3760 /* Pick a good remaining solution from the matches bitmap.
 3761 */
 3762 static
 3763 void iso_get_hc_sh(uint8_t *matches, uint32_t iso_image_size,
 3764                    int *hc, int *sh, int flag)
 3765 {
 3766     int i, j, k;
 3767     static int pref[][2] = {{64, 32}, {255, 63}}, prefs = 2;
 3768     
 3769     *hc = *sh = 0;
 3770 
 3771     if (matches[0] & 1)
 3772         return; /* Only trivial equations seen */
 3773 
 3774     /* Look for preferred layouts */
 3775     for (k = 0; k < prefs; k++) {
 3776         i = pref[k][0];
 3777         j = pref[k][1];
 3778         if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
 3779     continue;
 3780         if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
 3781             *hc = i;
 3782             *sh = j;
 3783             return;
 3784         }
 3785     }
 3786 
 3787     /* Look for largest possible cylinder */
 3788     for (i = 1; i <= 255; i++) {
 3789         for (j = 1; j <= 63; j++) {
 3790             if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size)
 3791         continue;
 3792             if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) {
 3793                 if( i * j < *hc * *sh)
 3794         continue;
 3795                 *hc = i;
 3796                 *sh = j;
 3797             }
 3798         }
 3799     }
 3800 }
 3801 
 3802 static
 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
 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
 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
 4002 int iso_analyze_mbr(IsoImage *image, IsoDataSource *src, int flag)
 4003 {
 4004     int sub_type = 2, ret, is_isohybrid = 0, is_grub2_mbr = 0;
 4005     int is_protective_label = 0;
 4006     uint64_t part2_start;
 4007     char *sad;
 4008     struct iso_imported_sys_area *sai;
 4009     struct iso_mbr_partition_request *part;
 4010 
 4011     sad = image->system_area_data;
 4012     sai = image->imported_sa_info;
 4013 
 4014     /* Is it an MBR ? */
 4015     if (((unsigned char *) sad)[510] != 0x55 ||
 4016         ((unsigned char *) sad)[511] != 0xaa)
 4017         {ret = 0; goto ex;}
 4018 
 4019     ret = iso_analyze_mbr_ptable(image, 0);
 4020     if (ret <= 0)
 4021         goto ex;
 4022 
 4023     ret = iso_analyze_isohybrid(image, 0);
 4024     if (ret < 0)
 4025         goto ex;
 4026     if (ret == 1) {
 4027         sub_type = 0;
 4028         is_isohybrid = 1;
 4029     } else if(ret == 2) {
 4030         /* will become sub_type 0 if protective_label */
 4031         is_grub2_mbr = 1;
 4032     }
 4033 
 4034     if (sai->mbr_req_count == 3 && !is_isohybrid) {
 4035         /* Check for libisofs PReP partitions :
 4036                0xee or 0xcd from 0 to a-1
 4037                0x41 from a to b
 4038                0x0c or 0xcd from b+1 to end
 4039         */
 4040         if ((sai->mbr_req[0]->start_block == 0 &&
 4041              (sai->mbr_req[0]->type_byte == 0xee ||
 4042               sai->mbr_req[0]->type_byte == 0xcd)) &&
 4043             sai->mbr_req[0]->block_count == sai->mbr_req[1]->start_block &&
 4044             sai->mbr_req[1]->type_byte == 0x41 &&
 4045             (sai->mbr_req[1]->start_block % 4) == 0 &&
 4046             sai->mbr_req[1]->start_block + sai->mbr_req[1]->block_count ==
 4047                                                 sai->mbr_req[2]->start_block &&
 4048             (sai->mbr_req[2]->type_byte == 0x0c ||
 4049              sai->mbr_req[2]->type_byte == 0xcd) &&
 4050             (sai->mbr_req[2]->start_block + sai->mbr_req[2]->block_count) / 4
 4051                                                           == sai->image_size) {
 4052             sai->prep_part_start = sai->mbr_req[1]->start_block / 4;
 4053             sai->prep_part_size = (sai->mbr_req[1]->block_count + 3) / 4;
 4054             sub_type = 0;
 4055         }
 4056     }
 4057     if (sai->mbr_req_count >= 1 &&
 4058         (sai->mbr_req[0]->type_byte == 0xee || !is_isohybrid) &&
 4059         !(sai->prep_part_start > 0)) {
 4060         part = sai->mbr_req[0];
 4061         part2_start = 0;
 4062         if (sai->mbr_req_count >= 2)
 4063             part2_start = sai->mbr_req[1]->start_block;
 4064         if (part->start_block == 1 &&
 4065             (part->block_count + 1 == ((uint64_t) sai->image_size) * 4 ||
 4066              (part->type_byte == 0xee &&
 4067               part->block_count + 1 >= ((uint64_t) sai->image_size) * 4 &&
 4068               (sai->mbr_req_count == 1 ||
 4069                (sai->mbr_req_count == 2 &&
 4070                 sai->mbr_req[1]->type_byte == 0x00))) ||
 4071              part->block_count + 1 == part2_start)) {
 4072             /* libisofs protective msdos label for GRUB2 */
 4073             is_protective_label = 1;
 4074             sub_type = 0;
 4075         } else if (sai->mbr_req_count == 1 && part->start_block == 0 &&
 4076                  part->block_count <= ((uint64_t) sai->image_size) * 4 &&
 4077                  part->block_count + 600 >= ((uint64_t) sai->image_size) * 4 &&
 4078                  part->type_byte == 0x96) {
 4079             /* CHRP (possibly without padding) */
 4080             sub_type = 1;
 4081         } else if (sai->mbr_req_count == 1 &&
 4082                    sai->mbr_req[0]->start_block > 0 &&
 4083                    (sai->mbr_req[0]->start_block % 4) == 0 &&
 4084                    (sai->mbr_req[0]->start_block +
 4085                         sai->mbr_req[0]->block_count) / 4 <= sai->image_size &&
 4086                    part->type_byte == 0x41) {
 4087             /* mkisofs PReP partition */
 4088             sai->prep_part_start = sai->mbr_req[0]->start_block / 4;
 4089             sai->prep_part_size = (sai->mbr_req[0]->block_count + 3) / 4;
 4090             sub_type = 0;
 4091         }
 4092     }
 4093 
 4094     /* Check for partition offset with extra set of meta data */
 4095     if (sai->mbr_req_count > 0) {
 4096         part = sai->mbr_req[0];
 4097         if ((part->status_byte == 0x80 || part->status_byte == 0) &&
 4098             part->start_block >= 64 && part->block_count >= 72 &&
 4099             part->start_block <= 2048 &&
 4100             part->start_block % 4 == 0 && part->block_count % 4 == 0 &&
 4101             (part->start_block + part->block_count) / 4 <= sai->image_size) {
 4102 
 4103             ret = iso_analyze_partition_offset(image, src, part->start_block,
 4104                                                part->block_count, 0);
 4105             if (ret < 0)
 4106                 goto ex;
 4107         }
 4108     }
 4109 
 4110     /* Set sa type 0, sub type as chosen */
 4111     sai->system_area_options = (sai->system_area_options & 0xffff8300) |
 4112                                is_protective_label |
 4113                                (is_isohybrid << 1) |
 4114                                (sub_type << 10) |
 4115                                (is_grub2_mbr << 14);
 4116     ret = 1;
 4117 ex:;
 4118     return ret;
 4119 }
 4120 
 4121 static
 4122 int iso_seems_usable_gpt_head(uint8_t *head, int flag)
 4123 {
 4124     uint32_t head_size, entry_size;
 4125 
 4126     if (strncmp((char *) head, "EFI PART", 8) != 0) /* signature */
 4127         return 0;
 4128     if (head[8] || head[9] || head[10] != 1 || head[11]) /* revision */
 4129         return 0;
 4130     head_size = iso_read_lsb(head + 12, 4);
 4131     if (head_size < 92)
 4132         return 0;
 4133     entry_size = iso_read_lsb(head + 84, 4);
 4134     if (entry_size != 128)
 4135         return 0;
 4136     return 1;
 4137 }
 4138 
 4139 static
 4140 int iso_analyze_gpt_backup(IsoImage *image, IsoDataSource *src, int flag)
 4141 {
 4142     struct iso_imported_sys_area *sai;
 4143     uint64_t part_start;
 4144     uint32_t iso_block, found_crc, crc, entry_count, array_crc;
 4145     uint8_t *head, *part_array, *b_part, *m_part;
 4146     int ret, i, num_iso_blocks, l, j, entries_diff;
 4147     unsigned char *buf = NULL;
 4148     char *comments = NULL;
 4149 
 4150     sai = image->imported_sa_info;
 4151     LIBISO_ALLOC_MEM(buf, unsigned char, 34 * 1024);
 4152     LIBISO_ALLOC_MEM(comments, char, 4096);
 4153 
 4154     /* Read ISO block with backup head */
 4155     if (sai->gpt_backup_lba >= ((uint64_t) sai->image_size) * 4 &&
 4156         (sai->mbr_req_count < 1 ||
 4157          sai->mbr_req[0]->start_block + sai->mbr_req[0]->block_count
 4158          > sai->gpt_backup_lba + 1))
 4159         sprintf(comments + strlen(comments), "Implausible header LBA %.f, ",
 4160                 (double) sai->gpt_backup_lba);
 4161     iso_block = sai->gpt_backup_lba / 4;
 4162     ret = src->read_block(src, iso_block, buf);
 4163     if (ret < 0) {
 4164         sprintf(comments + strlen(comments),
 4165                 "Cannot read header block at 2k LBA %.f, ",
 4166                 (double) iso_block);
 4167         ret = 0; goto ex;
 4168     }
 4169     head = buf + (sai->gpt_backup_lba % 4) * 512;
 4170     ret = iso_seems_usable_gpt_head(head, 0);
 4171     if (ret == 0)
 4172         strcat(comments,
 4173                "Not a GPT 1.0 header of 92 bytes for 128 bytes per entry, ");
 4174     if (ret <= 0) {
 4175         ret = 0; goto ex;
 4176     }
 4177 
 4178     /* Check head CRC */
 4179     found_crc = iso_read_lsb(head + 16, 4);
 4180     memset(head + 16, 0, 4);
 4181     crc = iso_crc32_gpt((unsigned char *) head, 92, 0);
 4182     if (found_crc != crc) {
 4183         sprintf(comments + strlen(comments),
 4184                 "Head CRC 0x%8x wrong. Should be 0x%8x",
 4185                 found_crc, crc);
 4186         crc = iso_crc32_gpt((unsigned char *) head, 512, 0);
 4187         if (found_crc == crc) {
 4188             strcat(comments, ". Matches all 512 block bytes, ");
 4189         } else {
 4190             strcat(comments, ", ");
 4191             ret = 0; goto ex;
 4192         }
 4193     }
 4194     for (i = 0; i < 16; i ++)
 4195         if (head[i + 56] != sai->gpt_disk_guid[i])
 4196     break;
 4197     if (i < 16) {
 4198         sprintf(comments + strlen(comments), "Disk GUID differs (");
 4199         iso_util_bin_to_hex(comments + strlen(comments), head + 56, 16, 0);
 4200         sprintf(comments + strlen(comments), "), ");
 4201     }
 4202 
 4203     /* Header content will possibly be overwritten now */
 4204     array_crc = iso_read_lsb(head + 88, 4);
 4205     part_start = iso_read_lsb64(head + 72);
 4206     entry_count = iso_read_lsb(head + 80, 4);
 4207     head = NULL;
 4208 
 4209     /* Read backup array */
 4210     if (entry_count != sai->gpt_max_entries) {
 4211         sprintf(comments + strlen(comments),
 4212                 "Number of array entries %u differs from main GPT %u, ",
 4213                 entry_count, sai->gpt_max_entries);
 4214         ret = 0; goto ex;
 4215     }
 4216     if (part_start + (entry_count + 3) / 4 != sai->gpt_backup_lba)
 4217         sprintf(comments + strlen(comments), "Implausible array LBA %.f, ",
 4218                 (double) part_start);
 4219     iso_block = part_start / 4;
 4220     num_iso_blocks = (part_start + (entry_count + 3) / 4) / 4 - iso_block + 1;
 4221     for (i = 0; i < num_iso_blocks; i++) {
 4222         ret = src->read_block(src, iso_block + (uint32_t) i, buf + i * 2048);
 4223         if (ret < 0) {
 4224             sprintf(comments + strlen(comments),
 4225                     "Cannot read array block at 2k LBA %.f, ",
 4226                     (double) iso_block);
 4227             ret = 0; goto ex;
 4228         }
 4229     }
 4230     part_array = buf + (part_start % 4) * 512;
 4231 
 4232     crc = iso_crc32_gpt((unsigned char *) part_array, 128 * entry_count, 0);
 4233     if (crc != array_crc)
 4234         sprintf(comments + strlen(comments),
 4235                 "Array CRC 0x%8x wrong. Should be 0x%8x, ", array_crc, crc);
 4236 
 4237     /* Compare entries */
 4238     entries_diff = 0;
 4239     for (i = 0; i < (int) entry_count; i++) {
 4240         b_part = part_array + 128 * i;
 4241         m_part = ((uint8_t *) image->system_area_data) +
 4242                  sai->gpt_part_start * 512 + 128 * i;
 4243         for (j = 0; j < 128; j++)
 4244             if (b_part[j] != m_part[j])
 4245         break;
 4246         if (j < 128) {
 4247             if (!entries_diff) {
 4248                 strcat(comments, "Entries differ for partitions");
 4249                 entries_diff = 1;
 4250             }
 4251             sprintf(comments + strlen(comments), " %d", i + 1);
 4252         }
 4253     }
 4254     if (entries_diff) {
 4255         strcat(comments, ", ");
 4256         ret = 0; goto ex;
 4257     }
 4258 
 4259     ret = 1;
 4260 ex:;
 4261     if (comments != NULL) {
 4262         l = strlen(comments);
 4263         if (l > 2)
 4264             if (comments[l - 2] == ',' && comments[l - 1] == ' ')
 4265                 comments[l - 2] = 0;
 4266         sai->gpt_backup_comments = strdup(comments);
 4267         if (sai->gpt_backup_comments == NULL)
 4268             ret = ISO_OUT_OF_MEM;
 4269     }
 4270     LIBISO_FREE_MEM(comments);
 4271     LIBISO_FREE_MEM(buf);
 4272     return ret;
 4273 }
 4274 
 4275 static
 4276 int iso_analyze_gpt_head(IsoImage *image, IsoDataSource *src, int flag)
 4277 {
 4278     struct iso_imported_sys_area *sai;
 4279     uint8_t *head;
 4280     uint32_t crc;
 4281     uint64_t part_start;
 4282     int ret;
 4283     unsigned char *crc_buf = NULL;
 4284 
 4285     sai = image->imported_sa_info;
 4286     head = ((uint8_t *) image->system_area_data) + 512;
 4287     LIBISO_ALLOC_MEM(crc_buf, unsigned char, 512);
 4288 
 4289     /* Is this a GPT header with digestible parameters ? */
 4290     ret = iso_seems_usable_gpt_head(head, 0);
 4291     if (ret <= 0)
 4292         goto ex;
 4293     memcpy(crc_buf, head, 512);
 4294     memset(crc_buf + 16, 0, 4); /* CRC is computed when head_crc is 0 */
 4295     sai->gpt_head_crc_found = iso_read_lsb(head + 16, 4);
 4296     sai->gpt_head_crc_should = iso_crc32_gpt((unsigned char *) crc_buf, 92, 0);
 4297     if (sai->gpt_head_crc_found != sai->gpt_head_crc_should) {
 4298         /* There was a bug during libisofs-1.2.4 to libisofs-1.2.8
 4299            (fixed in rev 1071). So accept the buggy CRC if it matches the
 4300            whole GPT header block. */
 4301         crc = iso_crc32_gpt((unsigned char *) crc_buf, 512, 0);
 4302         if (sai->gpt_head_crc_found != crc)
 4303             {ret = 0; goto ex;}
 4304     }
 4305     part_start = iso_read_lsb64(head + 72);
 4306     sai->gpt_max_entries = iso_read_lsb(head + 80, 4);
 4307     if (part_start + (sai->gpt_max_entries + 3) / 4 > 64)
 4308         {ret = 0; goto ex;}
 4309 
 4310     /* Fetch desired information */
 4311     memcpy(sai->gpt_disk_guid, head + 56, 16);
 4312     sai->gpt_part_start = part_start;
 4313     sai->gpt_backup_lba = iso_read_lsb64(head + 32);
 4314     sai->gpt_first_lba = iso_read_lsb64(head + 40);
 4315     sai->gpt_last_lba = iso_read_lsb64(head + 48);
 4316     sai->gpt_array_crc_found = iso_read_lsb(head + 88, 4);
 4317     sai->gpt_array_crc_should =
 4318                       iso_crc32_gpt((unsigned char *) image->system_area_data +
 4319                                     sai->gpt_part_start * 512,
 4320                                     sai->gpt_max_entries * 128, 0);
 4321 
 4322     ret = iso_analyze_gpt_backup(image, src, 0);
 4323     if (ret < 0)
 4324         goto ex;
 4325 
 4326     ret = 1;
 4327 ex:
 4328     LIBISO_FREE_MEM(crc_buf);
 4329     return ret;
 4330 }
 4331 
 4332 static
 4333 int iso_analyze_gpt(IsoImage *image, IsoDataSource *src, int flag)
 4334 {
 4335     int ret, i, j;
 4336     uint64_t start_block, block_count, flags, end_block, j_end, j_start;
 4337     uint8_t *part;
 4338     struct iso_imported_sys_area *sai;
 4339 
 4340     sai = image->imported_sa_info;
 4341 
 4342     ret = iso_analyze_gpt_head(image, src, 0);
 4343     if (ret <= 0)
 4344         return ret;
 4345 
 4346     for (i = 0; i < (int) sai->gpt_max_entries; i++) {
 4347         part = ((uint8_t *) image->system_area_data) +
 4348                sai->gpt_part_start * 512 + 128 * i;
 4349         for (j = 0; j < 128; j++)
 4350             if (part[j])
 4351         break;
 4352         if (j >= 128) /* all zero, invalid entry */
 4353     continue;
 4354         start_block = iso_read_lsb64(part + 32);
 4355         block_count = iso_read_lsb64(part + 40);
 4356         flags = iso_read_lsb64(part + 48);
 4357         if ((start_block == 0 && block_count == 0) ||
 4358             block_count + 1 < start_block)
 4359     continue;
 4360         block_count = block_count + 1 - start_block;
 4361         if (sai->gpt_req == NULL) {
 4362             sai->gpt_req = calloc(ISO_GPT_ENTRIES_MAX,
 4363                                   sizeof(struct iso_gpt_partition_request *));
 4364             if (sai->gpt_req == NULL)
 4365                 return ISO_OUT_OF_MEM;
 4366         }
 4367         ret = iso_quick_gpt_entry(sai->gpt_req, &(sai->gpt_req_count),
 4368                                   start_block, block_count,
 4369                                   part, part + 16, flags, part + 56);
 4370         if (ret < 0)
 4371             return ret;
 4372         sai->gpt_req[sai->gpt_req_count - 1]->idx = i + 1;
 4373     }
 4374 
 4375     /* sai->gpt_req_flags :
 4376           bit0= GPT partitions may overlap
 4377           >>> bit1= with bit0: neatly nested partitions
 4378                     without  : neatly divided disk 
 4379     */
 4380     for (i = 0; i < (int) sai->gpt_req_count && !(sai->gpt_req_flags & 1);
 4381          i++) {
 4382         if (sai->gpt_req[i]->block_count == 0)
 4383     continue;
 4384         start_block = sai->gpt_req[i]->start_block;
 4385         end_block = start_block + sai->gpt_req[i]->block_count;
 4386         for (j = i + 1; j < (int) sai->gpt_req_count; j++) {
 4387             if (sai->gpt_req[j]->block_count == 0)
 4388         continue;
 4389             j_start = sai->gpt_req[j]->start_block;
 4390             j_end = j_start + sai->gpt_req[j]->block_count;
 4391             if ((start_block <= j_start && j_start < end_block) ||
 4392                 (start_block <= j_end   && j_end   < end_block) ||
 4393                 (j_start <= start_block && start_block < j_end)) {
 4394                 sai->gpt_req_flags |= 1;
 4395         break;
 4396             }
 4397         }
 4398     }
 4399 
 4400     /* Check first GPT partition for ISO partition offset */
 4401     if (sai->partition_offset == 0 && sai->mbr_req_count > 0 &&
 4402         sai->gpt_req_count > 0) {
 4403         if (sai->mbr_req[0]->type_byte == 0xee &&
 4404             sai->mbr_req[0]->start_block == 1) { /* protective MBR */
 4405             start_block = sai->gpt_req[0]->start_block;
 4406             block_count = sai->gpt_req[0]->block_count;
 4407             if (start_block >= 64 && block_count >= 72 &&
 4408                 start_block <= 2048 && start_block % 4 == 0 &&
 4409                 block_count % 4 == 0) {
 4410 
 4411                 ret = iso_analyze_partition_offset(image, src, start_block,
 4412                                                    block_count, 0);
 4413                 if (ret < 0)
 4414                     return ret;
 4415             }
 4416         }
 4417     }
 4418 
 4419     return 1;
 4420 }
 4421 
 4422 
 4423 static
 4424 int iso_analyze_apm_head(IsoImage *image, IsoDataSource *src, int flag)
 4425 {
 4426     struct iso_imported_sys_area *sai;
 4427     char *sad;
 4428     uint32_t block_size;
 4429 
 4430     sai = image->imported_sa_info;
 4431     sad = image->system_area_data;
 4432 
 4433     if (sad[0] != 'E' || sad[1] != 'R')
 4434         return 0;
 4435     block_size = iso_read_msb(((uint8_t *) sad) + 2, 2);
 4436     if (block_size != 2048 && block_size != 512)
 4437         return 0;
 4438     sai->apm_block_size = block_size;
 4439     sai->apm_req_flags |= 4 | 2; /* start_block and block_count are in
 4440                                     block_size units, do not fill gaps */
 4441     return 1;
 4442 }
 4443 
 4444 static
 4445 int iso_analyze_apm(IsoImage *image, IsoDataSource *src, int flag)
 4446 {
 4447     int ret, i;
 4448     uint32_t map_entries, start_block, block_count, flags;
 4449     char *sad, *part, name[33], type_string[33];
 4450     struct iso_imported_sys_area *sai;
 4451 
 4452     sai = image->imported_sa_info;
 4453     sad = image->system_area_data;
 4454 
 4455     ret = iso_analyze_apm_head(image, src, 0);
 4456     if (ret <= 0)
 4457         return ret;
 4458 
 4459     part = sad + sai->apm_block_size;
 4460     map_entries = iso_read_msb(((uint8_t *) part) + 4, 4);
 4461     for (i = 0; i < (int) map_entries; i++) {
 4462         part = sad + (i + 1) * sai->apm_block_size;
 4463         if (part[0] != 'P' || part[1] != 'M')
 4464     break;
 4465         flags = iso_read_msb(((uint8_t *) part) + 88, 4);
 4466         if (!(flags & 3))
 4467     continue;
 4468         memcpy(type_string, part + 48, 32);
 4469         type_string[32] = 0;
 4470         if(strcmp(type_string, "Apple_partition_map") == 0)
 4471     continue;
 4472         start_block = iso_read_msb(((uint8_t *) part) + 8, 4);
 4473         block_count = iso_read_msb(((uint8_t *) part + 12), 4);
 4474         memcpy(name, part + 16, 32);
 4475         name[32] = 0;
 4476         if (sai->apm_req == NULL) {
 4477             sai->apm_req = calloc(ISO_APM_ENTRIES_MAX,
 4478                                   sizeof(struct iso_apm_partition_request *));
 4479             if (sai->apm_req == NULL)
 4480                 return ISO_OUT_OF_MEM;
 4481         }
 4482         ret = iso_quick_apm_entry(sai->apm_req, &(sai->apm_req_count),
 4483                                   start_block, block_count, name, type_string);
 4484         if (ret <= 0)
 4485             return ret;
 4486         if (strncmp(name, "Gap", 3) == 0 &&
 4487             strcmp(type_string, "ISO9660_data") == 0) {
 4488             if ('0' <= name[3] && name[3] <= '9' && (name[4] == 0 ||
 4489                  ('0' <= name[4] && name[4] <= '9' && name[5] == 0))) {
 4490                 sai->apm_gap_count++;
 4491                 sai->apm_req_flags &= ~2;
 4492             }
 4493         }
 4494     }
 4495     return 1;
 4496 }
 4497 
 4498 static
 4499 int iso_analyze_mips(IsoImage *image, IsoDataSource *src, int flag)
 4500 {
 4501     int ret = 0, spt, bps, i, j, idx;
 4502     uint32_t magic, chk, head_chk;
 4503     char *sad;
 4504     uint8_t *usad, *upart;
 4505     struct iso_imported_sys_area *sai;
 4506     IsoNode *node;
 4507 
 4508     sai = image->imported_sa_info;
 4509     sad = image->system_area_data;
 4510     usad = (uint8_t *) sad;
 4511 
 4512     magic = iso_read_msb(usad, 4);
 4513     if (magic != 0x0be5a941)
 4514         return 0;
 4515     spt = iso_read_msb(usad + 38, 2);
 4516     bps = iso_read_msb(usad + 40, 2);
 4517     if (spt != 32 || bps != 512)
 4518         return 0;
 4519     chk = 0;
 4520     for (i = 0; i < 504; i += 4)
 4521         chk -= iso_read_msb(usad + i, 4);
 4522     head_chk = iso_read_msb(usad + 504, 4);
 4523     if (chk != head_chk)
 4524         return 0;
 4525 
 4526     /* Verify that partitions 1 to 8 are empty */
 4527     for (j = 312; j < 408; j++)
 4528         if (sad[j])
 4529             return 0;
 4530 
 4531     /* >>> verify that partitions 9 and 10 match the image size */;
 4532 
 4533     for (i = 0; i < 15; i++) {
 4534         upart = usad + 72 + 16 * i;
 4535         for (j = 0; j < 16; j++)
 4536             if (upart[j])
 4537         break;
 4538         if (j == 16)
 4539     continue;
 4540         if (sai->mips_vd_entries == NULL) {
 4541             sai->mips_boot_file_paths = calloc(15, sizeof(char *));
 4542             sai->mips_vd_entries = calloc(15,
 4543                                        sizeof(struct iso_mips_voldir_entry *));
 4544             if (sai->mips_vd_entries == NULL ||
 4545                 sai->mips_boot_file_paths == NULL)
 4546                 return ISO_OUT_OF_MEM;
 4547             sai->num_mips_boot_files = 0;
 4548             for (j = 0; j < 15; j++) {
 4549                 sai->mips_boot_file_paths[j] = NULL;
 4550                 sai->mips_vd_entries[j] = NULL;
 4551             }
 4552         }
 4553 
 4554         /* Assess boot file entry */
 4555         if (sai->num_mips_boot_files >= 15)
 4556             return ISO_BOOT_TOO_MANY_MIPS;
 4557         idx = sai->num_mips_boot_files;
 4558         sai->mips_vd_entries[idx] =
 4559                                calloc(1, sizeof(struct iso_mips_voldir_entry));
 4560         if (sai->mips_vd_entries[idx] == NULL)
 4561             return ISO_OUT_OF_MEM;
 4562         memcpy(sai->mips_vd_entries[idx]->name, upart, 8);
 4563         sai->mips_vd_entries[idx]->name[8] = 0;
 4564         sai->mips_vd_entries[idx]->boot_block = iso_read_msb(upart + 8, 4);
 4565         sai->mips_vd_entries[idx]->boot_bytes = iso_read_msb(upart + 12, 4);
 4566         ret = iso_tree_get_node_of_block(image, NULL,
 4567                                      sai->mips_vd_entries[idx]->boot_block / 4,
 4568                                      &node, NULL, 0);
 4569         if (ret > 0)
 4570             sai->mips_boot_file_paths[idx] = iso_tree_get_node_path(node);
 4571         sai->num_mips_boot_files++;
 4572     }
 4573     if (sai->num_mips_boot_files > 0)
 4574         sai->system_area_options = (1 << 2);/* MIPS Big Endian Volume Header */
 4575 
 4576     return ret;
 4577 }
 4578 
 4579 static
 4580 int iso_analyze_mipsel(IsoImage *image, IsoDataSource *src, int flag)
 4581 {
 4582     int ret = 0, i, section_count;
 4583     char *sad;
 4584     uint8_t *usad;
 4585     uint32_t magic;
 4586     struct iso_imported_sys_area *sai;
 4587     IsoNode *node;
 4588     IsoFile *file;
 4589     struct iso_file_section *sections = NULL;
 4590 
 4591     sai = image->imported_sa_info;
 4592     sad = image->system_area_data;
 4593     usad = (uint8_t *) sad;
 4594 
 4595     for (i = 0; i < 8; i++)
 4596         if (sad[i])
 4597             return 0;
 4598     magic = iso_read_lsb(usad + 8, 4);
 4599     if (magic != 0x0002757a)
 4600         return 0;
 4601 
 4602     sai->mipsel_p_vaddr = iso_read_lsb(usad + 16, 4);
 4603     sai->mipsel_e_entry = iso_read_lsb(usad + 20, 4);
 4604     sai->mipsel_p_filesz = iso_read_lsb(usad + 24, 4) * 512;
 4605     sai->mipsel_seg_start = iso_read_lsb(usad + 28, 4);
 4606     ret = iso_tree_get_node_of_block(image, NULL, sai->mipsel_seg_start / 4,
 4607                                      &node, NULL, 0);
 4608     if (ret > 0) {
 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
 4628 int iso_analyze_sun(IsoImage *image, IsoDataSource *src, int flag)
 4629 {
 4630     int ret = 0, i, idx;
 4631     char *sad;
 4632     uint8_t *usad, checksum[2];
 4633     uint16_t perms;
 4634     uint64_t last_core_block;
 4635     struct iso_imported_sys_area *sai;
 4636     IsoNode *node;
 4637 
 4638     sai = image->imported_sa_info;
 4639     sad = image->system_area_data;
 4640     usad = (uint8_t *) sad;
 4641 
 4642     if (iso_read_msb(usad + 128, 4) != 1 ||
 4643         iso_read_msb(usad + 140, 2) != 8 ||
 4644         iso_read_msb(usad + 188, 4) != 0x600ddeee ||
 4645         iso_read_msb(usad + 430, 2) != 1 ||
 4646         iso_read_msb(usad + 508, 2) != 0xdabe)
 4647         return 0;
 4648     if (iso_read_msb(usad + 142, 2) != 4 ||
 4649         iso_read_msb(usad + 144, 2) != 0x10 ||
 4650         iso_read_msb(usad + 444, 4) != 0 ||
 4651         sai->image_size > 0x3fffffff ||
 4652         iso_read_msb(usad + 448, 4) < ((int64_t) sai->image_size * 4) - 600 ||
 4653         iso_read_msb(usad + 448, 4) > sai->image_size * 4)
 4654         return 0;
 4655     checksum[0] = checksum[1] = 0;
 4656     for (i = 0; i < 510; i += 2) {
 4657         checksum[0] ^= usad[i];
 4658         checksum[1] ^= usad[i + 1];
 4659     }
 4660     if (checksum[0] != usad[510] || checksum[1] != usad[511])
 4661         return 0;
 4662 
 4663     sai->sparc_disc_label = calloc(1, 129);
 4664     if (sai->sparc_disc_label == NULL)
 4665         return ISO_OUT_OF_MEM;
 4666     memcpy(sai->sparc_disc_label, sad, 128);
 4667     sai->sparc_disc_label[128] = 0;
 4668     sai->sparc_heads_per_cyl = iso_read_msb(usad + 436, 2);
 4669     sai->sparc_secs_per_head = iso_read_msb(usad + 438, 2);
 4670 
 4671     for (i = 0; i < 8; i++) {
 4672         perms = iso_read_msb(usad + 144 + 4 * i, 2);
 4673         if (perms == 0)
 4674     continue;
 4675         if (sai->sparc_entries == NULL) {
 4676             sai->sparc_entries = calloc(8,
 4677                                       sizeof(struct iso_sun_disk_label_entry));
 4678             if (sai->sparc_entries == NULL)
 4679                 return ISO_OUT_OF_MEM;
 4680         }
 4681         idx = sai->sparc_entry_count;
 4682         sai->sparc_entries[idx].idx = i + 1;
 4683         sai->sparc_entries[idx].id_tag = iso_read_msb(usad + 142 + 4 * i, 2);
 4684         sai->sparc_entries[idx].permissions = perms;
 4685         sai->sparc_entries[idx].start_cyl =
 4686                                            iso_read_msb(usad + 444 + 8 * i, 4);
 4687         sai->sparc_entries[idx].num_blocks =
 4688                                            iso_read_msb(usad + 448 + 8 * i, 4);
 4689         sai->sparc_entry_count++;
 4690     }
 4691 
 4692     /* GRUB2 SUN SPARC Core File Address */
 4693     sai->sparc_grub2_core_adr = iso_read_msb64(usad + 552);
 4694     sai->sparc_grub2_core_size = iso_read_msb(usad + 560, 4);
 4695     last_core_block = (sai->sparc_grub2_core_adr +
 4696                        sai->sparc_grub2_core_size + 2047) / 2048;
 4697     if (last_core_block > 0)
 4698         last_core_block--;
 4699     if (last_core_block > 17 && last_core_block < sai->image_size) {
 4700         ret = iso_tree_get_node_of_block(image, NULL,
 4701                                          (uint32_t) last_core_block, &node,
 4702                                          NULL, 0);
 4703         if (ret > 0) {
 4704             iso_node_ref(node);
 4705             sai->sparc_core_node = (IsoFile *) node;
 4706         }
 4707     } else {
 4708         sai->sparc_grub2_core_adr = 0;
 4709         sai->sparc_grub2_core_size = 0;
 4710     }
 4711 
 4712     /* SUN Disk Label for SUN SPARC */
 4713     sai->system_area_options = (3 << 2);
 4714     
 4715     return 1;
 4716 }
 4717 
 4718 static
 4719 int iso_analyze_hppa(IsoImage *image, IsoDataSource *src, int flag)
 4720 {
 4721     int ret = 0, i, cmd_adr, cmd_len;
 4722     char *sad, *paths[4];
 4723     uint8_t *usad;
 4724     uint16_t magic;
 4725     uint32_t adrs[4];
 4726     struct iso_imported_sys_area *sai;
 4727     IsoNode *node;
 4728 
 4729     sai = image->imported_sa_info;
 4730     sad = image->system_area_data;
 4731     usad = (uint8_t *) sad;
 4732 
 4733     magic = iso_read_msb(usad, 2);
 4734     if (magic != 0x8000 || strncmp(sad + 2, "PALO", 5) != 0 ||
 4735         sad[7] < 4 || sad[7] > 5)
 4736         return 0;
 4737 
 4738     sai->hppa_hdrversion = sad[7];
 4739     if (sai->hppa_hdrversion == 4) {
 4740         cmd_len = 127;
 4741         cmd_adr = 24;
 4742     } else {
 4743         cmd_len = 1023;
 4744         cmd_adr = 1024;
 4745     }
 4746     sai->hppa_cmdline = calloc(1, cmd_len + 1);
 4747     if (sai->hppa_cmdline == NULL)
 4748         return ISO_OUT_OF_MEM;
 4749     memcpy(sai->hppa_cmdline, sad + cmd_adr, cmd_len);
 4750         sai->hppa_cmdline[cmd_len] = 0;
 4751     adrs[0] = sai->hppa_kern32_adr = iso_read_msb(usad + 8, 4);
 4752     sai->hppa_kern32_len = iso_read_msb(usad + 12, 4);
 4753     adrs[1] = sai->hppa_kern64_adr = iso_read_msb(usad + 232, 4);
 4754     sai->hppa_kern64_len = iso_read_msb(usad + 236, 4);
 4755     adrs[2] = sai->hppa_ramdisk_adr = iso_read_msb(usad + 16, 4);
 4756     sai->hppa_ramdisk_len = iso_read_msb(usad + 20, 4);
 4757     adrs[3] = sai->hppa_bootloader_adr = iso_read_msb(usad + 240, 4);
 4758     sai->hppa_bootloader_len = iso_read_msb(usad + 244, 4);
 4759     for (i = 0; i < 4; i++) {
 4760         paths[i] = NULL;
 4761         ret = iso_tree_get_node_of_block(image, NULL, adrs[i] / 2048,
 4762                                          &node, NULL, 0);
 4763         if (ret > 0)
 4764             paths[i] = iso_tree_get_node_path(node);
 4765     }
 4766     sai->hppa_kernel_32 = paths[0];
 4767     sai->hppa_kernel_64 = paths[1];
 4768     sai->hppa_ramdisk = paths[2];
 4769     sai->hppa_bootloader = paths[3];
 4770 
 4771     if (sai->hppa_hdrversion == 5)
 4772         sai->hppa_ipl_entry = iso_read_msb(usad + 248, 4);
 4773 
 4774     /* HP-PA PALO boot sector version 4 or 5 for HP PA-RISC */
 4775     sai->system_area_options = (sai->hppa_hdrversion << 2);
 4776 
 4777     return 1;
 4778 }
 4779 
 4780 static
 4781 int iso_analyze_alpha_boot(IsoImage *image, IsoDataSource *src, int flag)
 4782 {
 4783     int ret = 0, i, section_count;
 4784     char *sad;
 4785     uint8_t *usad;
 4786     struct iso_imported_sys_area *sai;
 4787     IsoNode *node;
 4788     IsoFile *file;
 4789     uint64_t checksum_found, checksum_should = 0, size;
 4790     struct iso_file_section *sections = NULL;
 4791 
 4792     sai = image->imported_sa_info;
 4793     sad = image->system_area_data;
 4794     usad = (uint8_t *) sad;
 4795 
 4796     checksum_found = iso_read_lsb64(usad + 504);
 4797     for (i = 0; i < 63; i++)
 4798        checksum_should += iso_read_lsb64(usad + 8 * i);
 4799     if (checksum_found != checksum_should)
 4800        return 0;
 4801     sai->alpha_boot_image = NULL;
 4802     sai->alpha_boot_image_size = (uint64_t) iso_read_lsb64(usad + 480);
 4803     sai->alpha_boot_image_adr = (uint64_t) iso_read_lsb64(usad + 488);
 4804     ret = iso_tree_get_node_of_block(image, NULL,
 4805                                   (uint32_t) (sai->alpha_boot_image_adr / 4),
 4806                                   &node, NULL, 0);
 4807     if (ret > 0) {
 4808        if (iso_node_get_type(node) != LIBISO_FILE)
 4809            return 0;
 4810        file = (IsoFile *) node;
 4811        ret = iso_file_get_old_image_sections(file, &section_count,
 4812                                              &sections, 0);
 4813        if (ret > 0 && section_count > 0) {
 4814            size = sections[0].size / 512 + !!(sections[0].size % 512);
 4815            free(sections);
 4816            if (size != sai->alpha_boot_image_size)
 4817                return 0;
 4818        }
 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
 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
 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
 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
 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
 4889 void iso_impsysa_reduce_na(uint32_t block, uint32_t *na, uint32_t claim)
 4890 {
 4891     if ((*na == 0 || *na > claim) && block < claim)
 4892         *na = claim;
 4893 }
 4894 
 4895 static
 4896 int iso_impsysa_reduce_next_above(IsoImage *image, uint32_t block,
 4897                                   uint32_t *next_above, int flag)
 4898 {
 4899     int i, section_count, ret;
 4900     struct iso_imported_sys_area *sai;
 4901     struct el_torito_boot_image *img;
 4902     struct iso_file_section *sections = NULL;
 4903 
 4904     sai = image->imported_sa_info;
 4905 
 4906     /* PVD, path table, root directory of active and of first session */
 4907     for (i = 0; i < sai->num_meta_struct_blocks; i++)
 4908         iso_impsysa_reduce_na(block, next_above, sai->meta_struct_blocks[i]); 
 4909 
 4910     /* Partition tables */
 4911     for (i = 0; i < sai->mbr_req_count; i++) {
 4912         iso_impsysa_reduce_na(block, next_above,
 4913                               (uint32_t) (sai->mbr_req[i]->start_block / 4));
 4914         iso_impsysa_reduce_na(block, next_above,
 4915                               (uint32_t) ((sai->mbr_req[i]->start_block +
 4916                                            sai->mbr_req[i]->block_count) / 4));
 4917     }
 4918     for (i = 0; i < sai->gpt_req_count; i++) {
 4919         iso_impsysa_reduce_na(block, next_above,
 4920                               (uint32_t) (sai->gpt_req[i]->start_block / 4));
 4921         iso_impsysa_reduce_na(block, next_above,
 4922                               (uint32_t) ((sai->gpt_req[i]->start_block +
 4923                                            sai->gpt_req[i]->block_count) / 4));
 4924     }
 4925     for (i = 0; i < sai->apm_req_count; i++) {
 4926         iso_impsysa_reduce_na(block, next_above,
 4927                               (uint32_t) (sai->apm_req[i]->start_block /
 4928                                           (2048 / sai->apm_block_size)));
 4929         iso_impsysa_reduce_na(block, next_above,
 4930                               (uint32_t) ((sai->apm_req[i]->start_block +
 4931                                            sai->apm_req[i]->block_count) /
 4932                                            (2048 / sai->apm_block_size)));
 4933     }
 4934     if (image->bootcat != NULL) {
 4935         if (image->bootcat->node != NULL)
 4936             iso_impsysa_reduce_na(block, next_above,
 4937                                   image->bootcat->node->lba);
 4938         for (i= 0; i < image->bootcat->num_bootimages; i++) {
 4939             img = image->bootcat->bootimages[i];
 4940             ret = iso_file_get_old_image_sections(img->image, &section_count,
 4941                                                   &sections, 0);
 4942             if (ret > 0 && section_count > 0)
 4943                 if (block != sections[0].block)
 4944                     iso_impsysa_reduce_na(block, next_above,
 4945                                           sections[0].block);
 4946             if (sections != NULL) {
 4947                 free(sections);
 4948                 sections = NULL;
 4949             }
 4950         }
 4951     }
 4952 
 4953     iso_impsysa_reduce_na(block, next_above, sai->image_size);
 4954 
 4955     return ISO_SUCCESS;
 4956 }
 4957 
 4958 /* @param flag bit0= try to estimate the size if no path is found
 4959 */
 4960 static
 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
 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