Add support for multisession on Level 3 images.

This commit is contained in:
Vreixo Formoso 2008-08-19 02:45:20 +02:00
parent 3a503a3e85
commit 2e99e1aac9
9 changed files with 497 additions and 461 deletions

View File

@ -1,19 +1,19 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* Synchronized ring buffer, works with a writer thread and a read thread.
*
*
* TODO #00010 : optimize ring buffer
* - write/read at the end of buffer requires a second mutex_lock, even if
* there's enought space/data at the beginning
* - pre-buffer for writes < BLOCK_SIZE
*
*
*/
#include "buffer.h"
@ -30,13 +30,13 @@
struct iso_ring_buffer
{
uint8_t *buf;
/*
* Max number of bytes in buffer
*/
size_t cap;
/*
/*
* Number of bytes available.
*/
size_t size;
@ -45,11 +45,11 @@ struct iso_ring_buffer
size_t rpos;
size_t wpos;
/*
/*
* flags to report if read or writer threads ends execution
* 0 not finished, 1 finished ok, 2 finish with error
* 0 not finished, 1 finished ok, 2 finish with error
*/
unsigned int rend :2;
unsigned int rend :2;
unsigned int wend :2;
/* just for statistical purposes */
@ -63,9 +63,9 @@ struct iso_ring_buffer
/**
* Create a new buffer.
*
*
* The created buffer should be freed with iso_ring_buffer_free()
*
*
* @param size
* Number of blocks in buffer. You should supply a number >= 32, otherwise
* size will be ignored and 32 will be used by default, which leads to a
@ -85,14 +85,14 @@ int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf)
if (buffer == NULL) {
return ISO_OUT_OF_MEM;
}
buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE;
buffer->buf = malloc(buffer->cap);
if (buffer->buf == NULL) {
free(buffer);
return ISO_OUT_OF_MEM;
}
buffer->size = 0;
buffer->wpos = 0;
buffer->rpos = 0;
@ -126,7 +126,7 @@ void iso_ring_buffer_free(IsoRingBuffer *buf)
/**
* Write count bytes into buffer. It blocks until all bytes where written or
* reader close the buffer.
*
*
* @param buf
* the buffer
* @param data
@ -189,7 +189,7 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
* bytes has been read. If the writer finishes before outputting enought
* bytes, 0 (EOF) is returned, the number of bytes already read remains
* unknown.
*
*
* @return
* 1 success, 0 EOF, < 0 error
*/
@ -252,7 +252,7 @@ void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error)
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error)
{
pthread_mutex_lock(&buf->mutex);
if (buf->rend) {
/* reader already closed */
pthread_mutex_unlock(&buf->mutex);
@ -285,9 +285,9 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
/**
* Get the status of the buffer used by a burn_source.
*
*
* @param b
* A burn_source previously obtained with
* A burn_source previously obtained with
* iso_image_create_burn_source().
* @param size
* Will be filled with the total size of the buffer, in bytes
@ -302,7 +302,7 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
* 6="ended" : consumption has ended without input error
* 7="aborted" : consumption has ended after input error
*/
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
size_t *free_bytes)
{
int ret;
@ -311,7 +311,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
return ISO_NULL_POINTER;
}
buf = ((Ecma119Image*)(b->data))->buffer;
/* get mutex */
pthread_mutex_lock(&buf->mutex);
if (size) {
@ -322,7 +322,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
}
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
pthread_mutex_unlock(&buf->mutex);
return ret;
}

View File

