New API call iso_write_opts_set_system_area() acts like mkisofs option -G

This commit is contained in:
Thomas Schmitt 2010-04-06 14:41:36 +02:00
parent f0f378c38f
commit f13167335a
6 changed files with 218 additions and 39 deletions

View File

@ -73,6 +73,9 @@ void ecma119_image_free(Ecma119Image *t)
if (t->output_charset != NULL) if (t->output_charset != NULL)
free(t->output_charset); free(t->output_charset);
if (t->system_area_data != NULL)
free(t->system_area_data);
#ifdef Libisofs_with_checksumS #ifdef Libisofs_with_checksumS
if (t->checksum_ctx != NULL) { /* dispose checksum context */ if (t->checksum_ctx != NULL) { /* dispose checksum context */
char md5[16]; char md5[16];
@ -1127,6 +1130,17 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->eltorito = (src->bootcat == NULL ? 0 : 1); target->eltorito = (src->bootcat == NULL ? 0 : 1);
target->catalog = src->bootcat; target->catalog = src->bootcat;
target->system_area_data = NULL;
if(opts->system_area_data != NULL) {
target->system_area_data = calloc(32768, 1);
if (target->system_area_data == NULL) {
ret = ISO_OUT_OF_MEM;
goto target_cleanup;
}
memcpy(target->system_area_data, opts->system_area_data, 32768);
}
target->system_area_options = opts->system_area_options;
target->input_charset = strdup(iso_get_local_charset(0)); target->input_charset = strdup(iso_get_local_charset(0));
if (target->input_charset == NULL) { if (target->input_charset == NULL) {
ret = ISO_OUT_OF_MEM; ret = ISO_OUT_OF_MEM;
@ -1700,6 +1714,8 @@ void iso_write_opts_free(IsoWriteOpts *opts)
} }
free(opts->output_charset); free(opts->output_charset);
if(opts->system_area_data != NULL)
free(opts->system_area_data);
free(opts); free(opts);
} }
@ -2085,3 +2101,28 @@ int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start,
return ISO_SUCCESS; return ISO_SUCCESS;
} }
/*
* @param data Either NULL or 32 kB of data. Do not submit less bytes !
* @param options bit0 = apply GRUB protective msdos label
* @param flag bit0 = invalidate any attached system area data
* same as data == NULL
*/
int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768],
int options, int flag)
{
if (data == NULL || (flag & 1)) { /* Disable */
if (opts->system_area_data != NULL)
free(opts->system_area_data);
opts->system_area_data = NULL;
} else {
if (opts->system_area_data == NULL) {
opts->system_area_data = calloc(32768, 1);
if (opts->system_area_data == NULL)
return ISO_OUT_OF_MEM;
}
memcpy(opts->system_area_data, data, 32768);
}
opts->system_area_options = options & 1;
return ISO_SUCCESS;
}

View File

