"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/eltorito.c" (7 Nov 2020, 45593 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 "eltorito.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) 2010 - 2016 Thomas Schmitt
    4  *
    5  * This file is part of the libisofs project; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License version 2 
    7  * or later as published by the Free Software Foundation. 
    8  * See COPYING file for details.
    9  */
   10 
   11 #ifdef HAVE_CONFIG_H
   12 #include "../config.h"
   13 #endif
   14 
   15 #include "libisofs.h"
   16 #include "eltorito.h"
   17 #include "fsource.h"
   18 #include "filesrc.h"
   19 #include "image.h"
   20 #include "messages.h"
   21 #include "writer.h"
   22 #include "ecma119.h"
   23 
   24 #include <stdlib.h>
   25 #include <string.h>
   26 #include <stdio.h>
   27 
   28 /**
   29  * This table should be written with the actual values at offset
   30  * 8 of boot image, when used ISOLINUX boot loader
   31  */
   32 struct boot_info_table {
   33     uint8_t bi_pvd              BP(1, 4);  /* LBA of primary volume descriptor */
   34     uint8_t bi_file             BP(5, 8);  /* LBA of boot file */
   35     uint8_t bi_length           BP(9, 12); /* Length of boot file */
   36     uint8_t bi_csum             BP(13, 16); /* Checksum of boot file */
   37     uint8_t bi_reserved         BP(17, 56); /* Reserved */
   38 };
   39 
   40 /**
   41  * Structure for each one of the four entries in a partition table on a
   42  * hard disk image.
   43  */
   44 struct partition_desc {
   45     uint8_t boot_ind;
   46     uint8_t begin_chs[3];
   47     uint8_t type;
   48     uint8_t end_chs[3];
   49     uint8_t start[4];
   50     uint8_t size[4];
   51 };
   52 
   53 /**
   54  * Structures for a Master Boot Record of a hard disk image.
   55  */
   56 struct hard_disc_mbr {
   57     uint8_t code_area[440];
   58     uint8_t opt_disk_sg[4];
   59     uint8_t pad[2];
   60     struct partition_desc partition[4];
   61     uint8_t sign1;
   62     uint8_t sign2;
   63 };
   64 
   65 /* API */
   66 int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id)
   67 {
   68     bootimg->platform_id = id;
   69     return 1;
   70 }
   71 
   72 /* API */
   73 int el_torito_get_boot_platform_id(ElToritoBootImage *bootimg)
   74 {
   75     return bootimg->platform_id;
   76 }
   77 
   78 /**
   79  * Sets the load segment for the initial boot image. This is only for
   80  * no emulation boot images, and is a NOP for other image types.
   81  */
   82 void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
   83 {
   84     if (bootimg->type != 0)
   85         return;
   86     if (segment < 0)
   87         bootimg->load_seg = 0x1000 + segment;
   88     else
   89         bootimg->load_seg = segment;
   90 }
   91 
   92 /* API */
   93 int el_torito_get_load_seg(ElToritoBootImage *bootimg)
   94 {
   95    return (int) bootimg->load_seg;
   96 }
   97  
   98 /**
   99  * Sets the number of sectors (512b) to be load at load segment during
  100  * the initial boot procedure. This is only for no emulation boot images,
  101  * and is a NOP for other image types.
  102  */
  103 void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
  104 {
  105     if (bootimg->type != 0)
  106         return;
  107     if (sectors < 0)
  108         bootimg->load_size = 0x10000 + sectors;
  109     else
  110         bootimg->load_size = sectors;
  111 }
  112 
  113 /* API */
  114 int el_torito_get_load_size(ElToritoBootImage *bootimg)
  115 {
  116     return (int) bootimg->load_size;
  117 }
  118 
  119 /* API */
  120 void el_torito_set_full_load(ElToritoBootImage *bootimg, int mode)
  121 {
  122     if (bootimg->type != 0)
  123         return;
  124     bootimg->load_size_full= !!mode;
  125 }
  126 
  127 /* API */
  128 int el_torito_get_full_load(ElToritoBootImage *bootimg)
  129 {
  130     return bootimg->load_size_full;
  131 }
  132 
  133 
  134 /**
  135  * Marks the specified boot image as not bootable
  136  */
  137 void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
  138 {
  139     bootimg->bootable = 0;
  140 }
  141 
  142 /* API */
  143 int el_torito_get_bootable(ElToritoBootImage *bootimg)
  144 {   
  145     return !!bootimg->bootable;
  146 }
  147 
  148 /* API */
  149 int el_torito_set_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
  150 {
  151     memcpy(bootimg->id_string, id_string, 28);
  152     return 1;
  153 }
  154 
  155 /* API */
  156 int el_torito_get_id_string(ElToritoBootImage *bootimg, uint8_t id_string[28])
  157 {
  158     
  159     memcpy(id_string, bootimg->id_string, 28);
  160     return 1;
  161 }
  162 
  163 /* API */
  164 int el_torito_set_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
  165 {
  166     memcpy(bootimg->selection_crit, crit, 20);
  167     return 1;
  168 }
  169 
  170 /* API */
  171 int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
  172 {
  173     
  174     memcpy(crit, bootimg->selection_crit, 20);
  175     return 1;
  176 }
  177 
  178 /* API */
  179 int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag)
  180 {
  181     switch (flag & 15) {
  182     case 0:
  183         return bootimg->seems_boot_info_table;
  184     case 1:
  185         return bootimg->seems_grub2_boot_info;
  186     }
  187     return 0;
  188 }
  189 
  190 /**
  191  * Specifies that this image needs to be patched. This involves the writing
  192  * of a 56 bytes boot information table at offset 8 of the boot image file.
  193  * The original boot image file won't be modified.
  194  * This is needed for isolinux boot images.
  195  */
  196 void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
  197 {
  198     bootimg->isolinux_options |= 0x01;
  199 }
  200 
  201 
  202 /**
  203  * Specifies options for IsoLinux boot images. This should only be used with
  204  * isolinux boot images.
  205  *
  206  * @param options
  207  *        bitmask style flag. The following values are defined:
  208  *
  209  *        bit 0 -> 1 to path the image, 0 to not
  210  *                 Patching the image involves the writing of a 56 bytes
  211  *                 boot information table at offset 8 of the boot image file.
  212  *                 The original boot image file won't be modified. This is needed
  213  *                 to allow isolinux images to be bootable.
  214  *        bit 1 -> 1 to generate an hybrid image, 0 to not
  215  *                 An hybrid image is a boot image that boots from either CD/DVD
  216  *                 media or from USB sticks. For that, you should use an isolinux
  217  *                 image that supports hybrid mode. Recent images support this.
  218  * @return
  219  *      1 if success, < 0 on error
  220  * @since 0.6.12
  221  */
  222 int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag)
  223 {
  224     bootimg->isolinux_options = (options & 0x03ff);
  225     bootimg->seems_boot_info_table = !!(options & 1);
  226     bootimg->seems_grub2_boot_info = !!(options & (1 << 9));
  227     return ISO_SUCCESS;
  228 }
  229 
  230 /* API */
  231 int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag)
  232 {
  233     return bootimg->isolinux_options & 0x03ff;
  234 }
  235 
  236 /* API */
  237 int el_torito_get_boot_media_type(ElToritoBootImage *bootimg,
  238                                   enum eltorito_boot_media_type *media_type)
  239 {
  240     if (bootimg) {
  241         switch (bootimg->type) {
  242         case 1:
  243         case 2:
  244         case 3:
  245             *media_type = ELTORITO_FLOPPY_EMUL;
  246             return 1;
  247         case 4:
  248             *media_type = ELTORITO_HARD_DISC_EMUL;
  249             return 1;
  250         case 0:
  251             *media_type = ELTORITO_NO_EMUL;
  252             return 1;
  253         default:
  254             /* should never happen */
  255             return ISO_ASSERT_FAILURE;
  256             break;
  257         }
  258     }
  259     return ISO_WRONG_ARG_VALUE;
  260 }
  261 
  262 static
  263 int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
  264 {
  265     IsoBoot *node;
  266     IsoNode **pos;
  267     time_t now;
  268     int ret;
  269 
  270     if (parent == NULL || name == NULL || boot == NULL) {
  271         return ISO_NULL_POINTER;
  272     }
  273     if (boot) {
  274         *boot = NULL;
  275     }
  276 
  277     /* check if the name is valid */
  278     ret = iso_node_is_valid_name(name);
  279     if (ret < 0)
  280         return ret;
  281 
  282     /* find place where to insert */
  283     pos = &(parent->children);
  284     while (*pos != NULL && strcmp((*pos)->name, name) < 0) {
  285         pos = &((*pos)->next);
  286     }
  287     if (*pos != NULL && !strcmp((*pos)->name, name)) {
  288         /* a node with same name already exists */
  289         return ISO_NODE_NAME_NOT_UNIQUE;
  290     }
  291 
  292     node = calloc(1, sizeof(IsoBoot));
  293     if (node == NULL) {
  294         return ISO_OUT_OF_MEM;
  295     }
  296 
  297     node->node.refcount = 1;
  298     node->node.type = LIBISO_BOOT;
  299     node->node.name = strdup(name);
  300     if (node->node.name == NULL) {
  301         free(node);
  302         return ISO_OUT_OF_MEM;
  303     }
  304     node->lba = 0;
  305     node->size = 0;
  306     node->content = NULL;
  307 
  308     /* attributes from parent */
  309     node->node.mode = S_IFREG | (parent->node.mode & 0444);
  310     node->node.uid = parent->node.uid;
  311     node->node.gid = parent->node.gid;
  312     node->node.hidden = parent->node.hidden;
  313 
  314     /* current time */
  315     iso_nowtime(&now, 0);
  316     node->node.atime = now;
  317     node->node.ctime = now;
  318     node->node.mtime = now;
  319 
  320     /* add to dir */
  321     node->node.parent = parent;
  322     node->node.next = *pos;
  323     *pos = (IsoNode*)node;
  324 
  325     if (boot) {
  326         *boot = node;
  327     }
  328     return ++parent->nchildren;
  329 }
  330 
  331 /* Get start and size from "%d_start_%lus_size_%lud" */
  332 static
  333 void iso_parse_start_size(char *text, unsigned long *part_start,
  334                           unsigned long *part_size)
  335 {
  336     char *cpt;
  337     unsigned long start, size;
  338 
  339     cpt = strchr(text, '_');
  340     if (cpt == NULL)
  341         return;
  342     if (strncmp(cpt, "_start_", 7) != 0)
  343         return;
  344     sscanf(cpt + 7, "%lu", &start);
  345     cpt = strchr(cpt + 7, '_');
  346     if (cpt == NULL)
  347         return;
  348     if (*(cpt - 1) != 's')
  349         return;
  350     if (strncmp(cpt, "_size_", 6) != 0)
  351         return;
  352     sscanf(cpt + 6, "%lu", &size);
  353     for (cpt = cpt + 6; *cpt >= '0' && *cpt <= '9'; cpt++);
  354     if (*cpt != 'd')
  355         return;
  356 
  357     *part_start = start;
  358     *part_size = size;
  359 }
  360 
  361 static
  362 int create_image(IsoImage *image, const char *image_path,
  363                  enum eltorito_boot_media_type type,
  364                  struct el_torito_boot_image **bootimg,
  365                  IsoFile **bootnode)
  366 {
  367     int ret;
  368     struct el_torito_boot_image *boot;
  369     int boot_media_type = 0;
  370     int load_sectors = 0; /* number of sector to load */
  371     int part_idx = -1;
  372     unsigned long part_start = 0, part_size = 0;
  373     unsigned char partition_type = 0;
  374     off_t size;
  375     IsoNode *imgfile = NULL;
  376     IsoStream *stream = NULL;
  377 
  378     *bootnode = NULL;
  379 
  380     if (strncmp(image_path, "--interval:appended_partition_", 30) == 0) {
  381         /* --interval:appended_partition_N... */ 
  382         if (type != ELTORITO_NO_EMUL) {
  383 
  384             /* >>> ??? lift this ban by making a temporary IsoStream from
  385                        partition source, determine size,
  386                        and read ELTORITO_HARD_DISC_EMUL MBR ?
  387              */
  388 
  389             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  390                            "Appended partition cannot serve as El Torito boot image with FD/HD emulation");
  391             return ISO_BOOT_IMAGE_NOT_VALID;
  392         }
  393         sscanf(image_path + 30, "%d", &part_idx);
  394         if (part_idx < 1 || part_idx > ISO_MAX_PARTITIONS) {
  395             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  396           "Appended partition index for El Torito boot image is out of range");
  397             return ISO_BOOT_IMAGE_NOT_VALID;
  398         }
  399         iso_parse_start_size((char *) (image_path + 30),
  400                               &part_start, &part_size);
  401         part_idx--;
  402         size = 1;
  403     } else {
  404         ret = iso_tree_path_to_node(image, image_path, &imgfile);
  405         if (ret < 0) {
  406             return ret;
  407         }
  408         if (ret == 0) {
  409             iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
  410                        "El Torito boot image file missing in ISO image: '%s'",
  411                        image_path);
  412             return ISO_NODE_DOESNT_EXIST;
  413         }
  414 
  415         if (imgfile->type != LIBISO_FILE) {
  416             return ISO_BOOT_IMAGE_NOT_VALID;
  417         }
  418         *bootnode = (IsoFile *) imgfile;
  419 
  420         stream = ((IsoFile*)imgfile)->stream;
  421 
  422         /* we need to read the image at least two times */
  423         if (!iso_stream_is_repeatable(stream)) {
  424             return ISO_BOOT_IMAGE_NOT_VALID;
  425         }
  426 
  427         size = iso_stream_get_size(stream);
  428     }
  429     if (size <= 0) {
  430         iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  431                        "Boot image file is empty");
  432         return ISO_BOOT_IMAGE_NOT_VALID;
  433     }
  434 
  435     switch (type) {
  436     case ELTORITO_FLOPPY_EMUL:
  437         switch (size) {
  438         case 1200 * 1024:
  439             boot_media_type = 1; /* 1.2 meg diskette */
  440             break;
  441         case 1440 * 1024:
  442             boot_media_type = 2; /* 1.44 meg diskette */
  443             break;
  444         case 2880 * 1024:
  445             boot_media_type = 3; /* 2.88 meg diskette */
  446             break;
  447         default:
  448             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  449                           "Invalid image size %d Kb. Must be one of 1.2, 1.44"
  450                           "or 2.88 Mb", iso_stream_get_size(stream) / 1024);
  451             return ISO_BOOT_IMAGE_NOT_VALID;
  452             break;
  453         }
  454         /* it seems that for floppy emulation we need to load
  455          * a single sector (512b) */
  456         load_sectors = 1;
  457         break;
  458     case ELTORITO_HARD_DISC_EMUL:
  459         {
  460         size_t i;
  461         struct hard_disc_mbr mbr;
  462         int used_partition;
  463 
  464         /* read the MBR on disc and get the type of the partition */
  465         ret = iso_stream_open(stream);
  466         if (ret < 0) {
  467             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, ret,
  468                           "Can't open image file.");
  469             return ret;
  470         }
  471         ret = iso_stream_read(stream, &mbr, sizeof(mbr));
  472         iso_stream_close(stream);
  473         if (ret != sizeof(mbr)) {
  474             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  475                           "Can't read MBR from image file.");
  476             return ret < 0 ? ret : (int) ISO_FILE_READ_ERROR;
  477         }
  478 
  479         /* check valid MBR signature */
  480         if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
  481             iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  482                           "Invalid MBR. Wrong signature.");
  483             return (int) ISO_BOOT_IMAGE_NOT_VALID;
  484         }
  485 
  486         /* ensure single partition */
  487         used_partition = -1;
  488         for (i = 0; i < 4; ++i) {
  489             if (mbr.partition[i].type != 0) {
  490                 /* it's an used partition */
  491                 if (used_partition != -1) {
  492                     iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  493                                   "Invalid MBR. At least 2 partitions: %d and "
  494                                   "%d, are being used\n", used_partition, i);
  495                     return ISO_BOOT_IMAGE_NOT_VALID;
  496                 } else
  497                     used_partition = i;
  498             }
  499         }
  500         partition_type = mbr.partition[used_partition].type;
  501         }
  502         boot_media_type = 4;
  503 
  504         /* only load the MBR */
  505         load_sectors = 1;
  506         break;
  507     case ELTORITO_NO_EMUL:
  508         boot_media_type = 0;
  509         break;
  510     }
  511 
  512     boot = calloc(1, sizeof(struct el_torito_boot_image));
  513     if (boot == NULL) {
  514         return ISO_OUT_OF_MEM;
  515     }
  516     boot->image = (IsoFile*)imgfile;
  517     boot->appended_idx = part_idx;
  518     boot->appended_start = part_start;
  519     boot->appended_size = part_size;
  520     if (imgfile != NULL)
  521         iso_node_ref(imgfile); /* get our ref */
  522     boot->bootable = 1;
  523     boot->seems_boot_info_table = 0;
  524     boot->seems_grub2_boot_info = 0;
  525     boot->seems_isohybrid_capable = 0;
  526     boot->isolinux_options = 0;
  527     boot->type = boot_media_type;
  528     boot->partition_type = partition_type;
  529     boot->load_seg = 0;
  530     boot->load_size = load_sectors;
  531     boot->load_size_full = 0;
  532     boot->platform_id = 0; /* 80x86 */
  533     memset(boot->id_string, 0, sizeof(boot->id_string));
  534     memset(boot->selection_crit, 0, sizeof(boot->selection_crit));
  535     *bootimg = boot;
  536 
  537     return ISO_SUCCESS;
  538 }
  539 
  540 int iso_image_set_boot_image(IsoImage *image, const char *image_path,
  541                              enum eltorito_boot_media_type type,
  542                              const char *catalog_path,
  543                              ElToritoBootImage **boot)
  544 {
  545     int ret, i;
  546     struct el_torito_boot_catalog *catalog;
  547     ElToritoBootImage *boot_image= NULL;
  548     IsoBoot *cat_node= NULL;
  549     IsoFile *boot_node;
  550 
  551     if (image == NULL || image_path == NULL || catalog_path == NULL) {
  552         return ISO_NULL_POINTER;
  553     }
  554     if (image->bootcat != NULL) {
  555         return ISO_IMAGE_ALREADY_BOOTABLE;
  556     }
  557 
  558     /* create the node for the catalog */
  559     {
  560         IsoDir *parent;
  561         char *catdir = NULL, *catname = NULL;
  562         catdir = strdup(catalog_path);
  563         if (catdir == NULL) {
  564             return ISO_OUT_OF_MEM;
  565         }
  566 
  567         /* get both the dir and the name */
  568         catname = strrchr(catdir, '/');
  569         if (catname == NULL)
  570             catname = catdir;
  571         if (catname == catdir) {
  572             /* we are appending catalog to root node */
  573             parent = image->root;
  574         } else {
  575             IsoNode *p;
  576             catname[0] = '\0';
  577             ret = iso_tree_path_to_node(image, catdir, &p);
  578             if (ret <= 0) {
  579                 iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
  580          "Cannot find directory for El Torito boot catalog in ISO image: '%s'",
  581                                catdir);
  582                 free(catdir);
  583                 return ret < 0 ? ret : (int) ISO_NODE_DOESNT_EXIST;
  584             }
  585             if (p->type != LIBISO_DIR) {
  586                 free(catdir);
  587                 return ISO_WRONG_ARG_VALUE;
  588             }
  589             parent = (IsoDir*)p;
  590         }
  591         if (catname[0] == '/' || catname[0] == 0)
  592             catname++;
  593         ret = iso_tree_add_boot_node(parent, catname, &cat_node);
  594         free(catdir);
  595         if (ret < 0) {
  596             return ret;
  597         }
  598     }
  599 
  600     /* create the boot image */
  601     ret = create_image(image, image_path, type, &boot_image, &boot_node);
  602     if (ret < 0) {
  603         goto boot_image_cleanup;
  604     }
  605 
  606     /* creates the catalog with the given image */
  607     catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
  608     if (catalog == NULL) {
  609         ret = ISO_OUT_OF_MEM;
  610         goto boot_image_cleanup;
  611     }
  612     catalog->num_bootimages = 1;
  613     catalog->bootimages[0] = boot_image;
  614     for (i = 1; i < Libisofs_max_boot_imageS; i++)
  615         catalog->bootimages[i] = NULL;
  616     catalog->node = cat_node;
  617     catalog->sort_weight = 1000000000;                          /* very high */
  618     if (boot_node != NULL)
  619         if (!(boot_node->explicit_weight || boot_node->from_old_session))
  620             boot_node->sort_weight = 2;
  621     iso_node_ref((IsoNode*)cat_node);
  622     image->bootcat = catalog;
  623 
  624     if (boot) {
  625         *boot = boot_image;
  626     }
  627 
  628     return ISO_SUCCESS;
  629 
  630 boot_image_cleanup:;
  631     if (cat_node) {
  632         iso_node_take((IsoNode*)cat_node);
  633         iso_node_unref((IsoNode*)cat_node);
  634     }
  635     if (boot_image) {
  636         if (boot_image->image != NULL)
  637             iso_node_unref((IsoNode*)boot_image->image);
  638         free(boot_image);
  639     }
  640     return ret;
  641 }
  642 
  643 /**
  644  * Get the boot catalog and the El-Torito default boot image of an ISO image.
  645  *
  646  * This can be useful, for example, to check if a volume read from a previous
  647  * session or an existing image is bootable. It can also be useful to get
  648  * the image and catalog tree nodes. An application would want those, for
  649  * example, to prevent the user removing it.
  650  *
  651  * Both nodes are owned by libisofs and should not be freed. You can get your
  652  * own ref with iso_node_ref(). You can can also check if the node is already
  653  * on the tree by getting its parent (note that when reading El-Torito info
  654  * from a previous image, the nodes might not be on the tree even if you haven't
  655  * removed them). Remember that you'll need to get a new ref
  656  * (with iso_node_ref()) before inserting them again to the tree, and probably
  657  * you will also need to set the name or permissions.
  658  *
  659  * @param image
  660  *      The image from which to get the boot image.
  661  * @param boot
  662  *      If not NULL, it will be filled with a pointer to the boot image, if
  663  *      any. That  object is owned by the IsoImage and should not be freed by
  664  *      the user, nor dereferenced once the last reference to the IsoImage was
  665  *      disposed via iso_image_unref().
  666  * @param imgnode
  667  *      When not NULL, it will be filled with the image tree node. No extra ref
  668  *      is added, you can use iso_node_ref() to get one if you need it.
  669  * @param catnode
  670  *      When not NULL, it will be filled with the catnode tree node. No extra
  671  *      ref is added, you can use iso_node_ref() to get one if you need it.
  672  * @return
  673  *      1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
  674  *      image), < 0 error.
  675  */
  676 int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
  677                              IsoFile **imgnode, IsoBoot **catnode)
  678 {
  679     if (image == NULL) {
  680         return ISO_NULL_POINTER;
  681     }
  682     if (image->bootcat == NULL) {
  683         return 0;
  684     }
  685 
  686     /* ok, image is bootable */
  687     if (boot) {
  688         *boot = image->bootcat->bootimages[0];
  689     }
  690     if (imgnode) {
  691         *imgnode = image->bootcat->bootimages[0]->image;
  692     }
  693     if (catnode) {
  694         *catnode = image->bootcat->node;
  695     }
  696     return ISO_SUCCESS;
  697 }
  698 
  699 int iso_image_get_bootcat(IsoImage *image, IsoBoot **catnode, uint32_t *lba,
  700                           char **content, off_t *size)
  701 {
  702     IsoBoot *bootcat;
  703 
  704     *catnode = NULL;
  705     *lba = 0;
  706     *content = NULL;
  707     *size = 0;
  708     bootcat = image->bootcat->node;
  709     if (bootcat == NULL)
  710         return 0;
  711     *catnode = bootcat;
  712     *lba = bootcat->lba;
  713     if (bootcat->size > 0 && bootcat->content != NULL) {
  714         *content = calloc(1, bootcat->size);
  715         if (*content == NULL) 
  716             return ISO_OUT_OF_MEM;
  717         memcpy(*content, bootcat->content, bootcat->size);
  718     }
  719     if (*content != NULL)
  720         *size = bootcat->size;
  721     return 1;
  722 }
  723 
  724 int iso_image_get_all_boot_imgs(IsoImage *image, int *num_boots,
  725                ElToritoBootImage ***boots, IsoFile ***bootnodes, int flag)
  726 {
  727     int i;
  728     struct el_torito_boot_catalog *cat;
  729 
  730     if (image == NULL)
  731         return ISO_NULL_POINTER;
  732     if (image->bootcat == NULL)
  733         return 0;
  734     cat = image->bootcat;
  735     *num_boots = cat->num_bootimages;
  736     *boots = NULL;
  737     *bootnodes = NULL;
  738     if (*num_boots <= 0)
  739         return 0;
  740     *boots = calloc(*num_boots, sizeof(ElToritoBootImage *));
  741     *bootnodes = calloc(*num_boots, sizeof(IsoFile *));
  742     if(*boots == NULL || *bootnodes == NULL) {
  743         if (*boots != NULL)
  744             free(*boots);
  745         if (*bootnodes != NULL)
  746             free(*bootnodes);
  747         *boots = NULL;
  748         *bootnodes = NULL;
  749         return ISO_OUT_OF_MEM;
  750     }
  751     for (i = 0; i < *num_boots; i++) {
  752         (*boots)[i] = cat->bootimages[i];
  753         (*bootnodes)[i] = image->bootcat->bootimages[i]->image;
  754     }
  755     return 1;
  756 }
  757 
  758 /**
  759  * Removes the El-Torito bootable image.
  760  *
  761  * The IsoBoot node that acts as placeholder for the catalog is also removed
  762  * for the image tree, if there.
  763  * If the image is not bootable (don't have el-torito boot image) this function
  764  * just returns.
  765  */
  766 void iso_image_remove_boot_image(IsoImage *image)
  767 {
  768     if (image == NULL || image->bootcat == NULL)
  769         return;
  770 
  771     /*
  772      * remove catalog node from its parent and dispose it
  773      * (another reference is with the catalog)
  774      */
  775     if (iso_node_get_parent((IsoNode*) image->bootcat->node) != NULL) {
  776         iso_node_take((IsoNode*) image->bootcat->node);
  777         iso_node_unref((IsoNode*) image->bootcat->node);
  778     }
  779 
  780     /* free boot catalog and image, including references to nodes */
  781     el_torito_boot_catalog_free(image->bootcat);
  782     image->bootcat = NULL;
  783 }
  784 
  785 /* API */
  786 int iso_image_add_boot_image(IsoImage *image, const char *image_path,
  787                              enum eltorito_boot_media_type type, int flag,
  788                              ElToritoBootImage **boot)
  789 {
  790     int ret;
  791     struct el_torito_boot_catalog *catalog = image->bootcat;
  792     ElToritoBootImage *boot_img;
  793     IsoFile *boot_node;
  794 
  795     if(catalog == NULL)
  796       return ISO_BOOT_NO_CATALOG;
  797     if (catalog->num_bootimages >= Libisofs_max_boot_imageS)
  798         return ISO_BOOT_IMAGE_OVERFLOW;
  799     ret = create_image(image, image_path, type, &boot_img, &boot_node);
  800     if (ret < 0) 
  801         return ret;
  802     if (boot_node != NULL)
  803         if (!(boot_node->explicit_weight || boot_node->from_old_session))
  804             boot_node->sort_weight = 2;
  805     catalog->bootimages[catalog->num_bootimages] = boot_img;
  806     catalog->num_bootimages++;
  807     if (boot != NULL)
  808         *boot = boot_img;
  809     return 1;
  810 }
  811 
  812 /* API */
  813 int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight)
  814 {
  815     if (image->bootcat == NULL)
  816         return 0;
  817     image->bootcat->sort_weight = sort_weight;
  818     return 1;
  819 }
  820 
  821 /* API */
  822 int iso_image_set_boot_catalog_hidden(IsoImage *image, int hide_attrs)
  823 {
  824     if (image->bootcat == NULL)
  825         return 0;
  826     if (image->bootcat->node == NULL)
  827         return 0;
  828     iso_node_set_hidden((IsoNode *) image->bootcat->node, hide_attrs);
  829     return 1;
  830 }
  831 
  832 
  833 void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
  834 {
  835     struct el_torito_boot_image *image;
  836     int i;
  837 
  838     if (cat == NULL) {
  839         return;
  840     }
  841 
  842     for (i = 0; i < Libisofs_max_boot_imageS; i++) {
  843         image = cat->bootimages[i];
  844         if (image == NULL)
  845     continue;
  846         if ((IsoNode*)image->image != NULL)
  847             iso_node_unref((IsoNode*)image->image);
  848         free(image);
  849     }
  850     if ((IsoNode*)cat->node != NULL)
  851         iso_node_unref((IsoNode*)cat->node);
  852     free(cat);
  853 }
  854 
  855 /**
  856  * Stream that generates the contents of a El-Torito catalog.
  857  */
  858 struct catalog_stream
  859 {
  860     Ecma119Image *target;
  861     uint8_t buffer[BLOCK_SIZE];
  862     int offset; /* -1 if stream is not opened */
  863 };
  864 
  865 static void
  866 write_validation_entry(uint8_t *buf, uint8_t platform_id,
  867                        uint8_t id_string[24])
  868 {
  869     size_t i;
  870     int checksum;
  871 
  872     struct el_torito_validation_entry *ve =
  873         (struct el_torito_validation_entry*)buf;
  874     ve->header_id[0] = 1;
  875     ve->platform_id[0] = platform_id;
  876     memcpy(ve->id_string, id_string, sizeof(ve->id_string));
  877     ve->key_byte1[0] = 0x55;
  878     ve->key_byte2[0] = 0xAA;
  879     /* calculate the checksum, to ensure sum of all words is 0 */
  880     checksum = 0;
  881     for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
  882         checksum -= (int16_t) ((buf[i+1] << 8) | buf[i]);
  883     }
  884     iso_lsb(ve->checksum, checksum, 2);
  885 }
  886 
  887 static void
  888 write_section_header(uint8_t *buf, Ecma119Image *t, int idx, int num_entries)
  889 {
  890     char *id_string;
  891 
  892     struct el_torito_section_header *e =
  893         (struct el_torito_section_header *) buf;
  894 
  895     /* 0x90 = more section headers follow , 0x91 = final section */
  896     e->header_indicator[0] =
  897                       0x90 + (idx == t->catalog->num_bootimages - num_entries);
  898     e->platform_id[0] = t->catalog->bootimages[idx]->platform_id;
  899     e->num_entries[0] = num_entries & 0xff;
  900     e->num_entries[1] = (num_entries >> 8) & 0xff;;
  901     id_string = (char *) e->id_string;
  902     memcpy(id_string,  t->catalog->bootimages[idx]->id_string,
  903            sizeof(e->id_string));
  904 }
  905 
  906 static int
  907 write_section_load_size(struct el_torito_boot_image *img,
  908                         struct el_torito_section_entry *se,
  909                         uint16_t load_size, off_t full_byte_size, int flag)
  910 {
  911     uint16_t size;
  912     off_t blocks;
  913 
  914     size= load_size;
  915     if(img->type == 0 && img->load_size_full) {
  916         blocks= ((full_byte_size + 2047) / 2048) * 4;
  917         if (blocks > 65535) {
  918             if (img->platform_id == 0xef)
  919                 size= 0;
  920             else
  921                 size= 65535;
  922         } else if(blocks <= 0) {
  923             size= 1;
  924         } else {
  925             size= blocks;
  926         }
  927     }
  928     iso_lsb(se->sec_count, size, 2);
  929     return(1);
  930 }
  931 
  932 /**
  933  * Write one section entry.
  934  * Usable for the Default Entry
  935  * and for Section Entries with Selection criteria type == 0
  936  */
  937 static
  938 int write_section_entry(uint8_t *buf, Ecma119Image *t, int idx)
  939 {
  940     struct el_torito_boot_image *img;
  941     struct el_torito_section_entry *se =
  942         (struct el_torito_section_entry*)buf;
  943     int app_idx, mode = 0;
  944 
  945     img = t->catalog->bootimages[idx];
  946 
  947     se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
  948     se->boot_media_type[0] = img->type;
  949     iso_lsb(se->load_seg, img->load_seg, 2);
  950     se->system_type[0] = img->partition_type;
  951 
  952     if (t->boot_appended_idx[idx] >= 0)
  953         if (t->appended_part_size[t->boot_appended_idx[idx]] > 0)
  954             mode = 2; /* appended partition */
  955     if (mode == 0 && t->opts->appendable &&
  956         (t->boot_intvl_start[idx] > 0 || t->boot_intvl_size[idx] > 0) &&
  957          t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 <=
  958          t->opts->ms_block)
  959         mode = 1; /* image interval */
  960     if (mode == 0 && t->boot_appended_idx[idx] >= 0) {
  961         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  962           "Appended partition which shall serve as boot image does not exist");
  963         return ISO_BOOT_IMAGE_NOT_VALID;
  964     }
  965 
  966     if (mode == 1) {
  967         if (t->boot_intvl_start[idx] + (t->boot_intvl_size[idx] + 3) / 4 >
  968             t->total_size / 2048 + t->opts->ms_block - t->eff_partition_offset
  969            ) {
  970             iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  971      "Block interval which shall serve as boot image is outside result range");
  972             return ISO_BOOT_IMAGE_NOT_VALID;
  973         }
  974 
  975         /* >>> check for non-automatic load size */;
  976 
  977         if (t->boot_intvl_size[idx] > 65535) {
  978             if (img->platform_id == 0xef)
  979                 iso_lsb(se->sec_count, 0, 2);
  980             else
  981                 iso_lsb(se->sec_count, 65535, 2);
  982         } else {
  983             if (t->boot_intvl_size[idx] == 0) {
  984                 iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  985                "Block interval which shall serve as boot image has zero size");
  986                 return ISO_BOOT_IMAGE_NOT_VALID;
  987             }
  988             iso_lsb(se->sec_count, t->boot_intvl_size[idx], 2);
  989         }
  990         iso_lsb(se->block, t->boot_intvl_start[idx], 4);
  991     } else if (mode == 2) {
  992         app_idx = t->boot_appended_idx[idx];
  993 
  994         /* >>> check for non-automatic load size */;
  995 
  996         if (t->appended_part_size[app_idx] * 4 > 65535) {
  997             if (img->platform_id == 0xef)
  998                 iso_lsb(se->sec_count, 0, 2);
  999             else
 1000                 iso_lsb(se->sec_count, 65535, 2);
 1001         } else {
 1002             iso_lsb(se->sec_count, t->appended_part_size[app_idx] * 4, 2);
 1003         }
 1004         iso_lsb(se->block, t->appended_part_start[app_idx], 4);
 1005     } else {
 1006         write_section_load_size(img, se, (uint16_t) img->load_size,
 1007                                 (off_t) t->bootsrc[idx]->sections[0].size, 0);
 1008         iso_lsb(se->block, t->bootsrc[idx]->sections[0].block, 4);
 1009     }
 1010 
 1011     se->selec_criteria[0] = img->selection_crit[0];
 1012     memcpy(se->vendor_sc, img->selection_crit + 1, 19);
 1013     return ISO_SUCCESS;
 1014 }
 1015 
 1016 static
 1017 int catalog_open(IsoStream *stream)
 1018 {
 1019     int i, j, k, num_entries, ret;
 1020     struct catalog_stream *data;
 1021     uint8_t *wpt;
 1022     struct el_torito_boot_catalog *cat;
 1023     struct el_torito_boot_image **boots;
 1024 
 1025     if (stream == NULL) {
 1026         return ISO_NULL_POINTER;
 1027     }
 1028     data = stream->data;
 1029     cat = data->target->catalog;
 1030     boots = cat->bootimages;
 1031 
 1032     if (data->offset != -1) {
 1033         return ISO_FILE_ALREADY_OPENED;
 1034     }
 1035 
 1036     memset(data->buffer, 0, BLOCK_SIZE);
 1037 
 1038     /* fill the buffer with the catalog contents */
 1039     write_validation_entry(data->buffer,
 1040                            boots[0]->platform_id, boots[0]->id_string);
 1041 
 1042     /* write default entry = first boot image */
 1043     ret = write_section_entry(data->buffer + 32, data->target, 0);
 1044     if (ret < 0)
 1045         return ret;
 1046 
 1047     /* IMPORTANT: The maximum number of boot images must fit into BLOCK_SIZE */
 1048     wpt = data->buffer + 64;
 1049     for (i = 1; i < cat->num_bootimages; ) {
 1050         /* Look ahead and put images of same platform_id and id_string
 1051            into the same section */
 1052         for (j = i + 1; j < cat->num_bootimages; j++) {
 1053              if (boots[i]->platform_id != boots[j]->platform_id)
 1054         break;
 1055              for (k = 0; k < (int) sizeof(boots[i]->id_string); k++)
 1056                  if (boots[i]->id_string[k] != boots[j]->id_string[k])
 1057              break;
 1058              if (k < (int) sizeof(boots[i]->id_string))
 1059         break;
 1060         }
 1061         num_entries = j - i;
 1062 
 1063         write_section_header(wpt, data->target, i, num_entries);
 1064         wpt += 32;
 1065         for (j = 0; j < num_entries; j++) {
 1066             ret = write_section_entry(wpt,  data->target, i);
 1067             if (ret < 0)
 1068                 return ret;
 1069             wpt += 32;
 1070             i++;
 1071         }
 1072     }
 1073     data->offset = 0;
 1074     return ISO_SUCCESS;
 1075 }
 1076 
 1077 static
 1078 int catalog_close(IsoStream *stream)
 1079 {
 1080     struct catalog_stream *data;
 1081     if (stream == NULL) {
 1082         return ISO_NULL_POINTER;
 1083     }
 1084     data = stream->data;
 1085 
 1086     if (data->offset == -1) {
 1087         return ISO_FILE_NOT_OPENED;
 1088     }
 1089     data->offset = -1;
 1090     return ISO_SUCCESS;
 1091 }
 1092 
 1093 static
 1094 off_t catalog_get_size(IsoStream *stream)
 1095 {
 1096     return BLOCK_SIZE;
 1097 }
 1098 
 1099 static
 1100 int catalog_read(IsoStream *stream, void *buf, size_t count)
 1101 {
 1102     size_t len;
 1103     struct catalog_stream *data;
 1104     if (stream == NULL || buf == NULL) {
 1105         return ISO_NULL_POINTER;
 1106     }
 1107     if (count == 0) {
 1108         return ISO_WRONG_ARG_VALUE;
 1109     }
 1110     data = stream->data;
 1111 
 1112     if (data->offset == -1) {
 1113         return ISO_FILE_NOT_OPENED;
 1114     }
 1115 
 1116     len = MIN(count, (size_t) (BLOCK_SIZE - data->offset));
 1117     memcpy(buf, data->buffer + data->offset, len);
 1118     return len;
 1119 }
 1120 
 1121 static
 1122 int catalog_is_repeatable(IsoStream *stream)
 1123 {
 1124     return 1;
 1125 }
 1126 
 1127 /**
 1128  * fs_id will be the id reserved for El-Torito
 1129  * dev_id will be 0 for catalog, 1 for boot image (if needed)
 1130  * ino_id 0 is supposed to be unique. At write time it will get assigned
 1131  * an automatic file serial number in the ISO, if needed.
 1132  */
 1133 static
 1134 void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
 1135                    ino_t *ino_id)
 1136 {
 1137     *fs_id = ISO_ELTORITO_FS_ID;
 1138     *dev_id = 0;
 1139     *ino_id = 0;
 1140 }
 1141 
 1142 static
 1143 void catalog_free(IsoStream *stream)
 1144 {
 1145     free(stream->data);
 1146 }
 1147 
 1148 IsoStreamIface catalog_stream_class = {
 1149     0,
 1150     "boot",
 1151     catalog_open,
 1152     catalog_close,
 1153     catalog_get_size,
 1154     catalog_read,
 1155     catalog_is_repeatable,
 1156     catalog_get_id,
 1157     catalog_free,
 1158     NULL,
 1159     NULL,
 1160     NULL,
 1161     NULL
 1162 };
 1163 
 1164 /**
 1165  * Create an IsoStream for writing El-Torito catalog for a given target.
 1166  */
 1167 static
 1168 int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
 1169 {
 1170     IsoStream *str;
 1171     struct catalog_stream *data;
 1172 
 1173     if (target == NULL || stream == NULL || target->catalog == NULL) {
 1174         return ISO_NULL_POINTER;
 1175     }
 1176 
 1177     str = calloc(1, sizeof(IsoStream));
 1178     if (str == NULL) {
 1179         return ISO_OUT_OF_MEM;
 1180     }
 1181     data = calloc(1, sizeof(struct catalog_stream));
 1182     if (data == NULL) {
 1183         free(str);
 1184         return ISO_OUT_OF_MEM;
 1185     }
 1186 
 1187     /* fill data */
 1188     data->target = target;
 1189     data->offset = -1;
 1190 
 1191     str->refcount = 1;
 1192     str->data = data;
 1193     str->class = &catalog_stream_class;
 1194 
 1195     *stream = str;
 1196     return ISO_SUCCESS;
 1197 }
 1198 
 1199 int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
 1200 {
 1201     int ret;
 1202     IsoFileSrc *file;
 1203     IsoStream *stream;
 1204 
 1205     if (target == NULL || src == NULL || target->catalog == NULL) {
 1206         return ISO_OUT_OF_MEM;
 1207     }
 1208 
 1209     if (target->cat != NULL) {
 1210         /* catalog file src already created */
 1211         *src = target->cat;
 1212         return ISO_SUCCESS;
 1213     }
 1214 
 1215     file = calloc(1, sizeof(IsoFileSrc));
 1216     if (file == NULL) {
 1217         return ISO_OUT_OF_MEM;
 1218     }
 1219 
 1220     ret = catalog_stream_new(target, &stream);
 1221     if (ret < 0) {
 1222         free(file);
 1223         return ret;
 1224     }
 1225 
 1226     /* fill fields */
 1227     file->no_write = 0; /* TODO allow copy of old img catalog???? */
 1228     file->checksum_index = 0;
 1229     file->nsections = 1;
 1230     file->sections = calloc(1, sizeof(struct iso_file_section));
 1231     file->sort_weight = target->catalog->sort_weight;
 1232     file->stream = stream;
 1233 
 1234     ret = iso_file_src_add(target, file, src);
 1235     if (ret <= 0) {
 1236         iso_stream_unref(stream);
 1237         free(file);
 1238     } else {
 1239         target->cat = *src;
 1240     }
 1241     return ret;
 1242 }
 1243 
 1244 /******************* EL-TORITO WRITER *******************************/
 1245 
 1246 /**
 1247  * Insert boot info table content into buf.
 1248  *
 1249  * @return
 1250  *      1 on success, 0 error (but continue), < 0 error
 1251  */
 1252 int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
 1253                          uint32_t boot_lba, uint32_t imgsize)
 1254 {
 1255     struct boot_info_table *info;
 1256     uint32_t checksum;
 1257     uint32_t offset;
 1258 
 1259     info = (struct boot_info_table *) (buf + 8);
 1260     if (imgsize < 64)
 1261         return ISO_ISOLINUX_CANT_PATCH;
 1262 
 1263     /* compute checksum, as the the sum of all 32 bit words in boot image
 1264      * from offset 64 */
 1265     checksum = 0;
 1266     offset = 64;
 1267 
 1268     while (offset <= imgsize - 4) {
 1269         checksum += iso_read_lsb(buf + offset, 4);
 1270         offset += 4;
 1271     }
 1272     if (offset != imgsize) {
 1273         /*
 1274          * file length not multiple of 4
 1275          * empty space in isofs is padded with zero;
 1276          * assume same for last dword
 1277          */
 1278         checksum += iso_read_lsb(buf + offset, imgsize - offset);
 1279     }
 1280 
 1281     /*memset(info, 0, sizeof(struct boot_info_table));*/
 1282     iso_lsb(info->bi_pvd, pvd_lba, 4);
 1283     iso_lsb(info->bi_file, boot_lba, 4);
 1284     iso_lsb(info->bi_length, imgsize, 4);
 1285     iso_lsb(info->bi_csum, checksum, 4);
 1286     memset(buf + 24, 0, 40);
 1287     return ISO_SUCCESS;
 1288 }
 1289 
 1290 /**
 1291  * Patch an El Torito boot image by a boot info table.
 1292  *
 1293  * @return
 1294  *      1 on success, 0 error (but continue), < 0 error
 1295  */
 1296 static
 1297 int patch_boot_info_table(uint8_t *buf, Ecma119Image *t,
 1298                                size_t imgsize, int idx)
 1299 {
 1300     int ret;
 1301 
 1302     if (imgsize < 64) {
 1303         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
 1304             "Isolinux image too small. We won't patch it.");
 1305     }
 1306     if (t->bootsrc[idx] == NULL)
 1307         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
 1308             "Cannot apply ISOLINUX patching outside of ISO 9660 filesystem.");
 1309     ret = make_boot_info_table(buf, t->opts->ms_block + (uint32_t) 16,
 1310                                t->bootsrc[idx]->sections[0].block,
 1311                                (uint32_t) imgsize);
 1312     return ret;
 1313 }
 1314 
 1315 
 1316 /**
 1317  * Patch a GRUB2 El Torito boot image.
 1318  */
 1319 static
 1320 int patch_grub2_boot_image(uint8_t *buf, Ecma119Image *t,
 1321                            size_t imgsize, int idx,
 1322                            size_t pos, int offst)
 1323 {
 1324     uint64_t blk;
 1325 
 1326     if (imgsize < pos + 8)
 1327         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
 1328                      "Boot image too small for GRUB2. Will not patch it.");
 1329     if (t->bootsrc[idx] == NULL)
 1330         return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
 1331             "Cannot apply GRUB2 patching outside of ISO 9660 filesystem.");
 1332     blk = ((uint64_t) t->bootsrc[idx]->sections[0].block) * 4 + offst;
 1333     iso_lsb((buf + pos), blk & 0xffffffff, 4);
 1334     iso_lsb((buf + pos + 4), blk >> 32, 4);
 1335     return ISO_SUCCESS;
 1336 }
 1337 
 1338 
 1339 /* Patch the boot images if indicated */
 1340 int iso_patch_eltoritos(Ecma119Image *t)
 1341 {
 1342     int ret, idx;
 1343     size_t size;
 1344     uint8_t *buf;
 1345     IsoStream *new = NULL;
 1346     IsoStream *original = NULL;
 1347 
 1348     if (t->catalog == NULL)
 1349         return ISO_SUCCESS;
 1350 
 1351     for (idx = 0; idx < t->catalog->num_bootimages; idx++) {
 1352         if (!(t->catalog->bootimages[idx]->isolinux_options & 0x201))
 1353     continue;
 1354         if (t->bootsrc[idx] == NULL)
 1355             return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
 1356             "Cannot apply boot image patching outside of ISO 9660 filesystem");
 1357 
 1358         original = t->bootsrc[idx]->stream;
 1359         size = (size_t) iso_stream_get_size(original);
 1360         if (size > Libisofs_elto_max_patchablE)
 1361             return ISO_PATCH_OVERSIZED_BOOT;
 1362         if (iso_stream_get_input_stream(original, 0) != NULL)
 1363             return ISO_PATCH_FILTERED_BOOT;
 1364         buf = calloc(1, size);
 1365         if (buf == NULL) {
 1366             return ISO_OUT_OF_MEM;
 1367         }
 1368         ret = iso_stream_open(original);
 1369         if (ret < 0) {
 1370             free(buf);
 1371             return ret;
 1372         }
 1373         ret = iso_stream_read(original, buf, size);
 1374         iso_stream_close(original);
 1375         if (ret != (int) size) {
 1376             if (ret >= 0)
 1377                iso_msg_submit(t->image->id, ISO_FILE_READ_ERROR, 0,
 1378         "Cannot read all bytes from El Torito boot image for boot info table");
 1379             return (ret < 0) ? ret : (int) ISO_FILE_READ_ERROR;
 1380         }
 1381 
 1382         /* ok, patch the read buffer */
 1383         if (t->catalog->bootimages[idx]->isolinux_options & 0x200) {
 1384             /* GRUB2 boot provisions */
 1385             ret = patch_grub2_boot_image(buf, t, size, idx,
 1386                                          Libisofs_grub2_elto_patch_poS,
 1387                                          Libisofs_grub2_elto_patch_offsT);
 1388             if (ret < 0)
 1389                 return ret;
 1390     }
 1391         /* Must be done as last patching */
 1392         if (t->catalog->bootimages[idx]->isolinux_options & 0x01) {
 1393             /* Boot Info Table */
 1394             ret = patch_boot_info_table(buf, t, size, idx);
 1395             if (ret < 0)
 1396                 return ret;
 1397         }
 1398 
 1399         /* replace the original stream with a memory stream that reads from
 1400          * the patched buffer */
 1401         ret = iso_memory_stream_new(buf, size, &new);
 1402         if (ret < 0) {
 1403             return ret;
 1404         }
 1405         t->bootsrc[idx]->stream = new;
 1406         iso_stream_unref(original);
 1407     }
 1408     return ISO_SUCCESS;
 1409 }
 1410 
 1411 static
 1412 int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
 1413 {
 1414     /*
 1415      * We have nothing to write.
 1416      */
 1417     return ISO_SUCCESS;
 1418 }
 1419 
 1420 
 1421 /**
 1422  * Write the Boot Record Volume Descriptor (ECMA-119, 8.2)
 1423  */
 1424 static
 1425 int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
 1426 {
 1427     Ecma119Image *t;
 1428     struct ecma119_boot_rec_vol_desc vol;
 1429 
 1430     if (writer == NULL) {
 1431         return ISO_NULL_POINTER;
 1432     }
 1433 
 1434     t = writer->target;
 1435     iso_msg_debug(t->image->id, "Write El-Torito boot record");
 1436 
 1437     memset(&vol, 0, sizeof(struct ecma119_boot_rec_vol_desc));
 1438     vol.vol_desc_type[0] = 0;
 1439     memcpy(vol.std_identifier, "CD001", 5);
 1440     vol.vol_desc_version[0] = 1;
 1441     memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23);
 1442     iso_lsb(vol.boot_catalog,
 1443             t->cat->sections[0].block - t->eff_partition_offset, 4);
 1444     return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
 1445 }
 1446 
 1447 static
 1448 int eltorito_writer_write_data(IsoImageWriter *writer)
 1449 {
 1450     /* nothing to do, the files are written by the file writer */
 1451     return ISO_SUCCESS;
 1452 }
 1453 
 1454 static
 1455 int eltorito_writer_free_data(IsoImageWriter *writer)
 1456 {
 1457     /* nothing to do */
 1458     return ISO_SUCCESS;
 1459 }
 1460 
 1461 int eltorito_writer_create(Ecma119Image *target)
 1462 {
 1463     int ret, idx, outsource_efi = 0;
 1464     IsoImageWriter *writer;
 1465     IsoFile *bootimg = NULL;
 1466     IsoFileSrc *src = NULL;
 1467 
 1468     writer = calloc(1, sizeof(IsoImageWriter));
 1469     if (writer == NULL) {
 1470         return ISO_OUT_OF_MEM;
 1471     }
 1472 
 1473     writer->compute_data_blocks = eltorito_writer_compute_data_blocks;
 1474     writer->write_vol_desc = eltorito_writer_write_vol_desc;
 1475     writer->write_data = eltorito_writer_write_data;
 1476     writer->free_data = eltorito_writer_free_data;
 1477     writer->data = NULL;
 1478     writer->target = target;
 1479 
 1480     /* add this writer to image */
 1481     target->writers[target->nwriters++] = writer;
 1482 
 1483     /*
 1484      * get catalog and image file sources.
 1485      * Note that the catalog may be already added, when creating the low
 1486      * level ECMA-119 tree.
 1487      */
 1488     if (target->cat == NULL) {
 1489         ret = el_torito_catalog_file_src_create(target, &src);
 1490         if (ret < 0) {
 1491             return ret;
 1492         }
 1493     }
 1494 
 1495     if (target->opts->efi_boot_partition != NULL)
 1496         if (strcmp(target->opts->efi_boot_partition, "--efi-boot-image") == 0)
 1497             outsource_efi = 1;
 1498     for (idx = 0; idx < target->catalog->num_bootimages; idx++) {
 1499         target->bootsrc[idx] = NULL;
 1500         if (target->catalog->bootimages[idx]->appended_idx >= 0) {
 1501             /* Use an appended partition as boot image rather than IsoFile */
 1502             target->boot_appended_idx[idx] =
 1503                                 target->catalog->bootimages[idx]->appended_idx;
 1504             target->boot_intvl_start[idx] =
 1505                               target->catalog->bootimages[idx]->appended_start;
 1506             target->boot_intvl_size[idx] =
 1507                                target->catalog->bootimages[idx]->appended_size;
 1508     continue;
 1509         }
 1510 
 1511         bootimg = target->catalog->bootimages[idx]->image;
 1512         ret = iso_file_src_create(target, bootimg, &src);
 1513         if (ret < 0) {
 1514             return ret;
 1515         }
 1516         target->bootsrc[idx] = src;
 1517 
 1518         /* For patching an image, it needs to be copied always */
 1519         if (target->catalog->bootimages[idx]->isolinux_options & 0x01) {
 1520             src->no_write = 0;
 1521         }
 1522 
 1523         /* If desired: Recognize first EFI boot image that will be newly
 1524            written, and mark it as claimed for being a partition.
 1525         */
 1526         if (outsource_efi &&
 1527             target->catalog->bootimages[idx]->platform_id == 0xef &&
 1528             src->no_write == 0) {
 1529            target->efi_boot_part_filesrc = src;
 1530            src->sections[0].block = 0xfffffffe;
 1531            ((IsoNode *) bootimg)->hidden |=
 1532                                    LIBISO_HIDE_ON_HFSPLUS | LIBISO_HIDE_ON_FAT;
 1533            outsource_efi = 0;
 1534         }
 1535     }
 1536 
 1537     /* we need the bootable volume descriptor */
 1538     target->curblock++;
 1539 
 1540     if (outsource_efi) {
 1541         /* Disable EFI Boot partition and complain */
 1542         free(target->opts->efi_boot_partition);
 1543         target->opts->efi_boot_partition = NULL;
 1544         iso_msg_submit(target->image->id, ISO_BOOT_NO_EFI_ELTO, 0,
 1545 "No newly added El Torito EFI boot image found for exposure as GPT partition");
 1546         return ISO_BOOT_NO_EFI_ELTO;
 1547     }
 1548 
 1549     return ISO_SUCCESS;
 1550 }
 1551