Add support for reading Level 3 images.

This commit is contained in:
Vreixo Formoso 2008-08-19 01:08:46 +02:00
parent 3f6da75e9c
commit 87f08d27ac
3 changed files with 507 additions and 301 deletions

View File

@ -51,6 +51,7 @@ print_file_src(IsoFileSource *file)
iso_file_source_lstat(file, &info);
print_type(info.st_mode);
print_permissions(info.st_mode);
printf(" %10llu ", info.st_size);
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
name = iso_file_source_get_name(file);
printf(" %s", name);

View File

@ -240,7 +240,12 @@ struct image_fs_data
struct stat info; /**< filled struct stat */
char *name; /**< name of this file */
uint32_t block; /**< block of the extend */
/**
* Location of file extents.
*/
struct iso_file_section *sections;
int nsections;
unsigned int opened : 2; /**< 0 not opened, 1 opened file, 2 opened dir */
/* info for content reading */
@ -372,7 +377,8 @@ int read_dir(ImageFileSourceData *data)
fs = data->fs;
fsdata = fs->data;
block = data->block;
/* a dir has always a single extent */
block = data->sections[0].block;
ret = fsdata->src->read_block(fsdata->src, block, buffer);
if (ret < 0) {
return ret;
@ -434,11 +440,21 @@ int read_dir(ImageFileSourceData *data)
*/
ret = iso_file_source_new_ifs(fs, NULL, record, &child);
if (ret < 0) {
if (child) {
/*
* This can only happen with multi-extent files.
*/
ImageFileSourceData *ifsdata = child->data;
free(ifsdata->sections);
free(ifsdata->name);
free(ifsdata);
free(child);
}
return ret;
}
/* add to the child list */
if (ret != 0) {
if (ret == 1) {
struct child_list *node;
node = malloc(sizeof(struct child_list));
if (node == NULL) {
@ -453,6 +469,7 @@ int read_dir(ImageFileSourceData *data)
node->next = data->data.content;
node->file = child;
data->data.content = node;
child = NULL;
}
tlen += record->len_dr[0];
@ -556,6 +573,76 @@ int ifs_close(IsoFileSource *src)
return ISO_SUCCESS;
}
/**
* Computes the block where the given offset should start.
*/
static
uint32_t block_from_offset(int nsections, struct iso_file_section *sections,
off_t offset)
{
int section = 0;
off_t bytes = 0;
do {
if ( (offset - bytes) < (off_t) sections[section].size ) {
return sections[section].block + (offset - bytes) / BLOCK_SIZE;
} else {
bytes += (off_t) sections[section].size;
section++;
}
} while(section < nsections);
return 0; /* should never happen */
}
/**
* Get the size available for reading on the corresponding block
*/
static
uint32_t size_available(int nsections, struct iso_file_section *sections,
off_t offset)
{
int section = 0;
off_t bytes = 0;
do {
if ( (offset - bytes) < (off_t) sections[section].size ) {
uint32_t curr_section_offset = (uint32_t)(offset - bytes);
uint32_t curr_section_left = sections[section].size - curr_section_offset;
uint32_t available = BLOCK_SIZE - curr_section_offset % BLOCK_SIZE;
return MIN(curr_section_left, available);
} else {
bytes += (off_t) sections[section].size;
section++;
}
} while(section < nsections);
return 0; /* should never happen */
}
/**
* Get the block offset for reading the given file offset
*/
static
uint32_t block_offset(int nsections, struct iso_file_section *sections,
off_t offset)
{
int section = 0;
off_t bytes = 0;
do {
if ( (offset - bytes) < (off_t) sections[section].size ) {
return (uint32_t)(offset - bytes) % BLOCK_SIZE;
} else {
bytes += (off_t) sections[section].size;
section++;
}
} while(section < nsections);
return 0; /* should never happen */
}
/**
* Attempts to read up to count bytes from the given source into
* the buffer starting at buf.
@ -599,7 +686,7 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
size_t bytes;
uint8_t *orig;
if (data->data.offset % BLOCK_SIZE == 0) {
if (block_offset(data->nsections, data->sections, data->data.offset) == 0) {
/* we need to buffer next block */
uint32_t block;
_ImageFsData *fsdata;
@ -609,7 +696,8 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
break;
}
fsdata = data->fs->data;
block = data->block + (data->data.offset / BLOCK_SIZE);
block = block_from_offset(data->nsections, data->sections,
data->data.offset);
ret = fsdata->src->read_block(fsdata->src, block,
data->data.content);
if (ret < 0) {
@ -618,13 +706,13 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
}
/* how much can I read */
bytes = MIN(BLOCK_SIZE - (data->data.offset % BLOCK_SIZE),
bytes = MIN(size_available(data->nsections, data->sections, data->data.offset),
count - read);
if (data->data.offset + (off_t)bytes > data->info.st_size) {
bytes = data->info.st_size - data->data.offset;
}
orig = data->data.content;
orig += data->data.offset % BLOCK_SIZE;
orig += block_offset(data->nsections, data->sections, data->data.offset);
memcpy((uint8_t*)buf + read, orig, bytes);
read += bytes;
data->data.offset += (off_t)bytes;
@ -667,7 +755,11 @@ off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
return (off_t)ISO_WRONG_ARG_VALUE;
}
if (data->data.offset % BLOCK_SIZE != 0) {
/*
* We check for block_offset != 0 because if it is already 0, the block
* will be read from image in the read function
*/
if (block_offset(data->nsections, data->sections, data->data.offset) != 0) {
/* we need to buffer the block */
uint32_t block;
_ImageFsData *fsdata;
@ -675,7 +767,8 @@ off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
if (data->data.offset < data->info.st_size) {
int ret;
fsdata = data->fs->data;
block = data->block + (data->data.offset / BLOCK_SIZE);
block = block_from_offset(data->nsections, data->sections,
data->data.offset);
ret = fsdata->src->read_block(fsdata->src, block,
data->data.content);
if (ret < 0) {
@ -811,6 +904,8 @@ void ifs_free(IsoFileSource *src)
if (data->parent != NULL) {
iso_file_source_unref(data->parent);
}
free(data->sections);
free(data->name);
free(data);
}
@ -871,7 +966,11 @@ char *get_name(_ImageFsData *fsdata, const char *str, size_t len)
/**
*
* @param src
* if not-NULL, it points to a multi-extent file returned by a previous
* call to this function.
* @return
* 2 node is still incomplete (multi-extent)
* 1 success, 0 record ignored (not an error, can be a relocated dir),
* < 0 error
*/
@ -909,15 +1008,6 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
* First of all, check for unsupported ECMA-119 features
*/
/* check for unsupported multiextend */
if (record->flags[0] & 0x80) {
iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
"Unsupported image. This image makes use of Multi-Extend"
" features, that are not supported at this time. If you "
"need support for that, please request us this feature.");
return ISO_UNSUPPORTED_ECMA119;
}
/* check for unsupported interleaved mode */
if (record->file_unit_size[0] || record->interleave_gap_size[0]) {
iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
@ -941,6 +1031,81 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
/* TODO #00013 : check for unsupported flags when reading a dir record */
/*
* If src is not-NULL, it refers to more extents of this file. We ensure
* name matches, otherwise it means we are dealing with wrong image
*/
if (*src != NULL) {
ImageFileSourceData* data = (*src)->data;
char* new_name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
if (new_name == NULL) {
iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
"Can't retrieve file name");
return ISO_WRONG_ECMA119;
}
if (strcmp(new_name, data->name)) {
iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
"Multi-extent file lacks last entry.");
free(new_name);
return ISO_WRONG_ECMA119;
}
free(new_name);
}
/* check for multi-extent */
if (record->flags[0] & 0x80) {
iso_msg_debug(fsdata->msgid, "Found multi-extent file");
/*
* Directory entries can only have one section (ECMA-119, 6.8.1)
*/
if (record->flags[0] & 0x02) {
iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
"Directories with more than one section are not allowed.");
return ISO_WRONG_ECMA119;
}
if (*src == NULL) {
ifsdata = calloc(1, sizeof(ImageFileSourceData));
if (ifsdata == NULL) {
ret = ISO_OUT_OF_MEM;
goto ifs_cleanup;
}
ifsrc = calloc(1, sizeof(IsoFileSource));
if (ifsrc == NULL) {
ret = ISO_OUT_OF_MEM;
goto ifs_cleanup;
}
ifsrc->data = ifsdata;
ifsdata->name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
if (ifsdata->name == NULL) {
iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
"Can't retrieve file name");
ret = ISO_WRONG_ECMA119;
goto ifs_cleanup;
}
*src = ifsrc;
} else {
ifsdata = (*src)->data;
}
/* store current extent */
ifsdata->sections = realloc(ifsdata->sections,
(1 + ifsdata->nsections) * sizeof(struct iso_file_section));
if (ifsdata->sections == NULL) {
free(ifsdata->name);
ret = ISO_OUT_OF_MEM;
goto ifs_cleanup;
}
ifsdata->sections[ifsdata->nsections].block = iso_read_bb(record->block, 4, NULL);
ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
ifsdata->info.st_size += (off_t) ifsdata->sections[ifsdata->nsections].size;
ifsdata->nsections++;
return 2;
}
/*
* The idea is to read all the RR entries (if we want to do that and RR
* extensions exist on image), storing the info we want from that.
@ -1264,6 +1429,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
}
/* ok, we can now create the file source */
if (*src == NULL) {
ifsdata = calloc(1, sizeof(ImageFileSourceData));
if (ifsdata == NULL) {
ret = ISO_OUT_OF_MEM;
@ -1274,6 +1440,12 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
ret = ISO_OUT_OF_MEM;
goto ifs_cleanup;
}
} else {
ifsdata = (*src)->data;
ifsrc = (*src);
free(ifsdata->name); /* we will assign a new one */
atts.st_size += (off_t)ifsdata->info.st_size;
}
/* fill data */
ifsdata->fs = fs;
@ -1284,7 +1456,18 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
}
ifsdata->info = atts;
ifsdata->name = name;
ifsdata->block = iso_read_bb(record->block, 4, NULL);
/* save extents */
ifsdata->sections = realloc(ifsdata->sections,
(1 + ifsdata->nsections) * sizeof(struct iso_file_section));
if (ifsdata->sections == NULL) {
free(ifsdata->name);
ret = ISO_OUT_OF_MEM;
goto ifs_cleanup;
}
ifsdata->sections[ifsdata->nsections].block = iso_read_bb(record->block, 4, NULL);
ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL);
ifsdata->nsections++;
if (S_ISLNK(atts.st_mode)) {
ifsdata->data.content = linkdest;
@ -1332,6 +1515,7 @@ int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root)
}
/* get root attributes from "." entry */
*root = NULL;
ret = iso_file_source_new_ifs((IsoImageFilesystem*)fs, NULL,
(struct ecma119_dir_record*) buffer, root);
@ -2035,7 +2219,8 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
/* source is a regular file */
_ImageFsData *fsdata = data->fs->data;
if (fsdata->eltorito && data->block == fsdata->catblock) {
/* El-Torito images have only one section */
if (fsdata->eltorito && data->sections[0].block == fsdata->catblock) {
if (image->bootcat->node != NULL) {
ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
@ -2080,21 +2265,21 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
return ISO_OUT_OF_MEM;
}
/* the msblock is taken from the image */
file->msblock = data->block;
/* mark file as from old session */
file->from_old_session = 1;
/*
* 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->sort_weight = INT_MAX - data->sections[0].block;
file->stream = stream;
file->node.type = LIBISO_FILE;
new = (IsoNode*) file;
new->refcount = 0;
if (fsdata->eltorito && data->block == fsdata->imgblock) {
if (fsdata->eltorito && data->sections[0].block == fsdata->imgblock) {
/* it is boot image node */
if (image->bootcat->image->image != NULL) {
ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
@ -2264,13 +2449,22 @@ int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src)
goto boot_fs_cleanup;
}
ifsdata->sections = malloc(sizeof(struct iso_file_section));
if (ifsdata->sections == NULL) {
ret = ISO_OUT_OF_MEM;
goto boot_fs_cleanup;
}
/* fill data */
ifsdata->fs = fs;
iso_filesystem_ref(fs);
ifsdata->parent = NULL;
ifsdata->info = atts;
ifsdata->name = NULL;
ifsdata->block = fsdata->imgblock;
ifsdata->sections[0].block = fsdata->imgblock;
ifsdata->sections[0].size = BLOCK_SIZE;
ifsdata->nsections = 1;
ifsrc->class = &ifs_class;
ifsrc->data = ifsdata;

View File

@ -107,6 +107,17 @@ enum IsoNodeType {
#define ISO_NODE(n) ((IsoNode*)n)
/**
* File section in an old image.
*
* @since 0.6.8
*/
struct iso_file_section
{
uint32_t block;
uint32_t size;
};
/**
* Context for iterate on directory children.
* @see iso_dir_get_children()