New API call iso_write_opts_set_partition_img().

This commit is contained in:
Thomas Schmitt 2010-10-18 16:56:00 +02:00
parent ebb5937568
commit b58d1e28ef
8 changed files with 268 additions and 73 deletions

View File

@ -266,9 +266,8 @@ Cylinder/Head/Sector (C/H/S) and Logical Block Address (LBA). Both are based
on units of 512 bytes. So MBR_LBA = ISO_LBA * 4.
For C/H/S, the sector address is broken up into whole cylinders, remaining
heads, and remaining sectors. The nomenclature seems to stem from antique
heads, and remaining sectors + 1. The nomenclature seems to stem from antique
drum storage.
C/H/S counting starts with 0/0/1, not 0/0/0.
There are two parameters, sectors_per_head and heads_per_cylinder which are not
stored in the MBR. So it is more or less arbitray how to convert a LBA into
a C/H/S address and vice versa. For maximum range of C/H/S addresses one
@ -306,6 +305,7 @@ Byte Range | Value | Meaning
451 - 453 | ========== | C/H/S address of last absolute sector in partition
451 - 451 | end_head | Heads part of end address.
452 - 452 | end_c_s | Bits 0 to 5 : Sectors part of end address.
| Values: 1 to 63, not 0.
| | Bits 6 to 7 : Bits 8 to 9 of cylinders part.
453 - 453 | end_cyl | Lower 8 bits of cylinders part of end address
| |

View File

@ -107,7 +107,10 @@ void ecma119_image_free(Ecma119Image *t)
free(t->writers);
if (t->partition_root != NULL)
ecma119_node_free(t->partition_root);
t->partition_root = NULL;
for (i = 0; i < 4; i++)
if (t->appended_partitions[i] != NULL)
free(t->appended_partitions[i]);
free(t);
}
@ -1295,6 +1298,39 @@ static int finish_libjte(Ecma119Image *target)
}
static int write_mbr_partition_file(Ecma119Image *target, char *path,
uint32_t blocks, int flag)
{
FILE *fp = NULL;
uint32_t i;
uint8_t buf[BLOCK_SIZE];
int ret;
fp = fopen(path, "rb");
if (fp == NULL)
return ISO_BAD_PARTITION_FILE;
for (i = 0; i < blocks; i++) {
memset(buf, 0, BLOCK_SIZE);
if (fp != NULL) {
ret = fread(buf, 1, BLOCK_SIZE, fp);
if (ret != BLOCK_SIZE) {
fclose(fp);
fp = NULL;
}
}
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0) {
fclose(fp);
return ret;
}
}
fclose(fp);
return ISO_SUCCESS;
}
static
void *write_function(void *arg)
{
@ -1321,6 +1357,17 @@ void *write_function(void *arg)
}
}
/* Append partition data */
for (i = 0; i < 4; i++) {
if (target->appended_partitions[i] == NULL)
continue;
res = write_mbr_partition_file(target, target->appended_partitions[i],
target->appended_part_size[i], 0);
if (res < 0)
goto write_error;
}
/* Transplant checksum buffer from Ecma119Image to IsoImage */
transplant_checksum_buffer(target, 0);
@ -1469,7 +1516,6 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag)
return ISO_SUCCESS;
}
static
int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
{
@ -1589,6 +1635,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->partition_offset = opts->partition_offset;
target->partition_secs_per_head = opts->partition_secs_per_head;
target->partition_heads_per_cyl = opts->partition_heads_per_cyl;
if (target->partition_secs_per_head == 0)
target->partition_secs_per_head = 63;
if (target->partition_heads_per_cyl == 0)
target->partition_heads_per_cyl = 255;
target->eff_partition_offset = 0;
target->partition_root = NULL;
target->partition_l_table_pos = 0;
@ -1646,12 +1696,24 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
#endif /* Libisofs_with_libjtE */
target->tail_blocks = opts->tail_blocks;
target->mipsel_e_entry = 0;
target->mipsel_p_offset = 0;
target->mipsel_p_vaddr = 0;
target->mipsel_p_filesz = 0;
target->tail_blocks = opts->tail_blocks;
for (i = 0; i < 4; i++) {
if (opts->appended_partitions[i] != NULL) {
target->appended_partitions[i] =
strdup(opts->appended_partitions[i]);
if (target->appended_partitions[i] == NULL)
return ISO_OUT_OF_MEM;
target->appended_part_types[i] = opts->appended_part_types[i];
}
target->appended_part_start[i] = target->appended_part_size[i] = 0;
}
/*
* 2. Based on those options, create needed writers: iso, joliet...
@ -1843,6 +1905,18 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
goto target_cleanup;
}
/*
* The volume space size is just the size of the last session, in
* case of ms images.
*/
target->vol_space_size = target->curblock - target->ms_block;
target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE;
/* Add sizes of eventually appended partitions */
ret = iso_compute_append_partitions(target, 0);
if (ret < 0)
goto target_cleanup;
/* create the ring buffer */
if (opts->overwrite != NULL &&
opts->fifo_size / 2048 < 32 + target->partition_offset) {
@ -1936,13 +2010,6 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
}
}
/*
* The volume space size is just the size of the last session, in
* case of ms images.
*/
target->vol_space_size = target->curblock - target->ms_block;
target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE;
/* 4. Create and start writing thread */
if (target->md5_session_checksum) {
@ -2172,6 +2239,7 @@ int iso_write(Ecma119Image *target, void *buf, size_t count)
int iso_write_opts_new(IsoWriteOpts **opts, int profile)
{
int i;
IsoWriteOpts *wopts;
if (opts == NULL) {
@ -2231,6 +2299,8 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile)
#endif /* Libisofs_with_libjtE */
wopts->tail_blocks = 0;
for (i = 0; i < 4; i++)
wopts->appended_partitions[i] = NULL;
*opts = wopts;
return ISO_SUCCESS;
@ -2238,13 +2308,17 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile)
void iso_write_opts_free(IsoWriteOpts *opts)
{
int i;
if (opts == NULL) {
return;
}
free(opts->output_charset);
if (opts->system_area_data != NULL)
free(opts->system_area_data);
for (i = 0; i < 4; i++)
if (opts->appended_partitions[i] != NULL)
free(opts->appended_partitions[i]);
free(opts);
}
@ -2718,7 +2792,23 @@ int iso_write_opts_detach_jte(IsoWriteOpts *opts, void **libjte_handle)
int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks)
{
opts->tail_blocks = num_blocks;
return ISO_SUCCESS;
opts->tail_blocks = num_blocks;
return ISO_SUCCESS;
}
int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number,
uint8_t partition_type, char *image_path, int flag)
{
if (partition_number < 1 || partition_number > 4)
return ISO_BAD_PARTITION_NO;
if (opts->appended_partitions[partition_number - 1] != NULL)
free(opts->appended_partitions[partition_number - 1]);
opts->appended_partitions[partition_number - 1] = strdup(image_path);
if (opts->appended_partitions[partition_number - 1] == NULL)
return ISO_OUT_OF_MEM;
opts->appended_part_types[partition_number - 1] = partition_type;
return ISO_SUCCESS;
}

