Support for reading El-Torito info from previous images.

This commit is contained in:
Vreixo Formoso 2008-01-11 15:43:39 +01:00
parent 53c2215ab3
commit f27f2449f9
6 changed files with 315 additions and 71 deletions

View File

@ -150,8 +150,6 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
node->node.atime = now; node->node.atime = now;
node->node.ctime = now; node->node.ctime = now;
node->node.mtime = now; node->node.mtime = now;
node->msblock = 0;
/* add to dir */ /* add to dir */
node->node.parent = parent; node->node.parent = parent;

View File

@ -24,11 +24,6 @@
struct Iso_Boot struct Iso_Boot
{ {
IsoNode node; IsoNode node;
/**
* Location of a file extent in a ms disc, 0 for newly added file
*/
uint32_t msblock;
}; };
struct el_torito_boot_catalog { struct el_torito_boot_catalog {

View File

@ -51,6 +51,7 @@
#define ISO_UNSUPPORTED_RR -302 #define ISO_UNSUPPORTED_RR -302
#define ISO_WRONG_ECMA119 -303 #define ISO_WRONG_ECMA119 -303
#define ISO_UNSUPPORTED_ECMA119 -304 #define ISO_UNSUPPORTED_ECMA119 -304
#define ISO_WRONG_EL_TORITO -305
/* el-torito errors */ /* el-torito errors */
#define ISO_IMAGE_ALREADY_BOOTABLE -350 #define ISO_IMAGE_ALREADY_BOOTABLE -350

View File

@ -78,6 +78,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
free(fsrc); free(fsrc);
return ret; return ret;
} }
iso_stream_ref(fsrc->stream);
return ISO_SUCCESS; return ISO_SUCCESS;
} }
@ -115,6 +116,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
void iso_file_src_free(void *node) void iso_file_src_free(void *node)
{ {
iso_stream_unref(((IsoFileSrc*)node)->stream);
free(node); free(node);
} }

View File