@ -241,7 +241,7 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
uint32_t len;
uint32_t block;
uint8_t len_dr; /*< size of dir entry without SUSP fields */
int multi_extend = 0;
int multi_extend = 0;
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
: (uint8_t*)node->iso_name;
@ -262,17 +262,9 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == ECMA119_FILE) {
off_t size = iso_file_src_get_size(node->info.file)
- ((off_t)0xFFFFF800) * (off_t)extent; /* bytes in another extent */
if (size > (off_t) 0xffffffff) {
/* 2097151 is the number of blocks needed to store 4 GB - 2048 */
block = node->info.file->block + extent * 2097151;
len = 0xFFFFF800;
multi_extend = 1;
} else {
len = (uint32_t) size;
block = node->info.file->block;
}
block = node->info.file->sections[extent].block;
len = node->info.file->sections[extent].size;
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
} else {
/*
* for nodes other than files and dirs, we set both
@ -457,26 +449,27 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
buf += len;
for (i = 0; i < dir->info.dir->nchildren; i++) {
int section, nsections;
Ecma119Node *child = dir->info.dir->children[i];
int extent = 0;
do {
/* compute len of directory entry */
fi_len = strlen(child->iso_name);
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
if (need_version_number(t, child)) {
len += 2;
}
/* compute len of directory entry */
fi_len = strlen(child->iso_name);
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
if (need_version_number(t, child)) {
len += 2;
/* get the SUSP fields if rockridge is enabled */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
if (ret < 0) {
return ret;
}
len += info.suf_len;
}
/* get the SUSP fields if rockridge is enabled */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
if (ret < 0) {
return ret;
}
len += info.suf_len;
}
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
@ -488,22 +481,9 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
buf = buffer;
}
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len, &info, extent);
write_one_dir_record(t, child, -1, buf, fi_len, &info, section);
buf += len;
if (child->type == ECMA119_FILE) {
/* check if file is too big and need more extents */
off_t size = iso_file_src_get_size(child->info.file)
- ((off_t)0xFFFFF800) * (off_t)extent;
if (size > (off_t) 0xffffffff) {
extent++;
} else {
break;
}
} else {
break; /* we only have a single extent */
}
} while(1); /* loop for each extend */
}
}
/* write the last block */

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -26,7 +26,7 @@ struct boot_info_table {
uint8_t bi_file BP(5, 8); /* LBA of boot file */
uint8_t bi_length BP(9, 12); /* Length of boot file */
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
uint8_t bi_reserved BP(17, 56); /* Reserved */
uint8_t bi_reserved BP(17, 56); /* Reserved */
};
/**
@ -67,7 +67,7 @@ void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
/**
* Sets the number of sectors (512b) to be load at load segment during
* the initial boot procedure. This is only for no emulation boot images,
* the initial boot procedure. This is only for no emulation boot images,
* and is a NOP for other image types.
*/
void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
@ -109,7 +109,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
if (boot) {
*boot = NULL;
}
/* check if the name is valid */
if (!iso_node_is_valid_name(name)) {
return ISO_WRONG_ARG_VALUE;
@ -162,7 +162,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
}
static
static
int create_image(IsoImage *image, const char *image_path,
enum eltorito_boot_media_type type,
struct el_torito_boot_image **bootimg)
@ -182,18 +182,18 @@ int create_image(IsoImage *image, const char *image_path,
if (ret == 0) {
return ISO_NODE_DOESNT_EXIST;
}
if (imgfile->type != LIBISO_FILE) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
stream = ((IsoFile*)imgfile)->stream;
/* we need to read the image at least two times */
if (!iso_stream_is_repeatable(stream)) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
switch (type) {
case ELTORITO_FLOPPY_EMUL:
switch (iso_stream_get_size(stream)) {
@ -211,9 +211,9 @@ int create_image(IsoImage *image, const char *image_path,
"Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", iso_stream_get_size(stream) / 1024);
return ISO_BOOT_IMAGE_NOT_VALID;
break;
break;
}
/* it seems that for floppy emulation we need to load
/* it seems that for floppy emulation we need to load
* a single sector (512b) */
load_sectors = 1;
break;
@ -222,7 +222,7 @@ int create_image(IsoImage *image, const char *image_path,
size_t i;
struct hard_disc_mbr mbr;
int used_partition;
/* read the MBR on disc and get the type of the partition */
ret = iso_stream_open(stream);
if (ret < 0) {
@ -237,14 +237,14 @@ int create_image(IsoImage *image, const char *image_path,
"Can't read MBR from image file.");
return ret < 0 ? ret : ISO_FILE_READ_ERROR;
}
/* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Invalid MBR. Wrong signature.");
return ISO_BOOT_IMAGE_NOT_VALID;
}
/* ensure single partition */
used_partition = -1;
for (i = 0; i < 4; ++i) {
@ -252,7 +252,7 @@ int create_image(IsoImage *image, const char *image_path,
/* it's an used partition */
if (used_partition != -1) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Invalid MBR. At least 2 partitions: %d and "
"Invalid MBR. At least 2 partitions: %d and "
"%d, are being used\n", used_partition, i);
return ISO_BOOT_IMAGE_NOT_VALID;
} else
@ -262,15 +262,15 @@ int create_image(IsoImage *image, const char *image_path,
partition_type = mbr.partition[used_partition].type;
}
boot_media_type = 4;
/* only load the MBR */
load_sectors = 1;
break;
case ELTORITO_NO_EMUL:
boot_media_type = 0;
break;
break;
}
boot = calloc(1, sizeof(struct el_torito_boot_image));
if (boot == NULL) {
return ISO_OUT_OF_MEM;
@ -281,11 +281,11 @@ int create_image(IsoImage *image, const char *image_path,
boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type;
if (bootimg) {
*bootimg = boot;
}
return ISO_SUCCESS;
}
@ -298,14 +298,14 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
struct el_torito_boot_catalog *catalog;
ElToritoBootImage *boot_image= NULL;
IsoBoot *cat_node= NULL;
if (image == NULL || image_path == NULL || catalog_path == NULL) {
return ISO_NULL_POINTER;
}
if (image->bootcat != NULL) {
return ISO_IMAGE_ALREADY_BOOTABLE;
}
/* create the node for the catalog */
{
IsoDir *parent;
@ -314,8 +314,8 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
if (catdir == NULL) {
return ISO_OUT_OF_MEM;
}
/* get both the dir and the name */
/* get both the dir and the name */
catname = strrchr(catdir, '/');
if (catname == NULL) {
free(catdir);
@ -345,13 +345,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
return ret;
}
}
/* create the boot image */
ret = create_image(image, image_path, type, &boot_image);
if (ret < 0) {
goto boot_image_cleanup;
}
/* creates the catalog with the given image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
if (catalog == NULL) {
@ -362,13 +362,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
catalog->node = cat_node;
iso_node_ref((IsoNode*)cat_node);
image->bootcat = catalog;
if (boot) {
*boot = boot_image;
}
return ISO_SUCCESS;
boot_image_cleanup:;
if (cat_node) {
iso_node_take((IsoNode*)cat_node);
@ -383,32 +383,32 @@ boot_image_cleanup:;
/**
* Get El-Torito boot image of an ISO image, if any.
*
*
* This can be useful, for example, to check if a volume read from a previous
* session or an existing image is bootable. It can also be useful to get
* the image and catalog tree nodes. An application would want those, for
* the image and catalog tree nodes. An application would want those, for
* example, to prevent the user removing it.
*
*
* Both nodes are owned by libisofs and should not be freed. You can get your
* own ref with iso_node_ref(). You can can also check if the node is already
* on the tree by getting its parent (note that when reading El-Torito info
* from a previous image, the nodes might not be on the tree even if you haven't
* removed them). Remember that you'll need to get a new ref
* (with iso_node_ref()) before inserting them again to the tree, and probably
* own ref with iso_node_ref(). You can can also check if the node is already
* on the tree by getting its parent (note that when reading El-Torito info
* from a previous image, the nodes might not be on the tree even if you haven't
* removed them). Remember that you'll need to get a new ref
* (with iso_node_ref()) before inserting them again to the tree, and probably
* you will also need to set the name or permissions.
*
*
* @param image
* The image from which to get the boot image.
* @param boot
* If not NULL, it will be filled with a pointer to the boot image, if
* any. That object is owned by the IsoImage and should not be freed by
* If not NULL, it will be filled with a pointer to the boot image, if
* any. That object is owned by the IsoImage and should not be freed by
* the user, nor dereferenced once the last reference to the IsoImage was
* disposed via iso_image_unref().
* @param imgnode
* @param imgnode
* When not NULL, it will be filled with the image tree node. No extra ref
* is added, you can use iso_node_ref() to get one if you need it.
* @param catnode
* When not NULL, it will be filled with the catnode tree node. No extra
* @param catnode
* When not NULL, it will be filled with the catnode tree node. No extra
* ref is added, you can use iso_node_ref() to get one if you need it.
* @return
* 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
@ -423,7 +423,7 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
if (image->bootcat == NULL) {
return 0;
}
/* ok, image is bootable */
if (boot) {
*boot = image->bootcat->image;
@ -438,8 +438,8 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
}
/**
* Removes the El-Torito bootable image.
*
* Removes the El-Torito bootable image.
*
* The IsoBoot node that acts as placeholder for the catalog is also removed
* for the image tree, if there.
* If the image is not bootable (don't have el-torito boot image) this function
@ -449,13 +449,13 @@ void iso_image_remove_boot_image(IsoImage *image)
{
if (image == NULL || image->bootcat == NULL)
return;
/*
* remove catalog node from its parent
* (the reference will be disposed next)
/*
* remove catalog node from its parent
* (the reference will be disposed next)
*/
iso_node_take((IsoNode*)image->bootcat->node);
/* free boot catalog and image, including references to nodes */
el_torito_boot_catalog_free(image->bootcat);
image->bootcat = NULL;
@ -464,11 +464,11 @@ void iso_image_remove_boot_image(IsoImage *image)
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{
struct el_torito_boot_image *image;
if (cat == NULL) {
return;
}
image = cat->image;
iso_node_unref((IsoNode*)image->image);
free(image);
@ -486,19 +486,19 @@ struct catalog_stream
int offset; /* -1 if stream is not openned */
};
static void
static void
write_validation_entry(uint8_t *buf)
{
size_t i;
int checksum;
struct el_torito_validation_entry *ve =
struct el_torito_validation_entry *ve =
(struct el_torito_validation_entry*)buf;
ve->header_id[0] = 1;
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
ve->key_byte1[0] = 0x55;
ve->key_byte2[0] = 0xAA;
/* calculate the checksum, to ensure sum of all words is 0 */
checksum = 0;
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
@ -515,9 +515,9 @@ 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 *se =
(struct el_torito_section_entry*)buf;
img = t->catalog->image;
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
@ -525,7 +525,7 @@ write_section_entry(uint8_t *buf, Ecma119Image *t)
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->bootimg->block, 4);
iso_lsb(se->block, t->bootimg->sections[0].block, 4);
}
static
@ -536,13 +536,13 @@ int catalog_open(IsoStream *stream)
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->offset != -1) {
return ISO_FILE_ALREADY_OPENED;
}
memset(data->buffer, 0, BLOCK_SIZE);
/* fill the buffer with the catalog contents */
write_validation_entry(data->buffer);
@ -561,7 +561,7 @@ int catalog_close(IsoStream *stream)
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENED;
}
@ -587,11 +587,11 @@ int catalog_read(IsoStream *stream, void *buf, size_t count)
return ISO_WRONG_ARG_VALUE;
}
data = stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENED;
}
len = MIN(count, BLOCK_SIZE - data->offset);
memcpy(buf, data->buffer + data->offset, len);
return len;
@ -606,7 +606,7 @@ int catalog_is_repeatable(IsoStream *stream)
/**
* 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
* 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,
@ -636,7 +636,7 @@ IsoStreamIface catalog_stream_class = {
};
/**
* Create an IsoStream for writing El-Torito catalog for a given target.
* Create an IsoStream for writing El-Torito catalog for a given target.
*/
static
int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
@ -675,17 +675,17 @@ 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_OUT_OF_MEM;
}
if (target->cat != NULL) {
/* catalog file src already created */
*src = target->cat;
return ISO_SUCCESS;
}
file = malloc(sizeof(IsoFileSrc));
if (file == NULL) {
return ISO_OUT_OF_MEM;
@ -696,10 +696,11 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
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->nsections = 0; /* to be filled later */
file->sections = NULL;
file->sort_weight = 1000; /* slightly high */
file->stream = stream;
@ -746,34 +747,34 @@ int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
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, t->cat->block, 4);
iso_lsb(vol.boot_catalog, t->cat->sections[0].block, 4);
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
}
/**
* Patch an isolinux boot image.
*
*
* @return
* 1 on success, 0 error (but continue), < 0 error
*/
static
static
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
{
struct boot_info_table *info;
uint32_t checksum;
size_t offset;
if (imgsize < 64) {
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small. We won't patch it.");
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
offset = (size_t) 64;
while (offset <= imgsize - 4) {
checksum += iso_read_lsb(buf + offset, 4);
offset += 4;
@ -783,12 +784,12 @@ int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Unexpected isolinux image length. Patch might not work.");
}
/* 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->bootimg->block, 4);
iso_lsb(info->bi_file, t->bootimg->sections[0].block, 4);
iso_lsb(info->bi_length, imgsize, 4);
iso_lsb(info->bi_csum, checksum, 4);
return ISO_SUCCESS;
@ -799,7 +800,7 @@ int eltorito_writer_write_data(IsoImageWriter *writer)
{
/*
* We have nothing to write, but if we need to patch an isolinux image,
* this is a good place to do so.
* this is a good place to do so.
*/
Ecma119Image *t;
int ret;
@ -809,7 +810,7 @@ int eltorito_writer_write_data(IsoImageWriter *writer)
}
t = writer->target;
if (t->catalog->image->isolinux) {
/* we need to patch the image */
size_t size;
@ -830,13 +831,13 @@ int eltorito_writer_write_data(IsoImageWriter *writer)
if (ret != size) {
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
}
/* ok, patch the read buffer */
ret = patch_boot_image(buf, t, size);
if (ret < 0) {
return ret;
}
/* replace the original stream with a memory stream that reads from
* the patched buffer */
ret = iso_memory_stream_new(buf, size, &new);
@ -878,7 +879,7 @@ int eltorito_writer_create(Ecma119Image *target)
/* add this writer to image */
target->writers[target->nwriters++] = writer;
/*
/*
* get catalog and image file sources.
* Note that the catalog may be already added, when creating the low
* level ECMA-119 tree.
@ -895,7 +896,7 @@ int eltorito_writer_create(Ecma119Image *target)
return ret;
}
target->bootimg = src;
/* if we have selected to patch the image, it needs to be copied always */
if (target->catalog->image->isolinux) {
src->prev_img = 0;

View File

@ -61,20 +61,28 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
fsrc = malloc(sizeof(IsoFileSrc));
fsrc = calloc(1, sizeof(IsoFileSrc));
if (fsrc == NULL) {
return ISO_OUT_OF_MEM;
}
/* fill key and other atts */
fsrc->prev_img = file->msblock ? 1 : 0;
fsrc->block = file->msblock;
fsrc->prev_img = file->from_old_session;
if (file->from_old_session) {
int ret = iso_file_get_old_image_sections(file, &(fsrc->nsections),
&(fsrc->sections), 0);
if (ret < 0) {
free(fsrc);
return ISO_OUT_OF_MEM;
}
}
fsrc->sort_weight = file->sort_weight;
fsrc->stream = file->stream;
/* insert the filesrc in the tree */
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
if (ret <= 0) {
free(fsrc->sections);
free(fsrc);
return ret;
}
@ -117,6 +125,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(((IsoFileSrc*)node)->sections);
free(node);
}
@ -174,8 +183,31 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
/* fill block value */
for (i = 0; i < size; ++i) {
int extent = 0;
IsoFileSrc *file = filelist[i];
file->block = t->curblock;
off_t section_size = iso_stream_get_size(file->stream);
if (section_size > (off_t) 0xffffffff) {
file->nsections = DIV_UP(iso_stream_get_size(file->stream)
- (off_t) 0xffffffff, (off_t)0xFFFFF800) + 1;
} else {
file->nsections = 1;
}
file->sections = realloc(file->sections, file->nsections *
sizeof(struct iso_file_section));
for (extent = 0; extent < file->nsections - 1; ++extent) {
file->sections[extent].block = t->curblock + extent * 2097151;
file->sections[extent].size = 0xFFFFF800;
section_size -= (off_t) 0xFFFFF800;
}
/*
* final section
*/
file->sections[extent].block = t->curblock + extent * 2097151;
file->sections[extent].size = section_size;
section_size -= (off_t) 0xFFFFF800;
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
}

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_FILESRC_H_
@ -17,7 +17,11 @@
struct Iso_File_Src
{
unsigned int prev_img :1; /**< if the file comes from a previous image */
uint32_t block; /**< Block where this file will be written on image */
/** File Sections of the file in the image */
struct iso_file_section *sections;
int nsections;
int sort_weight;
IsoStream *stream;
};
@ -26,12 +30,12 @@ int iso_file_src_cmp(const void *n1, const void *n2);
/**
* Create a new IsoFileSrc to get data from a specific IsoFile.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
*
* 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. No new IsoFileSrc is created in that case.
*
*
* @param img
* The image where this file is to be written
* @param file
@ -45,12 +49,12 @@ 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
*
* 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
@ -58,7 +62,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
* @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.
* exists in the tree.
* @return
* 1 on success, 0 if file already exists on tree, < 0 error
*/
@ -76,7 +80,7 @@ off_t iso_file_src_get_size(IsoFileSrc *file);
/**
* Create a Writer for file contents.
*
*
* It takes care of written the files in the correct order.
*/
int iso_file_src_writer_create(Ecma119Image *target);

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -32,7 +32,7 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
*fname = NULL;
return ISO_SUCCESS;
}
if (!strcmp(t->input_charset, t->output_charset)) {
/* no conversion needed */
name = strdup(str);
@ -50,14 +50,14 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
name = strdup(str);
}
}
/* ISO 9660:1999 7.5.1 */
if (strlen(name) > 207) {
name[207] = '\0';
}
*fname = name;
return ISO_SUCCESS;
}
@ -117,7 +117,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
IsoFile *file = (IsoFile*) iso;
size = iso_stream_get_size(file->stream);
if (size > (off_t)0xffffffff) {
if (size > (off_t)0xffffffff && t->iso_level != 3) {
free(n);
return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
"File \"%s\" can't be added to image because is "
@ -159,7 +159,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
/**
* Create the low level ISO 9660:1999 tree from the high level ISO tree.
*
*
* @return
* 1 success, 0 file ignored, < 0 error
*/
@ -230,7 +230,7 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
} else {
/* log and ignore */
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"El-Torito catalog found on a image without El-Torito.",
"El-Torito catalog found on a image without El-Torito.",
iso->name);
}
break;
@ -238,7 +238,7 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
case LIBISO_SPECIAL:
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"Can't add %s to ISO 9660:1999 tree. This kind of files "
"can only be added to a Rock Ridget tree. Skipping.",
"can only be added to a Rock Ridget tree. Skipping.",
iso->name);
break;
default:
@ -269,15 +269,15 @@ cmp_node(const void *f1, const void *f2)
}
/**
* Sort the entries inside an ISO 9660:1999 directory, according to
* ISO 9660:1999, 9.3
* Sort the entries inside an ISO 9660:1999 directory, according to
* ISO 9660:1999, 9.3
*/
static
static
void sort_tree(Iso1999Node *root)
{
size_t i;
qsort(root->info.dir->children, root->info.dir->nchildren,
qsort(root->info.dir->children, root->info.dir->nchildren,
sizeof(void*), cmp_node);
for (i = 0; i < root->info.dir->nchildren; i++) {
Iso1999Node *child = root->info.dir->children[i];
@ -297,9 +297,9 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
nchildren = dir->info.dir->nchildren;
children = dir->info.dir->children;
/* a hash table will temporary hold the names, for fast searching */
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
(compare_function_t)strcmp, &table);
if (ret < 0) {
return ret;
@ -320,7 +320,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
int digits = 1; /* characters to change per name */
/* first, find all child with same name */
while (j + 1 < nchildren &&
while (j + 1 < nchildren &&
!cmp_node(children + i, children + j + 1)) {
++j;
}
@ -330,7 +330,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
}
/*
* A max of 7 characters is good enought, it allows handling up to
* A max of 7 characters is good enought, it allows handling up to
* 9,999,999 files with same name.
*/
while (digits < 8) {
@ -345,7 +345,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
dot = strrchr(full_name, '.');
if (dot != NULL && children[i]->type != ISO1999_DIR) {
/*
/*
* File (not dir) with extension.
*/
int extlen;
@ -358,17 +358,17 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
if (max <= 0) {
/* this can happen if extension is too long */
if (extlen + max > 3) {
/*
/*
* reduce extension len, to give name an extra char
* note that max is negative or 0
* note that max is negative or 0
*/
extlen = extlen + max - 1;
ext[extlen] = '\0';
max = 207 - extlen - 1 - digits;
} else {
/*
/*
* error, we don't support extensions < 3
* This can't happen with current limit of digits.
* This can't happen with current limit of digits.
*/
ret = ISO_ERROR;
goto mangle_cleanup;
@ -428,7 +428,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
children[k]->name = new;
iso_htable_add(table, new, new);
/*
/*
* if we change a name we need to sort again children
* at the end
*/
@ -459,7 +459,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
}
ret = ISO_SUCCESS;
mangle_cleanup : ;
iso_htable_destroy(table, NULL);
return ret;
@ -494,7 +494,7 @@ int iso1999_tree_create(Ecma119Image *t)
{
int ret;
Iso1999Node *root;
if (t == NULL) {
return ISO_NULL_POINTER;
}
@ -507,7 +507,7 @@ int iso1999_tree_create(Ecma119Image *t)
}
return ret;
}
/* the ISO 9660:1999 tree is stored in Ecma119Image target */
t->iso1999_root = root;
@ -559,10 +559,10 @@ size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
len += dirent_len;
}
}
/*
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* (ISO 9660:1999, 6.8.1.3)
*/
len = ROUND_UP(len, BLOCK_SIZE);
@ -626,7 +626,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
t = writer->target;
/* compute position of directories */
iso_msg_debug(t->image->id,
iso_msg_debug(t->image->id,
"Computing position of ISO 9660:1999 dir structure");
t->iso1999_ndirs = 0;
calc_dir_pos(t, t->iso1999_root);
@ -647,7 +647,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
/**
* Write a single directory record (ISO 9660:1999, 9.1).
*
*
* @param file_id
* if >= 0, we use it instead of the filename (for "." and ".." entries).
* @param len_fi
@ -655,11 +655,12 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
*/
static
void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
uint8_t *buf, size_t len_fi)
uint8_t *buf, size_t len_fi, int extent)
{
uint32_t len;
uint32_t block;
uint8_t len_dr; /*< size of dir entry */
int multi_extend = 0;
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
: (uint8_t*)node->name;
@ -674,12 +675,13 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == ISO1999_FILE) {
len = iso_file_src_get_size(node->info.file);
block = node->info.file->block;
block = node->info.file->sections[extent].block;
len = node->info.file->sections[extent].size;
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
} else {
/*
* for nodes other than files and dirs, we set both
* len and block to 0
/*
* for nodes other than files and dirs, we set both
* len and block to 0
*/
len = 0;
block = 0;
@ -695,20 +697,20 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
iso_bb(rec->block, block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
rec->flags[0] = (node->type == ISO1999_DIR) ? 2 : 0;
rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
iso_bb(rec->vol_seq_number, 1, 2);
rec->len_fi[0] = len_fi;
}
/**
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
*/
static
int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
{
IsoImage *image;
Ecma119Image *t;
/* The enhanced volume descriptor is like the sup vol desc */
struct ecma119_sup_vol_desc vol;
@ -741,7 +743,7 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
vol.vol_desc_type[0] = 2;
memcpy(vol.std_identifier, "CD001", 5);
/* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
vol.vol_desc_version[0] = 2;
strncpy_pad((char*)vol.volume_id, vol_id, 32);
@ -754,12 +756,12 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4);
iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4);
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1);
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1, 0);
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
strncpy_pad((char*)vol.data_prep_id, data_id, 128);
strncpy_pad((char*)vol.system_id, system_id, 32);
strncpy_pad((char*)vol.application_id, application_id, 128);
@ -801,30 +803,34 @@ int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
memset(buffer, 0, BLOCK_SIZE);