Support for reading El-Torito info from previous images.
This commit is contained in:
parent
53c2215ab3
commit
f27f2449f9
@ -151,8 +151,6 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
|
||||
node->node.ctime = now;
|
||||
node->node.mtime = now;
|
||||
|
||||
node->msblock = 0;
|
||||
|
||||
/* add to dir */
|
||||
node->node.parent = parent;
|
||||
node->node.next = *pos;
|
||||
|
@ -24,11 +24,6 @@
|
||||
struct Iso_Boot
|
||||
{
|
||||
IsoNode node;
|
||||
|
||||
/**
|
||||
* Location of a file extent in a ms disc, 0 for newly added file
|
||||
*/
|
||||
uint32_t msblock;
|
||||
};
|
||||
|
||||
struct el_torito_boot_catalog {
|
||||
|
@ -51,6 +51,7 @@
|
||||
#define ISO_UNSUPPORTED_RR -302
|
||||
#define ISO_WRONG_ECMA119 -303
|
||||
#define ISO_UNSUPPORTED_ECMA119 -304
|
||||
#define ISO_WRONG_EL_TORITO -305
|
||||
|
||||
/* el-torito errors */
|
||||
#define ISO_IMAGE_ALREADY_BOOTABLE -350
|
||||
|
@ -78,6 +78,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
free(fsrc);
|
||||
return ret;
|
||||
}
|
||||
iso_stream_ref(fsrc->stream);
|
||||
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)
|
||||
{
|
||||
iso_stream_unref(((IsoFileSrc*)node)->stream);
|
||||
free(node);
|
||||
}
|
||||
|
||||
|
287
src/fs_image.c
287
src/fs_image.c
@ -18,6 +18,7 @@
|
||||
#include "rockridge.h"
|
||||
#include "image.h"
|
||||
#include "tree.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -136,7 +137,15 @@ typedef struct
|
||||
*/
|
||||
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;
|
||||
|
||||
@ -1496,6 +1505,57 @@ int read_pvm(_ImageFsData *data, uint32_t block)
|
||||
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,
|
||||
struct libiso_msgs *messenger,
|
||||
IsoImageFilesystem **fs)
|
||||
@ -1582,13 +1642,26 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
|
||||
}
|
||||
switch (buffer[0]) {
|
||||
case 0:
|
||||
/*
|
||||
* This is a boot record
|
||||
* Here we handle el-torito
|
||||
*/
|
||||
//TODO add support for El-Torito
|
||||
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
|
||||
"El-Torito extensions not supported yet");
|
||||
/* boot record */
|
||||
{
|
||||
struct ecma119_boot_rec_vol_desc *vol;
|
||||
vol = (struct ecma119_boot_rec_vol_desc*)buffer;
|
||||
|
||||
/* some sanity checks */
|
||||
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;
|
||||
case 2:
|
||||
/* suplementary volume descritor */
|
||||
@ -1623,10 +1696,8 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
{
|
||||
iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD,
|
||||
"Ignoring Volume descriptor %x.", buffer[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
block++;
|
||||
@ -1717,6 +1788,8 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
/* source is a regular file */
|
||||
IsoStream *stream;
|
||||
IsoFile *file;
|
||||
_ImageFsData *fsdata = data->fs->fs.data;
|
||||
|
||||
result = iso_file_source_stream_new(src, &stream);
|
||||
if (result < 0) {
|
||||
free(name);
|
||||
@ -1724,6 +1797,31 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
}
|
||||
/* take a ref to the src, as stream has taken our ref */
|
||||
iso_file_source_ref(src);
|
||||
|
||||
if (fsdata->eltorito && data->block == fsdata->catblock) {
|
||||
|
||||
if (image->bootcat->node != NULL) {
|
||||
iso_msg_hint(image->messenger, LIBISO_EL_TORITO_UNHANLED,
|
||||
"More than one catalog node has been found. "
|
||||
"We will continue, but that could lead to "
|
||||
"problems");
|
||||
iso_node_unref((IsoNode*)image->bootcat->node);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@ -1743,6 +1841,19 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
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;
|
||||
case S_IFDIR:
|
||||
@ -1797,7 +1908,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
}
|
||||
|
||||
/* fill fields */
|
||||
new->refcount = 1;
|
||||
new->refcount++;
|
||||
new->name = name;
|
||||
new->mode = info.st_mode;
|
||||
new->uid = info.st_uid;
|
||||
@ -1843,6 +1954,77 @@ int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder)
|
||||
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,
|
||||
struct iso_read_opts *opts,
|
||||
struct iso_read_image_features *features)
|
||||
@ -1853,6 +2035,8 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
|
||||
IsoNodeBuilder *blback;
|
||||
IsoDir *oldroot;
|
||||
IsoFileSource *newroot;
|
||||
_ImageFsData *data;
|
||||
struct el_torito_boot_catalog *oldbootcat;
|
||||
|
||||
if (image == NULL || src == NULL || opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -1862,6 +2046,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
data = fs->fs.data;
|
||||
|
||||
/* get root from filesystem */
|
||||
ret = fs->fs.get_root((IsoFilesystem*)fs, &newroot);
|
||||
@ -1873,6 +2058,9 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
|
||||
fsback = image->fs;
|
||||
blback = image->builder;
|
||||
oldroot = image->root;
|
||||
oldbootcat = image->bootcat; /* could be NULL */
|
||||
|
||||
image->bootcat = NULL;
|
||||
|
||||
/* create new builder */
|
||||
ret = iso_image_builder_new(blback, &image->builder);
|
||||
@ -1900,26 +2088,76 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
|
||||
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 */
|
||||
ret = iso_add_dir_src_rec(image, image->root, newroot);
|
||||
|
||||
iso_node_builder_unref(image->builder);
|
||||
|
||||
/* error during recursive image addition? */
|
||||
if (ret <= 0) {
|
||||
iso_node_builder_unref(image->builder);
|
||||
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 */
|
||||
iso_node_unref((IsoNode*)oldroot);
|
||||
|
||||
/* recover backed fs and builder */
|
||||
image->fs = fsback;
|
||||
image->builder = blback;
|
||||
|
||||
{
|
||||
_ImageFsData *data;
|
||||
data = fs->fs.data;
|
||||
/* free old boot catalog */
|
||||
el_torito_boot_catalog_free(oldbootcat);
|
||||
|
||||
/* set volume attributes */
|
||||
iso_image_set_volset_id(image, data->volset_id);
|
||||
@ -1935,20 +2173,27 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
|
||||
if (features != NULL) {
|
||||
features->hasJoliet = data->joliet;
|
||||
features->hasRR = data->rr_version != 0;
|
||||
features->hasElTorito = data->eltorito;
|
||||
features->size = data->nblocks;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
goto import_cleanup;
|
||||
|
||||
import_revert:;
|
||||
|
||||
iso_node_unref((IsoNode*)image->root);
|
||||
el_torito_boot_catalog_free(image->bootcat);
|
||||
image->root = oldroot;
|
||||
image->fs = fsback;
|
||||
image->bootcat = oldbootcat;
|
||||
|
||||
import_cleanup:;
|
||||
|
||||
/* recover backed fs and builder */
|
||||
image->fs = fsback;
|
||||
image->builder = blback;
|
||||
|
||||
iso_file_source_unref(newroot);
|
||||
fs->close(fs);
|
||||
iso_filesystem_unref((IsoFilesystem*)fs);
|
||||
|
@ -306,10 +306,13 @@ struct iso_read_opts
|
||||
struct iso_read_image_features
|
||||
{
|
||||
/** 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. */
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user