You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3403 lines
112 KiB
3403 lines
112 KiB
/* |
|
* Copyright (c) 2008 Vreixo Formoso |
|
* Copyright (c) 2010 - 2022 Thomas Schmitt |
|
* |
|
* This file is part of the libisofs project; you can redistribute it and/or |
|
* modify it under the terms of the GNU General Public License version 2 |
|
* or later as published by the Free Software Foundation. |
|
* See COPYING file for details. |
|
*/ |
|
|
|
#ifdef HAVE_CONFIG_H |
|
#include "../config.h" |
|
#endif |
|
|
|
#include "libisofs.h" |
|
#include "system_area.h" |
|
#include "eltorito.h" |
|
#include "filesrc.h" |
|
#include "ecma119_tree.h" |
|
#include "image.h" |
|
#include "messages.h" |
|
#include "ecma119.h" |
|
#include "writer.h" |
|
|
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <unistd.h> |
|
#include <fcntl.h> |
|
|
|
/* for gettimeofday() */ |
|
#include <sys/time.h> |
|
|
|
/* >>> Need ./configure test for uuid_generate() which checks for: |
|
uuid_t, uuid_generate, the need for -luuid |
|
*/ |
|
/* |
|
#define Libisofs_with_uuid_generatE 1 |
|
*/ |
|
#ifdef Libisofs_with_uuid_generatE |
|
#include <uuid/uuid.h> |
|
#endif |
|
|
|
/* O_BINARY is needed for Cygwin but undefined elsewhere */ |
|
#ifndef O_BINARY |
|
#define O_BINARY 0 |
|
#endif |
|
|
|
|
|
/* |
|
* Create a MBR for an isohybrid enabled ISOLINUX boot image. |
|
* See libisofs/make_isohybrid_mbr.c |
|
* Deprecated. |
|
*/ |
|
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag); |
|
|
|
/* |
|
* The New ISOLINUX MBR Producer. |
|
* Be cautious with changing parameters. Only few combinations are tested. |
|
* |
|
*/ |
|
int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t, |
|
int part_offset, int part_number, int fs_type, |
|
uint8_t *buf, int flag); |
|
|
|
/* Find out whether GPT and APM are desired by isohybrid |
|
flag bit0 = register APM and GPT requests in Ecma119Image |
|
*/ |
|
int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], |
|
int *apm_count, int flag); |
|
|
|
|
|
static int precompute_gpt(Ecma119Image *t); |
|
|
|
|
|
/* |
|
* @param flag bit0= img_blocks is start address rather than end address: |
|
do not subtract 1 |
|
bit1= img_blocks is counted in 512-byte units rather than 2 KiB |
|
*/ |
|
static |
|
void iso_compute_cyl_head_sec(uint64_t img_blocks, int hpc, int sph, |
|
uint32_t *end_lba, uint32_t *end_sec, |
|
uint32_t *end_head, uint32_t *end_cyl, int flag) |
|
{ |
|
uint64_t secs; |
|
|
|
if(flag & 2) |
|
secs = img_blocks; |
|
else |
|
secs = img_blocks * 4; |
|
if (secs > (uint64_t) 0xfffffffc) |
|
secs = 0xfffffffc; /* truncate rather than roll over */ |
|
if (flag & 1) |
|
*end_lba = secs; /* first valid 512-lba */ |
|
else |
|
secs = *end_lba = secs - 1; /* last valid 512-lba */ |
|
*end_cyl = secs / (sph * hpc); |
|
secs -= *end_cyl * sph * hpc; |
|
*end_head = secs / sph; |
|
*end_sec = secs - *end_head * sph + 1; /* Sector count starts by 1 */ |
|
if (*end_cyl >= 1024) { |
|
*end_cyl = 1023; |
|
*end_head = hpc - 1; |
|
*end_sec = sph; |
|
} |
|
} |
|
|
|
/* @param flag bit0= The path contains instructions for the interval reader |
|
@return ISO_SUCCESS = ok, partition will be written |
|
ISO_SUCCESS + 1 = interval which shall be kept in place |
|
else : error code |
|
*/ |
|
static int compute_partition_size(Ecma119Image *t, char *disk_path, |
|
uint32_t *size, int flag) |
|
{ |
|
int ret, keep; |
|
off_t num; |
|
struct stat stbuf; |
|
struct iso_interval_reader *ivr; |
|
off_t byte_count; |
|
|
|
if (flag & 1) { |
|
ret = iso_interval_reader_new(t->image, disk_path, |
|
&ivr, &byte_count, 0); |
|
if (ret < 0) |
|
return ret; |
|
*size = (byte_count + BLOCK_SIZE - 1) / BLOCK_SIZE; |
|
keep = iso_interval_reader_keep(t, ivr, 0); |
|
iso_interval_reader_destroy(&ivr, 0); |
|
if (keep < 0) |
|
return keep; |
|
return ISO_SUCCESS + (keep > 0); |
|
} |
|
|
|
*size = 0; |
|
ret = stat(disk_path, &stbuf); |
|
if (ret == -1) |
|
return ISO_BAD_PARTITION_FILE; |
|
if (! S_ISREG(stbuf.st_mode)) |
|
return ISO_BAD_PARTITION_FILE; |
|
num = ((stbuf.st_size + 2047) / 2048); |
|
if (num > 0x3fffffff || num == 0) |
|
return ISO_BAD_PARTITION_FILE; |
|
*size = num; |
|
return ISO_SUCCESS; |
|
} |
|
|
|
/* Compute size and position of appended partitions. |
|
@param flag bit0= Partitions inside ISO : update t->curblock |
|
*/ |
|
int iso_compute_append_partitions(Ecma119Image *t, int flag) |
|
{ |
|
int ret, i, sa_type, cyl_align, cyl_size = 0; |
|
int first_partition, last_partition; |
|
uint32_t pos, size, add_pos = 0; |
|
off_t start_byte, byte_count; |
|
char msg[128]; |
|
|
|
sa_type = (t->system_area_options >> 2) & 0x3f; |
|
cyl_align = (t->system_area_options >> 8) & 0x3; |
|
if (sa_type == 0 && cyl_align == 3) { |
|
cyl_size = t->partition_heads_per_cyl * t->partition_secs_per_head; |
|
if (cyl_size % 4) |
|
cyl_size = 0; |
|
else |
|
cyl_size /= 4; |
|
} |
|
|
|
#ifdef Libisofs_appended_partitions_inlinE |
|
|
|
pos = t->curblock; |
|
|
|
#else |
|
|
|
pos = (t->vol_space_size + t->opts->ms_block); |
|
|
|
#endif |
|
|
|
iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0); |
|
for (i = 0; i < ISO_MAX_PARTITIONS; i++) { |
|
if (t->opts->appended_partitions[i] == NULL) |
|
continue; |
|
if (t->opts->appended_partitions[i][0] == 0) |
|
continue; |
|
if (i + 1 > last_partition || i + 1 < first_partition) { |
|
sprintf(msg, |
|
"Partition number %d of appended partition is out of range [%d - %d]", |
|
i + 1, first_partition, last_partition); |
|
iso_msgs_submit(0, msg, 0, "FAILURE", 0); |
|
return ISO_BAD_PARTITION_NO; |
|
} |
|
|
|
ret = compute_partition_size(t, t->opts->appended_partitions[i], &size, |
|
t->opts->appended_part_flags[i]); |
|
if (ret < 0) |
|
return ret; |
|
if (ret == ISO_SUCCESS + 1) { |
|
/* Interval from imported_iso in add-on session */ |
|
t->appended_part_prepad[i] = 0; |
|
ret = iso_interval_reader_start_size(t, |
|
t->opts->appended_partitions[i], |
|
&start_byte, &byte_count, 0); |
|
if (ret < 0) |
|
return ret; |
|
t->appended_part_start[i] = start_byte / 2048; |
|
t->appended_part_size[i] = size; |
|
t->opts->iso_mbr_part_type = 0; |
|
continue; |
|
} |
|
|
|
add_pos = 0; |
|
if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) { |
|
add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE); |
|
} else if (cyl_size > 0 && (pos % cyl_size)) { |
|
add_pos = cyl_size - (pos % cyl_size); |
|
} |
|
t->appended_part_prepad[i] = add_pos; |
|
t->appended_part_start[i] = pos + add_pos; |
|
|
|
if (cyl_size > 0 && (size % cyl_size)) { |
|
/* Obey cylinder alignment (missing data will be written as |
|
zeros by iso_write_partition_file()) */ |
|
size += cyl_size - (size % cyl_size); |
|
} |
|
t->appended_part_size[i] = size; |
|
pos += add_pos + size; |
|
t->total_size += (((off_t) add_pos) + size) * 2048; |
|
if (flag & 1) |
|
t->curblock = pos; |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
static int mbr_part_slot_is_unused(uint8_t *slot) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < 16; i++) |
|
if (slot[i] != 0) |
|
break; |
|
if (i >= 16) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
|
|
/* @param flag |
|
bit1= partition_offset and partition_size are counted in |
|
blocks of 512 rather than 2048 |
|
*/ |
|
static int write_mbr_partition_entry(int partition_number, int partition_type, |
|
uint64_t partition_offset, uint64_t partition_size, |
|
int sph, int hpc, uint8_t *buf, int flag) |
|
{ |
|
uint8_t *wpt; |
|
uint32_t end_lba, end_sec, end_head, end_cyl; |
|
uint32_t start_lba, start_sec, start_head, start_cyl; |
|
uint32_t after_end; |
|
int i; |
|
|
|
after_end = partition_offset + partition_size; |
|
iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph, |
|
&start_lba, &start_sec, &start_head, &start_cyl, |
|
1 | (flag & 2)); |
|
iso_compute_cyl_head_sec((uint64_t) after_end, hpc, sph, |
|
&end_lba, &end_sec, &end_head, &end_cyl, |
|
(flag & 2)); |
|
wpt = buf + 446 + (partition_number - 1) * 16; |
|
|
|
/* Not bootable */ |
|
*(wpt++) = 0x00; |
|
|
|
/* C/H/S of the start */ |
|
*(wpt++) = start_head; |
|
*(wpt++) = start_sec | ((start_cyl & 0x300) >> 2); |
|
*(wpt++) = start_cyl & 0xff; |
|
|
|
/* (partition type) */ |
|
*(wpt++) = partition_type; |
|
|
|
/* 3 bytes of C/H/S end */ |
|
*(wpt++) = end_head; |
|
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2); |
|
*(wpt++) = end_cyl & 0xff; |
|
|
|
/* LBA start in little endian */ |
|
for (i = 0; i < 4; i++) |
|
*(wpt++) = (start_lba >> (8 * i)) & 0xff; |
|
|
|
/* Number of sectors in partition, little endian */ |
|
end_lba = end_lba - start_lba + 1; |
|
for (i = 0; i < 4; i++) |
|
*(wpt++) = (end_lba >> (8 * i)) & 0xff; |
|
|
|
/* Afaik, partition tables are recognize donly with MBR signature */ |
|
buf[510] = 0x55; |
|
buf[511] = 0xAA; |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* This is the gesture of grub-mkisofs --protective-msdos-label as explained by |
|
Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org |
|
"Currently we use first and not last entry. You need to: |
|
1) Zero-fill 446-510 |
|
2) Put 0x55, 0xAA into 510-512 |
|
3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd |
|
(partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA |
|
start in little endian), [LBA end in little endian] at 446-462 |
|
" |
|
|
|
"C/H/S end" means the CHS address of the last block in the partition. |
|
It seems that not "[LBA end in little endian]" but "number of blocks" |
|
should go into bytes 458-461. But with a start lba of 1, this is the |
|
same number. |
|
See also http://en.wikipedia.org/wiki/Master_boot_record |
|
|
|
flag bit0= do not write 0x55, 0xAA to 510,511 |
|
bit1= do not mark partition as bootable |
|
*/ |
|
static |
|
int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc, |
|
uint8_t part_type, uint8_t *buf, int flag) |
|
{ |
|
uint8_t *wpt; |
|
uint32_t end_lba, end_sec, end_head, end_cyl; |
|
int i; |
|
|
|
iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph, |
|
&end_lba, &end_sec, &end_head, &end_cyl, 0); |
|
|
|
/* 1) Zero-fill 446-510 */ |
|
wpt = buf + 446; |
|
memset(wpt, 0, 64); |
|
|
|
if (!(flag & 1)) { |
|
/* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */ |
|
buf[510] = 0x55; |
|
buf[511] = 0xAA; |
|
} |
|
if ((!(flag & 2)) && part_type != 0xee && part_type != 0xef) { |
|
/* 3) Put 0x80 (for bootable partition), */ |
|
*(wpt++) = 0x80; |
|
} else { |
|
*(wpt++) = 0; |
|
} |
|
|
|
/* 0, 2, 0 (C/H/S of the start), */ |
|
*(wpt++) = 0; |
|
*(wpt++) = 2; |
|
*(wpt++) = 0; |
|
|
|
/* 0xcd (partition type) */ |
|
*(wpt++) = part_type; |
|
|
|
/* [3 bytes of C/H/S end], */ |
|
*(wpt++) = end_head; |
|
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2); |
|
*(wpt++) = end_cyl & 0xff; |
|
|
|
|
|
/* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */ |
|
*(wpt++) = 0x01; |
|
*(wpt++) = 0x00; |
|
*(wpt++) = 0x00; |
|
*(wpt++) = 0x00; |
|
|
|
/* [LBA end in little endian] */ |
|
for (i = 0; i < 4; i++) |
|
*(wpt++) = (end_lba >> (8 * i)) & 0xff; |
|
|
|
/* at 446-462 */ |
|
if (wpt - buf != 462) { |
|
fprintf(stderr, |
|
"libisofs: program error in make_grub_msdos_label: \"assert 462\"\n"); |
|
return ISO_ASSERT_FAILURE; |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* @param flag bit0= zeroize partitions entries 2, 3, 4 |
|
bit1= UEFI protective MBR: start LBA = 1 |
|
*/ |
|
static |
|
int iso_offset_partition_start(uint32_t img_blocks, int post_part_pad, |
|
uint32_t partition_offset, |
|
int sph, int hpc, uint8_t *buf, int flag) |
|
{ |
|
uint8_t *wpt; |
|
uint32_t end_lba, end_sec, end_head, end_cyl; |
|
uint32_t start_lba, start_sec, start_head, start_cyl; |
|
uint64_t img_hd_blocks; |
|
int i; |
|
|
|
iso_compute_cyl_head_sec((uint64_t) partition_offset, hpc, sph, |
|
&start_lba, &start_sec, &start_head, &start_cyl, 1); |
|
img_hd_blocks = ((uint64_t) img_blocks) * 4 - post_part_pad / 512; |
|
iso_compute_cyl_head_sec(img_hd_blocks, hpc, sph, |
|
&end_lba, &end_sec, &end_head, &end_cyl, 2); |
|
if (flag & 2) { |
|
start_lba = 1; |
|
start_sec = 2; |
|
start_head = start_cyl = 0; |
|
} |
|
wpt = buf + 446; |
|
|
|
/* Let pass only legal bootability values */ |
|
if (*wpt != 0 && *wpt != 0x80) |
|
(*wpt) = 0; |
|
wpt++; |
|
|
|
/* C/H/S of the start */ |
|
*(wpt++) = start_head; |
|
*(wpt++) = start_sec | ((start_cyl & 0x300) >> 2); |
|
*(wpt++) = start_cyl & 0xff; |
|
|
|
/* (partition type) */ |
|
wpt++; |
|
|
|
/* 3 bytes of C/H/S end */ |
|
*(wpt++) = end_head; |
|
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2); |
|
*(wpt++) = end_cyl & 0xff; |
|
|
|
/* LBA start in little endian */ |
|
for (i = 0; i < 4; i++) |
|
*(wpt++) = (start_lba >> (8 * i)) & 0xff; |
|
|
|
/* Number of sectors in partition, little endian */ |
|
end_lba = end_lba - start_lba + 1; |
|
for (i = 0; i < 4; i++) |
|
*(wpt++) = (end_lba >> (8 * i)) & 0xff; |
|
|
|
if (wpt - buf != 462) { |
|
fprintf(stderr, |
|
"libisofs: program error in iso_offset_partition_start: \"assert 462\"\n"); |
|
return ISO_ASSERT_FAILURE; |
|
} |
|
|
|
if (flag & 1) /* zeroize the other partition entries */ |
|
memset(wpt, 0, 3 * 16); |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
static int boot_nodes_from_iso_path(Ecma119Image *t, char *path, |
|
IsoNode **iso_node, Ecma119Node **ecma_node, |
|
char *purpose, int flag) |
|
{ |
|
int ret; |
|
|
|
ret = iso_tree_path_to_node(t->image, path, iso_node); |
|
if (ret <= 0) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0, |
|
"Cannot find in ISO image: %s '%s'", purpose, path); |
|
return ISO_BOOT_FILE_MISSING; |
|
} |
|
if ((*iso_node)->type != LIBISO_FILE) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"Designated boot file is not a data file: '%s'", path); |
|
return ISO_BOOT_IMAGE_NOT_VALID; |
|
} |
|
|
|
*ecma_node= ecma119_search_iso_node(t, *iso_node); |
|
if (*ecma_node == NULL) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"Program error: IsoFile has no Ecma119Node: '%s'", path); |
|
return ISO_ASSERT_FAILURE; |
|
} else { |
|
if ((*ecma_node)->type != ECMA119_FILE) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'", |
|
path); |
|
return ISO_ASSERT_FAILURE; |
|
} |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* This function was implemented according to doc/boot_sectors.txt section |
|
"MIPS Volume Header" which was derived by Thomas Schmitt from |
|
cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based |
|
on work of Florian Lohoff and Thiemo Seufer who possibly learned from |
|
documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer |
|
Systems, Inc. |
|
This function itself is entirely under copyright (C) 2010 Thomas Schmitt. |
|
*/ |
|
static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag) |
|
{ |
|
char *namept, *name_field; |
|
uint32_t num_cyl, idx, blocks, num, checksum; |
|
off_t image_size; |
|
static uint32_t bps = 512, spt = 32; |
|
Ecma119Node *ecma_node; |
|
IsoNode *node; |
|
IsoStream *stream; |
|
off_t file_size; |
|
uint32_t file_lba; |
|
int ret; |
|
|
|
/* Bytes 512 to 32767 may come from image or external file */ |
|
memset(buf, 0, 512); |
|
|
|
image_size = t->curblock * 2048; |
|
|
|
/* 0 - 3 | 0x0be5a941 | Magic number */ |
|
iso_msb(buf, 0x0be5a941, 4); |
|
|
|
/* 28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes */ |
|
num_cyl = (image_size + (bps * spt) - 1) / (bps * spt); |
|
iso_msb(buf + 28, num_cyl & 0xffff, 2); |
|
|
|
/* 32 - 33 | 1 | Number of tracks per cylinder */ |
|
iso_msb(buf + 32, 1, 2); |
|
|
|
/* 35 - 35 | num_cyl_h | Number of usable cylinders, high byte */ |
|
buf[35] = (num_cyl >> 16) & 0xff; |
|
|
|
/* 38 - 39 | 32 | Sectors per track */ |
|
iso_msb(buf + 38, spt, 2); |
|
|
|
/* 40 - 41 | 512 | Bytes per sector */ |
|
iso_msb(buf + 40, bps, 2); |
|
|
|
/* 44 - 47 | 0x00000034 | Controller characteristics */ |
|
iso_msb(buf + 44, 0x00000034, 4); |
|
|
|
/* 72 - 87 | ========== | Volume Directory Entry 1 */ |
|
/* 72 - 79 | boot_name | Boot file basename */ |
|
/* 80 - 83 | boot_block | ISO 9660 LBA of boot file * 4 */ |
|
/* 84 - 87 | boot_bytes | File length in bytes */ |
|
/* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */ |
|
|
|
for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) { |
|
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx], |
|
&node, &ecma_node, "MIPS boot file", 0); |
|
if (ret < 0) |
|
return ret; |
|
|
|
namept = (char *) iso_node_get_name(node); |
|
name_field = (char *) (buf + (72 + 16 * idx)); |
|
strncpy(name_field, namept, 8); |
|
|
|
file_lba = ecma_node->info.file->sections[0].block; |
|
|
|
iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4); |
|
|
|
stream = iso_file_get_stream((IsoFile *) node); |
|
file_size = iso_stream_get_size(stream); |
|
|
|
/* genisoimage rounds up to full multiples of 2048. |
|
libisofs did this too until 2020, but the arcload mips boot loader |
|
throws error if the rounded size is stored here. |
|
So now the exact bytecount gets stored. |
|
*/ |
|
iso_msb(buf + (72 + 16 * idx) + 12, file_size, 4); |
|
|
|
} |
|
|
|
/* 408 - 411 | part_blks | Number of 512 byte blocks in partition */ |
|
blocks = (image_size + bps - 1) / bps; |
|
iso_msb(buf + 408, blocks, 4); |
|
/* 416 - 419 | 0 | Partition is volume header */ |
|
iso_msb(buf + 416, 0, 4); |
|
|
|
/* 432 - 435 | part_blks | Number of 512 byte blocks in partition */ |
|
iso_msb(buf + 432, blocks, 4); |
|
iso_msb(buf + 444, 6, 4); |
|
|
|
/* 504 - 507 | head_chk | Volume header checksum |
|
The two's complement of bytes 0 to 503 read |
|
as big endian unsigned 32 bit: |
|
sum(32-bit-words) + head_chk == 0 |
|
*/ |
|
checksum = 0; |
|
for (idx = 0; idx < 504; idx += 4) { |
|
num = iso_read_msb(buf + idx, 4); |
|
/* Addition modulo a natural number is commutative and associative. |
|
Thus the inverse of a sum is the sum of the inverses of the addends. |
|
*/ |
|
checksum -= num; |
|
} |
|
iso_msb(buf + 504, checksum, 4); |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* The following two functions were implemented according to |
|
doc/boot_sectors.txt section "MIPS Little Endian" which was derived |
|
by Thomas Schmitt from |
|
cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based |
|
on work of Florian Lohoff and Thiemo Seufer, |
|
and from <elf.h> by Free Software Foundation, Inc. |
|
|
|
Both functions are entirely under copyright (C) 2010 Thomas Schmitt. |
|
*/ |
|
|
|
/** |
|
* Read the necessary ELF information from the first MIPS boot file. |
|
* This is done before image writing starts. |
|
*/ |
|
int iso_read_mipsel_elf(Ecma119Image *t, int flag) |
|
{ |
|
uint32_t phdr_adr, todo, count; |
|
int ret; |
|
uint8_t *elf_buf = NULL; |
|
IsoNode *iso_node; |
|
Ecma119Node *ecma_node; |
|
IsoStream *stream; |
|
|
|
if (t->image->num_mips_boot_files <= 0) |
|
{ret = ISO_SUCCESS; goto ex;} |
|
|
|
LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048); |
|
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0], |
|
&iso_node, &ecma_node, "MIPS boot file", 0); |
|
if (ret < 0) |
|
goto ex; |
|
stream = iso_file_get_stream((IsoFile *) iso_node); |
|
|
|
ret = iso_stream_open(stream); |
|
if (ret < 0) { |
|
iso_msg_submit(t->image->id, ret, 0, |
|
"Cannot open designated MIPS boot file '%s'", |
|
t->image->mips_boot_file_paths[0]); |
|
goto ex; |
|
} |
|
ret = iso_stream_read(stream, elf_buf, 32); |
|
if (ret != 32) { |
|
cannot_read:; |
|
iso_stream_close(stream); |
|
iso_msg_submit(t->image->id, ret, 0, |
|
"Cannot read from designated MIPS boot file '%s'", |
|
t->image->mips_boot_file_paths[0]); |
|
goto ex; |
|
} |
|
|
|
|
|
/* 24 - 27 | e_entry | Entry point virtual address */ |
|
t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4); |
|
|
|
/* 28 - 31 | e_phoff | Program header table file offset */ |
|
phdr_adr = iso_read_lsb(elf_buf + 28, 4); |
|
|
|
/* Skip stream up to byte address phdr_adr */ |
|
todo = phdr_adr - 32; |
|
while (todo > 0) { |
|
if (todo > 2048) |
|
count = 2048; |
|
else |
|
count = todo; |
|
todo -= count; |
|
ret = iso_stream_read(stream, elf_buf, count); |
|
if (ret != (int) count) |
|
goto cannot_read; |
|
} |
|
ret = iso_stream_read(stream, elf_buf, 20); |
|
if (ret != 20) |
|
goto cannot_read; |
|
|
|
/* 4 - 7 | p_offset | Segment file offset */ |
|
t->mipsel_p_offset = iso_read_lsb(elf_buf + 4, 4); |
|
|
|
/* 8 - 11 | p_vaddr | Segment virtual address */ |
|
t->mipsel_p_vaddr = iso_read_lsb(elf_buf + 8, 4); |
|
|
|
/* 16 - 19 | p_filesz | Segment size in file */ |
|
t->mipsel_p_filesz = iso_read_lsb(elf_buf + 16, 4); |
|
|
|
iso_stream_close(stream); |
|
ret = ISO_SUCCESS; |
|
ex:; |
|
LIBISO_FREE_MEM(elf_buf); |
|
return ret; |
|
} |
|
|
|
|
|
/** |
|
* Write DEC Bootblock from previously read ELF parameters. |
|
* This is done when image writing has already begun. |
|
*/ |
|
static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag) |
|
{ |
|
int ret; |
|
uint32_t seg_size, seg_start; |
|
IsoNode *iso_node; |
|
Ecma119Node *ecma_node; |
|
|
|
/* Bytes 512 to 32767 may come from image or external file */ |
|
memset(buf, 0, 512); |
|
|
|
if (t->image->num_mips_boot_files <= 0) |
|
return ISO_SUCCESS; |
|
|
|
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0], |
|
&iso_node, &ecma_node, "MIPS boot file", 0); |
|
if (ret < 0) |
|
return ret; |
|
|
|
/* 8 - 11 | 0x0002757a | Magic number */ |
|
iso_lsb(buf + 8, 0x0002757a, 4); |
|
|
|
/* 12 - 15 | 1 | Mode 1: Multi extent boot */ |
|
iso_lsb(buf + 12, 1, 4); |
|
|
|
/* 16 - 19 | load_adr | Load address */ |
|
iso_lsb(buf + 16, t->mipsel_p_vaddr, 4); |
|
|
|
/* 20 - 23 | exec_adr | Execution address */ |
|
iso_lsb(buf + 20, t->mipsel_e_entry, 4); |
|
|
|
/* 24 - 27 | seg_size | Segment size in file. */ |
|
seg_size = (t->mipsel_p_filesz + 511) / 512; |
|
iso_lsb(buf + 24, seg_size, 4); |
|
|
|
/* 28 - 31 | seg_start | Segment file offset */ |
|
seg_start = ecma_node->info.file->sections[0].block * 4 |
|
+ (t->mipsel_p_offset + 511) / 512; |
|
iso_lsb(buf + 28, seg_start, 4); |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* The following two functions were implemented according to |
|
doc/boot_sectors.txt section "SUN Disk Label and boot images" which |
|
was derived by Thomas Schmitt from |
|
cdrtools-2.01.01a77/mkisofs/sunlabel.h |
|
cdrtools-2.01.01a77/mkisofs/mkisofs.8 |
|
by Joerg Schilling |
|
|
|
Both functions are entirely under copyright (C) 2010 Thomas Schmitt. |
|
*/ |
|
|
|
/* @parm flag bit0= copy from next lower valid partition table entry |
|
*/ |
|
static int write_sun_partition_entry(int partition_number, |
|
char *appended_partitions[], |
|
uint32_t partition_offset[], uint32_t partition_size[], |
|
uint32_t cyl_size, uint8_t *buf, int flag) |
|
{ |
|
uint8_t *wpt; |
|
int read_idx, i; |
|
|
|
if (partition_number < 1 || partition_number > 8) |
|
return ISO_ASSERT_FAILURE; |
|
|
|
/* 142 - 173 | ========== | 8 partition entries of 4 bytes */ |
|
wpt = buf + 142 + (partition_number - 1) * 4; |
|
if (partition_number == 1) |
|
iso_msb(wpt, 4, 2); /* 4 = User partition */ |
|
else |
|
iso_msb(wpt, 2, 2); /* 2 = Root partition with boot image */ |
|
iso_msb(wpt + 2, 0x10, 2); /* Permissions: 0x10 = read-only */ |
|
|
|
/* 444 - 507 | ========== | Partition table */ |
|
wpt = buf + 444 + (partition_number - 1) * 8; |
|
read_idx = partition_number - 1; |
|
if (flag & 1) { |
|
/* Search next lower valid partition table entry. #1 is default */ |
|
for (read_idx = partition_number - 2; read_idx > 0; read_idx--) |
|
if (appended_partitions[read_idx] != NULL) |
|
if (appended_partitions[read_idx][0] != 0) |
|
break; |
|
} |
|
iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4); |
|
iso_msb(wpt + 4, partition_size[read_idx] * 4, 4); |
|
|
|
/* 510 - 511 | checksum | The result of exoring 2-byte words 0 to 254 */ |
|
buf[510] = buf[511] = 0; |
|
for (i = 0; i < 510; i += 2) { |
|
buf[510] ^= buf[i]; |
|
buf[511] ^= buf[i + 1]; |
|
} |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
/** |
|
* Write SUN Disk Label with ISO in partition 1 and unused 2 to 8 |
|
*/ |
|
static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag) |
|
{ |
|
int ret, i, l; |
|
uint64_t blk; |
|
|
|
/* Bytes 512 to 32767 may come from image or external file */ |
|
memset(buf, 0, 512); |
|
|
|
/* 0 - 127 | label | ASCII Label */ |
|
if (t->opts->ascii_disc_label[0]) { |
|
for (l = 0; l < 128 && t->opts->ascii_disc_label[l] != 0; l++); |
|
if (l > 0) |
|
memcpy((char *) buf, t->opts->ascii_disc_label, l); |
|
} else { |
|
strcpy((char *) buf, |
|
"CD-ROM Disc with Sun sparc boot created by libisofs"); |
|
} |
|
|
|
/* 128 - 131 | 1 | Layout version */ |
|
iso_msb(buf + 128, 1, 4); |
|
|
|
/* 140 - 141 | 8 | Number of partitions */ |
|
iso_msb(buf + 140, 8, 2); |
|
|
|
/* 188 - 191 | 0x600ddeee | vtoc sanity */ |
|
iso_msb(buf + 188, 0x600ddeee, 4); |
|
|
|
/* 420 - 421 | 350 | Rotations per minute */ |
|
iso_msb(buf + 420, 350, 2); |
|
|
|
/* 422 - 423 | 2048 | Number of physical cylinders (fixely 640 MB) */ |
|
iso_msb(buf + 422, 2048, 2); |
|
|
|
/* 430 - 431 | 1 | interleave factor */ |
|
iso_msb(buf + 430, 1, 2); |
|
|
|
/* 432 - 433 | 2048 | Number of data cylinders (fixely 640 MB) */ |
|
iso_msb(buf + 432, 2048, 2); |
|
|
|
/* 436 - 437 | 1 | Number of heads per cylinder (1 cyl = 320 kB)*/ |
|
iso_msb(buf + 436, 1, 2); |
|
|
|
/* 438 - 439 | 640 | Number of sectors per head (1 head = 320 kB) */ |
|
iso_msb(buf + 438, 640, 2); |
|
|
|
/* 508 - 509 | 0xdabe | Magic Number */ |
|
iso_msb(buf + 508, 0xdabe, 2); |
|
|
|
if (t->sparc_core_src != NULL) { |
|
/* May be used for grub-sparc. */ |
|
blk= ((uint64_t) t->sparc_core_src->sections[0].block) * |
|
(uint64_t) 2048; |
|
for (i = 0; i < 8; i++) |
|
buf[Libisofs_grub2_sparc_patch_adr_poS + i] = blk >> ((7 - i) * 8); |
|
iso_msb(buf + Libisofs_grub2_sparc_patch_size_poS, |
|
t->sparc_core_src->sections[0].size, 4); |
|
} |
|
|
|
/* Set partition 1 to describe ISO image and compute checksum */ |
|
t->appended_part_start[0] = 0; |
|
t->appended_part_size[0] = t->curblock; |
|
ret = write_sun_partition_entry(1, t->opts->appended_partitions, |
|
t->appended_part_start, t->appended_part_size, |
|
ISO_SUN_CYL_SIZE, buf, 0); |
|
if (ret < 0) |
|
return ret; |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
static int hppa_palo_get_filepar(Ecma119Image *t, char *path, |
|
uint32_t *adr, uint32_t *len, int flag) |
|
{ |
|
int ret; |
|
IsoNode *iso_node; |
|
Ecma119Node *ecma_node; |
|
off_t adr64; |
|
|
|
ret = boot_nodes_from_iso_path(t, path, |
|
&iso_node, &ecma_node, "HP-PA PALO boot file", 0); |
|
if (ret < 0) |
|
return ret; |
|
if (iso_node_get_type(iso_node) != LIBISO_FILE) { |
|
iso_msg_submit(t->image->id, ISO_HPPA_PALO_NOTREG, 0, |
|
"HP-PA PALO file is not a data file"); |
|
return ISO_HPPA_PALO_NOTREG; |
|
} |
|
adr64 = ((off_t) 2048) * (off_t) ecma_node->info.file->sections[0].block; |
|
if (adr64 > 0x7fffffff) { |
|
iso_msg_submit(t->image->id, ISO_HPPA_PALO_OFLOW, 0, |
|
"HP-PA PALO boot address exceeds 2 GB"); |
|
return ISO_HPPA_PALO_OFLOW; |
|
} |
|
*adr = adr64; |
|
*len = ecma_node->info.file->sections[0].size; |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/** |
|
* Write HP-PA PALO boot sector. See doc/boot_sectors.txt |
|
* |
|
* learned from cdrkit-1.1.10/genisoimage/boot-hppa.c |
|
* by Steve McIntyre <steve@einval.com> |
|
* who states "Heavily inspired by palo" |
|
* Public mail conversations with Helge Deller, beginning with |
|
* https://lists.debian.org/debian-hppa/2014/01/msg00016.html |
|
* http://git.kernel.org/cgit/linux/kernel/git/deller/palo.git/tree/lib/ |
|
* (especially struct firstblock in common.h and struct partition in part.h) |
|
* |
|
*/ |
|
static int make_hppa_palo_sector(Ecma119Image *t, uint8_t *buf, int hdrversion, |
|
int flag) |
|
{ |
|
int ret; |
|
IsoImage *img; |
|
uint32_t adr, len; |
|
|
|
img = t->image; |
|
if (img->hppa_cmdline == NULL && img->hppa_bootloader == NULL && |
|
img->hppa_kernel_32 == NULL && img->hppa_kernel_64 == NULL && |
|
img->hppa_ramdisk == NULL) |
|
return ISO_SUCCESS; |
|
if (img->hppa_cmdline == NULL || img->hppa_bootloader == NULL || |
|
img->hppa_kernel_32 == NULL || img->hppa_kernel_64 == NULL || |
|
img->hppa_ramdisk == NULL) { |
|
iso_msg_submit(img->id, ISO_HPPA_PALO_INCOMPL, 0, |
|
"Incomplete HP-PA PALO boot parameters"); |
|
return ISO_HPPA_PALO_INCOMPL; |
|
} |
|
if (hdrversion == 4) { |
|
/* Bytes 256 to 32767 may come from loaded ISO image or external file */ |
|
memset(buf, 0, 256); |
|
} else if(hdrversion == 5) { |
|
memset(buf, 0, 512); |
|
memset(buf + 1024, 0, 1024); |
|
} else { |
|
iso_msg_submit(img->id, ISO_WRONG_ARG_VALUE, 0, |
|
"Unsupported HP-PA PALO header version %d (can do 4 or 5)", |
|
hdrversion); |
|
return ISO_WRONG_ARG_VALUE; |
|
} |
|
|
|
/* Magic */ |
|
iso_msb(buf + 0, 0x8000, 2); |
|
/* Name of boot loader */ |
|
memcpy(buf + 2, "PALO", 5); |
|
/* Version */ |
|
buf[7] = hdrversion; |
|
|
|
/* Byte address and byte count of the "HPPA 32-bit kernel" file |
|
*/ |
|
ret = hppa_palo_get_filepar(t, img->hppa_kernel_32, &adr, &len, 0); |
|
if (ret < 0) |
|
return ret; |
|
iso_msb(buf + 8, adr, 4); |
|
iso_msb(buf + 12, len, 4); |
|
|
|
/* Byte address and byte count of the "HPPA ramdisk" file |
|
*/ |
|
ret = hppa_palo_get_filepar(t, img->hppa_ramdisk, &adr, &len, 0); |
|
if (ret < 0) |
|
return ret; |
|
iso_msb(buf + 16, adr, 4); |
|
iso_msb(buf + 20, len, 4); |
|
|
|
if (hdrversion == 4) { |
|
/* "Command line" */ |
|
if (strlen(img->hppa_cmdline) > 127) { |
|
iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0, |
|
"HP-PA PALO command line too long"); |
|
return ISO_HPPA_PALO_CMDLEN; |
|
} |
|
memcpy(buf + 24, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1); |
|
} |
|
|
|
/* Byte address and byte count of the "HPPA 64-bit kernel" file |
|
*/ |
|
ret = hppa_palo_get_filepar(t, img->hppa_kernel_64, &adr, &len, 0); |
|
if (ret < 0) |
|
return ret; |
|
iso_msb(buf + 232, adr, 4); |
|
iso_msb(buf + 236, len, 4); |
|
|
|
/* Byte address and byte count of the "HPPA bootloader" file |
|
*/ |
|
ret = hppa_palo_get_filepar(t, img->hppa_bootloader, &adr, &len, 0); |
|
if (ret < 0) |
|
return ret; |
|
iso_msb(buf + 240, adr, 4); |
|
iso_msb(buf + 244, len, 4); |
|
|
|
if (hdrversion == 5) { |
|
if (strlen(img->hppa_cmdline) > 1023) { |
|
iso_msg_submit(img->id, ISO_HPPA_PALO_CMDLEN, 0, |
|
"HP-PA PALO command line too long"); |
|
return ISO_HPPA_PALO_CMDLEN; |
|
} |
|
memcpy(buf + 1024, img->hppa_cmdline, strlen(img->hppa_cmdline) + 1); |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/** |
|
* Write DEC Alpha boot sector. See doc/boot_sectors.txt |
|
* |
|
* learned from cdrkit-1.1.10/genisoimage/boot-alpha.c |
|
* by Steve McIntyre <steve@einval.com> |
|
* who states "Heavily inspired by isomarkboot by David Mosberger in 1996" |
|
* |
|
*/ |
|
static int make_dec_alpha_sector(Ecma119Image *t, uint8_t *buf, int flag) |
|
{ |
|
int ret, i; |
|
IsoImage *img; |
|
IsoNode *iso_node; |
|
Ecma119Node *ecma_node; |
|
uint64_t size, lba, checksum = 0; |
|
|
|
img = t->image; |
|
if (img->alpha_boot_image == NULL) |
|
return ISO_SUCCESS; |
|
ret = boot_nodes_from_iso_path(t, img->alpha_boot_image, |
|
&iso_node, &ecma_node, "DEC Alpha boot file", 0); |
|
if (ret < 0) |
|
return ret; |
|
memset(buf, 0, 512); |
|
strcpy((char *) buf, "Linux/Alpha aboot for ISO filesystem."); |
|
lba = ecma_node->info.file->sections[0].block * 4; |
|
size = ecma_node->info.file->sections[0].size / 512 + |
|
!!(ecma_node->info.file->sections[0].size % 512); |
|
iso_lsb(buf + 480, size & 0xffffffff, 4); |
|
iso_lsb(buf + 484, (size >> 32) & 0xffffffff, 4); |
|
iso_lsb(buf + 488, lba & 0xffffffff, 4); |
|
iso_lsb(buf + 492, (lba >> 32) & 0xffffffff, 4); |
|
for (i = 0; i < 63; i++) |
|
checksum += iso_read_lsb64(buf + 8 * i); |
|
iso_lsb(buf + 504, checksum & 0xffffffff, 4); |
|
iso_lsb(buf + 508, (checksum >> 32) & 0xffffffff, 4); |
|
return ISO_SUCCESS; |
|
} |
|
|
|
/* Convenience frontend for iso_register_apm_entry(). |
|
name and type are 0-terminated strings. |
|
*/ |
|
int iso_quick_apm_entry(struct iso_apm_partition_request **req_array, |
|
int *apm_req_count, |
|
uint32_t start_block, uint32_t block_count, |
|
char *name, char *type) |
|
{ |
|
int ret, l; |
|
struct iso_apm_partition_request *entry; |
|
|
|
entry = calloc(1, sizeof(struct iso_apm_partition_request)); |
|
if (entry == NULL) |
|
return ISO_OUT_OF_MEM; |
|
entry->start_block = start_block; |
|
entry->block_count = block_count; |
|
for (l = 0; l < 32 && name[l] != 0; l++); |
|
if (l > 0) |
|
memcpy((char *) entry->name, name, l); |
|
for (l = 0; l < 32 && type[l] != 0; l++); |
|
if (l > 0) |
|
memcpy((char *) entry->type, type, l); |
|
entry->req_status = 0; |
|
ret = iso_register_apm_entry(req_array, apm_req_count, entry, 0); |
|
free(entry); |
|
return ret; |
|
} |
|
|
|
|
|
static int iso_find_gpt_entry(struct iso_gpt_partition_request **req_array, |
|
int gpt_req_count, |
|
uint64_t start_block, uint64_t block_count, |
|
int *index, int flag) |
|
{ |
|
struct iso_gpt_partition_request *entry; |
|
|
|
for (*index = 0; *index < gpt_req_count; (*index)++) { |
|
entry = req_array[*index]; |
|
if (entry->start_block == start_block && |
|
entry->block_count == block_count) |
|
return 1; |
|
} |
|
*index = -1; |
|
return 0; |
|
} |
|
|
|
|
|
/* Convenience frontend for iso_register_gpt_entry(). |
|
name has to be already encoded as UTF-16LE. |
|
*/ |
|
int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array, |
|
int *gpt_req_count, |
|
uint64_t start_block, uint64_t block_count, |
|
uint8_t type_guid[16], uint8_t partition_guid[16], |
|
uint64_t flags, uint8_t name[72]) |
|
{ |
|
int ret; |
|
struct iso_gpt_partition_request *entry; |
|
|
|
entry = calloc(1, sizeof(struct iso_gpt_partition_request)); |
|
if (entry == NULL) |
|
return ISO_OUT_OF_MEM; |
|
entry->start_block = start_block; |
|
entry->block_count = block_count; |
|
memcpy(entry->type_guid, type_guid, 16); |
|
memcpy(entry->partition_guid, partition_guid, 16); |
|
entry->flags = flags; |
|
memcpy(entry->name, name, 72); |
|
entry->req_status = 0; |
|
ret = iso_register_gpt_entry(req_array, gpt_req_count, entry, 0); |
|
free(entry); |
|
return ret; |
|
} |
|
|
|
|
|
int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array, |
|
int *mbr_req_count, |
|
uint64_t start_block, uint64_t block_count, |
|
uint8_t type_byte, uint8_t status_byte, |
|
int desired_slot) |
|
{ |
|
int ret; |
|
struct iso_mbr_partition_request *entry; |
|
|
|
ret = iso_mbr_entry_slot_is_free(req_array, *mbr_req_count, desired_slot); |
|
if (ret < 0) |
|
desired_slot = 0; |
|
else if (ret == 0) |
|
return ISO_BOOT_MBR_COLLISION; |
|
|
|
entry = calloc(1, sizeof(struct iso_mbr_partition_request)); |
|
if (entry == NULL) |
|
return ISO_OUT_OF_MEM; |
|
entry->start_block = start_block; |
|
entry->block_count = block_count; |
|
entry->type_byte = type_byte; |
|
entry->status_byte = status_byte; |
|
entry->desired_slot = desired_slot; |
|
ret = iso_register_mbr_entry(req_array, mbr_req_count, entry, 0); |
|
free(entry); |
|
return ret; |
|
} |
|
|
|
|
|
int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array, |
|
int mbr_req_count, int slot) |
|
{ |
|
int i; |
|
|
|
if (slot < 0 || slot > ISO_MBR_ENTRIES_MAX) |
|
return -1; |
|
if (slot == 0) |
|
return 1; |
|
for (i = 0; i < mbr_req_count; i++) |
|
if (req_array[i]->desired_slot == slot) |
|
return 0; |
|
return 1; |
|
} |
|
|
|
|
|
/** |
|
* Compare the block interval positions of two iso_apm_partition_request |
|
*/ |
|
static |
|
int cmp_partition_request(const void *f1, const void *f2) |
|
{ |
|
struct iso_partition_request { |
|
uint64_t start_block; |
|
uint64_t block_count; |
|
} *r1, *r2; |
|
|
|
r1 = *((struct iso_partition_request **) f1); |
|
r2 = *((struct iso_partition_request **) f2); |
|
if (r1->start_block < r2->start_block) |
|
return -1; |
|
if (r1->start_block > r2->start_block) |
|
return 1; |
|
|
|
/* In case of overlapping the largest partition shall be first */ |
|
if (r1->block_count > r2->block_count) |
|
return -1; |
|
if (r1->block_count < r2->block_count) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
|
|
/* @param flag bit0= This is the entry in block 1. Its blocks are already in |
|
the desired apm_block_size unit. Set block_fac to 1. |
|
Set flags to 3 rather than 0x13. |
|
*/ |
|
static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, |
|
struct iso_apm_partition_request *req, |
|
uint8_t *buf, int map_entries, int flag) |
|
{ |
|
uint8_t *wpt; |
|
uint32_t flags; |
|
int block_fac; |
|
|
|
if ((flag & 1) || (t->apm_req_flags & 4)) |
|
block_fac = 1; |
|
else |
|
block_fac = 2048 / apm_block_size; |
|
|
|
memset(buf, 0, apm_block_size); |
|
wpt = buf; |
|
|
|
/* Signature */ |
|
wpt[0] = 'P'; wpt[1] = 'M'; |
|
wpt+= 2; |
|
/* reserved */ |
|
wpt += 2; |
|
/* Number of partition entries */ |
|
iso_msb(wpt, (uint32_t) map_entries, 4); |
|
wpt += 4; |
|
/* Physical block start of partition */ |
|
iso_msb(wpt, (uint32_t) (req->start_block * block_fac), 4); |
|
wpt += 4; |
|
/* Physical block count of partition */ |
|
iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4); |
|
wpt += 4; |
|
/* Partition name */ |
|
memcpy(wpt, req->name, 32); |
|
wpt += 32; |
|
/* Type string */ |
|
memcpy(wpt, req->type, 32); |
|
wpt += 32; |
|
/* Logical block start */ |
|
iso_msb(wpt, (uint32_t) 0, 4); |
|
wpt += 4; |
|
/* Logical block count */ |
|
iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4); |
|
wpt += 4; |
|
/* Status flags : bit0= entry is valid , bit1= entry is allocated |
|
bit4= partition is readable , bit5= partition is writable |
|
bit30= automatic mount (legacy Mac) |
|
*/ |
|
if (flag & 1) { |
|
flags = 3; |
|
} else { |
|
flags = 0x13; |
|
if (strncmp((char *) req->type, "Apple_HFS", 9) == 0 && |
|
req->type[9] == 0) |
|
flags |= 0x40000000; |
|
} |
|
iso_msb(wpt, flags, 4); |
|
wpt += 4; |
|
|
|
/* boot_block , boot_bytes , processor , reserved : are all 0 */ |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* Sort and fill gaps in requested APM */ |
|
static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) |
|
{ |
|
int i, ret, gap_counter = 0, up_to; |
|
uint32_t part_end, goal, block_fac = 1; |
|
char gap_name[33]; |
|
|
|
if (t->apm_req_flags & 4) { |
|
if (t->opts->apm_block_size == 0) |
|
t->opts->apm_block_size = 2048; |
|
block_fac = 2048 / t->opts->apm_block_size; |
|
} |
|
|
|
/* Find out whether an entry with start_block <= 1 is requested */ |
|
for (i = 0; i < t->apm_req_count; i++) { |
|
if (t->apm_req[i]->start_block <= 1) |
|
break; |
|
} |
|
if (i >= t->apm_req_count) { |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
1, 0, "Apple", "Apple_partition_map"); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
|
|
qsort(t->apm_req, t->apm_req_count, |
|
sizeof(struct iso_apm_partition_request *), cmp_partition_request); |
|
|
|
if (t->opts->part_like_isohybrid) |
|
return 1; /* No filling, only sorting */ |
|
|
|
/* t->apm_req_count will grow during the loop */ |
|
up_to = t->apm_req_count + 1; |
|
for (i = 1; i < up_to; i++) { |
|
if (i < up_to - 1) |
|
goal = (uint32_t) t->apm_req[i]->start_block; |
|
else |
|
goal = img_blocks * block_fac; |
|
if (i == 1) { |
|
/* Description of APM itself */ |
|
/* Actual APM size is not yet known. Protection begins at PVD */ |
|
part_end = 16 * block_fac; |
|
if (goal < part_end && goal> 1) |
|
part_end = goal; |
|
} else { |
|
part_end = t->apm_req[i - 1]->start_block + |
|
t->apm_req[i - 1]->block_count; |
|
} |
|
if (part_end > goal) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0, |
|
"Program error: APM partitions %d and %d overlap by %lu blocks", |
|
i - 1, i, part_end - goal); |
|
return ISO_BOOT_APM_OVERLAP; |
|
} |
|
|
|
if (t->apm_req_flags & 2) /* Do not fill gaps */ |
|
continue; |
|
|
|
if (part_end < goal || i == up_to - 1) { /* Always add a final entry */ |
|
sprintf(gap_name, "Gap%d", gap_counter); |
|
gap_counter++; |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
part_end, goal - part_end, |
|
gap_name, "ISO9660_data"); |
|
if (ret < 0) |
|
return ret; |
|
/* Mark as automatically placed filler request */ |
|
t->apm_req[t->apm_req_count - 1]->req_status |= 1; |
|
} |
|
} |
|
|
|
/* Merge list of gap partitions with list of already sorted entries */ |
|
if (!(t->apm_req_flags & 2)) /* No gaps were filled */ |
|
qsort(t->apm_req, t->apm_req_count, |
|
sizeof(struct iso_apm_partition_request *), cmp_partition_request); |
|
|
|
return 1; |
|
} |
|
|
|
|
|
static int rectify_apm(Ecma119Image *t) |
|
{ |
|
int ret; |
|
|
|
#ifdef NIX |
|
/* Disabled */ |
|
|
|
/* <<< ts B20526 : Dummy mock-up */ |
|
if (t->apm_req_count <= 0) { |
|
/* |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
16, 20, "Test1_name_16_20", "Test1_type"); |
|
/ * >>> Caution: Size 90 causes intentional partition overlap error * / |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
30, 90, "BAD_30_90_BAD", "Test1_type"); |
|
*/ |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
30, 20, "Test1_name_30_20", "Test1_type"); |
|
if (ret < 0) |
|
return ret; |
|
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), |
|
100, 400, "Test2_name_100_400", "Test2_type"); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
#endif /* NIX */ |
|
|
|
if (t->apm_req_count == 0) |
|
return 1; |
|
|
|
if (t->gpt_req_count > 0 && |
|
t->opts->apm_block_size != 2048 && t->apm_req_count > 0) { |
|
iso_msgs_submit(0, |
|
"GPT and APM requested. APM block size would have to be 2048.", |
|
0, "FAILURE", 0); |
|
return ISO_BOOT_APM_GPT_BSIZE; |
|
} |
|
if (t->apm_req_count > 0) { |
|
ret = fill_apm_gaps(t, t->curblock); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
/* flag bit0= do not write Block0 |
|
*/ |
|
static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, |
|
int flag) |
|
{ |
|
int i, ret; |
|
uint32_t block_fac = 1; |
|
/* This is a micro mock-up of an APM Block0 |
|
and also harmless x86 machine code. |
|
*/ |
|
static uint8_t block0_template[8] = { |
|
0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff |
|
}; |
|
|
|
if (t->apm_req_count <= 0) |
|
return 2; |
|
|
|
if (t->opts->apm_block_size == 0) { |
|
/* One cannot be sure that all GPT partitions are registered |
|
already. So it is necessary to choose the block size which is |
|
combinable with GPT but not mountable on Linux. |
|
*/ |
|
t->opts->apm_block_size = 2048; |
|
} |
|
|
|
if (t->apm_req_flags & 4) |
|
block_fac = 2048 / t->opts->apm_block_size; |
|
|
|
if (!(t->apm_req_flags & 2)) { |
|
/* Gaps have been filled. Care for the final one */ |
|
/* Adjust last partition to img_size. This size was not known when the |
|
number of APM partitions was determined. |
|
*/ |
|
if (img_blocks * block_fac < |
|
t->apm_req[t->apm_req_count - 1]->start_block) |
|
t->apm_req[t->apm_req_count - 1]->block_count = 0; |
|
else |
|
t->apm_req[t->apm_req_count - 1]->block_count = |
|
img_blocks * block_fac - |
|
t->apm_req[t->apm_req_count - 1]->start_block; |
|
/* If it is still empty, remove it */ |
|
if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { |
|
free(t->apm_req[t->apm_req_count - 1]); |
|
t->apm_req_count--; |
|
} |
|
} |
|
|
|
/* If block size is larger than 512, then not all 63 entries will fit */ |
|
if ((t->apm_req_count + 1) * t->opts->apm_block_size > 32768) |
|
return ISO_BOOT_TOO_MANY_APM; |
|
|
|
/* Block 1 describes the APM itself */ |
|
t->apm_req[0]->start_block = 1; |
|
t->apm_req[0]->block_count = t->apm_req_count; |
|
|
|
if (!(flag & 1)) { |
|
/* Write APM block 0. Very sparse, not to overwrite much of |
|
possible MBR. |
|
*/ |
|
memcpy(buf, block0_template, 8); |
|
buf[2]= (t->opts->apm_block_size >> 8) & 0xff; |
|
buf[3]= 0; |
|
} |
|
|
|
/* Write APM Block 1 to t->apm_req_count */ |
|
for (i = 0; i < t->apm_req_count; i++) { |
|
ret = iso_write_apm_entry(t, t->opts->apm_block_size, t->apm_req[i], |
|
buf + (i + 1) * t->opts->apm_block_size, t->apm_req_count, |
|
i == 0); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) |
|
{ |
|
int i, ret, req_of_slot[ISO_MBR_ENTRIES_MAX], q, j; |
|
|
|
#ifdef NIX |
|
/* Disabled */ |
|
|
|
/* <<< Dummy mock-up */ |
|
if (t->mbr_req_count <= 0) { |
|
ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), |
|
(uint64_t) 0, (uint64_t) 0, 0xee, 0, 0); |
|
if (ret < 0) |
|
return ret; |
|
ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), |
|
((uint64_t) 100) * 4, (uint64_t) 0, |
|
0x0c, 0x80, 1); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
#endif /* NIX */ |
|
|
|
if (t->mbr_req_count <= 0) |
|
return 2; |
|
|
|
/* >>> Sort by start block ? */ |
|
|
|
/* Adjust partition ends */ |
|
for (i = 0; i < t->mbr_req_count; i++) { |
|
if (i > 0) { |
|
if (t->mbr_req[i]->start_block <= t->mbr_req[i - 1]->start_block && |
|
!(t->mbr_req[i]->block_count == 0 && |
|
t->mbr_req[i]->start_block == |
|
t->mbr_req[i - 1]->start_block)) |
|
return ISO_BOOT_MBR_OVERLAP; |
|
if (t->mbr_req[i - 1]->start_block + |
|
t->mbr_req[i - 1]->block_count > t->mbr_req[i]->start_block) |
|
return ISO_BOOT_MBR_OVERLAP; |
|
} |
|
if (t->mbr_req[i]->block_count != 0) |
|
continue; |
|
if (i < t->mbr_req_count - 1) |
|
t->mbr_req[i]->block_count = t->mbr_req[i + 1]->start_block - |
|
t->mbr_req[i]->start_block; |
|
else |
|
t->mbr_req[i]->block_count = ((uint64_t) img_blocks) * 4 - |
|
t->mbr_req[i]->start_block; |
|
} |
|
|
|
/* Assign requested entries to slot numbers */ |
|
for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) |
|
req_of_slot[i] = -1; |
|
for (i = 0; i < t->mbr_req_count; i++) { |
|
if (t->mbr_req[i]->desired_slot < 1 || |
|
t->mbr_req[i]->desired_slot > ISO_MBR_ENTRIES_MAX) |
|
continue; |
|
if (req_of_slot[t->mbr_req[i]->desired_slot - 1] >= 0) |
|
return ISO_BOOT_MBR_COLLISION; |
|
req_of_slot[t->mbr_req[i]->desired_slot - 1] = i; |
|
} |
|
for (i = 0; i < t->mbr_req_count; i++) { |
|
if (t->mbr_req[i]->desired_slot > 0) |
|
continue; |
|
for (j = 0; j < ISO_MBR_ENTRIES_MAX; j++) |
|
if (req_of_slot[j] < 0) |
|
break; |
|
if (j >= ISO_MBR_ENTRIES_MAX) |
|
return ISO_BOOT_TOO_MANY_MBR; |
|
req_of_slot[j] = i; |
|
} |
|
|
|
/* Write partition slots */ |
|
for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) { |
|
memset(buf + 446 + i * 16, 0, 16); |
|
q = req_of_slot[i]; |
|
if (q < 0) |
|
continue; |
|
if (t->mbr_req[q]->block_count == 0) |
|
continue; |
|
ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[q]->type_byte, |
|
t->mbr_req[q]->start_block, t->mbr_req[q]->block_count, |
|
t->partition_secs_per_head, t->partition_heads_per_cyl, |
|
buf, 2); |
|
if (ret < 0) |
|
return ret; |
|
buf[446 + i * 16] = t->mbr_req[q]->status_byte; |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
static void iso_write_gpt_entry(Ecma119Image *t, uint8_t *buf, |
|
uint8_t type_guid[16], uint8_t part_uuid[16], |
|
uint64_t start_lba, uint64_t end_lba, |
|
uint64_t flags, uint8_t name[72]) |
|
{ |
|
char *wpt; |
|
int i; |
|
|
|
wpt = (char *) buf; |
|
memcpy(wpt, type_guid, 16); |
|
wpt += 16; |
|
for (i = 0; i < 16; i++) |
|
if (part_uuid[i]) |
|
break; |
|
if (i == 16) { |
|
if (!t->gpt_disk_guid_set) |
|
iso_gpt_uuid(t, t->gpt_disk_guid); |
|
t->gpt_disk_guid_set = 1; |
|
iso_gpt_uuid(t, part_uuid); |
|
} |
|
memcpy(wpt, part_uuid, 16); |
|
wpt += 16; |
|
iso_lsb_to_buf(&wpt, start_lba & 0xffffffff, 4, 0); |
|
iso_lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 4, 0); |
|
iso_lsb_to_buf(&wpt, end_lba & 0xffffffff, 4, 0); |
|
iso_lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 4, 0); |
|
iso_lsb_to_buf(&wpt, flags & 0xffffffff, 4, 0); |
|
iso_lsb_to_buf(&wpt, (flags >> 32) & 0xffffffff, 4, 0); |
|
memcpy(wpt, name, 72); |
|
} |
|
|
|
|
|
int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, |
|
uint8_t *buf, uint32_t max_entries, |
|
uint32_t part_start, uint32_t p_arr_crc) |
|
{ |
|
static char *sig = "EFI PART"; |
|
static char revision[4] = {0x00, 0x00, 0x01, 0x00}; |
|
char *wpt; |
|
uint32_t crc; |
|
off_t back_lba; |
|
|
|
memset(buf, 0, 512); |
|
wpt = (char *) buf; |
|
|
|
/* >>> Make signature adjustable */ |
|
memcpy(wpt, sig, 8); /* no trailing 0 */ |
|
wpt += 8; |
|
|
|
memcpy(wpt, revision, 4); |
|
wpt += 4; |
|
iso_lsb_to_buf(&wpt, 92, 4, 0); |
|
|
|
/* CRC will be inserted later */ |
|
wpt += 4; |
|
|
|
/* reserved */ |
|
iso_lsb_to_buf(&wpt, 0, 4, 0); |
|
/* Own LBA low 32 */ |
|
iso_lsb_to_buf(&wpt, 1, 4, 0); |
|
/* Own LBA high 32 */ |
|
iso_lsb_to_buf(&wpt, 0, 4, 0); |
|
|
|
/* Backup header LBA is 1 hd block before backup GPT area end */ |
|
back_lba = t->gpt_backup_end * 4 - 1; |
|
iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1); |
|
iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1); |
|
|
|
/* First usable LBA for partitions (4 entries per hd block) */ |
|
iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0); |
|
iso_lsb_to_buf(&wpt, 0, 4, 0); |
|
|
|
/* Last usable LBA for partitions is 1 hd block before first backup entry*/ |
|
iso_lsb_to_buf(&wpt, |
|
(uint32_t) ((back_lba - max_entries / 4 - 1) & 0xffffffff), |
|
4, 1); |
|
iso_lsb_to_buf(&wpt, |
|
(uint32_t) ((back_lba - max_entries / 4 - 1) >> 32), 4, 1); |
|
|
|
/* Disk GUID */ |
|
if (!t->gpt_disk_guid_set) |
|
iso_gpt_uuid(t, t->gpt_disk_guid); |
|
t->gpt_disk_guid_set = 1; |
|
memcpy(wpt, t->gpt_disk_guid, 16); |
|
wpt += 16; |
|
|
|
/* Partition entries start */ |
|
iso_lsb_to_buf(&wpt, part_start, 4, 0); |
|
iso_lsb_to_buf(&wpt, 0, 4, 0); |
|
|
|
/* Number of partition entries */ |
|
iso_lsb_to_buf(&wpt, max_entries, 4, 0); |
|
|
|
/* Size of a partition entry */ |
|
iso_lsb_to_buf(&wpt, 128, 4, 0); |
|
|
|
/* CRC-32 of the partition array */ |
|
iso_lsb_to_buf(&wpt, p_arr_crc, 4, 0); |
|
|
|
|
|
/* <<< Only for a first test */ |
|
if (wpt - (char *) buf != 92) { |
|
iso_msgs_submit(0, |
|
"program error : write_gpt_header_block : wpt != 92", |
|
0, "FATAL", 0); |
|
return ISO_ISOLINUX_CANT_PATCH; |
|
} |
|
|
|
/* CRC-32 of this header while head_crc is 0 */ |
|
crc = iso_crc32_gpt((unsigned char *) buf, 92, 0); |
|
wpt = ((char *) buf) + 16; |
|
iso_lsb_to_buf(&wpt, crc, 4, 0); |
|
|
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* Only for up to 36 characters ISO-8859-1 (or ASCII) input */ |
|
void iso_ascii_utf_16le(uint8_t gap_name[72]) |
|
{ |
|
int i; |
|
|
|
for (i = strlen((char *) gap_name) - 1; i >= 0; i--) { |
|
gap_name[2 * i] = gap_name[i]; |
|
gap_name[2 * i + 1] = 0; |
|
} |
|
} |
|
|
|
|
|
static int intvl_overlap(uint64_t start1, uint64_t end1, |
|
uint64_t start2, uint64_t end2, int second) |
|
{ |
|
if (start1 >= start2 && start1 <= end2) |
|
return 1; |
|
if (end1 >= start2 && end1 <= end2) |
|
return 1; |
|
if (!second) |
|
return intvl_overlap(start2, end2, start1, end1, 1); |
|
return 0; |
|
} |
|
|
|
|
|
/* Check APM HFS+ partitions whether they would fit in gaps. |
|
If so, add them as GPT partitions, too. |
|
*/ |
|
static int iso_copy_apmhfs_to_gpt(Ecma119Image *t, int flag) |
|
{ |
|
int a, i, counter = 0, ret; |
|
uint64_t bfac = 4; |
|
static uint8_t hfs_plus_uuid[16] = { |
|
0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, |
|
0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac |
|
}; |
|
static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
|
uint8_t gpt_name[72]; |
|
static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; |
|
|
|
if ((t->apm_req_flags & 4) && t->opts->apm_block_size / 512 > 0) |
|
bfac = t->opts->apm_block_size / 512; |
|
|
|
for (a = 0; a < t->apm_req_count; a++) { |
|
if (strcmp((char *) t->apm_req[a]->type, "Apple_HFS") != 0) |
|
continue; |
|
for (i = 0; i < t->gpt_req_count; i++) |
|
if (intvl_overlap(t->apm_req[a]->start_block * bfac, |
|
(t->apm_req[a]->start_block + |
|
t->apm_req[a]->block_count - 1) * bfac, |
|
t->gpt_req[i]->start_block, |
|
t->gpt_req[i]->start_block + |
|
t->gpt_req[i]->block_count - 1, 0)) |
|
break; |
|
if (i >= t->gpt_req_count) { |
|
memset(gpt_name, 0, 72); |
|
counter++; |
|
if (counter > 1) |
|
sprintf((char *) gpt_name, "HFSPLUS_%d", counter); |
|
else |
|
sprintf((char *) gpt_name, "HFSPLUS"); |
|
iso_ascii_utf_16le(gpt_name); |
|
ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), |
|
t->apm_req[a]->start_block * bfac, |
|
t->apm_req[a]->block_count * bfac, |
|
hfs_plus_uuid, zero_uuid, |
|
gpt_flags, gpt_name); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) |
|
{ |
|
static uint8_t basic_data_uuid[16] = { |
|
0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, |
|
0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 |
|
}; |
|
|
|
uint32_t p_arr_crc = 0; |
|
uint64_t start_lba, end_lba, goal, part_end, next_end, backup_end_lba; |
|
uint64_t eff_gpt_flags; |
|
int ret, i, gap_counter = 0, up_to; |
|
struct iso_gpt_partition_request *req; |
|
uint8_t gpt_name[72]; |
|
static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
|
static uint8_t *type_guid; |
|
static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; |
|
|
|
if (t->gpt_req_count == 0) |
|
return 2; |
|
backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * 4; |
|
|
|
ret = iso_copy_apmhfs_to_gpt(t, 0); |
|
if (ret <= 0) |
|
return ret; |
|
|
|
/* Sort and fill gaps */ |
|
qsort(t->gpt_req, t->gpt_req_count, |
|
sizeof(struct iso_gpt_partition_request *), cmp_partition_request); |
|
/* t->gpt_req_count will grow during the loop */ |
|
up_to = t->gpt_req_count + 1; |
|
goal = 0; |
|
part_end = 0; |
|
|
|
if (t->opts->part_like_isohybrid) |
|
up_to = 0; /* No gap filling */ |
|
|
|
for (i = 0; i < up_to; i++) { |
|
if (i < up_to - 1) { |
|
goal = t->gpt_req[i]->start_block; |
|
} else { |
|
goal = ((uint64_t) img_blocks) * 4; |
|
if (goal > backup_end_lba) |
|
goal = backup_end_lba; |
|
} |
|
if (i == 0) { |
|
if (goal <= 16 * 4) |
|
continue; |
|
next_end = 16 * 4; |
|
} else { |
|
next_end = t->gpt_req[i - 1]->start_block + |
|
t->gpt_req[i - 1]->block_count; |
|
} |
|
if (next_end > part_end) |
|
part_end = next_end; |
|
if (part_end > goal) { |
|
if (!(t->gpt_req_flags & 1)) { |
|
iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0, |
|
"Program error: GPT partitions %d and %d overlap by %.f blocks", |
|
i - 1, i, (double) (part_end - goal)); |
|
return ISO_BOOT_GPT_OVERLAP; |
|
} |
|
} else if (part_end < goal) { |
|
memset(gpt_name, 0, 72); |
|
type_guid = basic_data_uuid; |
|
eff_gpt_flags= gpt_flags; |
|
if (goal == t->vol_space_size * (uint64_t) 4 && |
|
part_end == t->opts->partition_offset * (uint64_t) 4) { |
|
sprintf((char *) gpt_name, "ISO9660"); |
|
if (t->opts->iso_gpt_flag & 1) |
|
type_guid = t->opts->iso_gpt_type_guid; |
|
if (t->system_area_options & (1 << 16)) |
|
eff_gpt_flags|= 4; /* Legacy BIOS bootable */ |
|
if (t->system_area_options & (1 << 17)) |
|
eff_gpt_flags&= ~(((uint64_t) 1) << 60);/* Not read-only */ |
|
} else { |
|
sprintf((char *) gpt_name, "Gap%d", gap_counter); |
|
} |
|
iso_ascii_utf_16le(gpt_name); |
|
gap_counter++; |
|
ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), |
|
part_end, goal - part_end, |
|
type_guid, zero_uuid, |
|
eff_gpt_flags, gpt_name); |
|
if (ret < 0) |
|
return ret; |
|
/* Mark as automatically placed filler request */ |
|
t->gpt_req[t->gpt_req_count - 1]->req_status |= 1; |
|
} |
|
} |
|
/* Merge list of gap partitions with list of already sorted entries */ |
|
qsort(t->gpt_req, t->gpt_req_count, |
|
sizeof(struct iso_gpt_partition_request *), cmp_partition_request); |
|
|
|
if ((int) t->gpt_max_entries < t->gpt_req_count) |
|
return ISO_BOOT_TOO_MANY_GPT; |
|
|
|
/* Write the GPT entries to buf */ |
|
for (i = 0; i < t->gpt_req_count; i++) { |
|
req = t->gpt_req[i]; |
|
start_lba = req->start_block; |
|
end_lba = req->start_block + req->block_count; |
|
if (req->start_block == t->opts->partition_offset * ((uint64_t) 4) && |
|
req->block_count == ((uint64_t) 4) * 0xffffffff) |
|
end_lba = t->vol_space_size * 4; |
|
if (end_lba > backup_end_lba) |
|
end_lba = backup_end_lba; |
|
end_lba = end_lba - 1; |
|
iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i, |
|
req->type_guid, req->partition_guid, |
|
start_lba, end_lba, req->flags, req->name); |
|
} |
|
for (; i < (int) t->gpt_max_entries; i++) |
|
memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128); |
|
|
|
p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start, |
|
128 * t->gpt_max_entries, 0); |
|
ret = iso_write_gpt_header_block(t, img_blocks, buf + 512, |
|
t->gpt_max_entries, |
|
t->gpt_part_start, p_arr_crc); |
|
if (ret < 0) |
|
return ret; |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* Add a dummy MBR partition of type 0 with boot flag */ |
|
static void iso_dummy_mbr_partition(uint8_t *buf, int mode) |
|
{ |
|
int i; |
|
/* bootable , start 0/0/1, type 0x00, end 0/0/1, |
|
start LBA 0, block count 1 */ |
|
static uint8_t dummy_entry[16] = { |
|
0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, |
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; |
|
|
|
for (i = 0; i < 4; i++) { |
|
if (mbr_part_slot_is_unused(buf + 446 + 16 * i)) { |
|
memcpy(buf + 446 + 16 * i, dummy_entry, 16); |
|
return; |
|
} |
|
} |
|
/* Abundance of 0xee and 0xef partitions. No other one free. */ |
|
for (i = 0; i < 4; i++) { |
|
if (buf[446 + 16 * i + 4] != 0xef) { |
|
buf[446 + 16 * i] |= 0x80; |
|
return; |
|
} |
|
} |
|
i = 3; |
|
buf[446 + 16 * i] |= 0x80; |
|
} |
|
|
|
|
|
/* flag bit0= only accept partition 1 as match for partition_offset |
|
*/ |
|
static |
|
int iso_ensure_mbr_part_table(Ecma119Image *t, uint32_t img_blocks, |
|
uint8_t *buf, int flag) |
|
{ |
|
int part_type, ret, i, found_part = 0; |
|
uint32_t start_lba, num_blocks; |
|
|
|
/* Look for MBR partition which starts at t->opts->partition_offset * 4 |
|
and has non-zero length |
|
*/ |
|
if (buf[510] == 0x55 && buf[511] == 0xaa && |
|
t->opts->partition_offset < 0x3fffffff && img_blocks < 0x3fffffff ) { |
|
for (i = 0; i < 4; i++) { |
|
start_lba = iso_read_lsb(buf + 446 + i * 16 + 8, 4); |
|
num_blocks = iso_read_lsb(buf + 446 + i * 16 + 12, 4); |
|
if (t->opts->partition_offset * 4 == start_lba && num_blocks > 0) { |
|
found_part = i + 1; |
|
break; |
|
} |
|
if (flag & 1) |
|
break; |
|
} |
|
} |
|
if (found_part > 0) { |
|
/* Update size fields in found_part */ |
|
part_type = buf[446 + (found_part - 1) * 16 + 4]; |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
ret = write_mbr_partition_entry(found_part, part_type, |
|
start_lba, img_blocks * 4, |
|
t->partition_secs_per_head, |
|
t->partition_heads_per_cyl, buf, 2); |
|
} else { |
|
part_type = 0xcd; |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head, |
|
t->partition_heads_per_cyl, |
|
(uint8_t) part_type, buf, 2); |
|
} |
|
if (ret != ISO_SUCCESS) /* error should never happen */ |
|
return ISO_ASSERT_FAILURE; |
|
return ISO_SUCCESS; |
|
} |
|
|
|
|
|
/* @param flag |
|
bit0= t->opts->ms_block is not counted in t->total_size |
|
*/ |
|
int iso_write_system_area(Ecma119Image *t, uint8_t *buf, int flag) |
|
{ |
|
int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0; |
|
int first_partition = 1, last_partition = 4, apm_flag, part_type = 0; |
|
int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0; |
|
int offset_flag = 0, risk_of_ee = 0; |
|
uint32_t img_blocks, gpt_blocks, mbrp1_blocks, pml_blocks; |
|
uint64_t blk; |
|
uint8_t *wpt; |
|
|
|
if ((t == NULL) || (buf == NULL)) { |
|
return ISO_NULL_POINTER; |
|
} |
|
|
|
/* set buf to 0s */ |
|
memset(buf, 0, 16 * BLOCK_SIZE); |
|
|
|
sa_type = (t->system_area_options >> 2) & 0x3f; |
|
|
|
iso_tell_max_part_range(t->opts, &first_partition, &last_partition, 0); |
|
for (i = first_partition - 1; i <= last_partition - 1; i++) |
|
if (t->opts->appended_partitions[i] != NULL) { |
|
will_append = 1; |
|
break; |
|
} |
|
|
|
#ifdef Libisofs_appended_partitions_inlinE |
|
img_blocks = t->vol_space_size; |
|
#else |
|
img_blocks = t->curblock; |
|
#endif |
|
|
|
if (t->system_area_data != NULL) { |
|
/* Write more or less opaque boot image */ |
|
memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE); |
|
|
|
} else if (sa_type == 0 && t->catalog != NULL && |
|
(t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) { |
|
/* Check for isolinux image with magic number of 3.72 and produce |
|
an MBR from our built-in template. (Deprecated since 31 Mar 2010) |
|
*/ |
|
if (t->bootsrc[0] == NULL) |
|
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem."); |
|
if (img_blocks < 0x80000000) { |
|
int_img_blocks= img_blocks; |
|
} else { |
|
int_img_blocks= 0x7ffffff0; |
|
} |
|
ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block, |
|
&int_img_blocks, (char*)buf, 0); |
|
if (ret != 1) { |
|
/* error, it should never happen */ |
|
return ISO_ASSERT_FAILURE; |
|
} |
|
return ISO_SUCCESS; |
|
} |
|
|
|
/* If APM entries were submitted to iso_register_apm_entry(), then they |
|
get sprinkled over the system area after the system area template was |
|
loaded and before any other data get inserted. |
|
Note that if APM and MBR get combined, then the first 8 bytes of the MBR |
|
template must be replaceable by: |
|
{0x45, 0x52, 0x08 0x00, 0xeb, 0x02, 0xff, 0xff} |
|
|
|
>>> ts B20526 |
|
>>> This does not care for eventual image enlargements in last minute. |
|
>>> A sa_type, that does this, will have to adjust the last APM entry |
|
>>> if exactness matters. |
|
*/ |
|
|
|
apm_flag = 0; |
|
if (sa_type == 0 && ((t->system_area_options & 3) == 2 || |
|
t->opts->part_like_isohybrid)) { |
|
if (sa_type == 0 && (t->system_area_options & 3) == 2) |
|
do_isohybrid = 1; |
|
|
|
/* >>> Coordinate with partprepend writer */ |
|
/* <<< provisory trap */ |
|
if (t->mbr_req_count > 0) |
|
return ISO_BOOT_MBR_OVERLAP; |
|
|
|
/* If own APM is desired, set flag bit0 to prevent writing of Block0 |
|
which would interfere with the own Block0 of isohybrid. |
|
*/ |
|
ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0); |
|
if (ret < 0) |
|
return ret; |
|
if (apm_count > 0) |
|
apm_flag |= 1; |
|
} |
|
|
|
ret = iso_write_apm(t, img_blocks, buf, apm_flag); |
|
if (ret < 0) { |
|
iso_msg_submit(t->image->id, ret, 0, |
|
"Cannot set up Apple Partition Map"); |
|
return ret; |
|
} |
|
ret = iso_write_mbr(t, img_blocks, buf); |
|
if (ret < 0) { |
|
iso_msg_submit(t->image->id, ret, 0, |
|
"Cannot set up MBR partition table"); |
|
return ret; |
|
} |
|
if (t->mbr_req_count > 0) { |
|
if (sa_type != 0) |
|
return ISO_NON_MBR_SYS_AREA; |
|
risk_of_ee = 1; |
|
} |
|
|
|
if (t->gpt_backup_outside) |
|
gpt_blocks = t->total_size / BLOCK_SIZE + |
|
(flag & 1) * t->opts->ms_block; |
|
else |
|
gpt_blocks = img_blocks; |
|
ret = iso_write_gpt(t, gpt_blocks, buf); |
|
if (ret < 0) { |
|
iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); |
|
return ret; |
|
} |
|
|
|
if (sa_type == 0 && (t->system_area_options & 1)) { |
|
if (t->mbr_req_count == 0){ |
|
/* Write GRUB protective msdos label, i.e. a simple partition |
|
table */ |
|
if (t->gpt_req_count > 0 && ! t->opts->part_like_isohybrid) { |
|
part_type = 0xee; |
|
pml_blocks = gpt_blocks; |
|
} else { |
|
part_type = 0xcd; |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
pml_blocks = img_blocks; |
|
} |
|
ret = make_grub_msdos_label(pml_blocks, t->partition_secs_per_head, |
|
t->partition_heads_per_cyl, |
|
(uint8_t) part_type, buf, 0); |
|
if (ret != ISO_SUCCESS) /* error should never happen */ |
|
return ISO_ASSERT_FAILURE; |
|
risk_of_ee = 1; |
|
} else if (t->gpt_req_count > 0) { |
|
|
|
/* >>> ??? change first partition type to 0xee */; |
|
|
|
} |
|
} else if (do_isohybrid || t->opts->part_like_isohybrid) { |
|
/* Patch externally provided system area as isohybrid MBR |
|
or at least write an MBR partition table as of isohybrid |
|
*/ |
|
if ((t->catalog == NULL || t->system_area_data == NULL) && |
|
do_isohybrid) { |
|
/* isohybrid makes only sense together with ISOLINUX boot image |
|
and externally provided System Area. |
|
*/ |
|
return ISO_ISOLINUX_CANT_PATCH; |
|
} |
|
|
|
if (gpt_count > 0 || apm_count > 0) { |
|
/* Decision can be revoked in make_isolinux_mbr if !do_isohybrid */ |
|
part_type = 0x00; |
|
} else { |
|
part_type = 0x17; |
|
} |
|
/* By tradition, real isohybrid insists in 0x00 if GPT or APM */ |
|
if (part_type != 0x00 || !do_isohybrid) |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
|
|
if (t->opts->appended_as_gpt && t->have_appended_partitions) { |
|
part_type = 0xee; |
|
risk_of_ee = 1; |
|
img_blocks = gpt_blocks; |
|
no_boot_mbr = 2; |
|
} |
|
|
|
/* ??? Why was partition_offset 0 here ? |
|
It gets adjusted later by iso_offset_partition_start() |
|
Does it harm to give the real offset here ? |
|
Now this is really needed for checking whether partitions |
|
are inside the ISO 9660 partition if !do_isohybrid |
|
*/ |
|
ret = make_isolinux_mbr(&img_blocks, t, t->opts->partition_offset * 4, |
|
1, part_type, buf, |
|
1 | no_boot_mbr | ((!do_isohybrid) << 2) | |
|
((!do_isohybrid) << 3)); |
|
if (ret != 1) |
|
return ret; |
|
} else if (sa_type == 1) { |
|
ret = make_mips_volume_header(t, buf, 0); |
|
if (ret != ISO_SUCCESS) |
|
return ret; |
|
} else if (sa_type == 2) { |
|
ret = make_mipsel_boot_block(t, buf, 0); |
|
if (ret != ISO_SUCCESS) |
|
return ret; |
|
} else if (sa_type == 3) { |
|
ret = make_sun_disk_label(t, buf, 0); |
|
if (ret != ISO_SUCCESS) |
|
return ret; |
|
} else if (sa_type == 4 || sa_type == 5) { |
|
/* (By coincidence, sa_type and PALO header versions match) */ |
|
ret = make_hppa_palo_sector(t, buf, sa_type, 0); |
|
if (ret != ISO_SUCCESS) |
|
return ret; |
|
} else if (sa_type == 6) { |
|
ret = make_dec_alpha_sector(t, buf, 0); |
|
if (ret != ISO_SUCCESS) |
|
return ret; |
|
} else if ((t->opts->partition_offset > 0 || will_append) && |
|
sa_type == 0 && t->mbr_req_count == 0) { |
|
ret= iso_ensure_mbr_part_table(t, img_blocks, buf, |
|
((t->opts->appended_as_gpt && t->have_appended_partitions) || |
|
t->opts->partition_offset == 0)); |
|
if (ret != ISO_SUCCESS) /* error should never happen */ |
|
return ISO_ASSERT_FAILURE; |
|
risk_of_ee = 1; |
|
if (t->opts->appended_as_gpt && t->have_appended_partitions) { |
|
|
|
/* >>> ??? Do this in any case of t->gpt_req_count > ? */; |
|
|
|
/* Re-write partition entry 1 : protective MBR for GPT */ |
|
part_type = 0xee; |
|
risk_of_ee = 1; |
|
ret = write_mbr_partition_entry(1, part_type, |
|
(uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1, |
|
t->partition_secs_per_head, t->partition_heads_per_cyl, |
|
buf, 2); |
|
if (ret < 0) |
|
return ret; |
|
} else if (t->opts->partition_offset == 0) { |
|
/* Re-write partition entry 1 : start at 0, type Linux */ |
|
blk = ((uint64_t) img_blocks) * 4 - t->post_iso_part_pad / 512; |
|
part_type = 0x83; |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
ret = write_mbr_partition_entry(1, part_type, (uint64_t) 0, blk, |
|
t->partition_secs_per_head, t->partition_heads_per_cyl, |
|
buf, 2); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
|
|
/* Check for protective MBR in mbr_req and adjust to GPT size */ |
|
if (t->gpt_req_count > 0 && sa_type == 0 && t->mbr_req_count == 1) { |
|
if (t->mbr_req[0]->type_byte == 0xee && buf[450] == 0xee && |
|
t->mbr_req[0]->desired_slot <= 1) { |
|
part_type = 0xee; |
|
risk_of_ee = 1; |
|
ret = write_mbr_partition_entry(1, part_type, |
|
(uint64_t) 1, ((uint64_t) gpt_blocks) * 4 - 1, |
|
t->partition_secs_per_head, t->partition_heads_per_cyl, |
|
buf, 2); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
|
|
if (t->opts->partition_offset > 0 && sa_type == 0 && |
|
t->mbr_req_count == 0) { |
|
/* Adjust partition table to partition offset. |
|
With t->mbr_req_count > 0 this has already been done, |
|
*/ |
|
|
|
#ifndef Libisofs_appended_partitions_inlinE |
|
|
|
img_blocks = t->curblock; /* value might have been altered */ |
|
|
|
#else |
|
|
|
/* A change of t->curblock does not matter in this case */ |
|
|
|
#endif |
|
|
|
if (part_type == 0xee && t->gpt_req_count > 0) { |
|
mbrp1_blocks = t->total_size / BLOCK_SIZE + |
|
(flag & 1) * t->opts->ms_block; |
|
offset_flag |= 2 | 1; /* protective MBR, no other partitions */ |
|
} else { |
|
mbrp1_blocks = img_blocks; |
|
} |
|
ret = iso_offset_partition_start(mbrp1_blocks, t->post_iso_part_pad, |
|
t->opts->partition_offset, |
|
t->partition_secs_per_head, |
|
t->partition_heads_per_cyl, buf, |
|
offset_flag); |
|
if (ret != ISO_SUCCESS) /* error should never happen */ |
|
return ISO_ASSERT_FAILURE; |
|
} |
|
|
|
/* This possibly overwrites the non-mbr_req partition table entries |
|
made so far. Overwriting those from t->mbr_req is not allowed. |
|
*/ |
|
if (sa_type == 3 || |
|
!(t->opts->appended_as_gpt || t->opts->appended_as_apm)) { |
|
for (i = first_partition - 1; i <= last_partition - 1; i++) { |
|
if (t->opts->appended_partitions[i] == NULL) |
|
continue; |
|
if (i < t->mbr_req_count) |
|
return ISO_BOOT_MBR_COLLISION; |
|
if (sa_type == 3) { |
|
ret = write_sun_partition_entry(i + 1, |
|
t->opts->appended_partitions, |
|
t->appended_part_start, t->appended_part_size, |
|
ISO_SUN_CYL_SIZE, |
|
buf, t->opts->appended_partitions[i][0] == 0); |
|
} else { |
|
ret = write_mbr_partition_entry(i + 1, |
|
t->opts->appended_part_types[i], |
|
(uint64_t) t->appended_part_start[i], |
|
(uint64_t) t->appended_part_size[i], |
|
t->partition_secs_per_head, t->partition_heads_per_cyl, |
|
buf, 0); |
|
} |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
|
|
if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) { |
|
/* Patch MBR for GRUB2 */ |
|
if (t->num_bootsrc <= 0) |
|
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"No boot image found as jump target for GRUB2 MBR."); |
|
if (t->bootsrc[0] == NULL) |
|
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, |
|
"Cannot refer by GRUB2 MBR to data outside of ISO 9660 filesystem."); |
|
blk = t->bootsrc[0]->sections[0].block * 4 + |
|
Libisofs_grub2_mbr_patch_offsT; |
|
wpt = buf + Libisofs_grub2_mbr_patch_poS; |
|
for (i = 0; i < 8; i++) |
|
wpt[i] = blk >> (i * 8); |
|
} |
|
|
|
/* Prevent partition type 0xee if no GPT emerged */ |
|
|
|
/* >>> ??? check for GPT magic number at byte 512 ff. ? */; |
|
|
|
if (sa_type == 0 && ((t->system_area_options & 3) || risk_of_ee) && |
|
(t->opts->part_like_isohybrid || t->gpt_req_count == 0) && |
|
t->opts->iso_mbr_part_type != 0xee) { |
|
for (i = 0; i < 4; i++) { |
|
if (buf[446 + 16 * i + 4] == 0xee) { |
|
iso_msgs_submit(0, |
|
"Prevented partition type 0xEE in MBR without GPT", |
|
0, "WARNING", 0); |
|
part_type = 0xcd; |
|
if (t->opts->iso_mbr_part_type >= 0 && |
|
t->opts->iso_mbr_part_type <= 255) |
|
part_type= t->opts->iso_mbr_part_type; |
|
buf[446 + 16 * i + 4] = (uint8_t) part_type; |
|
} |
|
} |
|
} |
|
|
|
if (sa_type == 0 && ( |
|
(t->system_area_options & 3) || |
|
(t->system_area_options & (1 << 14)) || |
|
(((t->system_area_options >> 10) & 15) != 1 && |
|
(t- |