|
|
|
@ -3,6 +3,7 @@
|
|
|
|
|
#include "eltorito.h"
|
|
|
|
|
#include "volume.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "messages.h"
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <malloc.h>
|
|
|
|
@ -15,46 +16,6 @@
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct el_torito_validation_entry {
|
|
|
|
|
uint8_t header_id BP(1, 1);
|
|
|
|
|
uint8_t platform_id BP(2, 2);
|
|
|
|
|
uint8_t reserved BP(3, 4);
|
|
|
|
|
uint8_t id_string BP(5, 28);
|
|
|
|
|
uint8_t checksum BP(29, 30);
|
|
|
|
|
uint8_t key_byte1 BP(31, 31);
|
|
|
|
|
uint8_t key_byte2 BP(32, 32);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct el_torito_default_entry {
|
|
|
|
|
uint8_t boot_indicator BP(1, 1);
|
|
|
|
|
uint8_t boot_media_type BP(2, 2);
|
|
|
|
|
uint8_t load_seg BP(3, 4);
|
|
|
|
|
uint8_t system_type BP(5, 5);
|
|
|
|
|
uint8_t unused1 BP(6, 6);
|
|
|
|
|
uint8_t sec_count BP(7, 8);
|
|
|
|
|
uint8_t block BP(9, 12);
|
|
|
|
|
uint8_t unused2 BP(13, 32);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct el_torito_section_header_entry {
|
|
|
|
|
uint8_t header_indicator BP(1, 1);
|
|
|
|
|
uint8_t platform_id BP(2, 2);
|
|
|
|
|
uint8_t number BP(3, 4);
|
|
|
|
|
uint8_t character BP(5, 32);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct el_torito_section_entry {
|
|
|
|
|
uint8_t boot_indicator BP(1, 1);
|
|
|
|
|
uint8_t boot_media_type BP(2, 2);
|
|
|
|
|
uint8_t load_seg BP(3, 4);
|
|
|
|
|
uint8_t system_type BP(5, 5);
|
|
|
|
|
uint8_t unused1 BP(6, 6);
|
|
|
|
|
uint8_t sec_count BP(7, 8);
|
|
|
|
|
uint8_t block BP(9, 12);
|
|
|
|
|
uint8_t selec_criteria BP(13, 13);
|
|
|
|
|
uint8_t vendor_sc BP(14, 32);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This table should be written with accuracy values at offset
|
|
|
|
|
* 8 of boot image, when used ISOLINUX boot loader
|
|
|
|
@ -85,18 +46,67 @@ struct hard_disc_mbr {
|
|
|
|
|
uint8_t sign2;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
el_torito_image_free(struct el_torito_boot_image *image)
|
|
|
|
|
{
|
|
|
|
|
assert(image);
|
|
|
|
|
|
|
|
|
|
/* unref image node */
|
|
|
|
|
iso_tree_free((struct iso_tree_node*)image->node);
|
|
|
|
|
free(image);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct iso_tree_node_boot*
|
|
|
|
|
create_boot_image_node(struct iso_tree_node_file *image)
|
|
|
|
|
{
|
|
|
|
|
struct iso_tree_node_boot *boot;
|
|
|
|
|
struct iso_tree_node_dir *parent;
|
|
|
|
|
|
|
|
|
|
assert(image);
|
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot));
|
|
|
|
|
boot->node.attrib = image->node.attrib;
|
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT;
|
|
|
|
|
boot->node.name = strdup(image->node.name);
|
|
|
|
|
boot->node.hide_flags = image->node.hide_flags;
|
|
|
|
|
boot->node.refcount = 2; /* mine and tree */
|
|
|
|
|
boot->loc.path = strdup(image->loc.path);
|
|
|
|
|
boot->img = 1; /* it refers to image */
|
|
|
|
|
|
|
|
|
|
/* replace iso_tree_node_file with the image */
|
|
|
|
|
parent = image->node.parent;
|
|
|
|
|
iso_tree_node_remove(parent, (struct iso_tree_node*)image);
|
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
|
|
|
|
|
|
|
|
|
|
return boot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct el_torito_boot_image *
|
|
|
|
|
create_image(struct iso_tree_node *image,
|
|
|
|
|
create_image(const char *path,
|
|
|
|
|
enum eltorito_boot_media_type type)
|
|
|
|
|
{
|
|
|
|
|
struct stat attrib;
|
|
|
|
|
struct el_torito_boot_image *boot;
|
|
|
|
|
int boot_media_type = 0;
|
|
|
|
|
int load_sectors = 0; /* number of sector to load */
|
|
|
|
|
unsigned char partition_type = 0;
|
|
|
|
|
|
|
|
|
|
if (stat(path, &attrib)) {
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't access file.");
|
|
|
|
|
libisofs_errno = NO_FILE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !S_ISREG(attrib.st_mode) ) {
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"We can only create boot images from regular files");
|
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case ELTORITO_FLOPPY_EMUL:
|
|
|
|
|
switch (image->attrib.st_size) {
|
|
|
|
|
switch (attrib.st_size) {
|
|
|
|
|
case 1200 * 1024:
|
|
|
|
|
boot_media_type = 1; /* 1.2 meg diskette */
|
|
|
|
|
break;
|
|
|
|
@ -107,10 +117,14 @@ create_image(struct iso_tree_node *image,
|
|
|
|
|
boot_media_type = 3; /* 2.88 meg diskette */
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
|
|
|
|
|
"or 2.88 Mb", (int) image->attrib.st_size / 1024);
|
|
|
|
|
{
|
|
|
|
|
char msg[72];
|
|
|
|
|
sprintf(msg, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
|
|
|
|
|
"or 2.88 Mb", (int) attrib.st_size / 1024);
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
|
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* it seems that for floppy emulation we need to load
|
|
|
|
@ -125,13 +139,16 @@ create_image(struct iso_tree_node *image,
|
|
|
|
|
int used_partition;
|
|
|
|
|
|
|
|
|
|
/* read the MBR on disc and get the type of the partition */
|
|
|
|
|
fd = open(((struct iso_tree_node_file*)image)->loc.path, O_RDONLY);
|
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
|
if ( fd == -1 ) {
|
|
|
|
|
fprintf(stderr, "Can't open image file\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't open image file.");
|
|
|
|
|
libisofs_errno = NO_READ_ACCESS;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if ( read(fd, &mbr, sizeof(mbr)) ) {
|
|
|
|
|
fprintf(stderr, "Can't read MBR from image file\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"Can't read MBR from image file.");
|
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
|
|
|
|
close(fd);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -139,7 +156,9 @@ create_image(struct iso_tree_node *image,
|
|
|
|
|
|
|
|
|
|
/* check valid MBR signature */
|
|
|
|
|
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
|
|
|
|
|
fprintf(stderr, "Invalid MBR. Wrong signature.\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"Invalid MBR. Wrong signature.");
|
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -149,8 +168,11 @@ create_image(struct iso_tree_node *image,
|
|
|
|
|
if (mbr.partition[i].type != 0) {
|
|
|
|
|
/* it's an used partition */
|
|
|
|
|
if (used_partition != -1) {
|
|
|
|
|
fprintf(stderr, "Invalid MBR. At least 2 partitions: %d and "
|
|
|
|
|
char msg[72];
|
|
|
|
|
sprintf(msg, "Invalid MBR. At least 2 partitions: %d and "
|
|
|
|
|
"%d, are being used\n", used_partition, i);
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
|
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
|
|
|
|
return NULL;
|
|
|
|
|
} else
|
|
|
|
|
used_partition = i;
|
|
|
|
@ -170,67 +192,180 @@ create_image(struct iso_tree_node *image,
|
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct el_torito_boot_image));
|
|
|
|
|
boot->bootable = 1;
|
|
|
|
|
boot->image = (struct iso_tree_node_file *) image;
|
|
|
|
|
boot->type = boot_media_type;
|
|
|
|
|
boot->load_size = load_sectors;
|
|
|
|
|
boot->partition_type = partition_type;
|
|
|
|
|
return boot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct iso_tree_node_boot_catalog*
|
|
|
|
|
/* parent and name can be null */
|
|
|
|
|
static struct iso_tree_node_boot*
|
|
|
|
|
create_boot_catalog_node(struct iso_tree_node_dir *parent,
|
|
|
|
|
const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct iso_tree_node_boot_catalog *boot;
|
|
|
|
|
struct iso_tree_node_boot *boot;
|
|
|
|
|
|
|
|
|
|
assert( parent && name );
|
|
|
|
|
assert( (parent && name) || (!parent && !name) );
|
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog));
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot));
|
|
|
|
|
boot->node.attrib.st_mode = S_IFREG | 0444;
|
|
|
|
|
boot->node.attrib.st_atime =
|
|
|
|
|
boot->node.attrib.st_mtime =
|
|
|
|
|
boot->node.attrib.st_ctime = time(NULL);
|
|
|
|
|
boot->node.type = LIBISO_NODE_BOOTCATALOG;
|
|
|
|
|
boot->node.name = strdup(name);
|
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
|
|
|
|
|
boot->node.attrib.st_size = 2048;
|
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT;
|
|
|
|
|
boot->node.name = name ? strdup(name) : NULL;
|
|
|
|
|
boot->node.refcount = 1; /* mine */
|
|
|
|
|
if (parent) {
|
|
|
|
|
boot->node.refcount++; /* add tree ref */
|
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
|
|
|
|
|
}
|
|
|
|
|
return boot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image *
|
|
|
|
|
iso_volume_create_boot_catalog(struct iso_volume *volume,
|
|
|
|
|
struct iso_tree_node *image,
|
|
|
|
|
enum eltorito_boot_media_type type,
|
|
|
|
|
struct iso_tree_node_dir *dir,
|
|
|
|
|
char *name)
|
|
|
|
|
struct el_torito_boot_image*
|
|
|
|
|
iso_volume_set_boot_image(struct iso_volume *volume,
|
|
|
|
|
struct iso_tree_node *image,
|
|
|
|
|
enum eltorito_boot_media_type type,
|
|
|
|
|
struct iso_tree_node_dir *dir,
|
|
|
|
|
char *name)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_image *boot_image;
|
|
|
|
|
struct iso_tree_node_boot *cat_node;
|
|
|
|
|
struct el_torito_boot_catalog *catalog;
|
|
|
|
|
struct iso_tree_node_file *imgfile;
|
|
|
|
|
|
|
|
|
|
assert(volume && !volume->bootcat);
|
|
|
|
|
assert(image && ISO_ISREG(image));
|
|
|
|
|
assert(dir && name);
|
|
|
|
|
|
|
|
|
|
imgfile = (struct iso_tree_node_file*)image;
|
|
|
|
|
|
|
|
|
|
if (image->procedence == LIBISO_PREVIMG) {
|
|
|
|
|
/* FIXME mmm, what to do here? */
|
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't use prev. image files "
|
|
|
|
|
"as boot images");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boot_image = create_image(imgfile->loc.path, type);
|
|
|
|
|
if ( !boot_image )
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* create image node */
|
|
|
|
|
boot_image->node = create_boot_image_node(imgfile);
|
|
|
|
|
|
|
|
|
|
/* creates the catalog with the given default image */
|
|
|
|
|
catalog = malloc(sizeof(struct el_torito_boot_catalog));
|
|
|
|
|
if (!catalog) {
|
|
|
|
|
el_torito_image_free(boot_image);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
catalog->image = boot_image;
|
|
|
|
|
|
|
|
|
|
/* add catalog file */
|
|
|
|
|
cat_node = create_boot_catalog_node(dir, name);
|
|
|
|
|
catalog->node = cat_node;
|
|
|
|
|
|
|
|
|
|
volume->bootcat = catalog;
|
|
|
|
|
|
|
|
|
|
return boot_image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image*
|
|
|
|
|
iso_volume_set_boot_image_hidden(struct iso_volume *volume, const char* path,
|
|
|
|
|
enum eltorito_boot_media_type type)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_image *boot_image;
|
|
|
|
|
struct iso_tree_node_boot_catalog *boot_node;
|
|
|
|
|
struct iso_tree_node_boot *cat_node;
|
|
|
|
|
struct el_torito_boot_catalog *catalog;
|
|
|
|
|
|
|
|
|
|
assert( volume && !volume->bootcat);
|
|
|
|
|
assert( image && ISO_ISREG(image) && dir && name);
|
|
|
|
|
assert(volume && !volume->bootcat);
|
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
|
|
boot_image = create_image(image, type);
|
|
|
|
|
boot_image = create_image(path, type);
|
|
|
|
|
if ( !boot_image )
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* create image node */
|
|
|
|
|
{
|
|
|
|
|
struct iso_tree_node_boot *boot;
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot));
|
|
|
|
|
/* we assume the stat won't fail, as we already stat the same file above */
|
|
|
|
|
stat(path, &boot->node.attrib);
|
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT;
|
|
|
|
|
boot->node.refcount = 1; /* mine */
|
|
|
|
|
boot->loc.path = strdup(path);
|
|
|
|
|
boot->img = 1; /* it refers to image */
|
|
|
|
|
boot_image->node = boot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* creates the catalog with the given default image */
|
|
|
|
|
catalog = malloc(sizeof(struct el_torito_boot_catalog));
|
|
|
|
|
catalog->nentries = 1;
|
|
|
|
|
catalog->entries = malloc(sizeof(struct el_torito_boot_image *));
|
|
|
|
|
catalog->entries[0] = boot_image;
|
|
|
|
|
catalog->file = malloc(sizeof(struct iso_file));
|
|
|
|
|
catalog->file->size = 2048;
|
|
|
|
|
if (!catalog) {
|
|
|
|
|
el_torito_image_free(boot_image);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
catalog->image = boot_image;
|
|
|
|
|
|
|
|
|
|
/* add catalog file */
|
|
|
|
|
boot_node = create_boot_catalog_node(dir, name);
|
|
|
|
|
boot_node->catalog = catalog;
|
|
|
|
|
cat_node = create_boot_catalog_node(NULL, NULL);
|
|
|
|
|
catalog->node = cat_node;
|
|
|
|
|
|
|
|
|
|
volume->bootcat = catalog;
|
|
|
|
|
|
|
|
|
|
return boot_image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image*
|
|
|
|
|
iso_volume_get_boot_image(struct iso_volume *volume,
|
|
|
|
|
struct iso_tree_node **imgnode,
|
|
|
|
|
struct iso_tree_node **catnode)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_catalog *catalog;
|
|
|
|
|
|
|
|
|
|
assert(volume);
|
|
|
|
|
|
|
|
|
|
catalog = volume->bootcat;
|
|
|
|
|
if (!catalog)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (imgnode)
|
|
|
|
|
*imgnode = (struct iso_tree_node*)catalog->image->node;
|
|
|
|
|
|
|
|
|
|
if (catnode)
|
|
|
|
|
*catnode = (struct iso_tree_node*)catalog->node;
|
|
|
|
|
|
|
|
|
|
return catalog->image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
iso_volume_remove_boot_image(struct iso_volume *volume)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_catalog *catalog;
|
|
|
|
|
struct iso_tree_node *catnode;
|
|
|
|
|
struct iso_tree_node *imgnode;
|
|
|
|
|
assert(volume);
|
|
|
|
|
|
|
|
|
|
catalog = volume->bootcat;
|
|
|
|
|
if (!catalog)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* remove node from tree */
|
|
|
|
|
catnode = (struct iso_tree_node*)catalog->node;
|
|
|
|
|
if (catnode->parent)
|
|
|
|
|
iso_tree_node_remove(catnode->parent, catnode);
|
|
|
|
|
|
|
|
|
|
/* remove image from tree */
|
|
|
|
|
imgnode = (struct iso_tree_node*)catalog->image->node;
|
|
|
|
|
if (imgnode->parent)
|
|
|
|
|
iso_tree_node_remove(imgnode->parent, imgnode);
|
|
|
|
|
|
|
|
|
|
/* remove catalog */
|
|
|
|
|
el_torito_boot_catalog_free(catalog);
|
|
|
|
|
volume->bootcat = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
|
|
|
|
|
{
|
|
|
|
@ -254,43 +389,20 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg)
|
|
|
|
|
el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg)
|
|
|
|
|
{
|
|
|
|
|
bootimg->patch_isolinux = 1;
|
|
|
|
|
bootimg->isolinux = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
assert(cat);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < cat->nentries; ++i) {
|
|
|
|
|
free(cat->entries[i]);
|
|
|
|
|
}
|
|
|
|
|
free(cat->entries);
|
|
|
|
|
free(cat->file);
|
|
|
|
|
el_torito_image_free(cat->image);
|
|
|
|
|
iso_tree_free((struct iso_tree_node*)cat->node);
|
|
|
|
|
free(cat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void el_torito_get_image_files(struct ecma119_write_target *t)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog;
|
|
|
|
|
assert(cat);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < cat->nentries; ++i) {
|
|
|
|
|
|
|
|
|
|
struct iso_tree_node_file *image = cat->entries[i]->image;
|
|
|
|
|
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
|
|
|
|
|
if ( file == NULL ) {
|
|
|
|
|
file = iso_file_new(image);
|
|
|
|
|
iso_file_table_add_file(t->file_table, file);
|
|
|
|
|
}
|
|
|
|
|
cat->entries[i]->file = file;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write the Boot Record Volume Descriptor
|
|
|
|
|
*/
|
|
|
|
@ -307,7 +419,7 @@ el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|
|
|
|
memcpy(vol->std_identifier, "CD001", 5);
|
|
|
|
|
vol->vol_desc_version[0] = 1;
|
|
|
|
|
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
|
|
|
|
|
iso_lsb(vol->boot_catalog, cat->file->block, 4);
|
|
|
|
|
iso_lsb(vol->boot_catalog, t->catblock, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
@ -333,104 +445,139 @@ write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
patch_boot_file(struct el_torito_boot_image *img)
|
|
|
|
|
patch_boot_image(uint8_t *buf, struct ecma119_write_target *t, ssize_t imgsize)
|
|
|
|
|
{
|
|
|
|
|
struct boot_info_table info;
|
|
|
|
|
int fd;
|
|
|
|
|
struct boot_info_table *info;
|
|
|
|
|
uint32_t checksum;
|
|
|
|
|
ssize_t len;
|
|
|
|
|
uint8_t buf[4];
|
|
|
|
|
ssize_t offset;
|
|
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
|
|
|
|
|
|
/* open image */
|
|
|
|
|
fd = open(img->image->loc.path, O_RDWR);
|
|
|
|
|
if ( fd == -1 ) {
|
|
|
|
|
//TODO what do do? exit or just continue?
|
|
|
|
|
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path);
|
|
|
|
|
close(fd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* compute checksum, as the the sum of all 32 bit words in boot image
|
|
|
|
|
* from offset 64 */
|
|
|
|
|
checksum = 0;
|
|
|
|
|
lseek(fd, (off_t) 64, SEEK_SET);
|
|
|
|
|
offset = (ssize_t) 64;
|
|
|
|
|
|
|
|
|
|
//TODO this can (must) be optimizied by reading to a longer buffer
|
|
|
|
|
while ( (len = read(fd, buf, 4) ) == 4 ) {
|
|
|
|
|
checksum += iso_read_lsb(buf, 4);
|
|
|
|
|
while (offset < imgsize) {
|
|
|
|
|
checksum += iso_read_lsb(buf + offset, 4);
|
|
|
|
|
offset += 4;
|
|
|
|
|
}
|
|
|
|
|
if ( len != 0 ) {
|
|
|
|
|
/* error reading file, or file length not multiple of 4 */
|
|
|
|
|
//TODO what do do? exit or just continue?
|
|
|
|
|
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path);
|
|
|
|
|
close(fd);
|
|
|
|
|
return;
|
|
|
|
|
if (offset != imgsize) {
|
|
|
|
|
/* file length not multiple of 4 */
|
|
|
|
|
iso_msg_warn(LIBISO_ISOLINUX_CANT_PATCH,
|
|
|
|
|
"Unexpected isolinux image length. Patch might not work.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fill boot info table */
|
|
|
|
|
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
|
|
|
|
|
iso_lsb(info.bi_file, img->file->block, 4);
|
|
|
|
|
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4);
|
|
|
|
|
iso_lsb(info.bi_csum, checksum, 4);
|
|
|
|
|
|
|
|
|
|
/* patch file */
|
|
|
|
|
lseek(fd, (off_t) 8, SEEK_SET);
|
|
|
|
|
write(fd, &info, sizeof(info));
|
|
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
/* patch boot info table */
|
|
|
|
|
info = (struct boot_info_table*)(buf + 8);
|
|
|
|
|
memset(info, 0, sizeof(struct boot_info_table));
|
|
|
|
|
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
|
|
|
|
|
iso_lsb(info->bi_file, t->imgblock, 4);
|
|
|
|
|
iso_lsb(info->bi_length, imgsize, 4);
|
|
|
|
|
iso_lsb(info->bi_csum, checksum, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
el_torito_patch_image_files(struct ecma119_write_target *t)
|
|
|
|
|
static void
|
|
|
|
|
write_boot_image(uint8_t *buf, struct ecma119_write_target *t)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog;
|
|
|
|
|
assert(cat);
|
|
|
|
|
ssize_t imgsize;
|
|
|
|
|
struct el_torito_boot_image *image;
|
|
|
|
|
|
|
|
|
|
image = t->catalog->image;
|
|
|
|
|
imgsize= image->node->node.attrib.st_size;
|
|
|
|
|
|
|
|
|
|
/* copy image contents to memory buffer */
|
|
|
|
|
if (image->node->node.procedence == LIBISO_PREVIMG) {
|
|
|
|
|
int block, nblocks;
|
|
|
|
|
uint8_t *memloc;
|
|
|
|
|
assert(t->src);
|
|
|
|
|
|
|
|
|
|
block = 0;
|
|
|
|
|
memloc = buf;
|
|
|
|
|
nblocks = imgsize ? div_up(imgsize, 2048) : 1;
|
|
|
|
|
while (block < nblocks) {
|
|
|
|
|
if (t->src->read_block(t->src,
|
|
|
|
|
image->node->loc.block + block, memloc)) {
|
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_IMG,
|
|
|
|
|
"Unable to read boot image from previous image.");
|
|
|
|
|
break; /* exit loop */
|
|
|
|
|
}
|
|
|
|
|
memloc += 2048;
|
|
|
|
|
++block;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
int fd;
|
|
|
|
|
ssize_t nread, tread;
|
|
|
|
|
uint8_t *memloc;
|
|
|
|
|
const char *path = image->node->loc.path;
|
|
|
|
|
memloc = buf;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cat->nentries; ++i) {
|
|
|
|
|
struct el_torito_boot_image *img = cat->entries[i];
|
|
|
|
|
if ( img->patch_isolinux )
|
|
|
|
|
patch_boot_file(img);
|
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_FILE,
|
|
|
|
|
"Can't open boot image file for reading. Skipping");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tread = 0;
|
|
|
|
|
while (tread < imgsize) {
|
|
|
|
|
nread = read(fd, memloc, t->block_size);
|
|
|
|
|
if (nread <= 0) {
|
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_FILE,
|
|
|
|
|
"Problem reading boot image file. Skipping");
|
|
|
|
|
break; /* exit loop */
|
|
|
|
|
}
|
|
|
|
|
tread += nread;
|
|
|
|
|
memloc += nread;
|
|
|
|
|
}
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (image->isolinux) {
|
|
|
|
|
/* we need to patch the image */
|
|
|
|
|
patch_boot_image(buf, t, imgsize);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write one section entry.
|
|
|
|
|
* Currently this is used for both default and other entries since we
|
|
|
|
|
* put selection criteria no 0 (no sel. criteria)
|
|
|
|
|
* Currently this is used only for default image (the only supported just now)
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img)
|
|
|
|
|
write_section_entry(uint8_t *buf, struct ecma119_write_target *t)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_image *img;
|
|
|
|
|
struct el_torito_section_entry *se =
|
|
|
|
|
(struct el_torito_section_entry*)buf;
|
|
|
|
|
|
|
|
|
|
img = t->catalog->image;
|
|
|
|
|
|
|
|
|
|
assert(img);
|
|
|
|
|
|
|
|
|
|
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
|
|
|
|
|
se->boot_media_type[0] = img->type;
|
|
|
|
|
iso_lsb(se->load_seg, img->load_seg, 2);
|
|
|
|
|
se->system_type[0] = 0; //TODO need to get the partition type
|
|
|
|
|
se->system_type[0] = img->partition_type;
|
|
|
|
|
iso_lsb(se->sec_count, img->load_size, 2);
|
|
|
|
|
iso_lsb(se->block, img->file->block, 4);
|
|
|
|
|
iso_lsb(se->block, t->imgblock, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write El-Torito Boot Catalog
|
|
|
|
|
* Write El-Torito Boot Catalog plus image
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
write_catalog(struct ecma119_write_target *t, uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog;
|
|
|
|
|
assert(cat);
|
|
|
|
|
assert(cat->nentries >= 1 && cat->nentries < 63);
|
|
|
|
|
assert(cat->image);
|
|
|
|
|
|
|
|
|
|
write_validation_entry(t, buf);
|
|
|
|
|
|
|
|
|
|
/* write default entry */
|
|
|
|
|
write_section_entry(buf + 32, cat->entries[0]);
|
|
|
|
|
write_section_entry(buf + 32, t);
|
|
|
|
|
|
|
|
|
|
//TODO write all images
|
|
|
|
|
write_boot_image(buf + 2048, t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -446,9 +593,27 @@ el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|
|
|
|
void
|
|
|
|
|
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
|
|
|
|
|
{
|
|
|
|
|
off_t size;
|
|
|
|
|
off_t imgsize;
|
|
|
|
|
assert(t->catalog);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note that when this is called, we need to write el-torito info to
|
|
|
|
|
* image. Note, however, that the image could come from a previous session
|
|
|
|
|
* and maybe we don't know its size
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
imgsize = t->catalog->image->node->node.attrib.st_size;
|
|
|
|
|
if (imgsize == 0) {
|
|
|
|
|
iso_msg_warn(LIBISO_EL_TORITO_BLIND_COPY,
|
|
|
|
|
"Can get boot image size, only one block will be copied");
|
|
|
|
|
imgsize = 2048;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = 2048 + div_up(imgsize, t->block_size);
|
|
|
|
|
|
|
|
|
|
ecma119_start_chunking(t,
|
|
|
|
|
write_catalog,
|
|
|
|
|
2048,
|
|
|
|
|
size,
|
|
|
|
|
buf);
|
|
|
|
|
}
|
|
|
|
|