@ -18,6 +18,7 @@
#include "rockridge.h" #include "rockridge.h"
#include "image.h" #include "image.h"
#include "tree.h" #include "tree.h"
#include "eltorito.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -136,7 +137,15 @@ typedef struct
*/ */
uint32_t nblocks; uint32_t nblocks;
//TODO el-torito information /* el-torito information */
unsigned int eltorito : 1; /* is el-torito available */
unsigned int bootable:1; /**< If the entry is bootable. */
unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sectors to load. */
uint32_t imgblock; /**< Block for El-Torito boot image */
uint32_t catblock; /**< Block for El-Torito catalog */
} _ImageFsData; } _ImageFsData;
@ -1496,6 +1505,57 @@ int read_pvm(_ImageFsData *data, uint32_t block)
return ISO_SUCCESS; return ISO_SUCCESS;
} }
static
int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
{
int ret;
struct el_torito_validation_entry *ve;
struct el_torito_default_entry *entry;
unsigned char buffer[BLOCK_SIZE];
ret = data->src->read_block(data->src, block, buffer);
if (ret < 0) {
return ret;
}
ve = (struct el_torito_validation_entry*)buffer;
/* check if it is a valid catalog (TODO: check also the checksum)*/
if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55)
|| (ve->key_byte2[0] != 0xAA) ) {
iso_msg_sorry(data->messenger, LIBISO_EL_TORITO_WRONG,
"Wrong or damaged El-Torito Catalog. El-Torito info "
"will be ignored.");
return ISO_WRONG_EL_TORITO;
}
/* check for a valid platform */
if (ve->platform_id[0] != 0) {
iso_msg_hint(data->messenger, LIBISO_EL_TORITO_UNHANLED,
"Unsupported El-Torito platform. Only 80x86 is "
"supported. El-Torito info will be ignored.");
return ISO_WRONG_EL_TORITO;
}
/* ok, once we are here we assume it is a valid catalog */
/* parse the default entry */
entry = (struct el_torito_default_entry *)(buffer + 32);
data->eltorito = 1;
data->bootable = entry->boot_indicator[0] ? 1 : 0;
data->type = entry->boot_media_type[0];
data->partition_type = entry->system_type[0];
data->load_seg = iso_read_lsb(entry->load_seg, 2);
data->load_size = iso_read_lsb(entry->sec_count, 2);
data->imgblock = iso_read_lsb(entry->block, 4);
//TODO check if there are more entries?
return ISO_SUCCESS;
}
int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
struct libiso_msgs *messenger, struct libiso_msgs *messenger,
IsoImageFilesystem **fs) IsoImageFilesystem **fs)
@ -1582,13 +1642,26 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
} }
switch (buffer[0]) { switch (buffer[0]) {
case 0: case 0:
/* /* boot record */
* This is a boot record {
* Here we handle el-torito struct ecma119_boot_rec_vol_desc *vol;
*/ vol = (struct ecma119_boot_rec_vol_desc*)buffer;
//TODO add support for El-Torito
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD, /* some sanity checks */
"El-Torito extensions not supported yet"); if (strncmp((char*)vol->std_identifier, "CD001", 5)
|| vol->vol_desc_version[0] != 1
|| strncmp((char*)vol->boot_sys_id,
"EL TORITO SPECIFICATION", 23)) {
iso_msg_hint(data->messenger, LIBISO_BOOT_VD_UNHANLED,
"Unsupported Boot Vol. Desc. Only El-Torito "
"Specification, Version 1.0 Volume "
"Descriptors are supported. Ignoring boot info");
break;
}
data->catblock = iso_read_lsb(vol->boot_catalog, 4);
read_el_torito_boot_catalog(data, data->catblock);
}
break; break;
case 2: case 2:
/* suplementary volume descritor */ /* suplementary volume descritor */
@ -1623,10 +1696,8 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
*/ */
break; break;
default: default:
{ iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD, "Ignoring Volume descriptor %x.", buffer[0]);
"Ignoring Volume descriptor %x.", buffer[0]);
}
break; break;
} }
block++; block++;
@ -1717,6 +1788,8 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
/* source is a regular file */ /* source is a regular file */
IsoStream *stream; IsoStream *stream;
IsoFile *file; IsoFile *file;
_ImageFsData *fsdata = data->fs->fs.data;
result = iso_file_source_stream_new(src, &stream); result = iso_file_source_stream_new(src, &stream);
if (result < 0) { if (result < 0) {
free(name); free(name);
@ -1724,25 +1797,63 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
} }
/* take a ref to the src, as stream has taken our ref */ /* take a ref to the src, as stream has taken our ref */
iso_file_source_ref(src); iso_file_source_ref(src);
file = calloc(1, sizeof(IsoFile));
if (file == NULL) {
free(name);
iso_stream_unref(stream);
return ISO_MEM_ERROR;
}
/* the msblock is taken from the image */
file->msblock = data->block;
/* if (fsdata->eltorito && data->block == fsdata->catblock) {
* and we set the sort weight based on the block on image, to
* improve performance on image modifying. if (image->bootcat->node != NULL) {
*/ iso_msg_hint(image->messenger, LIBISO_EL_TORITO_UNHANLED,
file->sort_weight = INT_MAX - data->block; "More than one catalog node has been found. "
"We will continue, but that could lead to "
file->stream = stream; "problems");
file->node.type = LIBISO_FILE; iso_node_unref((IsoNode*)image->bootcat->node);
new = (IsoNode*) file; }
/* we create a placeholder for the catalog instead of
* a regular file */
new = calloc(1, sizeof(IsoBoot));
if (new == NULL) {
result = ISO_MEM_ERROR;
free(name);
return result;
}
/* and set the image node */
image->bootcat->node = (IsoBoot*)new;
new->refcount++;
} else {
file = calloc(1, sizeof(IsoFile));
if (file == NULL) {
free(name);
iso_stream_unref(stream);
return ISO_MEM_ERROR;
}
/* the msblock is taken from the image */
file->msblock = data->block;
/*
* and we set the sort weight based on the block on image, to
* improve performance on image modifying.
*/
file->sort_weight = INT_MAX - data->block;
file->stream = stream;
file->node.type = LIBISO_FILE;
new = (IsoNode*) file;
if (fsdata->eltorito && data->block == fsdata->imgblock) {
/* it is boot image node */
if (image->bootcat->image->image != NULL) {
iso_msg_hint(image->messenger, LIBISO_EL_TORITO_UNHANLED,
"More than one image node has been found. ");
} else {
/* and set the image node */
image->bootcat->image->image = file;
new->refcount++;
}
}
}
} }
break; break;
case S_IFDIR: case S_IFDIR:
@ -1797,7 +1908,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
} }
/* fill fields */ /* fill fields */
new->refcount = 1; new->refcount++;
new->name = name; new->name = name;
new->mode = info.st_mode; new->mode = info.st_mode;
new->uid = info.st_uid; new->uid = info.st_uid;
@ -1843,6 +1954,77 @@ int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder)
return ISO_SUCCESS; return ISO_SUCCESS;
} }
/**
* Create a file source to access the El-Torito boot image, when it is not
* accessible from the ISO filesystem.
*/
static
int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src)
{
int ret;
struct stat atts;
_ImageFsData *fsdata;
IsoFileSource *ifsrc = NULL;
ImageFileSourceData *ifsdata = NULL;
if (fs == NULL || fs->fs.data == NULL || src == NULL) {
return ISO_NULL_POINTER;
}
fsdata = (_ImageFsData*)fs->fs.data;
memset(&atts, 0, sizeof(struct stat));
atts.st_mode = S_IFREG;
atts.st_ino = fsdata->imgblock; /* not the best solution, but... */
atts.st_nlink = 1;
/*
* this is the greater problem. We don't know the size. For now, we
* just use a single block of data. In a future, maybe we could figure out
* a better idea. Another alternative is to use several blocks, that way
* is less probable that we throw out valid data.
*/
atts.st_size = (off_t)BLOCK_SIZE;
/* Fill last entries */
atts.st_dev = fsdata->id;
atts.st_blksize = BLOCK_SIZE;
atts.st_blocks = div_up(atts.st_size, BLOCK_SIZE);
/* ok, we can now create the file source */
ifsdata = calloc(1, sizeof(ImageFileSourceData));
if (ifsdata == NULL) {
ret = ISO_MEM_ERROR;
goto boot_fs_cleanup;
}
ifsrc = calloc(1, sizeof(IsoFileSource));
if (ifsrc == NULL) {
ret = ISO_MEM_ERROR;
goto boot_fs_cleanup;
}
/* fill data */
ifsdata->fs = fs;
iso_filesystem_ref((IsoFilesystem*)fs);
ifsdata->parent = NULL;
ifsdata->info = atts;
ifsdata->name = NULL;
ifsdata->block = fsdata->imgblock;
ifsrc->class = &ifs_class;
ifsrc->data = ifsdata;
ifsrc->refcount = 1;
*src = ifsrc;
return ISO_SUCCESS;
boot_fs_cleanup: ;
free(ifsdata);
free(ifsrc);
return ret;
}
int iso_image_import(IsoImage *image, IsoDataSource *src, int iso_image_import(IsoImage *image, IsoDataSource *src,
struct iso_read_opts *opts, struct iso_read_opts *opts,
struct iso_read_image_features *features) struct iso_read_image_features *features)
@ -1853,6 +2035,8 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
IsoNodeBuilder *blback; IsoNodeBuilder *blback;
IsoDir *oldroot; IsoDir *oldroot;
IsoFileSource *newroot; IsoFileSource *newroot;
_ImageFsData *data;
struct el_torito_boot_catalog *oldbootcat;
if (image == NULL || src == NULL || opts == NULL) { if (image == NULL || src == NULL || opts == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
@ -1862,6 +2046,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
data = fs->fs.data;
/* get root from filesystem */ /* get root from filesystem */
ret = fs->fs.get_root((IsoFilesystem*)fs, &newroot); ret = fs->fs.get_root((IsoFilesystem*)fs, &newroot);
@ -1873,6 +2058,9 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
fsback = image->fs; fsback = image->fs;
blback = image->builder; blback = image->builder;
oldroot = image->root; oldroot = image->root;
oldbootcat = image->bootcat; /* could be NULL */
image->bootcat = NULL;
/* create new builder */ /* create new builder */
ret = iso_image_builder_new(blback, &image->builder); ret = iso_image_builder_new(blback, &image->builder);
@ -1889,7 +2077,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
} }
{ {
struct stat info; struct stat info;
/* I know this will not fail */ /* I know this will not fail */
iso_file_source_lstat(newroot, &info); iso_file_source_lstat(newroot, &info);
image->root->node.mode = info.st_mode; image->root->node.mode = info.st_mode;
@ -1898,56 +2086,113 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
image->root->node.atime = info.st_atime; image->root->node.atime = info.st_atime;
image->root->node.mtime = info.st_mtime; image->root->node.mtime = info.st_mtime;
image->root->node.ctime = info.st_ctime; image->root->node.ctime = info.st_ctime;
} }
/* if old image has el-torito, add a new catalog */
if (data->eltorito) {
struct el_torito_boot_catalog *catalog;
ElToritoBootImage *boot_image= NULL;
boot_image = calloc(1, sizeof(ElToritoBootImage));
if (boot_image == NULL) {
ret = ISO_MEM_ERROR;
goto import_revert;
}
boot_image->bootable = data->bootable;
boot_image->type = data->type;
boot_image->partition_type = data->partition_type;
boot_image->load_seg = data->load_seg;
boot_image->load_size = data->load_size;
catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
if (catalog == NULL) {
ret = ISO_MEM_ERROR;
goto import_revert;
}
catalog->image = boot_image;
image->bootcat = catalog;
}
/* recursively add image */ /* recursively add image */
ret = iso_add_dir_src_rec(image, image->root, newroot); ret = iso_add_dir_src_rec(image, image->root, newroot);
iso_node_builder_unref(image->builder);
/* error during recursive image addition? */ /* error during recursive image addition? */
if (ret <= 0) { if (ret <= 0) {
iso_node_builder_unref(image->builder);
goto import_revert; goto import_revert;
} }
if (data->eltorito) {
/* if catalog and image nodes were not filled, we create them here */
if (image->bootcat->image->image == NULL) {
IsoFileSource *src;
IsoNode *node;
ret = create_boot_img_filesrc(fs, &src);
if (ret < 0) {
iso_node_builder_unref(image->builder);
goto import_revert;
}
ret = image_builder_create_node(image->builder, image, src, &node);
if (ret < 0) {
iso_node_builder_unref(image->builder);
goto import_revert;
}
image->bootcat->image->image = (IsoFile*)node;
}
if (image->bootcat->node == NULL) {
IsoNode *node = calloc(1, sizeof(IsoBoot));
if (node == NULL) {
ret = ISO_MEM_ERROR;
goto import_revert;
}
node->mode = S_IFREG;
node->refcount = 1;
image->bootcat->node = (IsoBoot*)node;
}
}
iso_node_builder_unref(image->builder);
/* free old root */ /* free old root */
iso_node_unref((IsoNode*)oldroot); iso_node_unref((IsoNode*)oldroot);
/* recover backed fs and builder */
image->fs = fsback;
image->builder = blback;
{
_ImageFsData *data;
data = fs->fs.data;
/* set volume attributes */ /* free old boot catalog */
iso_image_set_volset_id(image, data->volset_id); el_torito_boot_catalog_free(oldbootcat);
iso_image_set_volume_id(image, data->volume_id);
iso_image_set_publisher_id(image, data->publisher_id); /* set volume attributes */
iso_image_set_data_preparer_id(image, data->data_preparer_id); iso_image_set_volset_id(image, data->volset_id);
iso_image_set_system_id(image, data->system_id); iso_image_set_volume_id(image, data->volume_id);
iso_image_set_application_id(image, data->application_id); iso_image_set_publisher_id(image, data->publisher_id);
iso_image_set_copyright_file_id(image, data->copyright_file_id); iso_image_set_data_preparer_id(image, data->data_preparer_id);
iso_image_set_abstract_file_id(image, data->abstract_file_id); iso_image_set_system_id(image, data->system_id);
iso_image_set_biblio_file_id(image, data->biblio_file_id); iso_image_set_application_id(image, data->application_id);
iso_image_set_copyright_file_id(image, data->copyright_file_id);
if (features != NULL) { iso_image_set_abstract_file_id(image, data->abstract_file_id);
features->hasJoliet = data->joliet; iso_image_set_biblio_file_id(image, data->biblio_file_id);
features->hasRR = data->rr_version != 0;
features->size = data->nblocks; if (features != NULL) {
} features->hasJoliet = data->joliet;
features->hasRR = data->rr_version != 0;
features->hasElTorito = data->eltorito;
features->size = data->nblocks;
} }
ret = ISO_SUCCESS; ret = ISO_SUCCESS;
goto import_cleanup; goto import_cleanup;
import_revert:; import_revert:;
iso_node_unref((IsoNode*)image->root);
el_torito_boot_catalog_free(image->bootcat);
image->root = oldroot; image->root = oldroot;
image->fs = fsback; image->fs = fsback;
image->bootcat = oldbootcat;
import_cleanup:; import_cleanup:;
/* recover backed fs and builder */
image->fs = fsback;
image->builder = blback;
iso_file_source_unref(newroot); iso_file_source_unref(newroot);
fs->close(fs); fs->close(fs);

View File

@ -306,10 +306,13 @@ struct iso_read_opts
struct iso_read_image_features struct iso_read_image_features
{ {
/** It will be set to 1 if RR extensions are present, to 0 if not. */ /** It will be set to 1 if RR extensions are present, to 0 if not. */
unsigned int hasRR:1; unsigned int hasRR :1;
/** It will be set to 1 if Joliet extensions are present, to 0 if not. */ /** It will be set to 1 if Joliet extensions are present, to 0 if not. */
unsigned int hasJoliet:1; unsigned int hasJoliet :1;
/** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/
unsigned int hasElTorito :1;
/** /**
* Will be filled with the size (in 2048 byte block) of the image, as * Will be filled with the size (in 2048 byte block) of the image, as