"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/system_area.c" (26 Nov 2020, 111514 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 "system_area.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) 2008 Vreixo Formoso
    3  * Copyright (c) 2010 - 2019 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 "system_area.h"
   17 #include "eltorito.h"
   18 #include "filesrc.h"
   19 #include "ecma119_tree.h"
   20 #include "image.h"
   21 #include "messages.h"
   22 #include "ecma119.h"
   23 #include "writer.h"
   24 
   25 #include <string.h>
   26 #include <stdio.h>
   27 #include <sys/types.h>
   28 #include <sys/stat.h>
   29 #include <unistd.h>
   30 #include <fcntl.h>
   31 
   32 /* for gettimeofday() */
   33 #include <sys/time.h>
   34 
   35 /* >>> Need ./configure test for uuid_generate() which checks for:
   36        uuid_t, uuid_generate, the need for -luuid
   37 */
   38 /*
   39 #define Libisofs_with_uuid_generatE 1
   40 */
   41 #ifdef Libisofs_with_uuid_generatE
   42 #include <uuid/uuid.h>
   43 #endif
   44 
   45 /* O_BINARY is needed for Cygwin but undefined elsewhere */
   46 #ifndef O_BINARY
   47 #define O_BINARY 0
   48 #endif
   49 
   50 
   51 /*
   52  * Create a MBR for an isohybrid enabled ISOLINUX boot image.
   53  * See libisofs/make_isohybrid_mbr.c
   54  * Deprecated.
   55  */
   56 int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
   57 
   58 /*
   59  * The New ISOLINUX MBR Producer.
   60  * Be cautious with changing parameters. Only few combinations are tested.
   61  *
   62  */
   63 int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
   64                       int part_offset, int part_number, int fs_type,
   65                       uint8_t *buf, int flag);
   66 
   67 /* Find out whether GPT and APM are desired by isohybrid
   68    flag bit0 = register APM and GPT requests in Ecma119Image
   69 */
   70 int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
   71                              int *apm_count, int flag);
   72 
   73 
   74 static int precompute_gpt(Ecma119Image *t);
   75 
   76 
   77 /*
   78  * @param flag bit0= img_blocks is start address rather than end address:
   79                      do not subtract 1
   80                bit1= img_blocks is counted in 512-byte units rather than 2 KiB
   81  */
   82 static
   83 void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph,
   84                               uint32_t *end_lba, uint32_t *end_sec,
   85                               uint32_t *end_head, uint32_t *end_cyl, int flag)
   86 {
   87     uint64_t secs;
   88 
   89     if(flag & 2)
   90         secs = img_blocks;
   91     else
   92         secs = img_blocks * 4;
   93     if (secs > (uint64_t) 0xfffffffc)
   94       secs = 0xfffffffc;                   /* truncate rather than roll over */
   95     if (flag & 1)
   96         *end_lba = secs;                              /* first valid 512-lba */
   97     else
   98         secs = *end_lba = secs - 1;                    /* last valid 512-lba */
   99     *end_cyl = secs / (sph * hpc);
  100     secs -= *end_cyl * sph * hpc;
  101     *end_head = secs / sph;
  102     *end_sec = secs - *end_head * sph + 1;   /* Sector count starts by 1 */
  103     if (*end_cyl >= 1024) {
  104         *end_cyl = 1023;
  105         *end_head = hpc - 1;
  106         *end_sec = sph;
  107     }
  108 }
  109 
  110 /* @param flag bit0= The path contains instructions for the interval reader
  111    @return ISO_SUCCESS     = ok, partition will be written
  112            ISO_SUCCESS + 1 = interval which shall be kept in place
  113            else : error code
  114 */
  115 static int compute_partition_size(Ecma119Image *t, char *disk_path,
  116                                   uint32_t *size, int flag)
  117 {
  118     int ret, keep;
  119     off_t num;
  120     struct stat stbuf;
  121     struct iso_interval_reader *ivr;
  122     off_t byte_count;
  123 
  124     if (flag & 1) {
  125         ret = iso_interval_reader_new(t->image, disk_path,
  126                                       &ivr, &byte_count, 0);
  127         if (ret < 0)
  128             return ret;
  129         *size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE;
  130         keep = iso_interval_reader_keep(t, ivr, 0);
  131         iso_interval_reader_destroy(&ivr, 0);
  132         if (keep < 0)
  133             return keep;
  134         return ISO_SUCCESS + (keep > 0);
  135     }
  136 
  137     *size = 0;
  138     ret = stat(disk_path, &stbuf);
  139     if (ret == -1)
  140         return ISO_BAD_PARTITION_FILE;
  141     if (! S_ISREG(stbuf.st_mode))
  142         return ISO_BAD_PARTITION_FILE;
  143     num = ((stbuf.st_size + 2047) / 2048);
  144     if (num > 0x3fffffff || num == 0)
  145         return ISO_BAD_PARTITION_FILE;
  146     *size = num;
  147     return ISO_SUCCESS;
  148 }
  149 
  150 /* Compute size and position of appended partitions.
  151    @param flag bit0= Partitions inside ISO : update t->curblock
  152 */
  153 int iso_compute_append_partitions(Ecma119Image *t, int flag)
  154 {
  155     int ret, i, sa_type, cyl_align, cyl_size = 0;
  156     int first_partition, last_partition;
  157     uint32_t pos, size, add_pos = 0;
  158     off_t start_byte, byte_count;
  159     char msg[128];
  160 
  161     sa_type = (t->system_area_options >> 2) & 0x3f;
  162     cyl_align = (t->system_area_options >> 8) & 0x3;
  163     if (sa_type == 0 && cyl_align == 3) {
  164         cyl_size = t->partition_heads_per_cyl * t->partition_secs_per_head;
  165         if (cyl_size % 4)
  166             cyl_size = 0;
  167         else
  168             cyl_size /= 4;
  169     }
  170 
  171 #ifdef Libisofs_appended_partitions_inlinE
  172 
  173     pos = t->curblock;
  174 
  175 #else
  176 
  177     pos = (t->vol_space_size + t->opts->ms_block);
  178 
  179 #endif
  180 
  181     iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
  182     for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
  183         if (t->opts->appended_partitions[i] == NULL)
  184     continue;
  185         if (t->opts->appended_partitions[i][0] == 0)
  186     continue;
  187         if (i + 1 > last_partition || i + 1 < first_partition) {
  188             sprintf(msg,
  189          "Partition number %d of appended partition is out of range [%d - %d]",
  190                     i + 1, first_partition, last_partition);
  191             iso_msgs_submit(0, msg, 0, "FAILURE", 0);
  192             return ISO_BAD_PARTITION_NO;
  193         }
  194 
  195         ret = compute_partition_size(t, t->opts->appended_partitions[i], &size,
  196                                      t->opts->appended_part_flags[i]);
  197         if (ret < 0)
  198             return ret;
  199         if (ret == ISO_SUCCESS + 1) {
  200             /* Interval from imported_iso in add-on session */
  201             t->appended_part_prepad[i] = 0;
  202             ret = iso_interval_reader_start_size(t,
  203                                                t->opts->appended_partitions[i],
  204                                                &start_byte, &byte_count, 0);
  205             if (ret < 0)
  206                 return ret;
  207             t->appended_part_start[i] = start_byte / 2048;
  208             t->appended_part_size[i] = size;
  209             t->opts->iso_mbr_part_type = 0;
  210     continue;
  211         }
  212 
  213         add_pos = 0;
  214         if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) {
  215             add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE);
  216         } else if (cyl_size > 0 && (pos % cyl_size)) {
  217             add_pos = cyl_size - (pos % cyl_size);
  218         }
  219         t->appended_part_prepad[i] = add_pos;
  220         t->appended_part_start[i] = pos + add_pos;
  221 
  222         if (cyl_size > 0 && (size % cyl_size)) {
  223             /* Obey cylinder alignment (missing data will be written as
  224                zeros by iso_write_partition_file()) */
  225             size += cyl_size - (size % cyl_size);
  226         }
  227         t->appended_part_size[i] = size;
  228         pos += add_pos + size;
  229         t->total_size += (((off_t) add_pos) + size) * 2048;
  230         if (flag & 1)
  231             t->curblock = pos;
  232     }
  233     return ISO_SUCCESS;
  234 }
  235 
  236 
  237 static int mbr_part_slot_is_unused(uint8_t *slot)
  238 {
  239     int i;
  240 
  241     for (i = 0; i < 16; i++)
  242         if (slot[i] != 0)
  243     break;
  244     if (i >= 16)
  245         return 1;
  246     return 0;
  247 }
  248 
  249 
  250 /* @param flag
  251                 bit1= partition_offset and partition_size are counted in
  252                       blocks of 512 rather than 2048
  253  */
  254 static int write_mbr_partition_entry(int partition_number, int partition_type,
  255                   uint64_t partition_offset, uint64_t partition_size,
  256                   int sph, int hpc, uint8_t *buf, int flag)
  257 {
  258     uint8_t *wpt;
  259     uint32_t end_lba, end_sec, end_head, end_cyl;
  260     uint32_t start_lba, start_sec, start_head, start_cyl;
  261     uint32_t after_end;
  262     int i;
  263 
  264     after_end = partition_offset + partition_size;
  265     iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
  266                              &start_lba, &start_sec, &start_head, &start_cyl,
  267                              1 | (flag & 2));
  268     iso_compute_cyl_head_sec((uint64_t) after_end, hpc, sph,
  269                              &end_lba, &end_sec, &end_head, &end_cyl,
  270                              (flag & 2));
  271     wpt = buf + 446 + (partition_number - 1) * 16;
  272 
  273     /* Not bootable */
  274     *(wpt++) = 0x00;
  275 
  276     /* C/H/S of the start */
  277     *(wpt++) = start_head;
  278     *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
  279     *(wpt++) = start_cyl & 0xff;
  280 
  281     /* (partition type) */
  282     *(wpt++) = partition_type;
  283 
  284     /* 3 bytes of C/H/S end */
  285     *(wpt++) = end_head;
  286     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  287     *(wpt++) = end_cyl & 0xff;
  288     
  289     /* LBA start in little endian */
  290     for (i = 0; i < 4; i++)
  291        *(wpt++) = (start_lba >> (8 * i)) & 0xff;
  292 
  293     /* Number of sectors in partition, little endian */
  294     end_lba = end_lba - start_lba + 1;
  295     for (i = 0; i < 4; i++)
  296        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  297 
  298     /* Afaik, partition tables are recognize donly with MBR signature */
  299     buf[510] = 0x55;
  300     buf[511] = 0xAA;
  301 
  302     return ISO_SUCCESS;
  303 }
  304 
  305 
  306 /* This is the gesture of grub-mkisofs --protective-msdos-label as explained by
  307    Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org
  308    "Currently we use first and not last entry. You need to:
  309     1) Zero-fill 446-510
  310     2) Put 0x55, 0xAA into 510-512
  311     3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
  312       (partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
  313       start in little endian), [LBA end in little endian] at 446-462
  314    "
  315 
  316    "C/H/S end" means the CHS address of the last block in the partition.
  317    It seems that not "[LBA end in little endian]" but "number of blocks"
  318    should go into bytes 458-461. But with a start lba of 1, this is the
  319    same number.
  320    See also http://en.wikipedia.org/wiki/Master_boot_record
  321 
  322    flag   bit0= do not write 0x55, 0xAA to 510,511
  323           bit1= do not mark partition as bootable
  324 */
  325 static
  326 int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
  327                           uint8_t part_type, uint8_t *buf, int flag)
  328 {
  329     uint8_t *wpt;
  330     uint32_t end_lba, end_sec, end_head, end_cyl;
  331     int i;
  332 
  333     iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph,
  334                              &end_lba, &end_sec, &end_head, &end_cyl, 0);
  335 
  336     /* 1) Zero-fill 446-510 */
  337     wpt = buf + 446;
  338     memset(wpt, 0, 64);
  339 
  340     if (!(flag & 1)) {
  341         /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
  342         buf[510] = 0x55;
  343         buf[511] = 0xAA;
  344     }
  345     if ((!(flag & 2)) && part_type != 0xee && part_type != 0xef) {
  346       /* 3) Put 0x80 (for bootable partition), */
  347       *(wpt++) = 0x80;
  348     } else {
  349       *(wpt++) = 0;
  350     }
  351 
  352     /* 0, 2, 0 (C/H/S of the start), */
  353     *(wpt++) = 0;
  354     *(wpt++) = 2;
  355     *(wpt++) = 0;
  356 
  357     /* 0xcd (partition type) */
  358     *(wpt++) = part_type;
  359 
  360     /* [3 bytes of C/H/S end], */
  361     *(wpt++) = end_head;
  362     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  363     *(wpt++) = end_cyl & 0xff;
  364     
  365 
  366     /* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */
  367     *(wpt++) = 0x01;
  368     *(wpt++) = 0x00;
  369     *(wpt++) = 0x00;
  370     *(wpt++) = 0x00;
  371 
  372     /* [LBA end in little endian] */
  373     for (i = 0; i < 4; i++)
  374        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  375 
  376     /* at 446-462 */
  377     if (wpt - buf != 462) {
  378         fprintf(stderr,
  379         "libisofs: program error in make_grub_msdos_label: \"assert 462\"\n");
  380         return ISO_ASSERT_FAILURE;
  381     }
  382     return ISO_SUCCESS;
  383 }
  384 
  385 
  386 /* @param flag bit0= zeroize partitions entries 2, 3, 4
  387                bit1= UEFI protective MBR: start LBA = 1
  388 */
  389 static
  390 int iso_offset_partition_start(uint32_t img_blocks, int post_part_pad,
  391                                uint32_t partition_offset,
  392                                int sph, int hpc, uint8_t *buf, int flag)
  393 {
  394     uint8_t *wpt;
  395     uint32_t end_lba, end_sec, end_head, end_cyl;
  396     uint32_t start_lba, start_sec, start_head, start_cyl;
  397     uint64_t img_hd_blocks;
  398     int i;
  399 
  400     iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph,
  401                            &start_lba, &start_sec, &start_head, &start_cyl, 1);
  402     img_hd_blocks = ((uint64_t) img_blocks) * 4 - post_part_pad / 512;
  403     iso_compute_cyl_head_sec(img_hd_blocks, hpc, sph,
  404                              &end_lba, &end_sec, &end_head, &end_cyl, 2);
  405     if (flag & 2) {
  406         start_lba = 1;
  407         start_sec = 2;
  408         start_head = start_cyl = 0;
  409     }
  410     wpt = buf + 446;
  411 
  412     /* Let pass only legal bootability values */
  413     if (*wpt != 0 && *wpt != 0x80)
  414         (*wpt) = 0;
  415     wpt++;
  416 
  417     /* C/H/S of the start */
  418     *(wpt++) = start_head;
  419     *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
  420     *(wpt++) = start_cyl & 0xff;
  421 
  422     /* (partition type) */
  423     wpt++;
  424 
  425     /* 3 bytes of C/H/S end */
  426     *(wpt++) = end_head;
  427     *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
  428     *(wpt++) = end_cyl & 0xff;
  429     
  430     /* LBA start in little endian */
  431     for (i = 0; i < 4; i++)
  432        *(wpt++) = (start_lba >> (8 * i)) & 0xff;
  433 
  434     /* Number of sectors in partition, little endian */
  435     end_lba = end_lba - start_lba + 1;
  436     for (i = 0; i < 4; i++)
  437        *(wpt++) = (end_lba >> (8 * i)) & 0xff;
  438 
  439     if (wpt - buf != 462) {
  440         fprintf(stderr,
  441     "libisofs: program error in iso_offset_partition_start: \"assert 462\"\n");
  442         return ISO_ASSERT_FAILURE;
  443     }
  444 
  445     if (flag & 1) /* zeroize the other partition entries */
  446         memset(wpt, 0, 3 * 16);
  447 
  448     return ISO_SUCCESS;
  449 }
  450 
  451 
  452 static int boot_nodes_from_iso_path(Ecma119Image *t, char *path, 
  453                                    IsoNode **iso_node, Ecma119Node **ecma_node,
  454                                    char *purpose, int flag)
  455 {
  456     int ret;
  457 
  458     ret = iso_tree_path_to_node(t->image, path, iso_node);
  459     if (ret <= 0) {
  460         iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
  461                        "Cannot find in ISO image: %s '%s'", purpose, path);
  462         return ISO_BOOT_FILE_MISSING;
  463     }
  464     if ((*iso_node)->type != LIBISO_FILE) {
  465         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  466                        "Designated boot file is not a data file: '%s'", path);
  467         return ISO_BOOT_IMAGE_NOT_VALID;
  468     }
  469 
  470     *ecma_node= ecma119_search_iso_node(t, *iso_node);
  471     if (*ecma_node == NULL) {
  472         iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  473                       "Program error: IsoFile has no Ecma119Node: '%s'", path);
  474         return ISO_ASSERT_FAILURE;
  475     } else {
  476         if ((*ecma_node)->type != ECMA119_FILE) {
  477             iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  478               "Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'",
  479                           path);
  480             return ISO_ASSERT_FAILURE;
  481         }
  482     }
  483     return ISO_SUCCESS;
  484 }
  485 
  486 
  487 /* This function was implemented according to doc/boot_sectors.txt section
  488    "MIPS Volume Header" which was derived by Thomas Schmitt from
  489    cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based
  490    on work of Florian Lohoff and Thiemo Seufer who possibly learned from
  491    documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer
  492    Systems, Inc.
  493    This function itself is entirely under copyright (C) 2010 Thomas Schmitt.
  494 */
  495 static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
  496 {
  497     char *namept, *name_field;
  498     uint32_t num_cyl, idx, blocks, num, checksum;
  499     off_t image_size;
  500     static uint32_t bps = 512, spt = 32;
  501     Ecma119Node *ecma_node;
  502     IsoNode *node;
  503     IsoStream *stream;
  504     off_t file_size;
  505     uint32_t file_lba;
  506     int ret;
  507 
  508     /* Bytes 512 to 32767 may come from image or external file */
  509     memset(buf, 0, 512);
  510 
  511     image_size = t->curblock * 2048;
  512 
  513     /* 0 -   3 | 0x0be5a941 | Magic number */
  514     iso_msb(buf, 0x0be5a941, 4);
  515 
  516     /* 28 -  29 |  num_cyl_l | Number of usable cylinder, lower two bytes */
  517     num_cyl = (image_size + (bps * spt) - 1) / (bps * spt);
  518     iso_msb(buf + 28, num_cyl & 0xffff, 2);
  519 
  520     /* 32 -  33 |          1 | Number of tracks per cylinder */
  521     iso_msb(buf + 32, 1, 2);
  522 
  523     /* 35 -  35 |  num_cyl_h | Number of usable cylinders, high byte */
  524     buf[35] = (num_cyl >> 16) & 0xff;
  525     
  526     /* 38 -  39 |         32 | Sectors per track */
  527     iso_msb(buf + 38, spt, 2);
  528 
  529     /* 40 -  41 |        512 | Bytes per sector */
  530     iso_msb(buf + 40, bps, 2);
  531 
  532     /* 44 -  47 | 0x00000034 | Controller characteristics */
  533     iso_msb(buf + 44, 0x00000034, 4);
  534 
  535     /*  72 -  87 | ========== | Volume Directory Entry 1 */
  536     /*  72 -  79 |  boot_name | Boot file basename */
  537     /*  80 -  83 | boot_block | ISO 9660 LBA of boot file * 4 */
  538     /*  84 -  87 | boot_bytes | File length in bytes */
  539     /*  88 - 311 |          0 | Volume Directory Entries 2 to 15 */
  540 
  541     for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) {
  542         ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx], 
  543                                        &node, &ecma_node, "MIPS boot file", 0);
  544         if (ret < 0)
  545             return ret;
  546 
  547         namept = (char *) iso_node_get_name(node);
  548         name_field = (char *) (buf + (72 + 16 * idx));
  549         strncpy(name_field, namept, 8);
  550 
  551         file_lba = ecma_node->info.file->sections[0].block;
  552 
  553         iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
  554 
  555         stream = iso_file_get_stream((IsoFile *) node);
  556         file_size = iso_stream_get_size(stream);
  557 
  558         /* genisoimage rounds up to full multiples of 2048.
  559            libisofs did this too until 2020, but the arcload mips boot loader
  560            throws error if the rounded size is stored here.
  561            So now the exact bytecount gets stored.
  562         */
  563         iso_msb(buf + (72 + 16 * idx) + 12, file_size, 4);
  564         
  565     }
  566 
  567     /* 408 - 411 |  part_blks | Number of 512 byte blocks in partition */
  568     blocks = (image_size + bps - 1) / bps;
  569     iso_msb(buf + 408, blocks, 4);
  570     /* 416 - 419 |          0 | Partition is volume header */
  571     iso_msb(buf + 416, 0, 4);
  572 
  573     /* 432 - 435 |  part_blks | Number of 512 byte blocks in partition */
  574     iso_msb(buf + 432, blocks, 4);
  575     iso_msb(buf + 444, 6, 4);
  576 
  577     /* 504 - 507 |   head_chk | Volume header checksum  
  578                                 The two's complement of bytes 0 to 503 read
  579                                 as big endian unsigned 32 bit:
  580                                   sum(32-bit-words) + head_chk == 0
  581     */
  582     checksum = 0;
  583     for (idx = 0; idx < 504; idx += 4) {
  584         num = iso_read_msb(buf + idx, 4);
  585         /* Addition modulo a natural number is commutative and associative.
  586            Thus the inverse of a sum is the sum of the inverses of the addends.
  587         */
  588         checksum -= num;
  589     }
  590     iso_msb(buf + 504, checksum, 4);
  591 
  592     return ISO_SUCCESS;
  593 }
  594 
  595 
  596 /* The following two functions were implemented according to
  597    doc/boot_sectors.txt section "MIPS Little Endian" which was derived
  598    by Thomas Schmitt from
  599    cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based
  600    on work of Florian Lohoff and Thiemo Seufer,
  601    and from <elf.h> by Free Software Foundation, Inc.
  602 
  603    Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
  604 */
  605 
  606 /**
  607  * Read the necessary ELF information from the first MIPS boot file.
  608  * This is done before image writing starts.
  609  */
  610 int iso_read_mipsel_elf(Ecma119Image *t, int flag)
  611 {
  612     uint32_t phdr_adr, todo, count;
  613     int ret;
  614     uint8_t *elf_buf = NULL;
  615     IsoNode *iso_node;
  616     Ecma119Node *ecma_node;
  617     IsoStream *stream;
  618     
  619     if (t->image->num_mips_boot_files <= 0)
  620         {ret = ISO_SUCCESS; goto ex;}
  621 
  622     LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048);
  623     ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
  624                                    &iso_node, &ecma_node, "MIPS boot file", 0);
  625     if (ret < 0)
  626         goto ex;
  627     stream = iso_file_get_stream((IsoFile *) iso_node);
  628 
  629     ret = iso_stream_open(stream);
  630     if (ret < 0) {
  631         iso_msg_submit(t->image->id, ret, 0,
  632                        "Cannot open designated MIPS boot file '%s'",
  633                        t->image->mips_boot_file_paths[0]);
  634         goto ex;
  635     }
  636     ret = iso_stream_read(stream, elf_buf, 32);
  637     if (ret != 32) {
  638 cannot_read:;
  639         iso_stream_close(stream);
  640         iso_msg_submit(t->image->id, ret, 0,
  641                        "Cannot read from designated MIPS boot file '%s'",
  642                        t->image->mips_boot_file_paths[0]);
  643         goto ex;
  644     }
  645 
  646 
  647     /*  24 -  27 |    e_entry | Entry point virtual address */
  648     t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4);
  649 
  650     /* 28 -  31 |    e_phoff | Program header table file offset */
  651     phdr_adr = iso_read_lsb(elf_buf + 28, 4);
  652 
  653     /* Skip stream up to byte address phdr_adr */
  654     todo = phdr_adr - 32;
  655     while (todo > 0) {
  656         if (todo > 2048)
  657             count = 2048;
  658         else
  659             count = todo;
  660         todo -= count;
  661         ret = iso_stream_read(stream, elf_buf, count);
  662         if (ret != (int) count)
  663             goto cannot_read;
  664     }
  665     ret = iso_stream_read(stream, elf_buf, 20);
  666     if (ret != 20)
  667         goto cannot_read;
  668 
  669     /*  4 -   7 |   p_offset | Segment file offset */
  670     t->mipsel_p_offset = iso_read_lsb(elf_buf + 4, 4);
  671 
  672     /*  8 -  11 |    p_vaddr | Segment virtual address */
  673     t->mipsel_p_vaddr = iso_read_lsb(elf_buf + 8, 4);
  674 
  675     /* 16 -  19 |   p_filesz | Segment size in file */
  676     t->mipsel_p_filesz = iso_read_lsb(elf_buf + 16, 4);
  677 
  678     iso_stream_close(stream);
  679     ret = ISO_SUCCESS;
  680 ex:;
  681     LIBISO_FREE_MEM(elf_buf);
  682     return ret;
  683 }
  684 
  685 
  686 /**
  687  * Write DEC Bootblock from previously read ELF parameters.
  688  * This is done when image writing has already begun.
  689  */
  690 static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag)
  691 {
  692     int ret;
  693     uint32_t seg_size, seg_start;
  694     IsoNode *iso_node;
  695     Ecma119Node *ecma_node;
  696     
  697     /* Bytes 512 to 32767 may come from image or external file */
  698     memset(buf, 0, 512);
  699 
  700     if (t->image->num_mips_boot_files <= 0)
  701         return ISO_SUCCESS;
  702 
  703     ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
  704                                    &iso_node, &ecma_node, "MIPS boot file", 0);
  705     if (ret < 0)
  706         return ret;
  707 
  708     /*  8 -  11 | 0x0002757a | Magic number */
  709     iso_lsb(buf + 8, 0x0002757a, 4);
  710 
  711     /* 12 -  15 |          1 | Mode  1: Multi extent boot */
  712     iso_lsb(buf + 12, 1, 4);
  713 
  714     /* 16 -  19 |   load_adr | Load address */
  715     iso_lsb(buf + 16, t->mipsel_p_vaddr, 4);
  716 
  717     /* 20 -  23 |   exec_adr | Execution address */
  718     iso_lsb(buf + 20, t->mipsel_e_entry, 4);
  719 
  720     /* 24 -  27 |   seg_size | Segment size in file. */
  721     seg_size = (t->mipsel_p_filesz + 511) / 512;
  722     iso_lsb(buf + 24, seg_size, 4);
  723     
  724     /* 28 -  31 |  seg_start | Segment file offset */
  725     seg_start = ecma_node->info.file->sections[0].block * 4
  726                 + (t->mipsel_p_offset + 511) / 512;
  727     iso_lsb(buf + 28, seg_start, 4);
  728     
  729     return ISO_SUCCESS;
  730 }
  731 
  732 
  733 /* The following two functions were implemented according to
  734    doc/boot_sectors.txt section "SUN Disk Label and boot images" which
  735    was derived by Thomas Schmitt from
  736      cdrtools-2.01.01a77/mkisofs/sunlabel.h
  737      cdrtools-2.01.01a77/mkisofs/mkisofs.8
  738      by Joerg Schilling
  739 
  740    Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
  741 */
  742 
  743 /* @parm flag bit0= copy from next lower valid partition table entry
  744  */
  745 static int write_sun_partition_entry(int partition_number,
  746                   char *appended_partitions[],
  747                   uint32_t partition_offset[], uint32_t partition_size[],
  748                   uint32_t cyl_size, uint8_t *buf, int flag)
  749 {
  750     uint8_t *wpt;
  751     int read_idx, i;
  752 
  753     if (partition_number < 1 || partition_number > 8)
  754         return ISO_ASSERT_FAILURE;
  755     
  756     /* 142 - 173 | ========== | 8 partition entries of 4 bytes */
  757     wpt = buf + 142 + (partition_number - 1) * 4;
  758     if (partition_number == 1)
  759         iso_msb(wpt, 4, 2);                            /* 4 = User partition */
  760     else
  761         iso_msb(wpt, 2, 2);            /* 2 = Root partition with boot image */
  762     iso_msb(wpt + 2, 0x10, 2);              /* Permissions: 0x10 = read-only */
  763 
  764     /* 444 - 507 | ========== | Partition table */
  765     wpt = buf + 444 + (partition_number - 1) * 8;
  766     read_idx = partition_number - 1;
  767     if (flag & 1) {
  768         /* Search next lower valid partition table entry. #1 is default */
  769         for (read_idx = partition_number - 2; read_idx > 0; read_idx--)
  770             if (appended_partitions[read_idx] != NULL)
  771                 if (appended_partitions[read_idx][0] != 0)
  772         break;
  773     }
  774     iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4);
  775     iso_msb(wpt + 4, partition_size[read_idx] * 4, 4);
  776 
  777     /* 510 - 511 |   checksum | The result of exoring 2-byte words 0 to 254 */
  778     buf[510] = buf[511] = 0;
  779     for (i = 0; i < 510; i += 2) {
  780         buf[510] ^= buf[i];
  781         buf[511] ^= buf[i + 1];
  782     }
  783 
  784     return ISO_SUCCESS;
  785 }
  786 
  787 /**
  788  * Write SUN Disk Label with ISO in partition 1 and unused 2 to 8
  789  */
  790 static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag)
  791 {
  792     int ret, i, l;
  793     uint64_t blk;
  794 
  795     /* Bytes 512 to 32767 may come from image or external file */
  796     memset(buf, 0, 512);
  797 
  798     /* 0 - 127 |      label | ASCII Label */
  799     if (t->opts->ascii_disc_label[0]) {
  800         for (l = 0; l < 128 && t->opts->ascii_disc_label[l] != 0; l++);
  801         if (l > 0)
  802             memcpy((char *) buf, t->opts->ascii_disc_label, l);
  803     } else {
  804         strcpy((char *) buf,
  805                "CD-ROM Disc with Sun sparc boot created by libisofs");
  806     }
  807     
  808     /* 128 - 131 |          1 | Layout version */
  809     iso_msb(buf + 128, 1, 4);
  810 
  811     /* 140 - 141 |          8 | Number of partitions */
  812     iso_msb(buf + 140, 8, 2);
  813 
  814     /* 188 - 191 | 0x600ddeee | vtoc sanity */
  815     iso_msb(buf + 188, 0x600ddeee, 4);
  816 
  817     /* 420 - 421 |        350 | Rotations per minute */
  818     iso_msb(buf + 420, 350, 2);
  819 
  820     /* 422 - 423 |       2048 | Number of physical cylinders (fixely 640 MB) */
  821     iso_msb(buf + 422, 2048, 2);
  822 
  823     /* 430 - 431 |          1 | interleave factor */
  824     iso_msb(buf + 430, 1, 2);
  825 
  826     /* 432 - 433 |       2048 | Number of data cylinders (fixely 640 MB) */
  827     iso_msb(buf + 432, 2048, 2);
  828 
  829     /* 436 - 437 |          1 | Number of heads per cylinder (1 cyl = 320 kB)*/
  830     iso_msb(buf + 436, 1, 2);
  831 
  832     /* 438 - 439 |        640 | Number of sectors per head (1 head = 320 kB) */
  833     iso_msb(buf + 438, 640, 2);
  834 
  835     /* 508 - 509 |     0xdabe | Magic Number */
  836     iso_msb(buf + 508, 0xdabe, 2);
  837 
  838     if (t->sparc_core_src != NULL) {
  839         /* May be used for grub-sparc. */
  840         blk= ((uint64_t) t->sparc_core_src->sections[0].block) *
  841              (uint64_t) 2048; 
  842         for (i = 0; i < 8; i++)
  843             buf[Libisofs_grub2_sparc_patch_adr_poS + i] = blk >> ((7 - i) * 8);
  844         iso_msb(buf + Libisofs_grub2_sparc_patch_size_poS,
  845                 t->sparc_core_src->sections[0].size, 4);
  846     }
  847 
  848     /* Set partition 1 to describe ISO image and compute checksum */
  849     t->appended_part_start[0] = 0;
  850     t->appended_part_size[0] = t->curblock;
  851     ret = write_sun_partition_entry(1, t->opts->appended_partitions,
  852                   t->appended_part_start, t->appended_part_size,
  853                   ISO_SUN_CYL_SIZE, buf, 0);
  854     if (ret < 0)
  855         return ret;
  856     return ISO_SUCCESS;
  857 }
  858 
  859 
  860 static int hppa_palo_get_filepar(Ecma119Image *t, char *path,
  861                                  uint32_t *adr, uint32_t *len, int flag)
  862 {
  863     int ret;
  864     IsoNode *iso_node;
  865     Ecma119Node *ecma_node;
  866     off_t adr64;
  867 
  868     ret = boot_nodes_from_iso_path(t, path,
  869                              &iso_node, &ecma_node, "HP-PA PALO boot file", 0);
  870     if (ret < 0)
  871         return ret;
  872     if (iso_node_get_type(iso_node) != LIBISO_FILE) {
  873         iso_msg_submit(t->image->id, ISO_HPPA_PALO_NOTREG, 0,
  874                        "HP-PA PALO file is not a data file");
  875         return ISO_HPPA_PALO_NOTREG;
  876     }
  877     adr64 = ((off_t) 2048) * (off_t) ecma_node->info.file->sections[0].block;
  878     if (adr64 > 0x7fffffff) {
  879         iso_msg_submit(t->image->id, ISO_HPPA_PALO_OFLOW, 0,
  880                        "HP-PA PALO boot address exceeds 2 GB");
  881         return ISO_HPPA_PALO_OFLOW;
  882     }
  883     *adr = adr64;
  884     *len = ecma_node->info.file->sections[0].size;
  885     return ISO_SUCCESS;
  886 }
  887 
  888 
  889 /**
  890  * Write HP-PA PALO boot sector. See doc/boot_sectors.txt
  891  *
  892  * learned from  cdrkit-1.1.10/genisoimage/boot-hppa.c
  893  * by Steve McIntyre <steve@einval.com>
  894  *    who states "Heavily inspired by palo"
  895  * Public mail conversations with Helge Deller, beginning with
  896  *    https://lists.debian.org/debian-hppa/2014/01/msg00016.html
  897  * http://git.kernel.org/cgit/linux/kernel/git/deller/palo.git/tree/lib/
  898  *    (especially struct firstblock in common.h and struct partition in part.h)
  899  *
  900  */
  901 static int make_hppa_palo_sector(Ecma119Image *t, uint8_t *buf, int hdrversion,
  902                                  int flag)
  903 {
  904     int ret;
  905     IsoImage *img;
  906     uint32_t adr, len;
  907 
  908     img = t->image;
  909     if (img->hppa_cmdline == NULL && img->hppa_bootloader == NULL &&
  910         img->hppa_kernel_32 == NULL && img->hppa_kernel_64 == NULL && 
  911         img->hppa_ramdisk == NULL)
  912         return ISO_SUCCESS;
  913     if (img->hppa_cmdline == NULL || img->hppa_bootloader == NULL ||
  914         img->hppa_kernel_32 == NULL || img->hppa_kernel_64 == NULL || 
  915         img->hppa_ramdisk == NULL) {
  916         iso_msg_submit(img->id, ISO_HPPA_PALO_INCOMPL, 0,
  917                        "Incomplete HP-PA PALO boot parameters");
  918         return ISO_HPPA_PALO_INCOMPL;
  919     }
  920     if (hdrversion == 4) {
  921         /* Bytes 256 to 32767 may come from loaded ISO image or external file */
  922         memset(buf, 0, 256);
  923     } else if(hdrversion == 5) {
  924         memset(buf, 0, 512);
  925         memset(buf + 1024, 0, 1024);
  926     } else {
  927         iso_msg_submit(img->id, ISO_WRONG_ARG_VALUE, 0,
  928                     "Unsupported HP-PA PALO header version %d (can do 4 or 5)",
  929                        hdrversion);
  930         return ISO_WRONG_ARG_VALUE;
  931     }
  932 
  933     /* Magic */
  934     iso_msb(buf + 0, 0x8000, 2);
  935     /* Name of boot loader */
  936     memcpy(buf + 2, "PALO", 5);
  937     /* Version */
  938     buf[7] = hdrversion;
  939 
  940     /* Byte address and byte count of the "HPPA 32-bit kernel" file
  941     */
  942     ret = hppa_palo_get_filepar(t, img->hppa_kernel_32, &adr, &len, 0);
  943     if (ret < 0)
  944         return ret;
  945     iso_msb(buf +  8, adr, 4);
  946     iso_msb(buf + 12, len, 4);
  947 
  948     /* Byte address and byte count of the "HPPA ramdisk" file
  949     */
  950     ret = hppa_palo_get_filepar(t, img->hppa_ramdisk, &adr, &len, 0);
  951     if (ret < 0)
  952         return ret;
  953     iso_msb(buf + 16, adr, 4);
  954     iso_msb(buf + 20, len, 4);
  955 
  956     if (hdrversion == 4) {
  957         /* "Command line" */
  958         if (strlen(img->hppa_cmdline) > 127) {
  959             iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
  960                            "HP-PA PALO command line too long");
  961             return ISO_HPPA_PALO_CMDLEN;
  962         }
  963         memcpy(buf + 24, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
  964     }
  965 
  966     /* Byte address and byte count of the "HPPA 64-bit kernel" file
  967     */
  968     ret = hppa_palo_get_filepar(t, img->hppa_kernel_64, &adr, &len, 0);
  969     if (ret < 0)
  970         return ret;
  971     iso_msb(buf + 232, adr, 4);
  972     iso_msb(buf + 236, len, 4);
  973 
  974     /* Byte address and byte count of the "HPPA bootloader" file
  975     */
  976     ret = hppa_palo_get_filepar(t, img->hppa_bootloader, &adr, &len, 0);
  977     if (ret < 0)
  978         return ret;
  979     iso_msb(buf + 240, adr, 4);
  980     iso_msb(buf + 244, len, 4);
  981 
  982     if (hdrversion == 5) {
  983         if (strlen(img->hppa_cmdline) > 1023) {
  984             iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0,
  985                            "HP-PA PALO command line too long");
  986             return ISO_HPPA_PALO_CMDLEN;
  987         }
  988         memcpy(buf + 1024, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1);
  989     }
  990     return ISO_SUCCESS;
  991 }
  992 
  993 
  994 /**
  995  * Write DEC Alpha boot sector. See doc/boot_sectors.txt
  996  *
  997  * learned from  cdrkit-1.1.10/genisoimage/boot-alpha.c
  998  * by Steve McIntyre <steve@einval.com>
  999  *    who states "Heavily inspired by isomarkboot by David Mosberger in 1996"
 1000  *
 1001  */
 1002 static int make_dec_alpha_sector(Ecma119Image *t, uint8_t *buf, int flag)
 1003 {
 1004     int ret, i;
 1005     IsoImage *img;
 1006     IsoNode *iso_node;
 1007     Ecma119Node *ecma_node;
 1008     uint64_t size, lba, checksum = 0;
 1009 
 1010     img = t->image;
 1011     if (img->alpha_boot_image == NULL)
 1012         return ISO_SUCCESS;
 1013     ret = boot_nodes_from_iso_path(t, img->alpha_boot_image,
 1014                               &iso_node, &ecma_node, "DEC Alpha boot file", 0);
 1015     if (ret < 0)
 1016         return ret;
 1017     memset(buf, 0, 512);
 1018     strcpy((char *) buf, "Linux/Alpha aboot for ISO filesystem.");
 1019     lba = ecma_node->info.file->sections[0].block * 4;
 1020     size = ecma_node->info.file->sections[0].size / 512 +
 1021            !!(ecma_node->info.file->sections[0].size % 512);
 1022     iso_lsb(buf + 480, size & 0xffffffff, 4);
 1023     iso_lsb(buf + 484, (size >> 32) & 0xffffffff, 4);
 1024     iso_lsb(buf + 488, lba & 0xffffffff, 4);
 1025     iso_lsb(buf + 492, (lba >> 32) & 0xffffffff, 4);
 1026     for (i = 0; i < 63; i++)
 1027        checksum += iso_read_lsb64(buf + 8 * i);
 1028     iso_lsb(buf + 504, checksum & 0xffffffff, 4);
 1029     iso_lsb(buf + 508, (checksum >> 32) & 0xffffffff, 4);
 1030     return ISO_SUCCESS;
 1031 }
 1032 
 1033 /* Convenience frontend for iso_register_apm_entry().
 1034    name and type are 0-terminated strings.
 1035 */
 1036 int iso_quick_apm_entry(struct iso_apm_partition_request **req_array,
 1037                         int *apm_req_count,
 1038                         uint32_t start_block, uint32_t block_count,
 1039                         char *name, char *type)
 1040 {
 1041     int ret, l;
 1042     struct iso_apm_partition_request *entry;
 1043 
 1044     entry = calloc(1, sizeof(struct iso_apm_partition_request));
 1045     if (entry == NULL)
 1046         return ISO_OUT_OF_MEM;
 1047     entry->start_block = start_block;
 1048     entry->block_count = block_count;
 1049     for (l = 0; l < 32 && name[l] != 0; l++);
 1050     if (l > 0)
 1051         memcpy((char *) entry->name, name, l);
 1052     for (l = 0; l < 32 && type[l] != 0; l++);
 1053     if (l > 0)
 1054         memcpy((char *) entry->type, type, l);
 1055     entry->req_status = 0;
 1056     ret = iso_register_apm_entry(req_array, apm_req_count, entry, 0);
 1057     free(entry);
 1058     return ret;
 1059 }
 1060 
 1061 
 1062 static int iso_find_gpt_entry(struct iso_gpt_partition_request **req_array,
 1063                         int gpt_req_count,
 1064                         uint64_t start_block, uint64_t block_count,
 1065                         int *index, int flag)
 1066 {
 1067     struct iso_gpt_partition_request *entry;
 1068 
 1069     for (*index = 0; *index < gpt_req_count; (*index)++) {
 1070         entry = req_array[*index];
 1071         if (entry->start_block == start_block &&
 1072             entry->block_count == block_count)
 1073             return 1;
 1074     }
 1075     *index = -1;
 1076     return 0;
 1077 }
 1078 
 1079 
 1080 /* Convenience frontend for iso_register_gpt_entry().
 1081    name has to be already encoded as UTF-16LE.
 1082 */
 1083 int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array,
 1084                         int *gpt_req_count,
 1085                         uint64_t start_block, uint64_t block_count,
 1086                         uint8_t type_guid[16], uint8_t partition_guid[16],
 1087                         uint64_t flags, uint8_t name[72])
 1088 {
 1089     int ret;
 1090     struct iso_gpt_partition_request *entry;
 1091 
 1092     entry = calloc(1, sizeof(struct iso_gpt_partition_request));
 1093     if (entry == NULL)
 1094         return ISO_OUT_OF_MEM;
 1095     entry->start_block = start_block;
 1096     entry->block_count = block_count;
 1097     memcpy(entry->type_guid, type_guid, 16);
 1098     memcpy(entry->partition_guid, partition_guid, 16);
 1099     entry->flags = flags;
 1100     memcpy(entry->name, name, 72);
 1101     entry->req_status = 0;
 1102     ret = iso_register_gpt_entry(req_array, gpt_req_count, entry, 0);
 1103     free(entry);
 1104     return ret;
 1105 }
 1106 
 1107 
 1108 int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array,
 1109                         int *mbr_req_count,
 1110                         uint64_t start_block, uint64_t block_count,
 1111                         uint8_t type_byte, uint8_t status_byte,
 1112                         int desired_slot)
 1113 {
 1114     int ret;
 1115     struct iso_mbr_partition_request *entry;
 1116 
 1117     ret = iso_mbr_entry_slot_is_free(req_array, *mbr_req_count, desired_slot);
 1118     if (ret < 0)
 1119         desired_slot = 0;
 1120     else if (ret == 0)
 1121         return ISO_BOOT_MBR_COLLISION;
 1122 
 1123     entry = calloc(1, sizeof(struct iso_mbr_partition_request));
 1124     if (entry == NULL)
 1125         return ISO_OUT_OF_MEM;
 1126     entry->start_block = start_block;
 1127     entry->block_count = block_count;
 1128     entry->type_byte = type_byte;
 1129     entry->status_byte = status_byte;
 1130     entry->desired_slot = desired_slot;
 1131     ret = iso_register_mbr_entry(req_array, mbr_req_count, entry, 0);
 1132     free(entry);
 1133     return ret;
 1134 }
 1135 
 1136 
 1137 int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array,
 1138                                int mbr_req_count, int slot)
 1139 {
 1140     int i;
 1141 
 1142     if (slot < 0 || slot > ISO_MBR_ENTRIES_MAX)
 1143         return -1;
 1144     if (slot == 0)
 1145         return 1;
 1146     for (i = 0; i < mbr_req_count; i++)
 1147         if (req_array[i]->desired_slot == slot)
 1148             return 0;
 1149     return 1;
 1150 }
 1151 
 1152 
 1153 /**
 1154  * Compare the block interval positions of two iso_apm_partition_request
 1155  */
 1156 static
 1157 int cmp_partition_request(const void *f1, const void *f2)
 1158 {
 1159     struct iso_partition_request {
 1160        uint64_t start_block;
 1161        uint64_t block_count;
 1162     } *r1, *r2;
 1163 
 1164     r1 = *((struct iso_partition_request **) f1);
 1165     r2 = *((struct iso_partition_request **) f2);
 1166     if (r1->start_block < r2->start_block)
 1167         return -1;
 1168     if (r1->start_block > r2->start_block)
 1169         return 1;
 1170 
 1171     /* In case of overlapping the largest partition shall be first */
 1172     if (r1->block_count > r2->block_count)
 1173         return -1;
 1174     if (r1->block_count < r2->block_count)
 1175         return 1;
 1176     return 0;
 1177 }
 1178 
 1179 
 1180 /* @param flag bit0= This is the entry in block 1. Its blocks are already in
 1181                      the desired apm_block_size unit. Set block_fac to 1.
 1182                      Set flags to 3 rather than 0x13.
 1183 */
 1184 static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size,
 1185                                struct iso_apm_partition_request *req,
 1186                                uint8_t *buf, int map_entries, int flag)
 1187 {
 1188     uint8_t *wpt;
 1189     uint32_t flags;
 1190     int block_fac;
 1191 
 1192     if ((flag & 1) || (t->apm_req_flags & 4))
 1193         block_fac = 1;
 1194     else
 1195         block_fac = 2048 / apm_block_size;
 1196         
 1197     memset(buf, 0, apm_block_size);
 1198     wpt = buf;
 1199 
 1200     /* Signature */
 1201     wpt[0] = 'P'; wpt[1] = 'M';
 1202     wpt+= 2;
 1203     /* reserved */
 1204     wpt += 2;
 1205     /* Number of partition entries */
 1206     iso_msb(wpt, (uint32_t) map_entries, 4);
 1207     wpt += 4;
 1208     /* Physical block start of partition */
 1209     iso_msb(wpt, (uint32_t) (req->start_block * block_fac), 4);
 1210     wpt += 4;
 1211     /* Physical block count of partition */
 1212     iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
 1213     wpt += 4;
 1214     /* Partition name */
 1215     memcpy(wpt, req->name, 32);
 1216     wpt += 32;
 1217     /* Type string */
 1218     memcpy(wpt, req->type, 32);
 1219     wpt += 32;
 1220     /* Logical block start */
 1221     iso_msb(wpt, (uint32_t) 0, 4);
 1222     wpt += 4;
 1223     /* Logical block count */
 1224     iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4);
 1225     wpt += 4;
 1226     /* Status flags : bit0= entry is valid , bit1= entry is allocated
 1227                       bit4= partition is readable , bit5= partition is writable
 1228                       bit30= automatic mount (legacy Mac)
 1229     */
 1230     if (flag & 1) {
 1231         flags = 3;
 1232     } else {
 1233         flags = 0x13;
 1234         if (strncmp((char *) req->type, "Apple_HFS", 9) == 0 &&
 1235             req->type[9] == 0)
 1236             flags |= 0x40000000;
 1237     }
 1238     iso_msb(wpt, flags, 4);
 1239     wpt += 4;
 1240 
 1241     /* boot_block , boot_bytes , processor , reserved : are all 0 */
 1242 
 1243     return ISO_SUCCESS;
 1244 }
 1245 
 1246 
 1247 /* Sort and fill gaps in requested APM */
 1248 static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks)
 1249 {
 1250     int i, ret, gap_counter = 0, up_to;
 1251     uint32_t part_end, goal, block_fac = 1;
 1252     char gap_name[33];
 1253 
 1254     if (t->apm_req_flags & 4) {
 1255         if (t->opts->apm_block_size == 0)
 1256             t->opts->apm_block_size = 2048;
 1257         block_fac = 2048 / t->opts->apm_block_size;
 1258     }
 1259 
 1260     /* Find out whether an entry with start_block <= 1 is requested */
 1261     for (i = 0; i < t->apm_req_count; i++) {
 1262         if (t->apm_req[i]->start_block <= 1)
 1263     break;
 1264     }
 1265     if (i >= t->apm_req_count) {
 1266         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1267                                   1, 0, "Apple", "Apple_partition_map");
 1268         if (ret < 0)
 1269             return ret;
 1270     }
 1271 
 1272     qsort(t->apm_req, t->apm_req_count,
 1273         sizeof(struct iso_apm_partition_request *), cmp_partition_request);
 1274 
 1275     if (t->opts->part_like_isohybrid)
 1276         return 1; /* No filling, only sorting */
 1277 
 1278     /* t->apm_req_count will grow during the loop */
 1279     up_to = t->apm_req_count + 1;
 1280     for (i = 1; i < up_to; i++) {
 1281         if (i < up_to - 1)
 1282             goal = (uint32_t) t->apm_req[i]->start_block;
 1283         else
 1284             goal = img_blocks * block_fac;
 1285         if (i == 1) {
 1286             /* Description of APM itself */
 1287             /* Actual APM size is not yet known. Protection begins at PVD */
 1288             part_end = 16 * block_fac;
 1289             if (goal < part_end && goal> 1)
 1290                     part_end = goal;
 1291         } else {
 1292             part_end = t->apm_req[i - 1]->start_block +
 1293                        t->apm_req[i - 1]->block_count;
 1294         }
 1295         if (part_end > goal) {
 1296             iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0,
 1297                "Program error: APM partitions %d and %d overlap by %lu blocks",
 1298                i - 1, i, part_end - goal);
 1299             return ISO_BOOT_APM_OVERLAP;
 1300         }
 1301 
 1302         if (t->apm_req_flags & 2) /* Do not fill gaps */
 1303     continue;
 1304 
 1305         if (part_end < goal || i == up_to - 1) { /* Always add a final entry */
 1306             sprintf(gap_name, "Gap%d", gap_counter);
 1307             gap_counter++;
 1308             ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1309                                       part_end, goal - part_end,
 1310                                       gap_name, "ISO9660_data");
 1311             if (ret < 0)
 1312                 return ret;
 1313             /* Mark as automatically placed filler request */
 1314             t->apm_req[t->apm_req_count - 1]->req_status |= 1;
 1315         }
 1316     }
 1317 
 1318     /* Merge list of gap partitions with list of already sorted entries */
 1319     if (!(t->apm_req_flags & 2)) /* No gaps were filled */
 1320         qsort(t->apm_req, t->apm_req_count,
 1321             sizeof(struct iso_apm_partition_request *), cmp_partition_request);
 1322 
 1323     return 1;
 1324 }
 1325 
 1326 
 1327 static int rectify_apm(Ecma119Image *t)
 1328 {
 1329     int ret;
 1330 
 1331 #ifdef NIX
 1332     /* Disabled */
 1333 
 1334     /* <<< ts B20526 : Dummy mock-up */
 1335     if (t->apm_req_count <= 0) {
 1336         /*
 1337         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1338                                   16, 20, "Test1_name_16_20", "Test1_type");
 1339         / * >>> Caution: Size 90 causes intentional partition overlap error * /
 1340         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1341                                   30, 90, "BAD_30_90_BAD", "Test1_type");
 1342         */
 1343         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1344                                   30, 20, "Test1_name_30_20", "Test1_type");
 1345         if (ret < 0)
 1346             return ret;
 1347         ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 1348                                  100, 400, "Test2_name_100_400", "Test2_type");
 1349         if (ret < 0)
 1350             return ret;
 1351     }
 1352 #endif /* NIX */
 1353 
 1354     if (t->apm_req_count == 0)
 1355         return 1;
 1356 
 1357     if (t->gpt_req_count > 0 &&
 1358         t->opts->apm_block_size != 2048 && t->apm_req_count > 0) {
 1359         iso_msgs_submit(0,
 1360                 "GPT and APM requested. APM block size would have to be 2048.",
 1361                         0, "FAILURE", 0);
 1362         return ISO_BOOT_APM_GPT_BSIZE;
 1363     }
 1364     if (t->apm_req_count > 0) {
 1365         ret = fill_apm_gaps(t, t->curblock);
 1366         if (ret < 0)
 1367             return ret;
 1368     }
 1369     return 1;
 1370 }
 1371 
 1372 
 1373 /* flag bit0= do not write Block0
 1374 */
 1375 static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf,
 1376                          int flag)
 1377 {
 1378     int i, ret;
 1379     uint32_t block_fac = 1;
 1380     /* This is a micro mock-up of an APM Block0
 1381        and also harmless x86 machine code.
 1382     */
 1383     static uint8_t block0_template[8] = {
 1384         0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff
 1385     };
 1386 
 1387     if (t->apm_req_count <= 0)
 1388         return 2;
 1389 
 1390     if (t->opts->apm_block_size == 0) {
 1391         /* One cannot be sure that all GPT partitions are registered
 1392            already. So it is necessary to choose the block size which is
 1393            combinable with GPT but not mountable on Linux.
 1394         */
 1395         t->opts->apm_block_size = 2048;
 1396     }
 1397 
 1398     if (t->apm_req_flags & 4)
 1399         block_fac = 2048 / t->opts->apm_block_size;
 1400 
 1401     if (!(t->apm_req_flags & 2)) {
 1402         /* Gaps have been filled. Care for the final one */
 1403         /* Adjust last partition to img_size. This size was not known when the
 1404            number of APM partitions was determined.
 1405         */
 1406         if (img_blocks * block_fac <
 1407             t->apm_req[t->apm_req_count - 1]->start_block)
 1408             t->apm_req[t->apm_req_count - 1]->block_count = 0;
 1409         else
 1410             t->apm_req[t->apm_req_count - 1]->block_count =
 1411                                  img_blocks * block_fac -
 1412                                  t->apm_req[t->apm_req_count - 1]->start_block;
 1413         /* If it is still empty, remove it */
 1414         if(t->apm_req[t->apm_req_count - 1]->block_count == 0) {
 1415           free(t->apm_req[t->apm_req_count - 1]);
 1416           t->apm_req_count--;
 1417         }
 1418     }
 1419 
 1420     /* If block size is larger than 512, then not all 63 entries will fit */
 1421     if ((t->apm_req_count + 1) * t->opts->apm_block_size > 32768) 
 1422         return ISO_BOOT_TOO_MANY_APM;
 1423 
 1424     /* Block 1 describes the APM itself */
 1425     t->apm_req[0]->start_block = 1;
 1426     t->apm_req[0]->block_count = t->apm_req_count;
 1427 
 1428     if (!(flag & 1)) {
 1429       /* Write APM block 0. Very sparse, not to overwrite much of
 1430          possible MBR.
 1431       */
 1432       memcpy(buf, block0_template, 8);
 1433       buf[2]= (t->opts->apm_block_size >> 8) & 0xff;
 1434       buf[3]= 0;
 1435     }
 1436 
 1437     /* Write APM Block 1 to t->apm_req_count */
 1438     for (i = 0; i < t->apm_req_count; i++) {
 1439         ret = iso_write_apm_entry(t, t->opts->apm_block_size, t->apm_req[i],
 1440                      buf + (i + 1) * t->opts->apm_block_size, t->apm_req_count,
 1441                      i == 0);
 1442         if (ret < 0)
 1443             return ret;
 1444     }
 1445     return ISO_SUCCESS;
 1446 }
 1447 
 1448 
 1449 static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
 1450 {
 1451     int i, ret, req_of_slot[ISO_MBR_ENTRIES_MAX], q, j;
 1452 
 1453 #ifdef NIX
 1454     /* Disabled */
 1455 
 1456     /* <<< Dummy mock-up */
 1457     if (t->mbr_req_count <= 0) {
 1458         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
 1459                                   (uint64_t) 0, (uint64_t) 0, 0xee, 0, 0);
 1460         if (ret < 0)
 1461             return ret;
 1462         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
 1463                                   ((uint64_t) 100) * 4, (uint64_t) 0,
 1464                                   0x0c, 0x80, 1);
 1465         if (ret < 0)
 1466             return ret;
 1467     }
 1468 #endif /* NIX */
 1469 
 1470     if (t->mbr_req_count <= 0)
 1471         return 2;
 1472 
 1473     /* >>> Sort by start block ? */
 1474 
 1475     /* Adjust partition ends */
 1476     for (i = 0; i < t->mbr_req_count; i++) {
 1477         if (i > 0) {
 1478             if (t->mbr_req[i]->start_block <= t->mbr_req[i - 1]->start_block &&
 1479                 !(t->mbr_req[i]->block_count == 0 &&
 1480                   t->mbr_req[i]->start_block ==
 1481                                              t->mbr_req[i - 1]->start_block))
 1482                 return ISO_BOOT_MBR_OVERLAP;
 1483             if (t->mbr_req[i - 1]->start_block +
 1484                    t->mbr_req[i - 1]->block_count > t->mbr_req[i]->start_block)
 1485                 return ISO_BOOT_MBR_OVERLAP;
 1486         }
 1487         if (t->mbr_req[i]->block_count != 0)
 1488     continue;
 1489         if (i < t->mbr_req_count - 1)
 1490             t->mbr_req[i]->block_count = t->mbr_req[i + 1]->start_block -
 1491                                          t->mbr_req[i]->start_block;
 1492         else
 1493             t->mbr_req[i]->block_count = ((uint64_t) img_blocks) * 4 -
 1494                                          t->mbr_req[i]->start_block;
 1495     }
 1496 
 1497     /* Assign requested entries to slot numbers */
 1498     for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++)
 1499         req_of_slot[i] = -1;
 1500     for (i = 0; i < t->mbr_req_count; i++) {
 1501         if (t->mbr_req[i]->desired_slot < 1 ||
 1502             t->mbr_req[i]->desired_slot > ISO_MBR_ENTRIES_MAX)
 1503     continue;
 1504         if (req_of_slot[t->mbr_req[i]->desired_slot - 1] >= 0)
 1505             return ISO_BOOT_MBR_COLLISION;
 1506         req_of_slot[t->mbr_req[i]->desired_slot - 1] = i;
 1507     }
 1508     for (i = 0; i < t->mbr_req_count; i++) {
 1509         if (t->mbr_req[i]->desired_slot > 0)
 1510     continue;
 1511         for (j = 0; j < ISO_MBR_ENTRIES_MAX; j++)
 1512              if (req_of_slot[j] < 0)
 1513         break;
 1514         if (j >= ISO_MBR_ENTRIES_MAX)
 1515             return ISO_BOOT_TOO_MANY_MBR;
 1516         req_of_slot[j] = i;
 1517     }
 1518 
 1519     /* Write partition slots */
 1520     for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) {
 1521         memset(buf + 446 + i * 16, 0, 16);
 1522         q = req_of_slot[i];
 1523         if (q < 0) 
 1524     continue;
 1525         if (t->mbr_req[q]->block_count == 0)
 1526     continue;
 1527         ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[q]->type_byte,
 1528                   t->mbr_req[q]->start_block, t->mbr_req[q]->block_count,
 1529                   t->partition_secs_per_head, t->partition_heads_per_cyl,
 1530                   buf, 2);
 1531         if (ret < 0)
 1532             return ret;
 1533         buf[446 + i * 16] = t->mbr_req[q]->status_byte;
 1534     }
 1535     return ISO_SUCCESS;
 1536 }
 1537 
 1538 
 1539 static void iso_write_gpt_entry(Ecma119Image *t, uint8_t *buf,
 1540                                 uint8_t type_guid[16], uint8_t part_uuid[16],
 1541                                 uint64_t start_lba, uint64_t end_lba,
 1542                                 uint64_t flags, uint8_t name[72])
 1543 {
 1544     char *wpt;
 1545     int i;
 1546 
 1547     wpt = (char *) buf;
 1548     memcpy(wpt, type_guid, 16);
 1549     wpt += 16;
 1550     for (i = 0; i < 16; i++)
 1551         if (part_uuid[i])
 1552     break;
 1553     if (i == 16) {
 1554         if (!t->gpt_disk_guid_set)
 1555             iso_gpt_uuid(t, t->gpt_disk_guid);
 1556         t->gpt_disk_guid_set = 1;
 1557         iso_gpt_uuid(t, part_uuid);
 1558     }
 1559     memcpy(wpt, part_uuid, 16);
 1560     wpt += 16;
 1561     iso_lsb_to_buf(&wpt, start_lba & 0xffffffff, 4, 0);
 1562     iso_lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 4, 0);
 1563     iso_lsb_to_buf(&wpt, end_lba & 0xffffffff, 4, 0);
 1564     iso_lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 4, 0);
 1565     iso_lsb_to_buf(&wpt, flags & 0xffffffff, 4, 0);
 1566     iso_lsb_to_buf(&wpt, (flags >> 32) & 0xffffffff, 4, 0);
 1567     memcpy(wpt, name, 72);
 1568 }
 1569 
 1570 
 1571 int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks,
 1572                                uint8_t *buf, uint32_t max_entries,
 1573                                uint32_t part_start, uint32_t p_arr_crc)
 1574 {
 1575     static char *sig = "EFI PART";
 1576     static char revision[4] = {0x00, 0x00, 0x01, 0x00};
 1577     char *wpt;
 1578     uint32_t crc;
 1579     off_t back_lba;
 1580 
 1581     memset(buf, 0, 512);
 1582     wpt = (char *) buf;
 1583 
 1584     /* >>> Make signature adjustable */
 1585     memcpy(wpt, sig, 8); /* no trailing 0 */
 1586     wpt += 8;
 1587 
 1588     memcpy(wpt, revision, 4);
 1589     wpt += 4;
 1590     iso_lsb_to_buf(&wpt, 92, 4, 0);
 1591 
 1592     /* CRC will be inserted later */
 1593     wpt += 4;
 1594 
 1595     /* reserved */
 1596     iso_lsb_to_buf(&wpt, 0, 4, 0);
 1597     /* Own LBA low 32 */
 1598     iso_lsb_to_buf(&wpt, 1, 4, 0);
 1599     /* Own LBA high 32 */
 1600     iso_lsb_to_buf(&wpt, 0, 4, 0);
 1601 
 1602     /* Backup header LBA is 1 hd block before backup GPT area end */
 1603     back_lba = t->gpt_backup_end * 4 - 1;
 1604     iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1);
 1605     iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1);
 1606 
 1607     /* First usable LBA for partitions (4 entries per hd block) */
 1608     iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0);
 1609     iso_lsb_to_buf(&wpt, 0, 4, 0);
 1610 
 1611     /* Last usable LBA for partitions is 1 hd block before first backup entry*/
 1612     iso_lsb_to_buf(&wpt,
 1613                    (uint32_t) ((back_lba - max_entries / 4 - 1) & 0xffffffff),
 1614                    4, 1);
 1615     iso_lsb_to_buf(&wpt,
 1616                    (uint32_t) ((back_lba - max_entries / 4 - 1) >> 32), 4, 1);
 1617 
 1618     /* Disk GUID */
 1619     if (!t->gpt_disk_guid_set)
 1620         iso_gpt_uuid(t, t->gpt_disk_guid);
 1621     t->gpt_disk_guid_set = 1;
 1622     memcpy(wpt, t->gpt_disk_guid, 16);
 1623     wpt += 16;
 1624 
 1625     /* Partition entries start */
 1626     iso_lsb_to_buf(&wpt, part_start, 4, 0);
 1627     iso_lsb_to_buf(&wpt, 0, 4, 0);
 1628 
 1629     /* Number of partition entries */
 1630     iso_lsb_to_buf(&wpt, max_entries, 4, 0);
 1631 
 1632     /* Size of a partition entry */
 1633     iso_lsb_to_buf(&wpt, 128, 4, 0);
 1634 
 1635     /* CRC-32 of the partition array */
 1636     iso_lsb_to_buf(&wpt, p_arr_crc, 4, 0);
 1637 
 1638 
 1639     /* <<< Only for a first test */
 1640     if (wpt - (char *) buf != 92) {
 1641         iso_msgs_submit(0,
 1642                    "program error : write_gpt_header_block : wpt != 92",
 1643                    0, "FATAL", 0);
 1644         return ISO_ISOLINUX_CANT_PATCH;
 1645     }
 1646 
 1647     /* CRC-32 of this header while head_crc is 0 */
 1648     crc = iso_crc32_gpt((unsigned char *) buf, 92, 0); 
 1649     wpt = ((char *) buf) + 16;
 1650     iso_lsb_to_buf(&wpt, crc, 4, 0);
 1651 
 1652     return ISO_SUCCESS;
 1653 }
 1654 
 1655 
 1656 /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */
 1657 void iso_ascii_utf_16le(uint8_t gap_name[72])
 1658 {
 1659     int i;
 1660 
 1661     for (i = strlen((char *) gap_name) - 1; i >= 0; i--) {
 1662         gap_name[2 * i] = gap_name[i];
 1663         gap_name[2 * i + 1] = 0;
 1664     }
 1665 }
 1666 
 1667 
 1668 static int intvl_overlap(uint64_t start1, uint64_t end1,
 1669                          uint64_t start2, uint64_t end2, int second)
 1670 {
 1671     if (start1 >= start2 && start1 <= end2)
 1672         return 1;
 1673     if (end1 >= start2 && end1 <= end2)
 1674         return 1;
 1675     if (!second)
 1676         return intvl_overlap(start2, end2, start1, end1, 1);
 1677     return 0;
 1678 }
 1679 
 1680 
 1681 /* Check APM HFS+ partitions whether they would fit in gaps.
 1682    If so, add them as GPT partitions, too.
 1683  */
 1684 static int iso_copy_apmhfs_to_gpt(Ecma119Image *t, int flag)
 1685 {
 1686     int a, i, counter = 0, ret;
 1687     uint64_t bfac = 4;
 1688     static uint8_t hfs_plus_uuid[16] = {
 1689         0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
 1690         0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
 1691     };
 1692     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 1693     uint8_t gpt_name[72];
 1694     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
 1695 
 1696     if ((t->apm_req_flags & 4) && t->opts->apm_block_size / 512 > 0)
 1697         bfac = t->opts->apm_block_size / 512;
 1698 
 1699     for (a = 0; a < t->apm_req_count; a++) {
 1700         if (strcmp((char *) t->apm_req[a]->type, "Apple_HFS") != 0)
 1701     continue;
 1702         for (i = 0; i < t->gpt_req_count; i++)
 1703             if (intvl_overlap(t->apm_req[a]->start_block * bfac,
 1704                               (t->apm_req[a]->start_block +
 1705                                t->apm_req[a]->block_count - 1) * bfac,
 1706                               t->gpt_req[i]->start_block,
 1707                               t->gpt_req[i]->start_block +
 1708                               t->gpt_req[i]->block_count - 1, 0))
 1709         break;
 1710         if (i >= t->gpt_req_count) {
 1711             memset(gpt_name, 0, 72);
 1712             counter++;
 1713             if (counter > 1)
 1714                 sprintf((char *) gpt_name, "HFSPLUS_%d", counter);
 1715             else
 1716                 sprintf((char *) gpt_name, "HFSPLUS");
 1717             iso_ascii_utf_16le(gpt_name);
 1718             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 1719                                       t->apm_req[a]->start_block * bfac,
 1720                                       t->apm_req[a]->block_count * bfac,
 1721                                       hfs_plus_uuid, zero_uuid,
 1722                                       gpt_flags, gpt_name);
 1723             if (ret < 0)
 1724                 return ret;
 1725         }
 1726     }
 1727     return 1;
 1728 }
 1729 
 1730 
 1731 static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
 1732 {
 1733     static uint8_t basic_data_uuid[16] = {
 1734         0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
 1735         0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
 1736     };
 1737 
 1738     uint32_t p_arr_crc = 0;
 1739     uint64_t start_lba, end_lba, goal, part_end, next_end, backup_end_lba;
 1740     int ret, i, gap_counter = 0, up_to;
 1741     struct iso_gpt_partition_request *req;
 1742     uint8_t gpt_name[72];
 1743     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 1744     static uint8_t *type_guid;
 1745     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
 1746 
 1747     if (t->gpt_req_count == 0)
 1748         return 2;
 1749     backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * 4;
 1750 
 1751     ret = iso_copy_apmhfs_to_gpt(t, 0);
 1752     if (ret <= 0)
 1753         return ret;
 1754     
 1755     /* Sort and fill gaps */
 1756     qsort(t->gpt_req, t->gpt_req_count,
 1757         sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
 1758     /* t->gpt_req_count will grow during the loop */
 1759     up_to = t->gpt_req_count + 1;
 1760     goal = 0;
 1761     part_end = 0;
 1762 
 1763     if (t->opts->part_like_isohybrid)
 1764         up_to = 0; /* No gap filling */
 1765 
 1766     for (i = 0; i < up_to; i++) {
 1767         if (i < up_to - 1) {
 1768             goal = t->gpt_req[i]->start_block;
 1769         } else {
 1770             goal = ((uint64_t) img_blocks) * 4;
 1771             if (goal > backup_end_lba)
 1772                 goal = backup_end_lba;
 1773         }
 1774         if (i == 0) {
 1775             if (goal <= 16 * 4)
 1776     continue;
 1777             next_end = 16 * 4;
 1778         } else {
 1779             next_end = t->gpt_req[i - 1]->start_block +
 1780                        t->gpt_req[i - 1]->block_count;
 1781         }
 1782         if (next_end > part_end)
 1783             part_end = next_end;
 1784         if (part_end > goal) {
 1785             if (!(t->gpt_req_flags & 1)) {
 1786                 iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0,
 1787                "Program error: GPT partitions %d and %d overlap by %.f blocks",
 1788                                i - 1, i, (double) (part_end - goal));
 1789                 return ISO_BOOT_GPT_OVERLAP;
 1790             }
 1791         } else if (part_end < goal) {
 1792             memset(gpt_name, 0, 72);
 1793             type_guid = basic_data_uuid;
 1794             if (goal == t->vol_space_size * (uint64_t) 4 &&
 1795                 part_end == t->opts->partition_offset * (uint64_t) 4) {
 1796                 sprintf((char *) gpt_name, "ISO9660");
 1797                 if (t->opts->iso_gpt_flag & 1)
 1798                     type_guid = t->opts->iso_gpt_type_guid;
 1799             } else {
 1800                 sprintf((char *) gpt_name, "Gap%d", gap_counter);
 1801             }
 1802             iso_ascii_utf_16le(gpt_name);
 1803             gap_counter++;
 1804             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 1805                                       part_end, goal - part_end,
 1806                                       type_guid, zero_uuid,
 1807                                       gpt_flags, gpt_name);
 1808             if (ret < 0)
 1809                 return ret;
 1810             /* Mark as automatically placed filler request */
 1811             t->gpt_req[t->gpt_req_count - 1]->req_status |= 1;
 1812         }
 1813     }
 1814     /* Merge list of gap partitions with list of already sorted entries */
 1815     qsort(t->gpt_req, t->gpt_req_count,
 1816         sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
 1817  
 1818     if ((int) t->gpt_max_entries < t->gpt_req_count)
 1819         return ISO_BOOT_TOO_MANY_GPT;
 1820 
 1821     /* Write the GPT entries to buf */
 1822     for (i = 0; i < t->gpt_req_count; i++) {
 1823         req = t->gpt_req[i];
 1824         start_lba = req->start_block;
 1825         end_lba = req->start_block + req->block_count;
 1826         if (req->start_block == t->opts->partition_offset * ((uint64_t) 4) &&
 1827             req->block_count == ((uint64_t) 4) * 0xffffffff)
 1828             end_lba = t->vol_space_size * 4;
 1829         if (end_lba > backup_end_lba)
 1830             end_lba = backup_end_lba;
 1831         end_lba = end_lba - 1;
 1832         iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i,
 1833                             req->type_guid, req->partition_guid, 
 1834                             start_lba, end_lba, req->flags, req->name);
 1835     }
 1836     for (; i < (int) t->gpt_max_entries; i++)
 1837         memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128);
 1838 
 1839     p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start,
 1840                               128 * t->gpt_max_entries, 0);
 1841     ret = iso_write_gpt_header_block(t, img_blocks, buf + 512,
 1842                                      t->gpt_max_entries,
 1843                                      t->gpt_part_start, p_arr_crc);
 1844     if (ret < 0)
 1845         return ret;
 1846     return ISO_SUCCESS;
 1847 }
 1848 
 1849 
 1850 /* Add a dummy MBR partition of type 0 with boot flag */
 1851 static void iso_dummy_mbr_partition(uint8_t *buf, int mode)
 1852 {
 1853     int i;
 1854                              /* bootable , start 0/0/1, type 0x00, end 0/0/1,
 1855                                 start LBA 0, block count 1 */
 1856     static uint8_t dummy_entry[16] = {
 1857                               0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
 1858                               0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
 1859 
 1860     for (i = 0; i < 4; i++) {
 1861         if (mbr_part_slot_is_unused(buf + 446 + 16 * i)) {
 1862             memcpy(buf + 446 + 16 * i, dummy_entry, 16);
 1863             return;
 1864         }
 1865     }
 1866     /* Abundance of 0xee and 0xef partitions. No other one free. */
 1867     for (i = 0; i < 4; i++) {
 1868         if (buf[446 + 16 * i + 4] != 0xef) {
 1869             buf[446 + 16 * i] |= 0x80;
 1870             return;
 1871         }
 1872     }
 1873     i = 3;
 1874     buf[446 + 16 * i] |= 0x80;
 1875 }
 1876 
 1877 
 1878 /* @param flag
 1879           bit0= t->opts->ms_block is not counted in t->total_size
 1880 */
 1881 int iso_write_system_area(Ecma119Image *t, uint8_t *buf, int flag)
 1882 {
 1883     int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0;
 1884     int first_partition = 1, last_partition = 4, apm_flag, part_type = 0;
 1885     int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0;
 1886     int offset_flag = 0, risk_of_ee = 0;
 1887     uint32_t img_blocks, gpt_blocks, mbrp1_blocks, pml_blocks;
 1888     uint64_t blk;
 1889     uint8_t *wpt;
 1890 
 1891     if ((t == NULL) || (buf == NULL)) {
 1892         return ISO_NULL_POINTER;
 1893     }
 1894 
 1895     /* set buf to 0s */
 1896     memset(buf, 0, 16 * BLOCK_SIZE);
 1897 
 1898     sa_type = (t->system_area_options >> 2) & 0x3f;
 1899 
 1900     iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0);
 1901     for (i = first_partition - 1; i <= last_partition - 1; i++)
 1902         if (t->opts->appended_partitions[i] != NULL) {
 1903             will_append = 1;
 1904     break;
 1905         }
 1906 
 1907 #ifdef Libisofs_appended_partitions_inlinE
 1908     img_blocks = t->vol_space_size;
 1909 #else
 1910     img_blocks = t->curblock;
 1911 #endif
 1912 
 1913     if (t->system_area_data != NULL) {
 1914         /* Write more or less opaque boot image */
 1915         memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE);
 1916 
 1917     } else if (sa_type == 0 && t->catalog != NULL &&
 1918                (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
 1919         /* Check for isolinux image with magic number of 3.72 and produce
 1920            an MBR from our built-in template. (Deprecated since 31 Mar 2010)
 1921         */
 1922         if (t->bootsrc[0] == NULL)
 1923             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
 1924       "Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
 1925         if (img_blocks < 0x80000000) {
 1926             int_img_blocks= img_blocks;
 1927         } else {
 1928             int_img_blocks= 0x7ffffff0;
 1929         }
 1930         ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block,
 1931                                  &int_img_blocks, (char*)buf, 0);
 1932         if (ret != 1) {
 1933             /* error, it should never happen */
 1934             return ISO_ASSERT_FAILURE;
 1935         }
 1936         return ISO_SUCCESS;
 1937     }
 1938 
 1939     /* If APM entries were submitted to iso_register_apm_entry(), then they
 1940        get sprinkled over the system area after the system area template was
 1941        loaded and before any other data get inserted.
 1942        Note that if APM and MBR get combined, then the first 8 bytes of the MBR
 1943        template must be replaceable by:
 1944           {0x45, 0x52, 0x08 0x00, 0xeb, 0x02, 0xff, 0xff}
 1945 
 1946        >>> ts B20526
 1947        >>> This does not care for eventual image enlargements in last minute.
 1948        >>> A sa_type, that does this, will have to adjust the last APM entry
 1949        >>> if exactness matters.
 1950     */
 1951 
 1952     apm_flag = 0;
 1953     if (sa_type == 0 && (t->system_area_options & 3) == 2) {
 1954         do_isohybrid = 1;
 1955 
 1956         /* >>> Coordinate with partprepend writer */
 1957         /* <<< provisory trap */
 1958         if (t->mbr_req_count > 0)
 1959             return ISO_BOOT_MBR_OVERLAP;
 1960 
 1961         /* If own APM is desired, set flag bit0 to prevent writing of Block0
 1962            which would interfere with the own Block0 of isohybrid.
 1963         */
 1964         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
 1965         if (ret < 0)
 1966             return ret;
 1967         if (apm_count > 0)
 1968             apm_flag |= 1;
 1969     }
 1970 
 1971     ret = iso_write_apm(t, img_blocks, buf, apm_flag);
 1972     if (ret < 0) {
 1973         iso_msg_submit(t->image->id, ret, 0,
 1974                        "Cannot set up Apple Partition Map");
 1975         return ret;
 1976     }
 1977     ret = iso_write_mbr(t, img_blocks, buf);
 1978     if (ret < 0) {
 1979         iso_msg_submit(t->image->id, ret, 0,
 1980                        "Cannot set up MBR partition table");
 1981         return ret;
 1982     }
 1983     if (t->mbr_req_count > 0) {
 1984         if (sa_type != 0)
 1985             return ISO_NON_MBR_SYS_AREA;
 1986         risk_of_ee = 1;
 1987     }
 1988 
 1989     if (t->gpt_backup_outside)
 1990         gpt_blocks = t->total_size / BLOCK_SIZE +
 1991                      (flag & 1) * t->opts->ms_block;
 1992     else
 1993         gpt_blocks = img_blocks;
 1994     ret = iso_write_gpt(t, gpt_blocks, buf);
 1995     if (ret < 0) {
 1996         iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT");
 1997         return ret;
 1998     }
 1999 
 2000     if (sa_type == 0 && (t->system_area_options & 1)) {
 2001         if (t->mbr_req_count == 0){
 2002             /* Write GRUB protective msdos label, i.e. a simple partition
 2003                table */
 2004             if (t->gpt_req_count > 0 && ! t->opts->part_like_isohybrid) {
 2005                 part_type = 0xee;
 2006                 pml_blocks = gpt_blocks;
 2007             } else {
 2008                 part_type = 0xcd;
 2009                 if (t->opts->iso_mbr_part_type >= 0 &&
 2010                     t->opts->iso_mbr_part_type <= 255)
 2011                     part_type= t->opts->iso_mbr_part_type;
 2012                 pml_blocks = img_blocks;
 2013             }
 2014             ret = make_grub_msdos_label(pml_blocks, t->partition_secs_per_head,
 2015                                         t->partition_heads_per_cyl,
 2016                                         (uint8_t) part_type, buf, 0);
 2017             if (ret != ISO_SUCCESS) /* error should never happen */
 2018                return ISO_ASSERT_FAILURE;
 2019             risk_of_ee = 1;
 2020         } else if (t->gpt_req_count > 0) {
 2021 
 2022            /* >>> ??? change first partition type to 0xee */;
 2023 
 2024         }
 2025     } else if (do_isohybrid) {
 2026         /* Patch externally provided system area as isohybrid MBR */
 2027         if (t->catalog == NULL || t->system_area_data == NULL) {
 2028             /* isohybrid makes only sense together with ISOLINUX boot image
 2029                and externally provided System Area.
 2030             */
 2031             return ISO_ISOLINUX_CANT_PATCH;
 2032         }
 2033 
 2034         if (gpt_count > 0 || apm_count > 0)
 2035             part_type = 0x00;
 2036         else {
 2037             part_type = 0x17;
 2038             if (t->opts->iso_mbr_part_type >= 0 &&
 2039                 t->opts->iso_mbr_part_type <= 255)
 2040                 part_type= t->opts->iso_mbr_part_type;
 2041         }
 2042 
 2043         if (t->opts->appended_as_gpt && t->have_appended_partitions) {
 2044             part_type = 0xee;
 2045             risk_of_ee = 1;
 2046             img_blocks = gpt_blocks;
 2047             no_boot_mbr = 2;
 2048         }
 2049 
 2050         /* >>> ??? Why is partition_offset 0 here ?
 2051                    It gets adjusted later by iso_offset_partition_start()
 2052                    Would it harm to give the real offset here ?
 2053         */;
 2054 
 2055         ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf,
 2056                                 1 | no_boot_mbr);
 2057         if (ret != 1)
 2058             return ret;
 2059     } else if (sa_type == 1) {
 2060         ret = make_mips_volume_header(t, buf, 0);
 2061         if (ret != ISO_SUCCESS)
 2062             return ret;
 2063     } else if (sa_type == 2) {
 2064         ret = make_mipsel_boot_block(t, buf, 0);
 2065         if (ret != ISO_SUCCESS)
 2066             return ret;
 2067     } else if (sa_type == 3) {
 2068         ret = make_sun_disk_label(t, buf, 0);
 2069         if (ret != ISO_SUCCESS)
 2070             return ret;
 2071     } else if (sa_type == 4 || sa_type == 5) {
 2072         /* (By coincidence, sa_type and PALO header versions match) */
 2073         ret = make_hppa_palo_sector(t, buf, sa_type, 0);
 2074         if (ret != ISO_SUCCESS)
 2075             return ret;
 2076     } else if (sa_type == 6) {
 2077         ret = make_dec_alpha_sector(t, buf, 0);
 2078         if (ret != ISO_SUCCESS)
 2079             return ret;
 2080     } else if ((t->opts->partition_offset > 0 || will_append) &&
 2081                sa_type == 0 && t->mbr_req_count == 0) {
 2082         /* Write a simple partition table. */
 2083         part_type = 0xcd;
 2084         if (t->opts->iso_mbr_part_type >= 0 &&
 2085             t->opts->iso_mbr_part_type <= 255)
 2086             part_type= t->opts->iso_mbr_part_type;
 2087         ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
 2088                                     t->partition_heads_per_cyl,
 2089                                     (uint8_t) part_type, buf, 2);
 2090         if (ret != ISO_SUCCESS) /* error should never happen */
 2091             return ISO_ASSERT_FAILURE;
 2092         risk_of_ee = 1;
 2093         if (t->opts->appended_as_gpt && t->have_appended_partitions) {
 2094 
 2095             /* >>> ??? Do this in any case of  t->gpt_req_count > ? */;
 2096 
 2097             /* Re-write partition entry 1 : protective MBR for GPT */
 2098             part_type = 0xee;
 2099             risk_of_ee = 1;
 2100             ret = write_mbr_partition_entry(1, part_type,
 2101                         (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1, 
 2102                         t->partition_secs_per_head, t->partition_heads_per_cyl,
 2103                         buf, 2);
 2104             if (ret < 0)
 2105                 return ret;
 2106         } else if (t->opts->partition_offset == 0) {
 2107             /* Re-write partition entry 1 : start at 0, type Linux */
 2108             blk = ((uint64_t) img_blocks) * 4 - t->post_iso_part_pad / 512;
 2109             part_type = 0x83;
 2110             if (t->opts->iso_mbr_part_type >= 0 &&
 2111                 t->opts->iso_mbr_part_type <= 255)
 2112                 part_type= t->opts->iso_mbr_part_type;
 2113             ret = write_mbr_partition_entry(1, part_type, (uint64_t) 0, blk,
 2114                         t->partition_secs_per_head, t->partition_heads_per_cyl,
 2115                         buf, 2);
 2116             if (ret < 0)
 2117                 return ret;
 2118         }
 2119     }
 2120 
 2121     /* Check for protective MBR in mbr_req and adjust to GPT size */
 2122     if (t->gpt_req_count > 0 && sa_type == 0 && t->mbr_req_count == 1) {
 2123         if (t->mbr_req[0]->type_byte == 0xee && buf[450] == 0xee &&
 2124             t->mbr_req[0]->desired_slot <= 1) {
 2125             part_type = 0xee;
 2126             risk_of_ee = 1;
 2127             ret = write_mbr_partition_entry(1, part_type,
 2128                         (uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1, 
 2129                         t->partition_secs_per_head, t->partition_heads_per_cyl,
 2130                         buf, 2);
 2131             if (ret < 0)
 2132                 return ret;
 2133         }
 2134     }
 2135 
 2136     if (t->opts->partition_offset > 0 && sa_type == 0 &&
 2137         t->mbr_req_count == 0) {
 2138         /* Adjust partition table to partition offset.
 2139            With t->mbr_req_count > 0 this has already been done,
 2140         */
 2141 
 2142 #ifndef Libisofs_appended_partitions_inlinE
 2143 
 2144         img_blocks = t->curblock;          /* value might have been altered */
 2145 
 2146 #else
 2147 
 2148         /* A change of t->curblock does not matter in this case */
 2149 
 2150 #endif
 2151 
 2152         if (part_type == 0xee && t->gpt_req_count > 0) {
 2153             mbrp1_blocks = t->total_size / BLOCK_SIZE +
 2154                            (flag & 1) * t->opts->ms_block;
 2155             offset_flag |= 2 | 1; /* protective MBR, no other partitions */
 2156         } else {
 2157             mbrp1_blocks = img_blocks;
 2158         }
 2159         ret = iso_offset_partition_start(mbrp1_blocks, t->post_iso_part_pad,
 2160                                          t->opts->partition_offset,
 2161                                          t->partition_secs_per_head,
 2162                                          t->partition_heads_per_cyl, buf,
 2163                                          offset_flag);
 2164         if (ret != ISO_SUCCESS) /* error should never happen */
 2165             return ISO_ASSERT_FAILURE;
 2166     }
 2167 
 2168     /* This possibly overwrites the non-mbr_req partition table entries
 2169        made so far. Overwriting those from t->mbr_req is not allowed.
 2170     */
 2171     if (sa_type == 3 ||
 2172         !(t->opts->appended_as_gpt || t->opts->appended_as_apm)) {
 2173         for (i = first_partition - 1; i <= last_partition - 1; i++) {
 2174             if (t->opts->appended_partitions[i] == NULL)
 2175         continue;
 2176             if (i < t->mbr_req_count)
 2177                 return ISO_BOOT_MBR_COLLISION;
 2178             if (sa_type == 3) {
 2179                 ret = write_sun_partition_entry(i + 1,
 2180                         t->opts->appended_partitions,
 2181                         t->appended_part_start, t->appended_part_size,
 2182                         ISO_SUN_CYL_SIZE,
 2183                         buf, t->opts->appended_partitions[i][0] == 0);
 2184             } else {
 2185                 ret = write_mbr_partition_entry(i + 1,
 2186                         t->opts->appended_part_types[i],
 2187                         (uint64_t) t->appended_part_start[i],
 2188                         (uint64_t) t->appended_part_size[i],
 2189                         t->partition_secs_per_head, t->partition_heads_per_cyl,
 2190                         buf, 0);
 2191             }
 2192             if (ret < 0)
 2193                 return ret;
 2194         }
 2195     }
 2196 
 2197     if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) {
 2198         /* Patch MBR for GRUB2 */
 2199     if (t->num_bootsrc <= 0)
 2200             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
 2201                           "No boot image found as jump target for GRUB2 MBR.");
 2202         if (t->bootsrc[0] == NULL)
 2203             return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
 2204           "Cannot refer by GRUB2 MBR to data outside of ISO 9660 filesystem.");
 2205         blk = t->bootsrc[0]->sections[0].block * 4 +
 2206                                                 Libisofs_grub2_mbr_patch_offsT;
 2207         wpt = buf + Libisofs_grub2_mbr_patch_poS;
 2208         for (i = 0; i < 8; i++)
 2209              wpt[i] = blk >> (i * 8);
 2210     }
 2211 
 2212     /* Prevent partition type 0xee if no GPT emerged */
 2213 
 2214     /* >>> ??? check for GPT magic number at byte 512 ff. ? */;
 2215 
 2216     if (sa_type == 0 && ((t->system_area_options & 3) || risk_of_ee) &&
 2217         (t->opts->part_like_isohybrid || t->gpt_req_count == 0) &&
 2218         t->opts->iso_mbr_part_type != 0xee) {
 2219         for (i = 0; i < 4; i++) {
 2220             if (buf[446 + 16 * i + 4] == 0xee) {
 2221                 iso_msgs_submit(0,
 2222                             "Prevented partition type 0xEE in MBR without GPT",
 2223                             0, "WARNING", 0);
 2224                 part_type = 0xcd;
 2225                 if (t->opts->iso_mbr_part_type >= 0 &&
 2226                     t->opts->iso_mbr_part_type <= 255)
 2227                     part_type= t->opts->iso_mbr_part_type;
 2228                 buf[446 + 16 * i + 4] = (uint8_t) part_type;
 2229             }
 2230         }
 2231     }
 2232 
 2233     if (sa_type == 0 && (
 2234         (t->system_area_options & 3) ||
 2235         (t->system_area_options & (1 << 14)) ||
 2236         (((t->system_area_options >> 10) & 15) != 1 &&
 2237          (t->system_area_options & (1 << 15)))
 2238         )) {
 2239         /* This is an MBR which shall have a bootable/active flag
 2240            protective-msdos-label, isohybrid, grub2-mbr, mbr-force-bootable
 2241          */
 2242         for (i = 0; i < 4; i++)
 2243             if (buf[446 + 16 * i] & 0x80)
 2244         break;
 2245         if (i >= 4) { /* no bootable/active flag set yet */
 2246             for (i = 0; i < 4; i++) {
 2247                 if ((!mbr_part_slot_is_unused(buf + 446 + 16 * i)) &&
 2248                     buf[446 + 16 * i + 4] != 0xee &&
 2249                     buf[446 + 16 * i + 4] != 0xef) {
 2250                     buf[446 + 16 * i] |= 0x80;
 2251             break;
 2252                 }
 2253             }
 2254             if (i >= 4) { /* still no bootable/active flag set */
 2255                 if (t->system_area_options & (1 << 15)) /* Force it */
 2256                     iso_dummy_mbr_partition(buf, 0);
 2257             }
 2258         }
 2259     }
 2260 
 2261     if ((((t->system_area_options >> 2) & 0x3f) == 0 &&
 2262          (t->system_area_options & 3) == 1) ||
 2263         t->opts->partition_offset > 0) {
 2264         /* Protective MBR || partition offset
 2265            ISO will not be a partition or add-on session.
 2266            It can span the whole image.
 2267         */
 2268         t->pvd_size_is_total_size = 1;
 2269     }
 2270 
 2271     return ISO_SUCCESS;
 2272 }
 2273 
 2274 /* Choose *heads_per_cyl so that
 2275    - *heads_per_cyl * secs_per_head * 1024 >= imgsize / 512
 2276    - *heads_per_cyl * secs_per_head is divisible by 4
 2277    - it is as small as possible (to reduce alignment overhead)
 2278    - it is <= 255
 2279    @return 1= success , 0= cannot achieve goals
 2280 */
 2281 static
 2282 int try_sph(off_t imgsize, int secs_per_head, int *heads_per_cyl, int flag)
 2283 {
 2284     off_t hd_blocks, hpc;
 2285 
 2286     hd_blocks= imgsize / 512;
 2287     hpc = hd_blocks / secs_per_head / 1024;
 2288     if (hpc * secs_per_head * 1024 < hd_blocks)
 2289         hpc++;
 2290     if ((secs_per_head % 4) == 0) {
 2291         ;
 2292     } else if ((secs_per_head % 2) == 0) {
 2293         hpc += (hpc % 2);
 2294     } else if(hpc % 4) {
 2295         hpc += 4 - (hpc % 4);
 2296     }
 2297     if (hpc > 255)
 2298         return 0;
 2299     *heads_per_cyl = hpc;
 2300     return 1;
 2301 }
 2302 
 2303 int iso_align_isohybrid(Ecma119Image *t, int flag)
 2304 {
 2305     int sa_type, ret, always_align;
 2306     uint32_t img_blocks;
 2307     off_t imgsize, cylsize = 0, frac;
 2308     char *msg = NULL;
 2309 
 2310 #ifdef Libisofs_part_align_writeR
 2311     int fap, lap, app_part_count;
 2312 #endif
 2313 
 2314     LIBISO_ALLOC_MEM(msg, char, 160);
 2315     sa_type = (t->system_area_options >> 2) & 0x3f;
 2316     if (sa_type != 0)
 2317         {ret = ISO_SUCCESS; goto ex;}
 2318     always_align = (t->system_area_options >> 8) & 3;
 2319 
 2320     if (!t->gpt_backup_outside) {
 2321         /* Take into account the backup GPT */;
 2322         ret = precompute_gpt(t);
 2323         if (ret < 0)
 2324             goto ex;
 2325     }
 2326 
 2327 #ifdef Libisofs_part_align_writeR
 2328 
 2329     /* If partitions get appended then t->opts->tail_blocks and
 2330        t->gpt_backup_size come after the alignment padding.
 2331     */
 2332     app_part_count = iso_count_appended_partitions(t, &fap, &lap);
 2333     img_blocks = t->curblock;
 2334     if (app_part_count == 0)
 2335         img_blocks += t->opts->tail_blocks + t->gpt_backup_size;
 2336 
 2337 #else
 2338 
 2339     img_blocks = t->curblock + t->opts->tail_blocks + t->gpt_backup_size;
 2340 
 2341 #endif
 2342 
 2343     imgsize = ((off_t) img_blocks) * (off_t) 2048;
 2344     if ((!(t->opts->appended_as_gpt && t->have_appended_partitions))
 2345         && ((t->system_area_options & 3) || always_align)
 2346         && (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head
 2347                     * 1024) * (off_t) 512 < imgsize) {
 2348         /* Choose small values which can represent the image size */
 2349         /* First try 32 sectors per head */
 2350         ret = try_sph(imgsize, 32, &(t->partition_heads_per_cyl), 0);
 2351         if (ret == 1) {
 2352             t->partition_secs_per_head = 32;
 2353         } else {
 2354             /* Did not work with 32. Try 63 */
 2355             t->partition_secs_per_head = 63;
 2356             ret = try_sph(imgsize, 63, &(t->partition_heads_per_cyl), 0);
 2357             if (ret != 1)
 2358                 t->partition_heads_per_cyl = 255;
 2359         }
 2360         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head *512;
 2361         frac = imgsize % cylsize;
 2362         sprintf(msg, "Automatically adjusted MBR geometry to %d/%d/%d",
 2363                       (int) (imgsize / cylsize + !!frac),
 2364                       t->partition_heads_per_cyl, t->partition_secs_per_head);
 2365         iso_msgs_submit(0, msg, 0, "NOTE", 0);
 2366     }
 2367 
 2368     if (always_align == 2)
 2369         {ret = ISO_SUCCESS; goto ex;}
 2370 
 2371     cylsize = 0;
 2372     if (t->catalog != NULL &&
 2373                (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
 2374         /* Check for isolinux image with magic number of 3.72 and produce
 2375            an MBR from our built-in template. (Deprecated since 31 Mar 2010)
 2376         */
 2377         if (img_blocks >= 0x40000000)
 2378             {ret = ISO_SUCCESS; goto ex;}
 2379         cylsize = 64 * 32 * 512;
 2380 
 2381     } else if (t->system_area_options & 2) {
 2382         /* Patch externally provided system area as isohybrid MBR */
 2383         if (t->catalog == NULL || t->system_area_data == NULL) {
 2384             /* isohybrid makes only sense together with ISOLINUX boot image
 2385                and externally provided System Area.
 2386             */
 2387             {ret = ISO_ISOLINUX_CANT_PATCH; goto ex;}
 2388         }
 2389         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
 2390                   * 512;
 2391     } else if (always_align) {
 2392         cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
 2393                   * 512;
 2394     } 
 2395     if (cylsize == 0)
 2396         {ret = ISO_SUCCESS; goto ex;}
 2397     if (((double) imgsize) / (double) cylsize > 1024.0) {
 2398         iso_msgs_submit(0,
 2399                   "Image size exceeds 1024 cylinders. Cannot align partition.",
 2400                   0, "WARNING", 0);
 2401         iso_msgs_submit(0,
 2402                "There are said to be BIOSes which will not boot this via MBR.",
 2403                0, "WARNING", 0);
 2404         {ret = ISO_SUCCESS; goto ex;}
 2405     }
 2406 
 2407     frac = imgsize % cylsize;
 2408     imgsize += (frac > 0 ? cylsize - frac : 0);
 2409 
 2410     frac = imgsize - ((off_t) img_blocks) * (off_t) 2048;
 2411     if (frac == 0)
 2412         {ret = ISO_SUCCESS; goto ex;}
 2413     t->post_iso_part_pad = 0;
 2414     if (frac % 2048) {
 2415         t->post_iso_part_pad = 2048 - frac % 2048;
 2416         sprintf(msg,
 2417  "Cylinder aligned image size is not divisible by 2048. Have to add %d bytes.",
 2418                 t->post_iso_part_pad);
 2419         iso_msgs_submit(0, msg, 0, "WARNING", 0);
 2420     }
 2421 
 2422 #ifdef Libisofs_part_align_writeR
 2423 
 2424     t->part_align_blocks = (frac + 2047) / 2048;
 2425 
 2426 #else
 2427 
 2428     t->opts->tail_blocks += (frac + 2047) / 2048;
 2429 
 2430 #endif /* ! Libisofs_part_align_writeR */
 2431 
 2432     ret = ISO_SUCCESS;
 2433 ex:;
 2434     LIBISO_FREE_MEM(msg);
 2435     return ret;
 2436 }
 2437 
 2438 
 2439 int iso_register_apm_entry(struct iso_apm_partition_request **req_array,
 2440                            int *apm_req_count,
 2441                            struct iso_apm_partition_request *req, int flag)
 2442 {
 2443     struct iso_apm_partition_request *entry;
 2444 
 2445     if (*apm_req_count >= ISO_APM_ENTRIES_MAX)
 2446         return ISO_BOOT_TOO_MANY_APM;
 2447     entry = calloc(1, sizeof(struct iso_apm_partition_request));
 2448     if (entry == NULL)
 2449         return ISO_OUT_OF_MEM;
 2450     
 2451     memcpy(entry, req, sizeof(struct iso_apm_partition_request));
 2452     req_array[*apm_req_count] = entry;
 2453     (*apm_req_count)++;
 2454     return ISO_SUCCESS;
 2455 }
 2456 
 2457 
 2458 int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array,
 2459                            int *mbr_req_count,
 2460                            struct iso_mbr_partition_request *req, int flag)
 2461 {
 2462     struct iso_mbr_partition_request *entry;
 2463 
 2464     if (*mbr_req_count >= ISO_MBR_ENTRIES_MAX)
 2465         return ISO_BOOT_TOO_MANY_MBR;
 2466     entry = calloc(1, sizeof(struct iso_mbr_partition_request));
 2467     if (entry == NULL)
 2468         return ISO_OUT_OF_MEM;
 2469     
 2470     memcpy(entry, req, sizeof(struct iso_mbr_partition_request));
 2471     req_array[*mbr_req_count] = entry;
 2472     (*mbr_req_count)++;
 2473     return ISO_SUCCESS;
 2474 }
 2475 
 2476 int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array,
 2477                            int *gpt_req_count,
 2478                            struct iso_gpt_partition_request *req, int flag)
 2479 {
 2480     struct iso_gpt_partition_request *entry;
 2481 
 2482     if (*gpt_req_count >= ISO_GPT_ENTRIES_MAX)
 2483         return ISO_BOOT_TOO_MANY_GPT;
 2484     entry = calloc(1, sizeof(struct iso_gpt_partition_request));
 2485     if (entry == NULL)
 2486         return ISO_OUT_OF_MEM;
 2487     
 2488     memcpy(entry, req, sizeof(struct iso_gpt_partition_request));
 2489     req_array[*gpt_req_count] = entry;
 2490     (*gpt_req_count)++;
 2491     return ISO_SUCCESS;
 2492 }
 2493 
 2494 #ifdef Libisofs_with_uuid_generatE
 2495 
 2496 static void swap_uuid(void *u_pt)
 2497 {
 2498      uint8_t tr, *u;
 2499 
 2500      u = (uint8_t *) u_pt;
 2501      tr = u[0]; u[0] = u[3]; u[3] = tr;
 2502      tr = u[1]; u[1] = u[2]; u[2] = tr;
 2503      tr = u[4]; u[4] = u[5]; u[5] = tr;
 2504      tr = u[6]; u[6] = u[7]; u[7] = tr;
 2505 }
 2506 
 2507 #endif /* Libisofs_with_uuid_generatE */
 2508 
 2509 
 2510 /* CRC-32 as of GPT and Ethernet.
 2511    Parameters are deduced from a table driven implementation in isohybrid.c
 2512 */
 2513 uint32_t iso_crc32_gpt(unsigned char *data, int count, int flag)
 2514 {   
 2515     unsigned int acc, top, result = 0;
 2516     long int i;
 2517 
 2518     /* Chosen so that the CRC of 0 bytes of input is 0x00000000 */
 2519     acc = 0x46af6449;
 2520 
 2521     /* Process data bits and flush numerator by 32 zero bits */
 2522     for (i = 0; i < count * 8 + 32; i++) {
 2523         top = acc & 0x80000000;
 2524         acc = (acc << 1);
 2525         if (i < count * 8)
 2526             /* The least significant bits of input bytes get processed first */
 2527             acc |= ((data[i / 8] >> (i % 8)) & 1);
 2528         if (top)
 2529             /* Division by the generating polynomial */
 2530             acc ^= 0x04c11db7;
 2531     }
 2532     /* Mirror residue bits */
 2533     for (i = 0; i < 32; i++)
 2534         if (acc & (1 << i))
 2535             result |= 1 << (31 - i);
 2536     /* Return bit complement */
 2537     return result ^ 0xffffffff;
 2538 }
 2539 
 2540 void iso_mark_guid_version_4(uint8_t *u)
 2541 {
 2542     /* Mark as UUID version 4. RFC 4122 says u[6], but UEFI prescribes
 2543        bytes 6 and 7 to be swapped.
 2544     */
 2545     u[7] = (u[7] & 0x0f) | 0x40;
 2546 
 2547     /* Variant is "1 0 x" as described in RFC 4122.
 2548     */
 2549     u[8] = (u[8] & 0x3f) | 0x80;
 2550 
 2551     return;
 2552 }
 2553 
 2554 void iso_generate_gpt_guid(uint8_t guid[16])
 2555 {
 2556 
 2557 #ifdef Libisofs_with_uuid_generatE
 2558 
 2559     uuid_t u;
 2560 
 2561     uuid_generate(u);
 2562     swap_uuid((void *) u);
 2563     memcpy(guid, u, 16);
 2564 
 2565 #else
 2566 
 2567     uint8_t *u;
 2568     /* produced by uuid_generate() and byte-swapped to UEFI specs */
 2569     static uint8_t uuid_template[16] = {
 2570         0xee, 0x29, 0x9d, 0xfc, 0x65, 0xcc, 0x7c, 0x40,
 2571         0x92, 0x61, 0x5b, 0xcd, 0x6f, 0xed, 0x08, 0x34
 2572     };
 2573     uint32_t rnd, salt;
 2574     struct timeval tv;
 2575     pid_t pid;
 2576     int i, ret, fd;
 2577 
 2578     u = guid;
 2579 
 2580     /* First try /dev/urandom
 2581     */
 2582     fd = open("/dev/urandom", O_RDONLY | O_BINARY);
 2583     if (fd == -1)
 2584         goto fallback;
 2585     ret = read(fd, u, 16);
 2586     if (ret != 16) {
 2587         close(fd);
 2588         goto fallback;
 2589     }
 2590     close(fd);
 2591     iso_mark_guid_version_4(u);
 2592     return;
 2593 
 2594 
 2595 fallback:;
 2596     pid = getpid();
 2597     salt = iso_crc32_gpt((unsigned char *) &guid, sizeof(uint8_t *), 0) ^ pid; 
 2598 
 2599     /* This relies on the uniqueness of the template and the rareness of
 2600        bootable ISO image production via libisofs. Estimated 48 bits of
 2601        entropy should influence the production of a single day. 
 2602        So first collisions are to be expected with about 16 million images
 2603        per day.
 2604     */
 2605     memcpy(u, uuid_template, 16);
 2606     gettimeofday(&tv, NULL);
 2607     for (i = 0; i < 4; i++)
 2608         u[i] = (salt >> (8 * i)) & 0xff;
 2609     for (i = 0; i < 2; i++)
 2610         u[4 + i] = (pid >> (8 * i)) & 0xff;
 2611     u[6] = ((salt >> 8) ^ (pid >> 16)) & 0xff;
 2612     rnd = ((0xffffff & tv.tv_sec) << 8) |
 2613           (((tv.tv_usec >> 16) ^ (salt & 0xf0)) & 0xff);
 2614     for (i = 0; i < 4; i++)
 2615         u[10 + i] ^= (rnd >> (8 * i)) & 0xff;
 2616     u[14] ^= (tv.tv_usec >> 8) & 0xff;
 2617     u[15] ^= tv.tv_usec & 0xff;
 2618 
 2619     iso_mark_guid_version_4(u);
 2620     return;
 2621 
 2622 #endif /* ! Libisofs_with_uuid_generatE */    
 2623 
 2624 }
 2625 
 2626 void iso_gpt_uuid(Ecma119Image *t, uint8_t uuid[16])
 2627 {
 2628     if (t->gpt_uuid_counter == 0)
 2629         iso_generate_gpt_guid(t->gpt_uuid_base);
 2630 
 2631     memcpy(uuid, t->gpt_uuid_base, 16);
 2632 
 2633     /* Previous implementation changed only byte 9. So i expand it by applying
 2634        the counter in little-endian style.
 2635     */
 2636     uuid[9] ^= t->gpt_uuid_counter & 0xff;
 2637     uuid[10] ^= (t->gpt_uuid_counter >> 8) & 0xff;
 2638     uuid[11] ^= (t->gpt_uuid_counter >> 16) & 0xff;
 2639     uuid[12] ^= (t->gpt_uuid_counter >> 24) & 0xff;
 2640     t->gpt_uuid_counter++;
 2641     return;
 2642 }
 2643 
 2644 int assess_appended_gpt(Ecma119Image *t, int flag)
 2645 {
 2646     static uint8_t basic_data_uuid[16] = {
 2647         0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
 2648         0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
 2649     };
 2650     static uint8_t efi_sys_uuid[16] = {
 2651        0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
 2652        0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
 2653     };
 2654     static uint8_t hfs_plus_uuid[16] = {
 2655         0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
 2656         0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
 2657     };
 2658     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 2659     int i, ret, do_apm = 0, do_gpt = 0, index, already_in_gpt = 0;
 2660     uint8_t gpt_name[72], *type_uuid;
 2661     char apm_type[33];
 2662 
 2663 #ifndef Libisofs_appended_partitions_inlinE
 2664     if (!t->gpt_backup_outside)
 2665         return 2;
 2666 #endif
 2667 
 2668     if ((t->apm_req_count > 0 && t->opts->part_like_isohybrid) ||
 2669        (t->have_appended_partitions && t->opts->appended_as_apm))
 2670        do_apm = 1;
 2671     if (t->gpt_req_count > 0 ||
 2672         (t->have_appended_partitions && t->opts->appended_as_gpt))
 2673        do_gpt = 1;
 2674 
 2675     if (do_apm == 0 && do_gpt == 0)
 2676             return 2;
 2677 
 2678     /* Represent appended partitions */
 2679     for (i = 0; i <= 3; i++) {
 2680         if (t->opts->appended_partitions[i] == NULL)
 2681     continue;
 2682         if (do_apm) {
 2683             memset(gpt_name, 0, 32);
 2684             sprintf((char *) gpt_name, "Appended%d", i + 1);
 2685             strcpy(apm_type, "Data");
 2686             if (t->opts->appended_part_gpt_flags[i] & 1) {
 2687                 if (memcmp(t->opts->appended_part_type_guids[i], hfs_plus_uuid,
 2688                            16) == 0)
 2689                     strcpy(apm_type, "Apple_HFS");
 2690             }
 2691             ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
 2692                             t->appended_part_start[i] * t->hfsp_iso_block_fac,
 2693                             t->appended_part_size[i] * t->hfsp_iso_block_fac,
 2694                             (char *) gpt_name, apm_type);
 2695             if (ret < 0)
 2696                 return ret;
 2697         }
 2698         if (do_gpt)
 2699             already_in_gpt = iso_find_gpt_entry(t->gpt_req, t->gpt_req_count,
 2700                                     ((uint64_t) t->appended_part_start[i]) * 4,
 2701                                     ((uint64_t) t->appended_part_size[i]) * 4,
 2702                                     &index, 0);
 2703         if (do_gpt && !already_in_gpt) {
 2704             memset(gpt_name, 0, 72);
 2705             sprintf((char *) gpt_name, "Appended%d", i + 1);
 2706             iso_ascii_utf_16le(gpt_name);
 2707             if (t->opts->appended_part_gpt_flags[i] & 1)
 2708                 type_uuid = t->opts->appended_part_type_guids[i];
 2709             else if (t->opts->appended_part_types[i] == 0xef)
 2710                 type_uuid = efi_sys_uuid;
 2711             else
 2712                 type_uuid = basic_data_uuid;
 2713             ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 2714                                   ((uint64_t) t->appended_part_start[i]) * 4,
 2715                                   ((uint64_t) t->appended_part_size[i]) * 4,
 2716                                   type_uuid, zero_uuid,
 2717                                   (uint64_t) 0, gpt_name);
 2718             if (ret < 0)
 2719                 return ret;
 2720         }
 2721     }
 2722     return ISO_SUCCESS;
 2723 }
 2724 
 2725 /* Probably already called by tail_writer_compute_data_blocks via
 2726    iso_align_isohybrid
 2727 */
 2728 static int precompute_gpt(Ecma119Image *t)
 2729 {
 2730     uint32_t gpt_part_start;
 2731     int ret, sa_type;
 2732     int gpt_count, gpt_idx[128], apm_count;
 2733 
 2734     /* Avoid repetition by  gpt_tail_writer_compute_data_blocks */
 2735     t->gpt_is_computed = 1;
 2736 
 2737 
 2738     /* Assess APM and GPT requests of isohybrid */
 2739     sa_type = (t->system_area_options >> 2) & 0x3f;
 2740     if (sa_type == 0 && (t->system_area_options & 3) == 2) {
 2741 
 2742         /* >>> ISOHYBRID :
 2743                Shall isohybrid be combinable with other APM and GPT requesters ?
 2744         */;
 2745         /* <<< provisorily: Not compatible */
 2746         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
 2747         if (ret < 0)
 2748             return ret;
 2749         if (t->gpt_req_count > 0 && gpt_count > 0)
 2750             return ISO_BOOT_GPT_OVERLAP;
 2751         if (t->apm_req_count > 0 && apm_count > 0)
 2752             return ISO_BOOT_APM_OVERLAP;
 2753         /* Register the GPT and APM partition entries */
 2754         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 1);
 2755         if (ret < 0)
 2756             return ret;
 2757     }
 2758 
 2759     /* With part_like_isohybrid:
 2760        If no GPT is registered yet, and MBR, but neither CHRP nor ISOLINUX
 2761        isohybrid is desired, then try to apply the isohybrid GPT and APM flags
 2762        nevertheless. Avoid an overall ISO image GPT partition.
 2763     */
 2764     if (t->opts->part_like_isohybrid && t->gpt_req_count <= 0 &&
 2765         ((t->system_area_options >> 2) & 0x3f) == 0 &&
 2766         ((t->system_area_options >> 10) & 0xf) != 1 &&
 2767         (!(t->system_area_options & 2))) {
 2768 
 2769         ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count,
 2770                                        1 | ((t->apm_req_count > 0) << 1) | 4);
 2771         if (ret <= 0)
 2772             return ret;
 2773         t->apm_req_flags |= 2; /* Do not fill APM gaps,
 2774                                   do not adjust final APM partition size */
 2775     }
 2776 
 2777     /* Assess impact of appended partitions on GPT */
 2778     ret = assess_appended_gpt(t, 0);
 2779     if (ret < 0)
 2780         return ret;
 2781 
 2782     /* Rectify APM requests early in order to learn the size of GPT.
 2783        iso_write_apm() relies on this being already done here.
 2784        So perform even if no GPT is required.
 2785     */
 2786     ret = rectify_apm(t);
 2787     if (ret < 0)
 2788         return ret;
 2789 
 2790 #ifdef NIX
 2791     /* Disabled */
 2792     
 2793     /* <<< ts B20526 : Dummy mock-up */
 2794     if (t->gpt_req_count <= 0) { 
 2795 
 2796         /* <<< ??? Move to system_area.h and publish as macro ?
 2797                    Or to make_isohybrid_mbr.c ?
 2798         */
 2799         static uint8_t hfs_uuid[16] = {
 2800             0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
 2801             0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
 2802         };
 2803         static uint8_t basic_data_uuid[16] = {
 2804             0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
 2805             0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
 2806         };
 2807 
 2808         uint8_t gpt_name[72];
 2809         static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 2810         static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
 2811 
 2812         memset(gpt_name, 0, 72);
 2813         gpt_name[0] = 'T'; gpt_name[2] = '1';
 2814         strcpy((char *) gpt_name, "GPT Test 1");
 2815         iso_ascii_utf_16le(gpt_name);
 2816         /*
 2817         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 2818                                   (uint64_t) (16 * 4),  (uint64_t) (20 * 4),
 2819                                   hfs_uuid, zero_uuid, gpt_flags, gpt_name);
 2820         / * Caution: Size 90 causes intentional partition overlap error * /
 2821         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 2822                                   (uint64_t) (30 * 4), (uint64_t) (90 * 4),
 2823                                   hfs_uuid, zero_uuid,
 2824                                   gpt_flags, gpt_name);
 2825         */ 
 2826         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 2827                                   (uint64_t) (30 * 4),  (uint64_t) (40 * 4), 
 2828                                   hfs_uuid, zero_uuid,
 2829                                   gpt_flags, gpt_name);
 2830         if (ret < 0)
 2831             return ret;
 2832         strcpy((char *) gpt_name, "GPT Test 2");
 2833         iso_ascii_utf_16le(gpt_name);
 2834         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
 2835                                   (uint64_t) (110 * 4),  (uint64_t) (60 * 4), 
 2836                                   basic_data_uuid, zero_uuid,
 2837                                   gpt_flags, gpt_name);
 2838         if (ret < 0)
 2839             return ret;
 2840     }
 2841 #endif /* NIX */
 2842 
 2843     /* Is a GPT requested ? */
 2844     t->gpt_backup_end = 0;
 2845     t->gpt_max_entries = 0;
 2846     if (t->gpt_req_count == 0)
 2847         return ISO_SUCCESS;
 2848 
 2849     /* Determine GPT partition start in System Area, */
 2850     gpt_part_start = 0;
 2851     if (t->apm_req_count > 0) {
 2852         if (t->opts->apm_block_size == 0)
 2853             t->opts->apm_block_size = 2048;
 2854         gpt_part_start = (t->apm_req_count + 1) *
 2855                          (t->opts->apm_block_size / 512);
 2856     }
 2857     if (gpt_part_start < 2)
 2858         gpt_part_start = 2; 
 2859     else if (gpt_part_start >= 64)
 2860         return ISO_BOOT_TOO_MANY_GPT;
 2861     t->gpt_part_start = gpt_part_start;
 2862 
 2863     /* Necessary number of 2K blocks */
 2864     t->gpt_max_entries = (64 - t->gpt_part_start) * 4;
 2865     t->gpt_backup_size = ((t->gpt_max_entries / 4 + 1) * 512 + 2047) / 2048;
 2866 
 2867     return ISO_SUCCESS;
 2868 }
 2869 
 2870 
 2871 int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer)
 2872 {
 2873     Ecma119Image *t;
 2874     int ret;
 2875 
 2876     if (writer == NULL)
 2877         return ISO_ASSERT_FAILURE;
 2878     t = writer->target;
 2879 
 2880     if (! t->gpt_is_computed) {
 2881         ret = precompute_gpt(t);
 2882         if (ret < 0)
 2883             return ret;
 2884     }
 2885 
 2886     if (t->gpt_backup_outside) {
 2887         t->total_size += t->gpt_backup_size * 2048;
 2888         /* The ISO block number after the backup GPT header */
 2889         t->gpt_backup_end = t->total_size / BLOCK_SIZE + t->opts->ms_block;
 2890     } else {
 2891         t->curblock += t->gpt_backup_size;
 2892         /* The ISO block number after the backup GPT header */
 2893         t->gpt_backup_end = t->curblock;
 2894     }
 2895 
 2896     return ISO_SUCCESS;
 2897 }
 2898 
 2899 
 2900 int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer)
 2901 {
 2902     return ISO_SUCCESS;
 2903 }
 2904 
 2905 
 2906 static int gpt_tail_writer_write_data(IsoImageWriter *writer)
 2907 {
 2908     Ecma119Image *t;
 2909     uint8_t *head, *new_head, *entries;
 2910     uint8_t *backup_buf = NULL;
 2911     uint32_t crc, i;
 2912     uint64_t part_start;
 2913     int ret;
 2914 
 2915     t = writer->target;
 2916     if (t->gpt_backup_end == 0 || t->gpt_max_entries == 0)
 2917         return ISO_SUCCESS; /* No backup GPT area reserved by compute_data() */
 2918 
 2919     backup_buf = calloc(1, t->gpt_backup_size * 2048);
 2920     if (backup_buf == NULL)
 2921         return ISO_OUT_OF_MEM;
 2922     memset(backup_buf, 0, t->gpt_backup_size * 2048);
 2923 
 2924     /* Check whether GPT header block came through */
 2925     head = t->sys_area_as_written + 512;
 2926     if (strncmp((char *) head, "EFI PART", 8) != 0) {
 2927 tampered_head:;
 2928         /* Send error message but do not prevent further image production */
 2929         iso_msgs_submit(0,
 2930                  "GPT header block was altered before writing to System Area.",
 2931                  0, "FAILURE", 0);
 2932         goto write_zeros;
 2933     }
 2934     for (i = 92; i < 512; i++)
 2935         if (head[i])
 2936             goto tampered_head;
 2937 
 2938     /* Patch memorized header block */
 2939     new_head = backup_buf + t->gpt_backup_size * 2048 - 512;
 2940     memcpy(new_head, head, 512);
 2941     /* Exchange "Location of this header" and "Location of header backup" */
 2942     memcpy(new_head + 24, head + 32, 8);
 2943     memcpy(new_head + 32, head + 24, 8);
 2944     /* Point to the backup partition entries */
 2945     part_start = ((uint64_t) t->gpt_backup_end) * 4
 2946                  - 1 - t->gpt_max_entries / 4;
 2947     iso_lsb(new_head + 72, part_start & 0xffffffff, 4);
 2948     iso_lsb(new_head + 76, (part_start >> 32) & 0xffffffff, 4);
 2949 
 2950     /* Compute new header CRC */
 2951     memset(new_head + 16, 0, 4);
 2952     crc = iso_crc32_gpt((unsigned char *) new_head, 92, 0); 
 2953     iso_lsb(new_head + 16, crc, 4);
 2954 
 2955     /* Copy GPT entries */
 2956     entries = t->sys_area_as_written + t->gpt_part_start * 512;
 2957     memcpy(new_head - t->gpt_max_entries * 128,
 2958            entries, t->gpt_max_entries * 128);
 2959               
 2960     ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
 2961     free(backup_buf);
 2962     if (ret < 0)
 2963         return ret;
 2964 
 2965     if (!t->gpt_backup_outside) {
 2966 
 2967         /* >>> Why isn't t->curblock updated ? */;
 2968 
 2969     }
 2970     return ISO_SUCCESS;
 2971 
 2972 write_zeros:;
 2973     ret = iso_write(t, backup_buf, t->gpt_backup_size * 2048);
 2974     free(backup_buf);
 2975     if (ret < 0)
 2976         return ret;
 2977     return ISO_SUCCESS;
 2978 }
 2979 
 2980 
 2981 static int gpt_tail_writer_free_data(IsoImageWriter *writer)
 2982 {
 2983     return ISO_SUCCESS;
 2984 }
 2985 
 2986 
 2987 int gpt_tail_writer_create(Ecma119Image *target)
 2988 {
 2989     IsoImageWriter *writer;
 2990 
 2991     writer = calloc(1, sizeof(IsoImageWriter));
 2992     if (writer == NULL) {
 2993         return ISO_OUT_OF_MEM;
 2994     }
 2995     writer->compute_data_blocks = gpt_tail_writer_compute_data_blocks;
 2996     writer->write_vol_desc = gpt_tail_writer_write_vol_desc;
 2997     writer->write_data = gpt_tail_writer_write_data;
 2998     writer->free_data = gpt_tail_writer_free_data;
 2999     writer->data = NULL;
 3000     writer->target = target;
 3001 
 3002     /* add this writer to image */
 3003     target->writers[target->nwriters++] = writer;
 3004 
 3005     return ISO_SUCCESS;
 3006 }
 3007 
 3008 
 3009 /* ----------------------  Partition Prepend Writer --------------------- */
 3010 
 3011 
 3012 static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
 3013 {
 3014     Ecma119Image *t;
 3015     IsoFileSrc *src;
 3016     int ret, will_have_gpt = 0, with_chrp = 0, i, part_type, keep;
 3017     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 3018     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
 3019     uint8_t gpt_name[72];
 3020     uint64_t part_start;
 3021     off_t start_byte, byte_count;
 3022 
 3023     /* <<< ??? Move to system_area.h and publish as macro ? */
 3024     static uint8_t efi_sys_uuid[16] = {
 3025        0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11,
 3026        0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
 3027     };
 3028 
 3029     if (writer == NULL)
 3030         return ISO_ASSERT_FAILURE;
 3031     t = writer->target;
 3032 
 3033     with_chrp = ((t->system_area_options & 0x3cff) == 0x0400);
 3034     if (t->opts->efi_boot_partition != NULL ||
 3035         t->gpt_req_count > 0) /* Might not catch all cases with GPT */
 3036         will_have_gpt = 1;
 3037 
 3038     if (t->opts->efi_boot_partition != NULL) {
 3039         keep = 0;
 3040         if (t->efi_boot_part_filesrc != NULL) {
 3041             /* A file in the emerging ISO image shall store its content
 3042                as prepended partition.
 3043                Install absolute block addresses and determine partition size.
 3044             */
 3045             src = t->efi_boot_part_filesrc;
 3046             t->efi_boot_part_size = 0;
 3047             for (i = 0; i < src->nsections; i++) {
 3048                 src->sections[i].block = t->curblock + t->efi_boot_part_size;
 3049                 t->efi_boot_part_size += (src->sections[i].size + 2047) / 2048;
 3050             }
 3051             part_start = t->curblock * 4;
 3052         } else {
 3053             ret = compute_partition_size(t, t->opts->efi_boot_partition,
 3054                                          &(t->efi_boot_part_size),
 3055                                          t->opts->efi_boot_part_flag & 1);
 3056             if (ret < 0)
 3057                 return ret;
 3058             part_start = t->curblock * 4;
 3059             if (ret == ISO_SUCCESS + 1) {
 3060                 /* Interval from imported_iso in add-on session will be kept */
 3061                 ret = iso_interval_reader_start_size(t,
 3062                                                   t->opts->efi_boot_partition,
 3063                                                   &start_byte, &byte_count, 0);
 3064                 if (ret < 0)
 3065                     return ret;
 3066                 part_start = start_byte / 512;
 3067                 keep = 1;
 3068             }
 3069         }
 3070         memset(gpt_name, 0, 72);
 3071         strcpy((char *) gpt_name, "EFI boot partition");
 3072         iso_ascii_utf_16le(gpt_name);
 3073         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), part_start,
 3074                                  ((uint64_t) t->efi_boot_part_size) * 4,
 3075                                  efi_sys_uuid, zero_uuid, gpt_flags, gpt_name);
 3076         if (ret < 0)
 3077             return ret;
 3078         if (!keep)
 3079             t->curblock += t->efi_boot_part_size;
 3080     }
 3081 
 3082     if (with_chrp) {
 3083         /* CHRP is not compatible with any other partition in MBR */
 3084         if (t->opts->prep_partition != NULL || t->opts->fat || will_have_gpt ||
 3085             t->mbr_req_count > 0)
 3086             return ISO_BOOT_MBR_OVERLAP;
 3087         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
 3088                                   (uint64_t) 0, (uint64_t) 0, 0x96, 0x80, 0);
 3089         if (ret < 0)
 3090             return ret;
 3091         return ISO_SUCCESS;
 3092     }
 3093 
 3094     part_start = t->curblock * 4;
 3095     keep = 0;
 3096     if (t->opts->prep_partition != NULL) {
 3097         ret = compute_partition_size(t, t->opts->prep_partition,
 3098                                      &(t->prep_part_size),
 3099                                      t->opts->prep_part_flag & 1);
 3100         if (ret < 0)
 3101             return ret;
 3102         if (ret == ISO_SUCCESS + 1) {
 3103             /* Interval from imported_iso in add-on session will be kept */
 3104             ret = iso_interval_reader_start_size(t,
 3105                                                  t->opts->prep_partition,
 3106                                                  &start_byte, &byte_count, 0);
 3107             if (ret < 0)
 3108                 return ret;
 3109             part_start = start_byte / 512;
 3110             keep = 1;
 3111         }
 3112     }
 3113     if (t->prep_part_size > 0 || t->opts->fat || will_have_gpt) {
 3114         /* Protecting MBR entry for ISO start or whole ISO */
 3115         part_type = 0xcd;
 3116         if (t->opts->iso_mbr_part_type >= 0 &&
 3117             t->opts->iso_mbr_part_type <= 255)
 3118             part_type= t->opts->iso_mbr_part_type;
 3119         if (will_have_gpt)
 3120             part_type = 0xee;
 3121         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
 3122                                   will_have_gpt ? (uint64_t) 1 :
 3123                                   ((uint64_t) t->opts->partition_offset) * 4,
 3124                                   (uint64_t) 0, part_type, 0, 0);
 3125         if (ret < 0)
 3126             return ret;
 3127     }
 3128     if (t->prep_part_size > 0) {
 3129         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), part_start,
 3130                                   ((uint64_t) t->prep_part_size) * 4,
 3131                                   0x41, 0, 0);
 3132         if (ret < 0)
 3133             return ret;
 3134         if (!keep) {
 3135             t->curblock += t->prep_part_size;
 3136             part_start = t->curblock * 4;
 3137         } else {
 3138             part_start += t->prep_part_size * 4;
 3139         }
 3140     } else {
 3141         part_start = t->curblock * 4;
 3142     }
 3143     if (t->prep_part_size > 0 || t->opts->fat) {
 3144         /* FAT partition or protecting MBR entry for ISO end */
 3145         ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count),
 3146                                   part_start, (uint64_t) 0,
 3147                                   t->opts->fat ? 0x0c : 0xcd, 0, 0);
 3148         if (ret < 0)
 3149             return ret;
 3150     }
 3151 
 3152     return ISO_SUCCESS;
 3153 }
 3154 
 3155 
 3156 static int partprepend_writer_write_vol_desc(IsoImageWriter *writer)
 3157 {
 3158     return ISO_SUCCESS;
 3159 }
 3160 
 3161 
 3162 static int partprepend_writer_write_data(IsoImageWriter *writer)
 3163 {
 3164     Ecma119Image *t;
 3165     int ret;
 3166 
 3167     t = writer->target;
 3168 
 3169     if (t->opts->efi_boot_partition != NULL && t->efi_boot_part_size) {
 3170 
 3171         if (t->efi_boot_part_filesrc != NULL) {
 3172             ret = iso_filesrc_write_data(t, t->efi_boot_part_filesrc,
 3173                                          NULL, NULL, 0);
 3174         } else {
 3175             ret = iso_write_partition_file(t, t->opts->efi_boot_partition,
 3176                                        (uint32_t) 0, t->efi_boot_part_size,
 3177                                        t->opts->efi_boot_part_flag & 1);
 3178         }
 3179         if (ret < 0)
 3180             return ret;
 3181     }
 3182     if (t->opts->prep_partition != NULL && t->prep_part_size) {
 3183         ret = iso_write_partition_file(t, t->opts->prep_partition,
 3184                                        (uint32_t) 0, t->prep_part_size,
 3185                                        t->opts->prep_part_flag & 1);
 3186         if (ret < 0)
 3187             return ret;
 3188     }
 3189 
 3190     return ISO_SUCCESS;
 3191 }
 3192 
 3193 
 3194 static int partprepend_writer_free_data(IsoImageWriter *writer)
 3195 {
 3196     return ISO_SUCCESS;
 3197 }
 3198 
 3199 
 3200 int partprepend_writer_create(Ecma119Image *target)
 3201 {
 3202     IsoImageWriter *writer;
 3203 
 3204     writer = calloc(1, sizeof(IsoImageWriter));
 3205     if (writer == NULL) {
 3206         return ISO_OUT_OF_MEM;
 3207     }
 3208 
 3209     writer->compute_data_blocks = partprepend_writer_compute_data_blocks;
 3210     writer->write_vol_desc = partprepend_writer_write_vol_desc;
 3211     writer->write_data = partprepend_writer_write_data;
 3212     writer->free_data = partprepend_writer_free_data;
 3213     writer->data = NULL;
 3214     writer->target = target;
 3215 
 3216     /* add this writer to image */
 3217     target->writers[target->nwriters++] = writer;
 3218 
 3219     return ISO_SUCCESS;
 3220 }
 3221 
 3222 
 3223 #ifdef Libisofs_appended_partitions_inlinE
 3224 
 3225 /* ----------------- Inline Partition Append Writer ------------------ */
 3226 
 3227 
 3228 static int partappend_writer_compute_data_blocks(IsoImageWriter *writer)
 3229 {
 3230     int ret;
 3231 
 3232     ret = iso_compute_append_partitions(writer->target, 1);
 3233     return ret;
 3234 }
 3235 
 3236 
 3237 static int partappend_writer_write_vol_desc(IsoImageWriter *writer)
 3238 {
 3239     return ISO_SUCCESS;
 3240 }
 3241 
 3242 
 3243 static int partappend_writer_write_data(IsoImageWriter *writer)
 3244 {
 3245     Ecma119Image *target;
 3246     int res, first_partition = 1, last_partition = 0;
 3247     int i;
 3248 
 3249     target = writer->target;
 3250 
 3251     /* Append partition data */
 3252     iso_tell_max_part_range(target->opts,
 3253                             &first_partition, &last_partition, 0);
 3254     
 3255     for (i = first_partition - 1; i <= last_partition - 1; i++) {
 3256         if (target->opts->appended_partitions[i] == NULL)
 3257     continue;
 3258         if (target->opts->appended_partitions[i][0] == 0)
 3259     continue;
 3260         res = iso_write_partition_file(target,
 3261                                        target->opts->appended_partitions[i],
 3262                                        target->appended_part_prepad[i],
 3263                                        target->appended_part_size[i],
 3264                                      target->opts->appended_part_flags[i] & 1);
 3265         if (res < 0)
 3266             return res;
 3267         target->curblock += target->appended_part_size[i];
 3268     }
 3269     return ISO_SUCCESS;
 3270 }
 3271 
 3272 
 3273 static int partappend_writer_free_data(IsoImageWriter *writer)
 3274 {
 3275     return ISO_SUCCESS;
 3276 }
 3277 
 3278 
 3279 int partappend_writer_create(Ecma119Image *target)
 3280 {
 3281     IsoImageWriter *writer;
 3282 
 3283     writer = calloc(1, sizeof(IsoImageWriter));
 3284     if (writer == NULL) {
 3285         return ISO_OUT_OF_MEM;
 3286     }
 3287 
 3288     writer->compute_data_blocks = partappend_writer_compute_data_blocks;
 3289     writer->write_vol_desc = partappend_writer_write_vol_desc;
 3290     writer->write_data = partappend_writer_write_data;
 3291     writer->free_data = partappend_writer_free_data;
 3292     writer->data = NULL;
 3293     writer->target = target;
 3294 
 3295     /* add this writer to image */
 3296     target->writers[target->nwriters++] = writer;
 3297 
 3298     return ISO_SUCCESS;
 3299 }
 3300 
 3301 #endif /* Libisofs_appended_partitions_inlinE */
 3302 
 3303 
 3304 void iso_delete_gpt_apm_fillers(Ecma119Image *target, int flag)
 3305 {
 3306     int i, widx;
 3307 
 3308     /* Dispose the requests with req_status bit0 */
 3309     for (i = 0; i < target->gpt_req_count; i++) {
 3310         if (target->gpt_req[i]->req_status & 1) {
 3311             free(target->gpt_req[i]);
 3312             target->gpt_req[i] = NULL;
 3313         }
 3314     }
 3315     /* Densify the request arrays */
 3316     widx = 0;
 3317     for (i = 0; i < target->gpt_req_count; i++) {
 3318         if (target->gpt_req[i] != NULL) {
 3319             target->gpt_req[widx] = target->gpt_req[i];
 3320             widx++;
 3321         }
 3322     }
 3323     target->gpt_req_count = widx;
 3324 
 3325     /* And again for APM */
 3326     for (i = 0; i < target->apm_req_count; i++) {
 3327         if (target->apm_req[i]->req_status & 1) {
 3328             free(target->apm_req[i]);
 3329             target->apm_req[i] = NULL;
 3330         }
 3331     }
 3332     widx = 0;
 3333     for (i = 0; i < target->apm_req_count; i++) {
 3334         if (target->apm_req[i] != NULL) {
 3335             target->apm_req[widx] = target->apm_req[i];
 3336             widx++;
 3337         }
 3338     }
 3339     target->apm_req_count = widx;
 3340 }
 3341