@ -298,6 +298,11 @@ struct iso_write_opts {
*/ */
char *scdbackup_tag_written; char *scdbackup_tag_written;
/*
* See ecma119_image : System Area related information
*/
char *system_area_data;
int system_area_options;
}; };
typedef struct ecma119_image Ecma119Image; typedef struct ecma119_image Ecma119Image;
@ -436,6 +441,22 @@ struct ecma119_image
IsoFileSrc *cat; /**< location of the boot catalog in the new image */ IsoFileSrc *cat; /**< location of the boot catalog in the new image */
IsoFileSrc *bootimg; /**< location of the boot image in the new image */ IsoFileSrc *bootimg; /**< location of the boot image in the new image */
/*
* System Area related information
*/
/* Content of an embedded boot image. Valid if not NULL.
* In that case it must point to a memory buffer at least 32 kB.
*/
char *system_area_data;
/*
* bit0= make bytes 446 - 512 of the system area a partition
* table which reserves partition 1 from byte 63*512 to the
* end of the ISO image. Assumed are 63 secs/hed, 255 head/cyl.
* (GRUB protective msdos label.)
* This works with and without system_area_data.
*/
int system_area_options;
/* /*
* Number of pad blocks that we need to write. Padding blocks are blocks * Number of pad blocks that we need to write. Padding blocks are blocks
* filled by 0s that we put between the directory structures and the file * filled by 0s that we put between the directory structures and the file

View File

@ -333,9 +333,11 @@ int create_image(IsoImage *image, const char *image_path,
boot->image = (IsoFile*)imgfile; boot->image = (IsoFile*)imgfile;
iso_node_ref(imgfile); /* get our ref */ iso_node_ref(imgfile); /* get our ref */
boot->bootable = 1; boot->bootable = 1;
boot->isolinux_options = 0;
boot->type = boot_media_type; boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type; boot->partition_type = partition_type;
boot->load_seg = 0;
boot->load_size = load_sectors;
if (bootimg) { if (bootimg) {
*bootimg = boot; *bootimg = boot;

View File

@ -39,7 +39,8 @@ struct el_torito_boot_image {
/** /**
* isolinux options * isolinux options
* bit 0 -> whether to patch image * bit 0 -> whether to patch image
* bit 1 -> whether to create isolinux image * bit 1 -> whether to put built-in isolinux 3.72 isohybrid-MBR into image
* System Area (deprecated)
*/ */
unsigned int isolinux_options:2; unsigned int isolinux_options:2;
unsigned char type; /**< The type of image */ unsigned char type; /**< The type of image */

View File

@ -1680,6 +1680,32 @@ int iso_write_opts_set_overwrite_buf(IsoWriteOpts *opts, uint8_t *overwrite);
*/ */
int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size);
/*
* Attach 32 kB of binary data which shall get written to the first 32 kB
* of the ISO image, the ECMA-119 System Area. This space is intended for
* system dependent boot software, e.g. a Master Boot Record which allows to
* boot from USB sticks or hard disks. ECMA-119 makes no own assumptions or
* prescriptions about the byte content.
*
* If system area data are given or options bit0 is set, then bit1 of
* el_torito_set_isolinux_options() is automatically disabled.
* @param data
* Either NULL or 32 kB of data. Do not submit less bytes !
* @param options
* Can cause manipulations of submitted data before they get written:
* bit0= apply a --protective-msdos-label as of grub-mkisofs.
* This means to patch bytes 446 to 512 of the system area so
* that one partition is defined which begins at the second
* 512-byte block of the image and ends where the image ends.
* @param flag
* bit0 = invalidate any attached system area data. Same as data == NULL
* @return
* ISO_SUCCESS or error
* @since 0.6.30
*/
int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768],
int options, int flag);
/** /**
* Inquire the start address of the file data blocks after having used * Inquire the start address of the file data blocks after having used
* IsoWriteOpts with iso_image_create_burn_source(). * IsoWriteOpts with iso_image_create_burn_source().
@ -2325,19 +2351,27 @@ void el_torito_set_no_bootable(ElToritoBootImage *bootimg);
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg); void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg);
/** /**
* Specifies options for IsoLinux boot images. This should only be used with * Specifies options for ISOLINUX or GRUB boot images. This should only be used
* isolinux boot images. * if the type of boot image is known.
* *
* @param options * @param options
* bitmask style flag. The following values are defined: * bitmask style flag. The following values are defined:
* *
* bit 0 -> 1 to patch the image, 0 to not * bit 0 -> 1 to patch the boot info table of the boot image.
* Patching the image involves the writing of a 56 bytes * 1 does the same as mkisofs option -boot-info-table.
* boot information table at offset 8 of the boot image file. * Needed for ISOLINUX and for GRUB rescue boot images.
* The original boot image file will not be modified. This is * The table is located at byte 8 of the boot image file.
* needed to allow isolinux images to be bootable. * Its size is 56 bytes.
* bit 1 -> 1 to generate an hybrid image with MBR, 0 to not * The original boot image file on disk will not be modified.
* An hybrid image is a boot image that boots from either *
* bit 1 -> 1 to generate a ISOLINUX isohybrid image with MBR.
* ----------------------------------------------------------
* @deprecated since 31 Mar 2010:
* The author of syslinux, H. Peter Anvin requested that this
* feature shall not be used any more. He intends to cease
* support for the MBR template that is included in libisofs.
* ----------------------------------------------------------
* A hybrid image is a boot image that boots from either
* CD/DVD media or from disk-like media, e.g. USB stick. * CD/DVD media or from disk-like media, e.g. USB stick.
* For that you need isolinux.bin from SYSLINUX 3.72 or later. * For that you need isolinux.bin from SYSLINUX 3.72 or later.
* IMPORTANT: The application has to take care that the image * IMPORTANT: The application has to take care that the image

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2008 Vreixo Formoso * Copyright (c) 2008 Vreixo Formoso
* Copyright (c) 2010 Thomas Schmitt
* *
* This file is part of the libisofs project; you can redistribute it and/or * 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 * modify it under the terms of the GNU General Public License version 2
@ -12,28 +13,104 @@
#include "filesrc.h" #include "filesrc.h"
#include <string.h> #include <string.h>
#include <stdio.h>
/* /*
* Create a MBR for an isohybrid enabled ISOLINUX boot image. * Create a MBR for an isohybrid enabled ISOLINUX boot image.
* * See libisofs/make_isohybrid_mbr.c
* It is assumed that the caller has verified the readiness of the boot image * Deprecated.
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
*
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
* It will get rounded up to full MBs and that many blocks
* must really be written as ISO 9660 image.
* @param mbr A buffer of at least 512 bytes to take the result which is
* to be written as the very beginning of the ISO.
* @param flag unused yet, submit 0
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
*/ */
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag); int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
/* 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
*/
int make_grub_msdos_label(int img_blocks, uint8_t *buf, int flag)
{
uint8_t *wpt;
unsigned long end_lba, secs, end_sec, end_head, end_cyl;
int sph = 63, hpc = 255, i;
/* Partition table unit is 512 bytes per sector, ECMA-119 unit is 2048 */
if (img_blocks >= 0x40000000)
img_blocks = 0x40000000 - 1; /* truncate rather than roll over */
secs = end_lba = img_blocks * 4 - 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;
}
/* 1) Zero-fill 446-510 */
wpt = buf + 446;
memset(wpt, 0, 64);
/* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
buf[510] = 0x55;
buf[511] = 0xAA;
/* 3) Put 0x80 (for bootable partition), */
*(wpt++) = 0x80;
/* 0, 2, 0 (C/H/S of the start), */
*(wpt++) = 0;
*(wpt++) = 2;
*(wpt++) = 0;
/* 0xcd (partition type) */
*(wpt++) = 0xcd;
/* [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;
}
int iso_write_system_area(Ecma119Image *t, uint8_t *buf) int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
{ {
int ret;
int img_blocks;
if ((t == NULL) || (buf == NULL)) { if ((t == NULL) || (buf == NULL)) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
@ -41,26 +118,29 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
/* set buf to 0s */ /* set buf to 0s */
memset(buf, 0, 16 * BLOCK_SIZE); memset(buf, 0, 16 * BLOCK_SIZE);
if (t->catalog != NULL && t->catalog->image->isolinux_options & 0x02) { img_blocks = t->curblock;
/* We need to write a MBR for an hybrid image */ if (t->system_area_data != NULL) {
int ret; /* Write more or less opaque boot image */
int img_blocks; memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE);
img_blocks = t->curblock;
ret = make_isohybrid_mbr(t->bootimg->sections[0].block, &img_blocks, (char*)buf, 0);
/*
API description of el_torito_set_isolinux_options() prescribes
to pad to full MB.
So this is not urgent any more :
// FIXME the new img_blocks size should be taken into account
*/
} else if (t->catalog != NULL &&
(t->catalog->image->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)
*/
ret = make_isohybrid_mbr(t->bootimg->sections[0].block,
&img_blocks, (char*)buf, 0);
if (ret != 1) { if (ret != 1) {
/* error, it should never happen */ /* error, it should never happen */
return ISO_ASSERT_FAILURE; return ISO_ASSERT_FAILURE;
} }
return ISO_SUCCESS;
}
if (t->system_area_options & 1) {
/* Write GRUB protective msdos label, i.e. a isimple partition table */
ret = make_grub_msdos_label(img_blocks, buf, 0);
if (ret != 1) /* error should never happen */
return ISO_ASSERT_FAILURE;
} }
return ISO_SUCCESS; return ISO_SUCCESS;
} }