From 4f029437e2284008c5b93232809c855814b6f23d Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Thu, 10 Jan 2008 18:53:39 +0100 Subject: [PATCH] Handling of El-Torito boot catalog at low level. --- src/ecma119.c | 3 + src/ecma119.h | 8 ++ src/ecma119_tree.c | 42 ++++++++- src/eltorito.c | 212 ++++++++++++++++++++++++++++++++++++++++++++- src/eltorito.h | 7 ++ src/filesrc.c | 32 +++++++ src/filesrc.h | 21 +++++ src/joliet.c | 24 ++++- 8 files changed, 342 insertions(+), 7 deletions(-) diff --git a/src/ecma119.c b/src/ecma119.c index 5aa44a5..8bba8f8 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -853,6 +853,9 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) target->now = time(NULL); target->ms_block = opts->ms_block; target->appendable = opts->appendable; + + /* el-torito? */ + target->eltorito = (src->bootcat == NULL ? 0 : 1); /* default to locale charset */ setlocale(LC_CTYPE, ""); diff --git a/src/ecma119.h b/src/ecma119.h index 07b0ec4..8d6d46b 100644 --- a/src/ecma119.h +++ b/src/ecma119.h @@ -34,6 +34,7 @@ struct ecma119_image /* extensions */ unsigned int rockridge :1; unsigned int joliet :1; + unsigned int eltorito :1; /* relaxed constraints */ unsigned int omit_version_numbers :1; @@ -106,6 +107,13 @@ struct ecma119_image uint32_t joliet_path_table_size; uint32_t joliet_l_path_table_pos; uint32_t joliet_m_path_table_pos; + + /* + * El-Torito related information + */ + struct el_torito_boot_catalog *catalog; + IsoFileSrc *cat; /**< location of the boot catalog in the new image */ + uint32_t imgblock; /**< location of the boot image in the new image */ /* * Number of pad blocks that we need to write. Padding blocks are blocks diff --git a/src/ecma119_tree.c b/src/ecma119_tree.c index d721ef3..ca9d37f 100644 --- a/src/ecma119_tree.c +++ b/src/ecma119_tree.c @@ -15,6 +15,7 @@ #include "messages.h" #include "image.h" #include "stream.h" +#include "eltorito.h" #include #include @@ -160,6 +161,35 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node) return ret; } +/** + * Create a new ECMA-119 node representing a regular file from an El-Torito + * boot catalog + */ +static +int create_boot_cat(Ecma119Image *img, IsoBoot *iso, Ecma119Node **node) +{ + int ret; + IsoFileSrc *src; + + ret = el_torito_catalog_file_src_create(img, &src); + if (ret < 0) { + return ret; + } + + ret = create_ecma119_node(img, (IsoNode*)iso, node); + if (ret < 0) { + /* + * the src doesn't need to be freed, it is free together with + * the Ecma119Image + */ + return ret; + } + (*node)->type = ECMA119_FILE; + (*node)->info.file = src; + + return ret; +} + /** * Create a new ECMA-119 node representing a symbolic link from a iso symlink * node. @@ -276,9 +306,15 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree, } break; case LIBISO_BOOT: - //TODO - free(iso_name); - return 0; + if (image->eltorito) { + ret = create_boot_cat(image, (IsoBoot*)iso, &node); + } else { + /* log and ignore */ + iso_msg_note(image->image->messenger, LIBISO_FILE_IGNORED, + "El-Torito catalog found on a image without El-Torito.", + iso->name); + ret = 0; + } break; case LIBISO_DIR: { diff --git a/src/eltorito.c b/src/eltorito.c index 28663f3..85ba458 100644 --- a/src/eltorito.c +++ b/src/eltorito.c @@ -10,6 +10,7 @@ #include "stream.h" #include "error.h" #include "fsource.h" +#include "filesrc.h" #include "image.h" #include "messages.h" @@ -482,7 +483,7 @@ void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat) */ struct catalog_stream { - struct el_torito_boot_catalog *catalog; + Ecma119Image *target; uint8_t buffer[BLOCK_SIZE]; int offset; /* -1 if stream is not openned */ }; @@ -508,3 +509,212 @@ write_validation_entry(uint8_t *buf) } iso_lsb(ve->checksum, checksum, 2); } + +/** + * Write one section entry. + * Currently this is used only for default image (the only supported just now) + */ +static void +write_section_entry(uint8_t *buf, Ecma119Image *t) +{ + struct el_torito_boot_image *img; + struct el_torito_section_entry *se = + (struct el_torito_section_entry*)buf; + + img = t->catalog->image; + + 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] = img->partition_type; + iso_lsb(se->sec_count, img->load_size, 2); + iso_lsb(se->block, t->imgblock, 4); +} + +static +int catalog_open(IsoStream *stream) +{ + struct catalog_stream *data; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = stream->data; + + if (data->offset != -1) { + return ISO_FILE_ALREADY_OPENNED; + } + + memset(data->buffer, 0, BLOCK_SIZE); + + /* fill the buffer with the catalog contents */ + write_validation_entry(data->buffer); + + /* write default entry */ + write_section_entry(data->buffer + 32, data->target); + + data->offset = 0; + return ISO_SUCCESS; +} + +static +int catalog_close(IsoStream *stream) +{ + struct catalog_stream *data; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + data = stream->data; + + if (data->offset == -1) { + return ISO_FILE_NOT_OPENNED; + } + data->offset = -1; + return ISO_SUCCESS; +} + +static +off_t catalog_get_size(IsoStream *stream) +{ + return BLOCK_SIZE; +} + +static +int catalog_read(IsoStream *stream, void *buf, size_t count) +{ + size_t len; + struct catalog_stream *data; + if (stream == NULL || buf == NULL) { + return ISO_NULL_POINTER; + } + if (count == 0) { + return ISO_WRONG_ARG_VALUE; + } + data = stream->data; + + if (data->offset == -1) { + return ISO_FILE_NOT_OPENNED; + } + + len = MIN(count, BLOCK_SIZE - data->offset); + memcpy(buf, data->buffer + data->offset, len); + return len; +} + +static +int catalog_is_repeatable(IsoStream *stream) +{ + return 1; +} + +/** + * fs_id will be the id reserved for El-Torito + * dev_id will be 0 for catalog, 1 for boot image (if needed) + * we leave ino_id for future use when we support multiple boot images + */ +static +void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, + ino_t *ino_id) +{ + *fs_id = ISO_ELTORITO_FS_ID; + *dev_id = 0; + *ino_id = 0; +} + +static +char *catalog_get_name(IsoStream *stream) +{ + return strdup("El-Torito Boot Catalog"); +} + +static +void catalog_free(IsoStream *stream) +{ + free(stream->data); +} + +IsoStreamIface catalog_stream_class = { + catalog_open, + catalog_close, + catalog_get_size, + catalog_read, + catalog_is_repeatable, + catalog_get_id, + catalog_get_name, + catalog_free +}; + +/** + * Create an IsoStream for writing El-Torito catalog for a given target. + */ +static +int catalog_stream_new(Ecma119Image *target, IsoStream **stream) +{ + IsoStream *str; + struct catalog_stream *data; + + if (target == NULL || stream == NULL || target->catalog == NULL) { + return ISO_NULL_POINTER; + } + + str = malloc(sizeof(IsoStream)); + if (str == NULL) { + return ISO_MEM_ERROR; + } + data = malloc(sizeof(struct catalog_stream)); + if (str == NULL) { + free(str); + return ISO_MEM_ERROR; + } + + /* fill data */ + data->target = target; + data->offset = -1; + + str->refcount = 1; + str->data = data; + str->class = &catalog_stream_class; + + *stream = str; + return ISO_SUCCESS; +} + +int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src) +{ + int ret; + IsoFileSrc *file; + IsoStream *stream; + + if (target == NULL || src == NULL || target->catalog == NULL) { + return ISO_MEM_ERROR; + } + + if (target->cat != NULL) { + /* catalog file src already created */ + *src = target->cat; + return ISO_SUCCESS; + } + + file = malloc(sizeof(IsoFileSrc)); + if (file == NULL) { + return ISO_MEM_ERROR; + } + + ret = catalog_stream_new(target, &stream); + if (ret < 0) { + free(file); + return ret; + } + + /* fill fields */ + file->prev_img = 0; /* TODO allow copy of old img catalog???? */ + file->block = 0; /* to be filled later */ + file->sort_weight = 1000; /* slightly high */ + file->stream = stream; + + ret = iso_file_src_add(target, file, src); + if (ret <= 0) { + iso_stream_unref(stream); + free(file); + } + return ret; +} diff --git a/src/eltorito.h b/src/eltorito.h index 8036f90..2082b85 100644 --- a/src/eltorito.h +++ b/src/eltorito.h @@ -93,4 +93,11 @@ struct el_torito_section_entry { void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat); +/** + * Create a IsoFileSrc for writing the el-torito catalog for the given + * target, and add it to target. If the target already has a src for the + * catalog, it just returns. + */ +int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src); + #endif /* LIBISO_ELTORITO_H */ diff --git a/src/filesrc.c b/src/filesrc.c index 9d94b44..04174cf 100644 --- a/src/filesrc.c +++ b/src/filesrc.c @@ -81,6 +81,38 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) return ISO_SUCCESS; } +/** + * Add a given IsoFileSrc to the given image target. + * + * The IsoFileSrc will be cached in a tree to prevent the same file for + * being written several times to image. If you call again this function + * with a node that refers to the same source file, the previously + * created one will be returned. + * + * @param img + * The image where this file is to be written + * @param new + * The IsoFileSrc to add + * @param src + * Will be filled with a pointer to the IsoFileSrc really present in + * the tree. It could be different than new if the same file already + * exists in the tree. + * @return + * 1 on success, 0 if file already exists on tree, < 0 error + */ +int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src) +{ + int ret; + + if (img == NULL || new == NULL || src == NULL) { + return ISO_NULL_POINTER; + } + + /* insert the filesrc in the tree */ + ret = iso_rbtree_insert(img->files, new, (void**)src); + return ret; +} + void iso_file_src_free(void *node) { free(node); diff --git a/src/filesrc.h b/src/filesrc.h index 82c69e2..5a3c03c 100644 --- a/src/filesrc.h +++ b/src/filesrc.h @@ -43,6 +43,27 @@ int iso_file_src_cmp(const void *n1, const void *n2); */ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src); +/** + * Add a given IsoFileSrc to the given image target. + * + * The IsoFileSrc will be cached in a tree to prevent the same file for + * being written several times to image. If you call again this function + * with a node that refers to the same source file, the previously + * created one will be returned. + * + * @param img + * The image where this file is to be written + * @param new + * The IsoFileSrc to add + * @param src + * Will be filled with a pointer to the IsoFileSrc really present in + * the tree. It could be different than new if the same file already + * exists in the tree. + * @return + * 1 on success, 0 if file already exists on tree, < 0 error + */ +int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src); + /** * Free the IsoFileSrc especific data */ diff --git a/src/joliet.c b/src/joliet.c index f393ba9..64d1119 100644 --- a/src/joliet.c +++ b/src/joliet.c @@ -13,6 +13,7 @@ #include "error.h" #include "image.h" #include "filesrc.h" +#include "eltorito.h" #include #include @@ -118,9 +119,19 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node) } joliet->info.file = src; joliet->type = JOLIET_FILE; + } else if (iso->type == LIBISO_BOOT) { + /* it's a el-torito boot catalog, that we write as a file */ + IsoFileSrc *src; + + ret = el_torito_catalog_file_src_create(t, &src); + if (ret < 0) { + free(joliet); + return ret; + } + joliet->info.file = src; + joliet->type = JOLIET_FILE; } else { /* should never happen */ - //TODO handle boot nodes?!? free(joliet); return ISO_ERROR; } @@ -205,8 +216,15 @@ int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen) } break; case LIBISO_BOOT: - //TODO - return 0; + if (t->eltorito) { + ret = create_node(t, iso, &node); + } else { + /* log and ignore */ + iso_msg_note(t->image->messenger, LIBISO_FILE_IGNORED, + "El-Torito catalog found on a image without El-Torito.", + iso->name); + ret = 0; + } break; case LIBISO_SYMLINK: case LIBISO_SPECIAL: