Merge level3 branch, adding support for ISO-9660 Level 3.
This commit is contained in:
commit
c1a7702f52
@ -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);
|
||||
|
58
doc/devel/cookbook/Multi-Extent.txt
Normal file
58
doc/devel/cookbook/Multi-Extent.txt
Normal file
@ -0,0 +1,58 @@
|
||||
===============================================================================
|
||||
ISO-9660 Level 3 Cookbook
|
||||
===============================================================================
|
||||
|
||||
Creation date: 2008-Aug-17
|
||||
Author: Vreixo Formoso
|
||||
_______________________________________________________________________________
|
||||
|
||||
Contents:
|
||||
---------
|
||||
|
||||
1. References
|
||||
2. General
|
||||
3. OS Support
|
||||
4. Implementation
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
1. References:
|
||||
|
||||
ECMA-119 "Volume and File Structure of CDROM for Information Interchange"
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2. General
|
||||
|
||||
In ECMA-119 standard, the size of a file section cannot be bigger than 4GB - 1,
|
||||
because the Data Length field of the Directory Record is just 32 bits (9.1.4).
|
||||
|
||||
However, "each file shall consist of one or more File Sections" (6.5.1), and
|
||||
that way we can store files greater than 4GB in a ECMA-119 image. Such image,
|
||||
with multiple File Sections, is only supported at Level 3 (10.3), as Level 2
|
||||
(10.2) states that "each file shall consist of only one File Section".
|
||||
|
||||
On disc, each file section is stored in a Extent (6.4.2), i.e. a set of
|
||||
contiguous Logical Blocks.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
3. OS Support
|
||||
|
||||
Wikipedia states that "Microsoft Windows XP supports this, while Mac OS X
|
||||
(as of 10.4.8) does not handle this case properly. In the case of Mac OS X,
|
||||
the driver appears not to support file fragmentation at all (i.e. it only
|
||||
supports ISO 9660 Level 2 but not Level 3). Linux supports multiple extents.
|
||||
FreeBSD only shows and reads the last extent of a multi-extent file."
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
4. Implementation
|
||||
|
||||
Each File Section will have its own Directory Record (6.5.1). So, for files
|
||||
greater than 4 GB, we need to store several directory records, that will have
|
||||
the same File Identifier, and stored in the order of the File Sections they
|
||||
refer (9.3).
|
||||
|
||||
All but the last Directory Record must have the Multi-Extent flag set (9.1.6)
|
||||
|
||||
|
@ -117,18 +117,23 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
Ecma119Node *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
if (t->rockridge) {
|
||||
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
|
||||
*ce += ce_len;
|
||||
}
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
if (t->rockridge) {
|
||||
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
|
||||
*ce += ce_len;
|
||||
}
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,11 +240,13 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
*/
|
||||
static
|
||||
void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
|
||||
uint8_t *buf, size_t len_fi, struct susp_info *info)
|
||||
uint8_t *buf, size_t len_fi, struct susp_info *info,
|
||||
int extent)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr; /*< size of dir entry without SUSP fields */
|
||||
int multi_extend = 0;
|
||||
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
|
||||
: (uint8_t*)node->iso_name;
|
||||
|
||||
@ -260,8 +267,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) {
|
||||
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
|
||||
@ -281,11 +289,13 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *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 == ECMA119_DIR) ? 2 : 0;
|
||||
rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
|
||||
/* and finally write the SUSP fields */
|
||||
/*
|
||||
* and finally write the SUSP fields.
|
||||
*/
|
||||
if (info != NULL) {
|
||||
rrip_write_susp_fields(t, info, buf + len_dr);
|
||||
}
|
||||
@ -365,7 +375,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
|
||||
iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL);
|
||||
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0);
|
||||
|
||||
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
|
||||
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
|
||||
@ -429,7 +439,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
}
|
||||
}
|
||||
len = 34 + info.suf_len;
|
||||
write_one_dir_record(t, dir, 0, buf, 1, &info);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
|
||||
buf += len;
|
||||
|
||||
if (t->rockridge) {
|
||||
@ -439,40 +449,46 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
|
||||
}
|
||||
}
|
||||
len = 34 + info.suf_len;
|
||||
write_one_dir_record(t, dir, 1, buf, 1, &info);
|
||||
write_one_dir_record(t, dir, 1, buf, 1, &info, 0);
|
||||
buf += len;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
Ecma119Node *child = dir->info.dir->children[i];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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 */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
/* compute len of directory entry */
|
||||
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
|
||||
if (need_version_number(t, child)) {
|
||||
len += 2;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, &info, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, &info);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
@ -1273,7 +1289,7 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile)
|
||||
wopts->level = 1;
|
||||
break;
|
||||
case 1:
|
||||
wopts->level = 2;
|
||||
wopts->level = 3;
|
||||
wopts->rockridge = 1;
|
||||
break;
|
||||
case 2:
|
||||
@ -1315,7 +1331,7 @@ int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level)
|
||||
if (opts == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (level != 1 && level != 2) {
|
||||
if (level != 1 && level != 2 && level != 3) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
opts->level = level;
|
||||
|
@ -18,6 +18,18 @@
|
||||
|
||||
#define BLOCK_SIZE 2048
|
||||
|
||||
/*
|
||||
* Maximum file section size. Set to 4GB - 1 = 0xffffffff
|
||||
*/
|
||||
#define MAX_ISO_FILE_SECTION_SIZE 0xffffffff
|
||||
|
||||
/*
|
||||
* When a file need to be splitted in several sections, the maximum size
|
||||
* of such sections, but the last one. Set to a multiple of BLOCK_SIZE.
|
||||
* Default to 4GB - 2048 = 0xFFFFF800
|
||||
*/
|
||||
#define ISO_EXTENT_SIZE 0xFFFFF800
|
||||
|
||||
/**
|
||||
* Holds the options for the image generation.
|
||||
*/
|
||||
|
@ -161,7 +161,7 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
|
||||
off_t size;
|
||||
|
||||
size = iso_stream_get_size(iso->stream);
|
||||
if (size > (off_t)0xffffffff) {
|
||||
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && img->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(ISO_NODE(iso));
|
||||
ret = iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
"File \"%s\" can't be added to image because "
|
||||
|
@ -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
|
||||
@ -699,7 +699,8 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
|
||||
|
||||
/* 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,7 +747,7 @@ 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));
|
||||
}
|
||||
@ -788,7 +789,7 @@ int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
|
||||
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;
|
||||
|
@ -61,20 +61,45 @@ 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 && img->appendable) {
|
||||
/*
|
||||
* On multisession discs we keep file sections from old image.
|
||||
*/
|
||||
int ret = iso_file_get_old_image_sections(file, &(fsrc->nsections),
|
||||
&(fsrc->sections), 0);
|
||||
if (ret < 0) {
|
||||
free(fsrc);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* For new files, or for image copy, we compute our own file sections.
|
||||
* Block and size of each section will be filled later.
|
||||
*/
|
||||
off_t section_size = iso_stream_get_size(file->stream);
|
||||
if (section_size > (off_t) MAX_ISO_FILE_SECTION_SIZE) {
|
||||
fsrc->nsections = DIV_UP(section_size - (off_t) MAX_ISO_FILE_SECTION_SIZE,
|
||||
(off_t)ISO_EXTENT_SIZE) + 1;
|
||||
} else {
|
||||
fsrc->nsections = 1;
|
||||
}
|
||||
fsrc->sections = calloc(fsrc->nsections, sizeof(struct iso_file_section));
|
||||
}
|
||||
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 +142,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 +200,23 @@ 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);
|
||||
for (extent = 0; extent < file->nsections - 1; ++extent) {
|
||||
file->sections[extent].block = t->curblock + extent *
|
||||
(ISO_EXTENT_SIZE / BLOCK_SIZE);
|
||||
file->sections[extent].size = ISO_EXTENT_SIZE;
|
||||
section_size -= (off_t) ISO_EXTENT_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* final section
|
||||
*/
|
||||
file->sections[extent].block = t->curblock + extent * (ISO_EXTENT_SIZE / BLOCK_SIZE);
|
||||
file->sections[extent].size = (uint32_t)section_size;
|
||||
|
||||
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||
}
|
||||
|
||||
@ -259,11 +300,6 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
i = 0;
|
||||
while ((file = filelist[i++]) != NULL) {
|
||||
|
||||
/*
|
||||
* TODO WARNING
|
||||
* when we allow files greater than 4GB, current DIV_UP implementation
|
||||
* can overflow!!
|
||||
*/
|
||||
uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||
|
||||
res = filesrc_open(file);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
@ -2695,3 +2889,54 @@ int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f)
|
||||
{
|
||||
return f->hasElTorito;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the start addresses and the sizes of the data extents of a file node
|
||||
* if it was imported from an old image.
|
||||
*
|
||||
* @param file
|
||||
* The file
|
||||
* @param section_count
|
||||
* Returns the number of extent entries in sections arrays
|
||||
* @param sections
|
||||
* Returns the array of file sections. Apply free() to dispose it.
|
||||
* @param flag
|
||||
* Reserved for future usage, submit 0
|
||||
* @return
|
||||
* 1 if there are valid extents (file comes from old image),
|
||||
* 0 if file was newly added, i.e. it does not come from an old image,
|
||||
* < 0 error
|
||||
*/
|
||||
int iso_file_get_old_image_sections(IsoFile *file, int *section_count,
|
||||
struct iso_file_section **sections,
|
||||
int flag)
|
||||
{
|
||||
if (file == NULL || section_count == NULL || sections == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (flag != 0) {
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
if (file->from_old_session != 0) {
|
||||
|
||||
/*
|
||||
* When file is from old session, we retrieve the original IsoFileSource
|
||||
* to get the sections. This break encapsultation, but safes memory as
|
||||
* we don't need to store the sections in the IsoFile node.
|
||||
*/
|
||||
FSrcStreamData *data = file->stream->data;
|
||||
ImageFileSourceData *ifsdata = data->src->data;
|
||||
|
||||
*section_count = ifsdata->nsections;
|
||||
*sections = malloc(ifsdata->nsections *
|
||||
sizeof(struct iso_file_section));
|
||||
if (*sections == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
memcpy(*sections, ifsdata->sections,
|
||||
ifsdata->nsections * sizeof(struct iso_file_section));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -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)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
"File \"%s\" can't be added to image because is "
|
||||
@ -557,14 +557,19 @@ size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
Iso1999Node *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,11 +668,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;
|
||||
|
||||
@ -682,8 +688,9 @@ 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
|
||||
@ -703,7 +710,7 @@ 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;
|
||||
}
|
||||
@ -762,7 +769,7 @@ 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);
|
||||
@ -809,30 +816,34 @@ int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf, 1);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, 0);
|
||||
buf += 34;
|
||||
write_one_dir_record(t, dir, 1, buf, 1);
|
||||
write_one_dir_record(t, dir, 1, buf, 1, 0);
|
||||
buf += 34;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
Iso1999Node *child = dir->info.dir->children[i];
|
||||
|
||||
/* compute len of directory entry */
|
||||
fi_len = strlen(child->name);
|
||||
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
nsections = (child->type == ISO1999_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 */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
|
@ -111,7 +111,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
|
||||
IsoFile *file = (IsoFile*) iso;
|
||||
|
||||
size = iso_stream_get_size(file->stream);
|
||||
if (size > (off_t)0xffffffff) {
|
||||
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
|
||||
char *ipath = iso_tree_get_node_path(iso);
|
||||
free(joliet);
|
||||
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
|
||||
@ -590,14 +590,19 @@ size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||
size_t remaining;
|
||||
int section, nsections;
|
||||
JolietNode *child = dir->info.dir->children[i];
|
||||
size_t dirent_len = calc_dirent_len(t, child);
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
|
||||
nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
|
||||
for (section = 0; section < nsections; ++section) {
|
||||
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
|
||||
if (dirent_len > remaining) {
|
||||
/* child directory entry doesn't fit on block */
|
||||
len += remaining + dirent_len;
|
||||
} else {
|
||||
len += dirent_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -696,11 +701,12 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
*/
|
||||
static
|
||||
void write_one_dir_record(Ecma119Image *t, JolietNode *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;
|
||||
|
||||
@ -723,8 +729,9 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
len = node->info.dir->len;
|
||||
block = node->info.dir->block;
|
||||
} else if (node->type == JOLIET_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
|
||||
@ -744,7 +751,7 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *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 == JOLIET_DIR) ? 2 : 0;
|
||||
rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
}
|
||||
@ -827,7 +834,7 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
|
||||
iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1);
|
||||
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0);
|
||||
|
||||
ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
|
||||
ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
|
||||
@ -874,12 +881,13 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf, 1);
|
||||
write_one_dir_record(t, dir, 0, buf, 1, 0);
|
||||
buf += 34;
|
||||
write_one_dir_record(t, dir, 1, buf, 1);
|
||||
write_one_dir_record(t, dir, 1, buf, 1, 0);
|
||||
buf += 34;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
int section, nsections;
|
||||
JolietNode *child = dir->info.dir->children[i];
|
||||
|
||||
/* compute len of directory entry */
|
||||
@ -889,18 +897,23 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
|
||||
len += 4;
|
||||
}
|
||||
|
||||
if ( (buf + len - buffer) > BLOCK_SIZE) {
|
||||
/* dir doesn't fit in current block */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
nsections = (child->type == JOLIET_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 */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len, section);
|
||||
buf += len;
|
||||
}
|
||||
/* write the directory entry in any case */
|
||||
write_one_dir_record(t, child, -1, buf, fi_len);
|
||||
buf += len;
|
||||
}
|
||||
|
||||
/* write the last block */
|
||||
|
@ -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()
|
||||
@ -917,7 +928,7 @@ int iso_lib_is_compatible(int major, int minor, int micro);
|
||||
* start point from which to set your custom options.
|
||||
* ---> 1 [BACKUP]
|
||||
* POSIX compatibility for backup. Simple settings, ISO level is set to
|
||||
* 2 and RR extensions are enabled. Useful for backup purposes.
|
||||
* 3 and RR extensions are enabled. Useful for backup purposes.
|
||||
* ---> 2 [DISTRIBUTION]
|
||||
* Setting for information distribution. Both RR and Joliet are enabled
|
||||
* to maximize compatibility with most systems. Permissions are set to
|
||||
@ -943,6 +954,7 @@ void iso_write_opts_free(IsoWriteOpts *opts);
|
||||
* -> 1 for higher compatibility with old systems. With this level
|
||||
* filenames are restricted to 8.3 characters.
|
||||
* -> 2 to allow up to 31 filename characters.
|
||||
* -> 3 to allow files greater than 4GB
|
||||
* @return
|
||||
* 1 success, < 0 error
|
||||
*
|
||||
@ -2551,9 +2563,35 @@ IsoStream *iso_file_get_stream(IsoFile *file);
|
||||
* added, i.e. it does not come from an old image, < 0 error
|
||||
*
|
||||
* @since 0.6.4
|
||||
*
|
||||
* @deprecated Use iso_file_get_old_image_sections(), as this function does
|
||||
* not work with multi-extend files.
|
||||
*/
|
||||
int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag);
|
||||
|
||||
/**
|
||||
* Get the start addresses and the sizes of the data extents of a file node
|
||||
* if it was imported from an old image.
|
||||
*
|
||||
* @param file
|
||||
* The file
|
||||
* @param section_count
|
||||
* Returns the number of extent entries in sections array.
|
||||
* @param sections
|
||||
* Returns the array of file sections. Apply free() to dispose it.
|
||||
* @param flag
|
||||
* Reserved for future usage, submit 0
|
||||
* @return
|
||||
* 1 if there are valid extents (file comes from old image),
|
||||
* 0 if file was newly added, i.e. it does not come from an old image,
|
||||
* < 0 error
|
||||
*
|
||||
* @since 0.6.8
|
||||
*/
|
||||
int iso_file_get_old_image_sections(IsoFile *file, int *section_count,
|
||||
struct iso_file_section **sections,
|
||||
int flag);
|
||||
|
||||
/*
|
||||
* Like iso_file_get_old_image_lba(), but take an IsoNode.
|
||||
*
|
||||
|
@ -936,19 +936,27 @@ dev_t iso_special_get_dev(IsoSpecial *special)
|
||||
*/
|
||||
int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag)
|
||||
{
|
||||
int ret;
|
||||
int section_count;
|
||||
struct iso_file_section *sections;
|
||||
if (file == NULL || lba == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
if (flag != 0) {
|
||||
ret = iso_file_get_old_image_sections(file, §ion_count, §ions, flag);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
if (section_count != 1) {
|
||||
free(sections);
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
if (file->msblock != 0) {
|
||||
*lba = file->msblock;
|
||||
return 1;
|
||||
}
|
||||
*lba = sections[0].block;
|
||||
free(sections);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Like iso_file_get_old_image_lba(), but take an IsoNode.
|
||||
*
|
||||
|
@ -115,10 +115,7 @@ struct Iso_File
|
||||
{
|
||||
IsoNode node;
|
||||
|
||||
/**
|
||||
* Location of a file extent in a ms disc, 0 for newly added file
|
||||
*/
|
||||
uint32_t msblock;
|
||||
unsigned int from_old_session : 1;
|
||||
|
||||
/**
|
||||
* It sorts the order in which the file data is written to the CD image.
|
||||
|
@ -19,16 +19,6 @@ ino_t serial_id = (ino_t)1;
|
||||
ino_t mem_serial_id = (ino_t)1;
|
||||
ino_t cut_out_serial_id = (ino_t)1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IsoFileSource *src;
|
||||
|
||||
/* key for file identification inside filesystem */
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
off_t size; /**< size of this file */
|
||||
} FSrcStreamData;
|
||||
|
||||
static
|
||||
int fsrc_open(IsoStream *stream)
|
||||
{
|
||||
@ -612,6 +602,7 @@ void iso_stream_get_file_name(IsoStream *stream, char *name)
|
||||
FSrcStreamData *data = stream->data;
|
||||
char *path = iso_file_source_get_path(data->src);
|
||||
strncpy(name, path, PATH_MAX);
|
||||
free(path);
|
||||
} else if (!strncmp(type, "boot", 4)) {
|
||||
strcpy(name, "BOOT CATALOG");
|
||||
} else if (!strncmp(type, "mem ", 4)) {
|
||||
|
@ -13,6 +13,16 @@
|
||||
*/
|
||||
#include "fsource.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IsoFileSource *src;
|
||||
|
||||
/* key for file identification inside filesystem */
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
off_t size; /**< size of this file */
|
||||
} FSrcStreamData;
|
||||
|
||||
/**
|
||||
* Get an identifier for the file of the source, for debug purposes
|
||||
* @param name
|
||||
|
@ -23,7 +23,7 @@ static void test_rrip_calc_len_file()
|
||||
|
||||
file = malloc(sizeof(IsoFile));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(file);
|
||||
file->msblock = 0;
|
||||
file->from_old_session = 0;
|
||||
file->sort_weight = 0;
|
||||
file->stream = NULL; /* it is not needed here */
|
||||
file->node.type = LIBISO_FILE;
|
||||
@ -303,7 +303,7 @@ void test_rrip_get_susp_fields_file()
|
||||
|
||||
file = malloc(sizeof(IsoFile));
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(file);
|
||||
file->msblock = 0;
|
||||
file->from_old_session = 0;
|
||||
file->sort_weight = 0;
|
||||
file->stream = NULL; /* it is not needed here */
|
||||
file->node.type = LIBISO_FILE;
|
||||
|
Loading…
Reference in New Issue
Block a user