View File

@ -334,6 +334,11 @@ struct iso_write_opts {
*/
uint32_t tail_blocks;
/* Eventual disk file paths of prepared images which shall be appended
after the ISO image and described by partiton table entries in a MBR
*/
char *appended_partitions[4];
uint8_t appended_part_types[4];
};
typedef struct ecma119_image Ecma119Image;
@ -588,13 +593,20 @@ struct ecma119_image
struct libjte_env *libjte_handle;
#endif /* Libisofs_with_libjtE */
uint32_t tail_blocks;
/* Memorized ELF parameters from MIPS Little Endian boot file */
uint32_t mipsel_e_entry;
uint32_t mipsel_p_offset;
uint32_t mipsel_p_vaddr;
uint32_t mipsel_p_filesz;
uint32_t tail_blocks;
char *appended_partitions[4];
uint8_t appended_part_types[4];
/* Counted in blocks of 2048 */
uint32_t appended_part_start[4];
uint32_t appended_part_size[4];
};
#define BP(a,b) [(b) - (a) + 1]

View File

@ -1936,6 +1936,32 @@ int iso_write_opts_detach_jte(IsoWriteOpts *opts, void **libjte_handle);
*/
int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks);
/**
* Cause an arbitrary data file to be appended to the ISO image and to be
* described by a partition table entry in an MBR at the start of the
* ISO image.
* The partition entry will bear the size of the image file rounded up to
* the next multiple of 2048 bytes.
* @param opts
* The option set to be manipulated.
* @param partition_number
* Depicts the partition table entry which shall describe the
* appended image. Range 1 to 4.
* 1 will cause the whole ISO image to be unclaimable space before
* partition 1.
* @param image_path
* File address in the local file system.
* @param image_type
* The partition type. E.g. FAT12 = 0x01 , FAT16 = 0x06,
* Linux Native Partition = 0x83. See fdisk command L.
* @return
* ISO_SUCCESS or error
*
* @since 0.6.38
*/
int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number,
uint8_t partition_type, char *image_path, int flag);
/**
* Inquire the start address of the file data blocks after having used
@ -6321,12 +6347,17 @@ int iso_md5_match(char first_md5[16], char second_md5[16]);
(MISHAP, HIGH, -366) */
#define ISO_LIBJTE_FILE_FAILED 0xE430FE92
/** Too many MIPS Big Endian boot files given (max. 15) (FAILURE, HIGH, -365)*/
/** Too many MIPS Big Endian boot files given (max. 15) (FAILURE, HIGH, -367)*/
#define ISO_BOOT_TOO_MANY_MIPS 0xE830FE91
/** Boot file missing in image (MISHAP, HIGH, -364) */
/** Boot file missing in image (MISHAP, HIGH, -368) */
#define ISO_BOOT_FILE_MISSING 0xE430FE90
/** Partition number out of range (FAILURE, HIGH, -369) */
#define ISO_BAD_PARTITION_NO 0xE830FE8F
/** Cannot open data file for appended partition (FAILURE, HIGH, -370) */
#define ISO_BAD_PARTITION_FILE 0xE830FE8E
/* Internal developer note:

View File

@ -279,6 +279,7 @@ iso_write_opts_set_omit_version_numbers;
iso_write_opts_set_output_charset;
iso_write_opts_set_overwrite_buf;
iso_write_opts_set_part_offset;
iso_write_opts_set_partition_img;
iso_write_opts_set_pvd_times;
iso_write_opts_set_record_md5;
iso_write_opts_set_relaxed_vol_atts;

View File

@ -353,6 +353,10 @@ const char *iso_error_to_msg(int errcode)
return "Too many MIPS Big Endian boot files given (max. 15)";
case ISO_BOOT_FILE_MISSING:
return "Boot file missing in image";
case ISO_BAD_PARTITION_NO:
return "Partition number out of range";
case ISO_BAD_PARTITION_FILE:
return "Cannot open data file for appended partition";
default:
return "Unknown error";
}

View File

@ -22,6 +22,9 @@
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*
@ -72,6 +75,85 @@ void iso_compute_cyl_head_sec(uint32_t *img_blocks, int hpc, int sph,
}
/* Compute size and position of appended partitions.
*/
int iso_compute_append_partitions(Ecma119Image *t, int flag)
{
int ret, i;
uint32_t pos, size;
struct stat stbuf;
pos = (t->vol_space_size + t->ms_block);
for (i = 0; i < 4; i++) {
if (t->appended_partitions[i] == NULL)
continue;
ret = stat(t->appended_partitions[i], &stbuf);
if (ret == -1)
return ISO_BAD_PARTITION_FILE;
if (! S_ISREG(stbuf.st_mode))
return ISO_BAD_PARTITION_FILE;
size = ((stbuf.st_size + 2047) / 2048);
t->appended_part_start[i] = pos;
t->appended_part_size[i] = size;
pos += size;
t->total_size += size * 2048;
}
return ISO_SUCCESS;
}
/* Note: partition_offset and partition_size are counted in 2048 blocks
*/
static int write_mbr_partition_entry(int partition_number, int partition_type,
uint32_t partition_offset, uint32_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(&partition_offset, hpc, sph,
&start_lba, &start_sec, &start_head, &start_cyl, 1);
iso_compute_cyl_head_sec(&after_end, hpc, sph,
&end_lba, &end_sec, &end_head, &end_cyl, 0);
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:
@ -92,11 +174,12 @@ void iso_compute_cyl_head_sec(uint32_t *img_blocks, int hpc, int sph,
bit1= do not mark partition as bootable
*/
static
int make_grub_msdos_label(uint32_t img_blocks, uint8_t *buf, int flag)
int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
uint8_t *buf, int flag)
{
uint8_t *wpt;
uint32_t end_lba, end_sec, end_head, end_cyl;
int sph = 63, hpc = 255, i;
int i;
iso_compute_cyl_head_sec(&img_blocks, hpc, sph,
&end_lba, &end_sec, &end_head, &end_cyl, 0);
@ -155,17 +238,13 @@ int make_grub_msdos_label(uint32_t img_blocks, uint8_t *buf, int flag)
*/
static
int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset,
int sph_in, int hpc_in, uint8_t *buf, int flag)
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;
int sph = 63, hpc = 255, i;
int i;
if (sph_in > 0)
sph = sph_in;
if (hpc_in > 0)
hpc = hpc_in;
iso_compute_cyl_head_sec(&partition_offset, hpc, sph,
&start_lba, &start_sec, &start_head, &start_cyl, 1);
iso_compute_cyl_head_sec(&img_blocks, hpc, sph,
@ -180,7 +259,7 @@ int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset,
/* C/H/S of the start */
*(wpt++) = start_head;
*(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
*(wpt++) = end_cyl & 0xff;
*(wpt++) = start_cyl & 0xff;
/* (partition type) */
wpt++;
@ -302,9 +381,6 @@ static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
/* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */
for (idx = 0; idx < t->image->num_mips_boot_files; idx++) {
#ifndef NIX
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx],
&node, &ecma_node, "MIPS boot file", 0);
if (ret < 0)
@ -314,45 +390,6 @@ static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
name_field = (char *) (buf + (72 + 16 * idx));
strncpy(name_field, namept, 8);
#else /* ! NIX */
ret = iso_tree_path_to_node(t->image,
t->image->mips_boot_file_paths[idx], &node);
if (ret < 0) {
iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
"Cannot find MIPS boot file '%s'",
t->image->mips_boot_file_paths[idx]);
return ISO_BOOT_FILE_MISSING;
}
if (node->type != LIBISO_FILE) {
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Designated MIPS boot file is not a data file: '%s'",
t->image->mips_boot_file_paths[idx]);
return ISO_BOOT_IMAGE_NOT_VALID;
}
namept = (char *) iso_node_get_name(node);
name_field = (char *) (buf + (72 + 16 * idx));
strncpy(name_field, namept, 8);
ecma_node= ecma119_search_iso_node(t, node);
if (ecma_node != NULL) {
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'",
t->image->mips_boot_file_paths[idx]);
return ISO_ASSERT_FAILURE;
}
} else {
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Program error: IsoFile has no Ecma119Node: '%s'",
t->image->mips_boot_file_paths[idx]);
return ISO_ASSERT_FAILURE;
}
#endif /* NIX */
file_lba = ecma_node->info.file->sections[0].block;
iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
@ -529,7 +566,7 @@ static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag)
int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
{
int ret, int_img_blocks, sa_type;
int ret, int_img_blocks, sa_type, i;
uint32_t img_blocks;
if ((t == NULL) || (buf == NULL)) {
@ -565,7 +602,8 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
}
if (sa_type == 0 && (t->system_area_options & 1)) {
/* Write GRUB protective msdos label, i.e. a simple partition table */
ret = make_grub_msdos_label(img_blocks, buf, 0);
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
t->partition_heads_per_cyl, buf, 0);
if (ret != ISO_SUCCESS) /* error should never happen */
return ISO_ASSERT_FAILURE;
} else if(sa_type == 0 && (t->system_area_options & 2)) {
@ -577,7 +615,8 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
return ISO_ISOLINUX_CANT_PATCH;
}
ret = make_isolinux_mbr(&img_blocks, t->bootsrc[0]->sections[0].block,
(uint32_t) 0, 64, 32, 0, 1, 0x17, buf, 1);
(uint32_t) 0, t->partition_heads_per_cyl,
t->partition_secs_per_head, 0, 1, 0x17, buf, 1);
if (ret != 1)
return ret;
} else if(sa_type == 1) {
@ -590,7 +629,8 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
return ret;
} else if(t->partition_offset > 0 && sa_type == 0) {
/* Write a simple partition table. */
ret = make_grub_msdos_label(img_blocks, buf, 2);
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
t->partition_heads_per_cyl, buf, 2);
if (ret != ISO_SUCCESS) /* error should never happen */
return ISO_ASSERT_FAILURE;
}
@ -605,5 +645,17 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
return ISO_ASSERT_FAILURE;
}
/* This eventually overwrites the partition table entries made so far */
for (i = 0; i < 4; i++) {
if (t->appended_partitions[i] == NULL)
continue;
ret = write_mbr_partition_entry(i + 1, t->appended_part_types[i],
t->appended_part_start[i], t->appended_part_size[i],
t->partition_secs_per_head, t->partition_heads_per_cyl,
buf, 0);
if (ret < 0)
return ret;
}
return ISO_SUCCESS;
}

View File

@ -53,4 +53,9 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf);
*/
int iso_read_mipsel_elf(Ecma119Image *t, int flag);
/* Compute size and position of appended partitions.
*/
int iso_compute_append_partitions(Ecma119Image *t, int flag);
#endif /* SYSTEM_AREA_H_ */