Add support for reading Level 3 images.
This commit is contained in:
parent
3f6da75e9c
commit
87f08d27ac
@ -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);
|
||||
|
@ -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,15 +1429,22 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
|
||||
}
|
||||
|
||||
/* ok, we can now create the file source */
|
||||
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;
|
||||
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;
|
||||
}
|
||||
} 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 */
|
||||
@ -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;
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user