You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

4538 lines
133 KiB

/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2007 Mario Danic
* Copyright (c) 2009 - 2017 Thomas Schmitt
*
* 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
* or later as published by the Free Software Foundation.
* See COPYING file for details.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
/*
Use the copy of the struct burn_source definition in libisofs.h
*/
#define LIBISOFS_WITHOUT_LIBBURN yes
#include "libisofs.h"
#include "ecma119.h"
#include "joliet.h"
#include "hfsplus.h"
#include "iso1999.h"
#include "eltorito.h"
#include "ecma119_tree.h"
#include "filesrc.h"
#include "image.h"
#include "writer.h"
#include "messages.h"
#include "rockridge.h"
#include "util.h"
#include "system_area.h"
#include "md5.h"
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
#ifdef Xorriso_standalonE
#ifdef Xorriso_with_libjtE
#include "../libjte/libjte.h"
#endif
#else
#ifdef Libisofs_with_libjtE
#include <libjte/libjte.h>
#endif
#endif /* ! Xorriso_standalonE */
int iso_write_opts_clone(IsoWriteOpts *in, IsoWriteOpts **out, int flag);
/*
* TODO #00011 : guard against bad path table usage with more than 65535 dirs
* image with more than 65535 directories have path_table related problems
* due to 16 bits parent id. Note that this problem only affects to folders
* that are parent of another folder.
*/
static
void ecma119_image_free(Ecma119Image *t)
{
size_t i;
if (t == NULL)
return;
if (t->refcount > 1) {
t->refcount--;
return;
}
if (t->root != NULL)
ecma119_node_free(t->root);
if (t->opts != NULL)
iso_write_opts_free(t->opts);
if (t->image != NULL)
iso_image_unref(t->image);
if (t->files != NULL)
iso_rbtree_destroy(t->files, iso_file_src_free);
if (t->ecma119_hidden_list != NULL)
iso_filesrc_list_destroy(&(t->ecma119_hidden_list));
if (t->buffer != NULL)
iso_ring_buffer_free(t->buffer);
for (i = 0; i < t->nwriters; ++i) {
IsoImageWriter *writer = t->writers[i];
writer->free_data(writer);
free(writer);
}
if (t->input_charset != NULL)
free(t->input_charset);
if (t->output_charset != NULL)
free(t->output_charset);
if (t->bootsrc != NULL)
free(t->bootsrc);
if (t->boot_appended_idx != NULL)
free(t->boot_appended_idx);
if (t->boot_intvl_start != NULL)
free(t->boot_intvl_start);
if (t->boot_intvl_size != NULL)
free(t->boot_intvl_size);
if (t->system_area_data != NULL)
free(t->system_area_data);
if (t->checksum_ctx != NULL) { /* dispose checksum context */
char md5[16];
iso_md5_end(&(t->checksum_ctx), md5);
}
if (t->checksum_buffer != NULL)
free(t->checksum_buffer);
if (t->writers != NULL)
free(t->writers);
if (t->partition_root != NULL)
ecma119_node_free(t->partition_root);
for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
if (t->hfsplus_blessed[i] != NULL)
iso_node_unref(t->hfsplus_blessed[i]);
for (i = 0; (int) i < t->apm_req_count; i++)
if (t->apm_req[i] != NULL)
free(t->apm_req[i]);
for (i = 0; (int) i < t->mbr_req_count; i++)
if (t->mbr_req[i] != NULL)
free(t->mbr_req[i]);
for (i = 0; (int) i < t->gpt_req_count; i++)
if (t->gpt_req[i] != NULL)
free(t->gpt_req[i]);
free(t);
}
static int show_chunk_to_jte(Ecma119Image *target, char *buf, int count)
{
#ifdef Libisofs_with_libjtE
int ret;
if (target->opts->libjte_handle == NULL)
return ISO_SUCCESS;
ret = libjte_show_data_chunk(target->opts->libjte_handle, buf, count, 1);
if (ret <= 0) {
iso_libjte_forward_msgs(target->opts->libjte_handle,
target->image->id, ISO_LIBJTE_FILE_FAILED, 0);
return ISO_LIBJTE_FILE_FAILED;
}
#endif /* Libisofs_with_libjtE */
return ISO_SUCCESS;
}
/**
* Check if we should add version number ";" to the given node name.
*/
static
int need_version_number(IsoWriteOpts *opts, enum ecma119_node_type node_type)
{
if ((opts->omit_version_numbers & 1) ||
opts->max_37_char_filenames || opts->untranslated_name_len > 0) {
return 0;
}
if (node_type == ECMA119_DIR || node_type == ECMA119_PLACEHOLDER) {
return 0;
} else {
return 1;
}
}
/**
* Compute the size of a directory entry for a single node
*/
static
size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
{
int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
if (need_version_number(t->opts, n->type)) {
ret += 2; /* take into account version numbers */
}
if (ret % 2)
ret++;
return ret;
}
/**
* Computes the total size of all directory entries of a single dir,
* according to ECMA-119 6.8.1.1
*
* This also take into account the size needed for RR entries and
* SUSP continuation areas (SUSP, 5.1).
*
* @param ce
* Will be filled with the size needed for Continuation Areas
* @return
* The size needed for all dir entries of the given dir, without
* taking into account the continuation areas.
*/
static
size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
{
size_t i, len;
size_t ce_len = 0;
/* size of "." and ".." entries */
len = 34 + 34;
if (t->opts->rockridge) {
len += rrip_calc_len(t, dir, 1, 34, &ce_len, *ce);
*ce += ce_len;
len += rrip_calc_len(t, dir, 2, 34, &ce_len, *ce);
*ce += ce_len;
}
for (i = 0; i < dir->info.dir->nchildren; ++i) {
size_t remaining;
int section, nsections;
Ecma119Node *child = dir->info.dir->children[i];
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->opts->rockridge) {
dirent_len += rrip_calc_len(t, child, 0, dirent_len, &ce_len,
*ce);
*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;
}
}
}
/*
* 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
* (ECMA-119, 6.8.1.3)
*/
len = ROUND_UP(len, BLOCK_SIZE);
/* cache the len */
dir->info.dir->len = len;
return len;
}
static
void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir)
{
size_t i, len;
size_t ce_len = 0;
t->ndirs++;
dir->info.dir->block = t->curblock;
len = calc_dir_size(t, dir, &ce_len);
t->curblock += DIV_UP(len, BLOCK_SIZE);
if (t->opts->rockridge) {
t->curblock += DIV_UP(ce_len, BLOCK_SIZE);
}
for (i = 0; i < dir->info.dir->nchildren; i++) {
Ecma119Node *child = dir->info.dir->children[i];
if (child->type == ECMA119_DIR) {
calc_dir_pos(t, child);
}
}
}
/**
* Compute the length of the path table, in bytes.
*/
static
uint32_t calc_path_table_size(Ecma119Node *dir)
{
uint32_t size;
size_t i;
/* size of path table for this entry */
size = 8;
size += dir->iso_name ? strlen(dir->iso_name) : 1;
size += (size % 2);
/* and recurse */
for (i = 0; i < dir->info.dir->nchildren; i++) {
Ecma119Node *child = dir->info.dir->children[i];
if (child->type == ECMA119_DIR) {
size += calc_path_table_size(child);
}
}
return size;
}
static
int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
{
Ecma119Image *target;
uint32_t path_table_size;
size_t ndirs;
if (writer == NULL) {
return ISO_ASSERT_FAILURE;
}
target = writer->target;
/* compute position of directories */
iso_msg_debug(target->image->id, "Computing position of dir structure");
target->ndirs = 0;
calc_dir_pos(target, target->root);
/* compute length of pathlist */
iso_msg_debug(target->image->id, "Computing length of pathlist");
path_table_size = calc_path_table_size(target->root);
/* compute location for path tables */
target->l_path_table_pos = target->curblock;
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
target->m_path_table_pos = target->curblock;
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
target->path_table_size = path_table_size;
if (target->opts->md5_session_checksum) {
/* Account for first tree checksum tag */
target->checksum_tree_tag_pos = target->curblock;
target->curblock++;
}
if (target->opts->partition_offset > 0) {
/* Take into respect the second directory tree */
ndirs = target->ndirs;
target->ndirs = 0;
calc_dir_pos(target, target->partition_root);
if (target->ndirs != ndirs) {
iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0,
"Number of directories differs in ECMA-119 partiton_tree");
return ISO_ASSERT_FAILURE;
}
/* Take into respect the second set of path tables */
path_table_size = calc_path_table_size(target->partition_root);
target->partition_l_table_pos = target->curblock;
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
target->partition_m_table_pos = target->curblock;
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
/* >>> TWINTREE: >>> For now, checksum tags are only for the
image start and not for the partition */;
}
target->tree_end_block = target->curblock;
return ISO_SUCCESS;
}
/**
* Write a single directory record (ECMA-119, 9.1)
*
* @param file_id
* if >= 0, we use it instead of the filename (for "." and ".." entries).
* @param len_fi
* Computed length of the file identifier. Total size of the directory
* entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
* @param info
* SUSP entries for the given directory record. It will be NULL for the
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
* distinguish it from the "." entry in the root directory)
*/
static
void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
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;
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
IsoNode *iso;
len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
memcpy(rec->file_id, name, len_fi);
if (need_version_number(t->opts, node->type)) {
len_dr += 2;
rec->file_id[len_fi++] = ';';
rec->file_id[len_fi++] = '1';
}
if (node->type == ECMA119_DIR) {
/* use the cached length */
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == ECMA119_FILE) {
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 len to 0, and
* the content block address to a dummy value.
*/
len = 0;
if (! t->opts->old_empty)
block = t->empty_file_block;
else
block = 0;
}
/*
* For ".." entry we need to write the parent info!
*/
if (file_id == 1 && node->parent)
node = node->parent;
rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
iso_bb(rec->block, block - t->eff_partition_offset, 4);
iso_bb(rec->length, len, 4);
if (t->opts->dir_rec_mtime & 1) {
iso= node->node;
iso_datetime_7(rec->recording_time,
t->replace_timestamps ? t->timestamp : iso->mtime,
t->opts->always_gmt);
} else {
iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
}
rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
rec->len_fi[0] = len_fi;
/*
* and finally write the SUSP fields.
*/
if (info != NULL) {
rrip_write_susp_fields(t, info, buf + len_dr);
}
}
static
char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
{
int ret;
if (name == NULL) {
return NULL;
}
if (strcmp(t->input_charset, t->output_charset)) {
/* charset conversion needed */
char *str;
ret = strconv(name, t->input_charset, t->output_charset, &str);
if (ret == ISO_SUCCESS) {
return str;
}
iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
"Charset conversion error. Cannot convert from %s to %s",
t->input_charset, t->output_charset);
}
return strdup(name);
}
/**
* Set the timestamps of Primary, Supplementary, or Enhanced Volume Descriptor.
*/
void ecma119_set_voldescr_times(IsoImageWriter *writer,
struct ecma119_pri_vol_desc *vol)
{
Ecma119Image *t = writer->target;
IsoWriteOpts *o;
int i;
o = t->opts;
if (o->vol_uuid[0]) {
for(i = 0; i < 16; i++)
if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
break;
else
vol->vol_creation_time[i] = o->vol_uuid[i];
for(; i < 16; i++)
vol->vol_creation_time[i] = '1';
vol->vol_creation_time[16] = 0;
} else if (o->vol_creation_time > 0)
iso_datetime_17(vol->vol_creation_time, o->vol_creation_time,
o->always_gmt);
else
iso_datetime_17(vol->vol_creation_time, t->now, o->always_gmt);
if (o->vol_uuid[0]) {
for(i = 0; i < 16; i++)
if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
break;
else
vol->vol_modification_time[i] = o->vol_uuid[i];
for(; i < 16; i++)
vol->vol_modification_time[i] = '1';
vol->vol_modification_time[16] = 0;
} else if (o->vol_modification_time > 0)
iso_datetime_17(vol->vol_modification_time, o->vol_modification_time,
o->always_gmt);
else
iso_datetime_17(vol->vol_modification_time, t->now, o->always_gmt);
if (o->vol_expiration_time > 0) {
iso_datetime_17(vol->vol_expiration_time, o->vol_expiration_time,
o->always_gmt);
} else {
for(i = 0; i < 16; i++)
vol->vol_expiration_time[i] = '0';
vol->vol_expiration_time[16] = 0;
}
if (o->vol_effective_time > 0) {
iso_datetime_17(vol->vol_effective_time, o->vol_effective_time,
o->always_gmt);
} else {
for(i = 0; i < 16; i++)
vol->vol_effective_time[i] = '0';
vol->vol_effective_time[16] = 0;
}
}
/**
* Write the Primary Volume Descriptor (ECMA-119, 8.4)
*/
static
int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
{
IsoImage *image;
Ecma119Image *t;
struct ecma119_pri_vol_desc vol;
char *vol_id, *pub_id, *data_id, *volset_id;
char *system_id, *application_id, *copyright_file_id;
char *abstract_file_id, *biblio_file_id;
if (writer == NULL) {
return ISO_ASSERT_FAILURE;
}
t = writer->target;
image = t->image;
iso_msg_debug(image->id, "Write Primary Volume Descriptor");
memset(&vol, 0, sizeof(struct ecma119_pri_vol_desc));
if (t->opts->relaxed_vol_atts) {
vol_id = get_relaxed_vol_id(t, image->volume_id);
volset_id = get_relaxed_vol_id(t, image->volset_id);
} else {
str2d_char(t->input_charset, image->volume_id, &vol_id);
str2d_char(t->input_charset, image->volset_id, &volset_id);
}
str2a_char(t->input_charset, image->publisher_id, &pub_id);
str2a_char(t->input_charset, image->data_preparer_id, &data_id);
str2a_char(t->input_charset, image->system_id, &system_id);
str2a_char(t->input_charset, image->application_id, &application_id);
str2d_char(t->input_charset, image->copyright_file_id, &copyright_file_id);
str2d_char(t->input_charset, image->abstract_file_id, &abstract_file_id);
str2d_char(t->input_charset, image->biblio_file_id, &biblio_file_id);
vol.vol_desc_type[0] = 1;
memcpy(vol.std_identifier, "CD001", 5);
vol.vol_desc_version[0] = 1;
strncpy_pad((char*)vol.system_id, system_id, 32);
strncpy_pad((char*)vol.volume_id, vol_id, 32);
if (t->pvd_size_is_total_size) {
iso_bb(vol.vol_space_size,
t->total_size / 2048 + t->opts->ms_block - t->eff_partition_offset,
4);
} else {
iso_bb(vol.vol_space_size,
t->vol_space_size - t->eff_partition_offset, 4);
}
iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
iso_bb(vol.path_table_size, t->path_table_size, 4);
if (t->eff_partition_offset > 0) {
/* Point to second tables and second root */
iso_lsb(vol.l_path_table_pos,
t->partition_l_table_pos - t->eff_partition_offset, 4);
iso_msb(vol.m_path_table_pos,
t->partition_m_table_pos - t->eff_partition_offset, 4);
write_one_dir_record(t, t->partition_root, 0,
vol.root_dir_record, 1, NULL, 0);
} else {
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, 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.application_id, application_id, 128);
strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
ecma119_set_voldescr_times(writer, &vol);
vol.file_structure_version[0] = 1;
memcpy(vol.app_use, image->application_use, 512);
free(vol_id);
free(volset_id);
free(pub_id);
free(data_id);
free(system_id);
free(application_id);
free(copyright_file_id);
free(abstract_file_id);
free(biblio_file_id);
/* Finally write the Volume Descriptor */
return iso_write(t, &vol, sizeof(struct ecma119_pri_vol_desc));
}
static
int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
{
int ret;
uint8_t *buffer = NULL;
size_t i;
size_t fi_len, len;
struct susp_info info;
/* buf will point to current write position on buffer */
uint8_t *buf;
LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
buf = buffer;
/*
* set susp_info to 0's, this way code for both plain ECMA-119 and
* RR is very similar
*/
memset(&info, 0, sizeof(struct susp_info));
if (t->opts->rockridge) {
/* initialize the ce_block, it might be needed */
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
BLOCK_SIZE);
info.ce_susp_fields = NULL;
}
/* write the "." and ".." entries first */
if (t->opts->rockridge) {
ret = rrip_get_susp_fields(t, dir, 1, 34, &info);
if (ret < 0) {
goto ex;
}
}
len = 34 + info.suf_len;
write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
buf += len;
if (t->opts->rockridge) {
ret = rrip_get_susp_fields(t, dir, 2, 34, &info);
if (ret < 0) {
goto ex;
}
}
len = 34 + info.suf_len;
write_one_dir_record(t, parent, 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];
fi_len = strlen(child->iso_name);
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
/* compute len of directory entry */
len = fi_len + 33 + ((fi_len % 2) ? 0 : 1);
if (need_version_number(t->opts, child->type)) {
len += 2;
}
/* get the SUSP fields if rockridge is enabled */
if (t->opts->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, len, &info);
if (ret < 0) {
goto ex;
}
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) {
goto ex;
}
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 last block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
goto ex;
}
/* write the Continuation Area if needed */
if (info.ce_len > 0) {
ret = rrip_write_ce_fields(t, &info);
}
ex:;
LIBISO_FREE_MEM(buffer);
return ret;
}
static
int write_dirs(Ecma119Image *t, Ecma119Node *root, Ecma119Node *parent)
{
int ret;
size_t i;
/* write all directory entries for this dir */
ret = write_one_dir(t, root, parent);
if (ret < 0) {
return ret;
}
/* recurse */
for (i = 0; i < root->info.dir->nchildren; i++) {
Ecma119Node *child = root->info.dir->children[i];
if (child->type == ECMA119_DIR) {
ret = write_dirs(t, child, root);
if (ret < 0) {
return ret;
}
}
}
return ISO_SUCCESS;
}
static
int write_path_table(Ecma119Image *t, Ecma119Node **pathlist, int l_type)
{
size_t i, len;
uint8_t buf[64]; /* 64 is just a convenient size larger enought */
struct ecma119_path_table_record *rec;
void (*write_int)(uint8_t*, uint32_t, int);
Ecma119Node *dir;
uint32_t path_table_size;
int parent = 0;
int ret= ISO_SUCCESS;
uint8_t *zeros = NULL;
path_table_size = 0;
write_int = l_type ? iso_lsb : iso_msb;
for (i = 0; i < t->ndirs; i++) {
dir = pathlist[i];
/* find the index of the parent in the table */
while ((i) && pathlist[parent] != dir->parent) {
parent++;
}
/* write the Path Table Record (ECMA-119, 9.4) */
memset(buf, 0, 64);
rec = (struct ecma119_path_table_record*) buf;
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->info.dir->block - t->eff_partition_offset,
4);
write_int(rec->parent, parent + 1, 2);
if (dir->parent) {
memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
}
len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
ret = iso_write(t, buf, len);
if (ret < 0) {
/* error */
goto ex;
}
path_table_size += len;
}
/* we need to fill the last block with zeros */
path_table_size %= BLOCK_SIZE;
if (path_table_size) {
len = BLOCK_SIZE - path_table_size;
LIBISO_ALLOC_MEM(zeros, uint8_t, len);
ret = iso_write(t, zeros, len);
}
ex:;
LIBISO_FREE_MEM(zeros);
return ret;
}
static
int write_path_tables(Ecma119Image *t)
{
int ret;
size_t i, j, cur;
Ecma119Node **pathlist;
iso_msg_debug(t->image->id, "Writing ISO Path tables");
/* allocate temporal pathlist */
pathlist = malloc(sizeof(void*) * t->ndirs);
if (pathlist == NULL) {
return ISO_OUT_OF_MEM;
}
if (t->eff_partition_offset > 0) {
pathlist[0] = t->partition_root;
} else {
pathlist[0] = t->root;
}
cur = 1;
for (i = 0; i < t->ndirs; i++) {
Ecma119Node *dir = pathlist[i];
for (j = 0; j < dir->info.dir->nchildren; j++) {
Ecma119Node *child = dir->info.dir->children[j];
if (child->type == ECMA119_DIR) {
pathlist[cur++] = child;
}
}
}
/* Write L Path Table */
ret = write_path_table(t, pathlist, 1);
if (ret < 0) {
goto write_path_tables_exit;
}
/* Write L Path Table */
ret = write_path_table(t, pathlist, 0);
write_path_tables_exit: ;
free(pathlist);
return ret;
}
/**
* Write the directory structure (ECMA-119, 6.8) and the L and M
* Path Tables (ECMA-119, 6.9).
*/
static
int ecma119_writer_write_dirs(IsoImageWriter *writer)
{
int ret, isofs_ca_changed = 0;
Ecma119Image *t;
Ecma119Node *root;
char *value = NULL;
size_t value_length;
t = writer->target;
/* first of all, we write the directory structure */
if (t->eff_partition_offset > 0) {
root = t->partition_root;
if ((t->opts->md5_file_checksums & 1) ||
t->opts->md5_session_checksum) {
/* Take into respect the address offset in "isofs.ca" */
ret = iso_node_lookup_attr((IsoNode *) t->image->root, "isofs.ca",
&value_length, &value, 0);
if (value != NULL)
free(value);
if (ret == 1 && value_length == 20) {
/* "isofs.ca" does really exist and has the expected length */
ret = iso_root_set_isofsca((IsoNode *) t->image->root,
t->checksum_range_start - t->eff_partition_offset,
t->checksum_array_pos - t->eff_partition_offset,
t->checksum_idx_counter + 2, 16, "MD5", 0);
if (ret < 0)
return ret;
isofs_ca_changed = 1;
}
}
} else {
root = t->root;
}
ret = write_dirs(t, root, root);
if (ret < 0) {
return ret;
}
/* and write the path tables */
ret = write_path_tables(t);
if (ret < 0)
return ret;
if (t->opts->md5_session_checksum) {
/* Write tree checksum tag */
if (t->eff_partition_offset > 0) {
/* >>> TWINTREE: >>> For now, tags are only for the
image start and not for the partition */;
} else {
ret = iso_md5_write_tag(t, 3);
}
}
if (isofs_ca_changed) {
/* Restore old addresses offset in "isofs.ca" of root node */
ret = iso_root_set_isofsca((IsoNode *) t->image->root,
t->checksum_range_start,
t->checksum_array_pos,
t->checksum_idx_counter + 2, 16, "MD5", 0);
if (ret < 0)
return ret;
}
return ret;
}
/**
* Write directory structure and Path Tables of the ECMA-119 tree.
* This happens eventually a second time for the duplicates which use
* addresses with partition offset.
*/
static
int ecma119_writer_write_data(IsoImageWriter *writer)
{
int ret;
Ecma119Image *t;
uint32_t curblock;
char *msg = NULL;
if (writer == NULL)
{ret = ISO_ASSERT_FAILURE; goto ex;}
t = writer->target;
ret = ecma119_writer_write_dirs(writer);
if (ret < 0)
goto ex;
if (t->opts->partition_offset > 0) {
t->eff_partition_offset = t->opts->partition_offset;
ret = ecma119_writer_write_dirs(writer);
t->eff_partition_offset = 0;
if (ret < 0)
goto ex;
}
curblock = (t->bytes_written / 2048) + t->opts->ms_block;
if (curblock != t->tree_end_block) {
LIBISO_ALLOC_MEM(msg, char, 100);
sprintf(msg,
"Calculated and written ECMA-119 tree end differ: %lu <> %lu",
(unsigned long) t->tree_end_block,
(unsigned long) curblock);
iso_msgs_submit(0, msg, 0, "WARNING", 0);
t->tree_end_block = 1;/* Mark for harsher reaction at end of writing */
}
ret = ISO_SUCCESS;
ex:;
LIBISO_FREE_MEM(msg);
return ret;
}
static
int ecma119_writer_free_data(IsoImageWriter *writer)
{
/* nothing to do */
return ISO_SUCCESS;
}
int ecma119_writer_create(Ecma119Image *target)
{
int ret;
IsoImageWriter *writer;
writer = malloc(sizeof(IsoImageWriter));
if (writer == NULL) {
return ISO_OUT_OF_MEM;
}
writer->compute_data_blocks = ecma119_writer_compute_data_blocks;
writer->write_vol_desc = ecma119_writer_write_vol_desc;
writer->write_data = ecma119_writer_write_data;
writer->free_data = ecma119_writer_free_data;
writer->data = NULL;
writer->target = target;
/* add this writer to image */
target->writers[target->nwriters++] = writer;
iso_msg_debug(target->image->id, "Creating low level ECMA-119 tree...");
ret = ecma119_tree_create(target);
if (ret < 0) {
return ret;
}
if (target->image->sparc_core_node != NULL) {
/* Obtain a duplicate of the IsoFile's Ecma119Node->file */
ret = iso_file_src_create(target, target->image->sparc_core_node,
&target->sparc_core_src);
if (ret < 0)
return ret;
}
if(target->opts->partition_offset > 0) {
/* Create second tree */
target->eff_partition_offset = target->opts->partition_offset;
ret = ecma119_tree_create(target);
target->eff_partition_offset = 0;
if (ret < 0)
return ret;
}
/* we need the volume descriptor */
target->curblock++;
return ISO_SUCCESS;
}
/** compute how many padding bytes are needed */
static
int mspad_writer_compute_data_blocks(IsoImageWriter *writer)
{
Ecma119Image *target;
uint32_t min_size;
if (writer == NULL) {
return ISO_ASSERT_FAILURE;
}
target = writer->target;
min_size = 32 + target->opts->partition_offset;
if (target->curblock < min_size) {
target->mspad_blocks = min_size - target->curblock;
target->curblock = min_size;
}
return ISO_SUCCESS;
}
static
int mspad_writer_write_vol_desc(IsoImageWriter *writer)
{
/* nothing to do */
return ISO_SUCCESS;
}
static
int mspad_writer_write_data(IsoImageWriter *writer)
{
int ret;
Ecma119Image *t;
uint8_t *pad = NULL;
size_t i;
if (writer == NULL) {
{ret = ISO_ASSERT_FAILURE; goto ex;}
}
t = writer->target;
if (t->mspad_blocks == 0) {
{ret = ISO_SUCCESS; goto ex;}
}
LIBISO_ALLOC_MEM(pad, uint8_t, BLOCK_SIZE);
for (i = 0; i < t->mspad_blocks; ++i) {
ret = iso_write(t, pad, BLOCK_SIZE);
if (ret < 0) {
goto ex;
}
}
ret = ISO_SUCCESS;
ex:;
LIBISO_FREE_MEM(pad);
return ret;
}
static
int mspad_writer_free_data(IsoImageWriter *writer)
{
/* nothing to do */
return ISO_SUCCESS;
}
static
int mspad_writer_create(Ecma119Image *target)
{
IsoImageWriter *writer;
writer = malloc(sizeof(IsoImageWriter));
if (writer == NULL) {
return ISO_OUT_OF_MEM;
}
writer->compute_data_blocks = mspad_writer_compute_data_blocks;
writer->write_vol_desc = mspad_writer_write_vol_desc;
writer->write_data = mspad_writer_write_data;
writer->free_data = mspad_writer_free_data;
writer->data = NULL;
writer->target = target;
/* add this writer to image */
target->writers[target->nwriters++] = writer;
return ISO_SUCCESS;
}
/** ----- Zero padding writer ----- */
struct iso_zero_writer_data_struct {
uint32_t num_blocks;
};
static
int zero_writer_compute_data_blocks(IsoImageWriter *writer)
{
Ecma119Image *target;
struct iso_zero_writer_data_struct *data;
if (writer == NULL)
return ISO_ASSERT_FAILURE;
target = writer->target;
data = (struct iso_zero_writer_data_struct *) writer->data;
target->curblock += data->num_blocks;
return ISO_SUCCESS;
}
static
int zero_writer_write_vol_desc(IsoImageWriter *writer)
{
/* nothing to do */
return ISO_SUCCESS;
}
static
int zero_writer_write_data(IsoImageWriter *writer)
{
int ret;
Ecma119Image *t;
struct iso_zero_writer_data_struct *data;
uint8_t *pad = NULL;
size_t i;
if (writer == NULL)
{ret = ISO_ASSERT_FAILURE; goto ex;}
t = writer->target;
data = (struct iso_zero_writer_data_struct *) writer->data;
if (data->num_blocks == 0)
{ret = ISO_SUCCESS; goto ex;}
LIBISO_ALLOC_MEM(pad, uint8_t, BLOCK_SIZE);
for (i = 0; i < data->num_blocks; ++i) {
ret = iso_write(t, pad, BLOCK_SIZE);
if (ret < 0)
goto ex;
}
ret = ISO_SUCCESS;
ex:;
LIBISO_FREE_MEM(pad);
return ret;
}
static
int zero_writer_free_data(IsoImageWriter *writer)
{
if (writer == NULL)
return ISO_SUCCESS;
if (writer->data == NULL)
return ISO_SUCCESS;
free(writer->data);
writer->data = NULL;
return ISO_SUCCESS;
}
static
int tail_writer_compute_data_blocks(IsoImageWriter *writer)
{
int ret;
Ecma119Image *target;
struct iso_zero_writer_data_struct *data;
char msg[80];
target = writer->target;
ret = iso_align_isohybrid(target, 0);
if (ret < 0)
return ret;
data = (struct iso_zero_writer_data_struct *) writer->data;
if (data->num_blocks != target->opts->tail_blocks) {
sprintf(msg, "Aligned image size to cylinder size by %d blocks",
target->opts->tail_blocks - data->num_blocks);
iso_msgs_submit(0, msg, 0, "NOTE", 0);
data->num_blocks = target->opts->tail_blocks;
}
if (target->opts->tail_blocks <= 0)
return ISO_SUCCESS;
ret = zero_writer_compute_data_blocks(writer);
return ret;
}
/*
@param flag bit0= use tail_writer_compute_data_blocks rather than
zero_writer_compute_data_blocks
*/
static
int zero_writer_create(Ecma119Image *target, uint32_t num_blocks, int flag)
{
IsoImageWriter *writer;
struct iso_zero_writer_data_struct *data;
writer = malloc(sizeof(IsoImageWriter));
if (writer == NULL) {
return ISO_OUT_OF_MEM;
}
data = calloc(1, sizeof(struct iso_zero_writer_data_struct));
if (data == NULL) {
free(writer);
return ISO_OUT_OF_MEM;
}
data->num_blocks = num_blocks;
if (flag & 1) {
writer->compute_data_blocks = tail_writer_compute_data_blocks;
} else {
writer->compute_data_blocks = zero_writer_compute_data_blocks;
}
writer->write_vol_desc = zero_writer_write_vol_desc;
writer->write_data = zero_writer_write_data;
writer->free_data = zero_writer_free_data;
writer->data = data;
writer->target = target;
/* add this writer to image */
target->writers[target->nwriters++] = writer;
return ISO_SUCCESS;
}
/* @param flag bit0= restore preserved cx (else dispose them)
*/
static
int process_preserved_cx(IsoDir *dir, int flag)
{
int ret, i;
unsigned int cx_value;
void *xipt;
IsoNode *pos;
pos = dir->children;
for (pos = dir->children; pos != NULL; pos = pos->next) {
if (pos->type == LIBISO_FILE) {
if (flag & 1) {
/* Restore preserved cx state of nodes */
ret = iso_node_get_xinfo(pos, checksum_cx_xinfo_func,
&xipt);
if (ret == 1) {
/* xipt is an int disguised as void pointer */
cx_value = 0;
for (i = 0; i < 4; i++)
cx_value =
(cx_value << 8) | ((unsigned char *) &xipt)[i];
ret = iso_file_set_isofscx((IsoFile *) pos, cx_value, 0);
if (ret < 0)
return ret;
} else if (ret == 0) {
/* Node had no cx before the write run. Delete cx. */
iso_file_set_isofscx((IsoFile *) pos, 0, 1);
}
}
iso_node_remove_xinfo(pos, checksum_cx_xinfo_func);
} else if (pos->type == LIBISO_DIR) {
ret = process_preserved_cx((IsoDir *) pos, flag);
if (ret != 0)
return ret;
}
}
return 0;
}
static
int transplant_checksum_buffer(Ecma119Image *target, int flag)
{
/* Transplant checksum buffer from Ecma119Image to IsoImage */
iso_image_set_checksums(target->image, target->checksum_buffer,
target->checksum_range_start,
target->checksum_array_pos,
target->checksum_idx_counter + 2, 0);
target->checksum_buffer = NULL;
target->checksum_idx_counter = 0;
/* Delete recorded cx xinfo */
process_preserved_cx(target->image->root, 0);
return 1;
}
static
int write_vol_desc_terminator(Ecma119Image *target)
{
int ret;
uint8_t *buf = NULL;
struct ecma119_vol_desc_terminator *vol;
LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
vol = (struct ecma119_vol_desc_terminator *) buf;
vol->vol_desc_type[0] = 255;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
ret = iso_write(target, buf, BLOCK_SIZE);
ex:
LIBISO_FREE_MEM(buf);
return ret;
}
/* @param flag bit0= initialize system area by target->opts_overwrite
bit1= fifo is not yet draining. Inquire write_count from fifo.
*/
static
int write_head_part1(Ecma119Image *target, int *write_count, int flag)
{
int res, i, ret;
uint8_t *sa, *sa_local = NULL;
IsoImageWriter *writer;
size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0;
if (target->sys_area_already_written) {
LIBISO_ALLOC_MEM(sa_local, uint8_t, 16 * BLOCK_SIZE);
sa = sa_local;
} else {
sa = target->sys_area_as_written;
target->sys_area_already_written = 1;
}
iso_ring_buffer_get_buf_status(target->buffer, &buffer_size,
&buffer_start_free);
*write_count = 0;
/* Write System Area (ECMA-119, 6.2.1) */
if ((flag & 1) && target->opts_overwrite != NULL)
memcpy(sa, target->opts_overwrite, 16 * BLOCK_SIZE);
res = iso_write_system_area(target, sa);
if (res < 0)
goto write_error;
res = iso_write(target, sa, 16 * BLOCK_SIZE);
if (res < 0)
goto write_error;
*write_count = 16;
/* write volume descriptors, one per writer */
iso_msg_debug(target->image->id, "Write volume descriptors");
for (i = 0; i < (int) target->nwriters; ++i) {
writer = target->writers[i];
res = writer->write_vol_desc(writer);
if (res < 0)
goto write_error;
}
/* write Volume Descriptor Set Terminator (ECMA-119, 8.3) */
res = write_vol_desc_terminator(target);
if (res < 0)
goto write_error;
if(flag & 2) {
iso_ring_buffer_get_buf_status(target->buffer, &buffer_size,
&buffer_free);
*write_count = ( buffer_start_free - buffer_free ) / BLOCK_SIZE;
} else {
*write_count = target->bytes_written / BLOCK_SIZE;
}
ret = ISO_SUCCESS;
goto ex;
write_error:;
ret = res;
goto ex;
ex:
LIBISO_FREE_MEM(sa_local);
return ret;
}
static
int write_head_part2(Ecma119Image *target, int *write_count, int flag)
{
int ret, i;
uint8_t *buf = NULL;
IsoImageWriter *writer;
if (target->opts->partition_offset <= 0)
{ret = ISO_SUCCESS; goto ex;}
/* Write multi-session padding up to target->opts->partition_offset + 16 */
LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
for(; *write_count < (int) target->opts->partition_offset + 16;
(*write_count)++) {
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0)
goto ex;
}
/* Write volume descriptors subtracting
target->partiton_offset from any LBA pointer.
*/
target->eff_partition_offset = target->opts->partition_offset;
target->pvd_size_is_total_size = 0;
for (i = 0; i < (int) target->nwriters; ++i) {
writer = target->writers[i];
/* Not all writers have an entry in the partion volume descriptor set.
It must be guaranteed that they write exactly one block.
*/
/* >>> TWINTREE: Enhance ISO1999 writer and add it here */
if(writer->write_vol_desc != ecma119_writer_write_vol_desc &&
writer->write_vol_desc != joliet_writer_write_vol_desc)
continue;
ret = writer->write_vol_desc(writer);
if (ret < 0)
goto ex;
(*write_count)++;
}
ret = write_vol_desc_terminator(target);
if (ret < 0)
goto ex;
(*write_count)++;
target->eff_partition_offset = 0;
/* >>> TWINTREE: Postponed for now:
Write second superblock checksum tag */;
ret = ISO_SUCCESS;
ex:;
if (buf != NULL)
free(buf);
return ret;
}
static
int write_head_part(Ecma119Image *target, int flag)
{
int res, write_count = 0;
/* System area and volume descriptors */
res = write_head_part1(target, &write_count, 0);
if (res < 0)
return res;
/* Write superblock checksum tag */
if (target->opts->md5_session_checksum && target->checksum_ctx != NULL) {
res = iso_md5_write_tag(target, 2);
if (res < 0)
return res;
write_count++;
}
/* Second set of system area and volume descriptors for partition_offset */
res = write_head_part2(target, &write_count, 0);
if (res < 0)
return res;
return ISO_SUCCESS;
}
/* Eventually end Jigdo Template Extraction */
static int finish_libjte(Ecma119Image *target)
{
#ifdef Libisofs_with_libjtE
int ret;
if (target->opts->libjte_handle != NULL) {
ret = libjte_write_footer(target->opts->libjte_handle);
if (ret <= 0) {
iso_libjte_forward_msgs(target->opts->libjte_handle,
target->image->id, ISO_LIBJTE_END_FAILED, 0);
return ISO_LIBJTE_END_FAILED;
}
}
#endif /* Libisofs_with_libjtE */
return 1;
}
struct iso_interval_zeroizer {
int z_type; /* 0= $zero_start"-"$zero_end ,
1= "zero_mbrpt" , 2= "zero_gpt" , 3= "zero_apm"
*/
off_t zero_start;
off_t zero_end;
};
struct iso_interval_reader {
/* Setup */
IsoImage *image;
char *path;
int flags; /* bit0= imported_iso, else local_fs
*/
off_t start_byte;
off_t end_byte;
struct iso_interval_zeroizer *zeroizers;
int num_zeroizers;
char *source_pt; /* This is a parasite pointer of path. Do not free */
/* State information */
int initialized;
int is_block_aligned;
off_t cur_block;
int fd;
uint8_t read_buf[BLOCK_SIZE];
uint8_t *pending_read_pt;
int pending_read_bytes;
off_t read_count;
int eof;
int src_is_open;
uint32_t apm_block_size;
};
static
int iso_ivr_next_comp(char *read_pt, char **next_pt, int flag)
{
*next_pt = NULL;
if (read_pt == NULL)
return 0;
*next_pt = strchr(read_pt, ':');
if (*next_pt != NULL)
(*next_pt)++;
return 1;
}
/* @param flag bit1= end number requested, forward to iso_scanf_io_size()
*/
static
int iso_ivr_read_number(char *start_pt, char *end_pt, off_t *result, int flag)
{
char txt[20];
off_t num;
if (end_pt - start_pt <= 0 || end_pt - start_pt > 16) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Number text too short or too long in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
if (end_pt - start_pt > 0)
strncpy(txt, start_pt, end_pt - start_pt);
txt[end_pt - start_pt] = 0;
num = iso_scanf_io_size(start_pt, 1 | (flag & 2));
if (num < 0.0 || num > 281474976710655.0) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Negative or overly large number in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
*result = num;
return 1;
}
static
int iso_ivr_parse_interval(char *start_pt, char *end_pt, off_t *start_byte,
off_t *end_byte, int flag)
{
int ret;
char *m_pt;
m_pt = strchr(start_pt, '-');
if (m_pt == NULL) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Malformed byte interval in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ret = iso_ivr_read_number(start_pt, m_pt, start_byte, 0);
if (ret < 0)
return ret;
ret = iso_ivr_read_number(m_pt + 1, end_pt - 1, end_byte, 2);
if (ret < 0)
return ret;
return ISO_SUCCESS;
}
static
int iso_ivr_parse_zeroizers(struct iso_interval_reader *ivr,
char *pathpt, char *end_pt, int flag)
{
int ret, num_zs = 1, idx, i;
char *rpt, *cpt;
ivr->num_zeroizers = 0;
if (pathpt[0] == 0 || pathpt == end_pt)
return ISO_SUCCESS;
for(cpt = pathpt - 1; cpt != NULL && cpt < end_pt; num_zs++)
cpt = strchr(cpt + 1, ',');
LIBISO_ALLOC_MEM(ivr->zeroizers, struct iso_interval_zeroizer, num_zs);
for (i = 0; i < num_zs; i++)
ivr->zeroizers[i].zero_end = -1;
idx = 0;
for (rpt = pathpt; rpt != NULL && rpt < end_pt; idx++) {
cpt = strchr(rpt, ',');
if (cpt == NULL || cpt > end_pt)
cpt = end_pt;
if (cpt == rpt) {
continue;
} else if (strncmp(rpt, "zero_mbrpt", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 1;
} else if (strncmp(rpt, "zero_gpt", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 2;
} else if (strncmp(rpt, "zero_apm", cpt - rpt) == 0) {
ivr->zeroizers[idx].z_type = 3;
} else {
ivr->zeroizers[idx].z_type = 0;
ret = iso_ivr_parse_interval(rpt, cpt,
&(ivr->zeroizers[idx].zero_start),
&(ivr->zeroizers[idx].zero_end), 0);
if (ret < 0)
goto ex;
}
rpt = cpt + 1;
ivr->num_zeroizers++;
}
ret = ISO_SUCCESS;
ex:;
return ret;
}
static
int iso_ivr_parse(struct iso_interval_reader *ivr, char *path, int flag)
{
int ret;
char *flags_pt, *interval_pt, *zeroize_pt;
flags_pt = path;
iso_ivr_next_comp(flags_pt, &interval_pt, 0);
iso_ivr_next_comp(interval_pt, &zeroize_pt, 0);
iso_ivr_next_comp(zeroize_pt, &(ivr->source_pt), 0);
if (ivr->source_pt == NULL) {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Not enough components in interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ivr->flags = 0;
if (strncmp(flags_pt, "imported_iso", 12) == 0) {
ivr->flags |= 1;
} else if (strncmp(flags_pt, "local_fs", 8) == 0) {
;
} else {
iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
"Unknown flag name in first component of interval reader description string");
return ISO_MALFORMED_READ_INTVL;
}
ret = iso_ivr_parse_interval(interval_pt, zeroize_pt, &(ivr->start_byte),
&(ivr->end_byte), 0);
if (ret < 0)
goto ex;
ret = iso_ivr_parse_zeroizers(ivr, zeroize_pt, ivr->source_pt - 1, 0);
if (ret < 0)
goto ex;
ret = ISO_SUCCESS;
ex:;
return ret;
}
int iso_interval_reader_destroy(struct iso_interval_reader **ivr, int flag)
{
struct iso_interval_reader *o;
if (*ivr == NULL)
return 0;
o = *ivr;
LIBISO_FREE_MEM(o->path);
LIBISO_FREE_MEM(o->zeroizers);
if (o->fd != -1)
close(o->fd);
if (o->src_is_open)
(*o->image->import_src->close)(o->image->import_src);
LIBISO_FREE_MEM(*ivr);
return ISO_SUCCESS;
}
/* @param flag bit0= tolerate lack of import_src
*/
int iso_interval_reader_new(IsoImage *img, char *path,
struct iso_interval_reader **ivr,
off_t *byte_count, int flag)
{
int ret, no_img = 0;
struct iso_interval_reader *o = NULL;
*ivr = NULL;
*byte_count = 0;
LIBISO_ALLOC_MEM(o, struct iso_interval_reader, 1);
o->image = img;
o->path = NULL;
o->zeroizers = NULL;
o->num_zeroizers = 0;
o->source_pt = NULL;
o->initialized = 0;
o->is_block_aligned = 0;
o->fd = -1;
o->pending_read_pt = NULL;
o->pending_read_bytes = 0;
o->eof = 0;
o->read_count = 0;
o->src_is_open = 0;
o->apm_block_size = 0;
LIBISO_ALLOC_MEM(o->path, char, strlen(path) + 1);
strcpy(o->path, path);
ret = iso_ivr_parse(o, path, 0);
if (ret < 0)
goto ex;
if (o->image == NULL)
no_img = 1;
else if (o->image->import_src == NULL)
no_img = 1;
if ((o->flags & 1) && no_img) {
iso_msg_submit(-1, ISO_NO_KEPT_DATA_SRC, 0,
"Interval reader lacks of data source object of imported ISO");
if (!(flag & 1)) {
ret = ISO_BAD_PARTITION_FILE;
goto ex;
}
o->eof = 1;
}
*byte_count = o->end_byte - o->start_byte + 1;
*ivr = o;
ret = ISO_SUCCESS;
ex:;
if (ret < 0)
iso_interval_reader_destroy(&o, 0);
return ret;
}
static
int iso_ivr_zeroize(struct iso_interval_reader *ivr, uint8_t *buf,
int buf_fill, int flag)
{
int i;
off_t low, high, part_start, entry_count, apm_offset = -1, map_entries;
uint8_t *apm_buf;
struct iso_interval_zeroizer *zr;
for (i = 0; i < ivr->num_zeroizers; i++) {
zr = ivr->zeroizers + i;
if (zr->z_type == 1) { /* zero_mbrpt */
if (ivr->read_count > 0 || buf_fill < 512)
continue;
if (buf[510] != 0x55 || buf[511] != 0xaa)
continue;
memset(buf + 446, 0, 64);
} else if (zr->z_type == 2) { /* zero_gpt */
if (zr->zero_start <= zr->zero_end)
goto process_interval;
if (ivr->read_count > 0 || buf_fill < 512 + 92)
continue;
if (strncmp((char *) buf + 512, "EFI PART", 8) != 0 ||
buf[520] != 0 || buf[521] != 0 || buf[522] != 1 ||
buf[523] != 0)
continue;
/* head_size , curr_lba , entry_size */
if (iso_read_lsb(buf + 524, 4) != 92 ||
iso_read_lsb(buf + 536, 4) != 1 ||
iso_read_lsb(buf + 596, 4) != 128)
continue;
part_start = iso_read_lsb(buf + 584, 4);
entry_count = iso_read_lsb(buf + 592, 4);
if (part_start < 2 || part_start + (entry_count + 3) / 4 > 64)
continue;
zr->zero_start = part_start * 512;
zr->zero_end = (part_start + (entry_count + 3) / 4) * 512 - 1;
memset(buf + 512, 0, 92);
} else if (zr->z_type == 3) { /* zero_apm */
if (zr->zero_start <= zr->zero_end)
goto process_interval;
if (ivr->read_count == 0) {
if (buf_fill < 512)
continue;
if (buf[0] != 'E' || buf[1] != 'R')
continue;
ivr->apm_block_size = iso_read_msb(buf + 2, 2);
if ((ivr->apm_block_size != 512 &&
ivr->apm_block_size != 1024 &&
ivr->apm_block_size != 2048) ||
((uint32_t) buf_fill) < ivr->apm_block_size) {
ivr->apm_block_size = 0;
continue;
}
if (ivr->read_count + buf_fill >= 2 * ivr->apm_block_size)
apm_offset = ivr->apm_block_size;
} else if (ivr->read_count == 2048 &&
ivr->apm_block_size == 2048 && buf_fill == 2048) {
apm_offset = 0;
}
if (apm_offset < 0)
continue;
/* Check for first APM entry */
apm_buf = buf + apm_offset;
if(apm_buf[0] != 'P' || apm_buf[1] != 'M')
continue;
if (iso_read_msb(apm_buf + 8, 4) != 1)
continue;
map_entries = iso_read_msb(apm_buf + 4, 4);
if ((1 + map_entries) * ivr->apm_block_size > 16 * 2048)
continue;
zr->zero_start = ivr->apm_block_size;
zr->zero_end = (1 + map_entries) * ivr->apm_block_size;
}
process_interval:;
/* If an interval is defined by now: zeroize its intersection with buf
*/
if (zr->zero_start <= zr->zero_end) {
low = ivr->read_count >= zr->zero_start ?
ivr->read_count : zr->zero_start;
high = ivr->read_count + buf_fill - 1 <= zr->zero_end ?
ivr->read_count + buf_fill - 1 : zr->zero_end;
if (low <= high)
memset(buf + low - ivr->read_count, 0, high - low + 1);
}
}
return ISO_SUCCESS;
}
int iso_interval_reader_read(struct iso_interval_reader *ivr, uint8_t *buf,
int *buf_fill, int flag)
{
int ret, read_done, to_copy, initializing = 0;
IsoDataSource *src;
uint8_t *read_buf;
off_t to_read;
*buf_fill = 0;
src = ivr->image->import_src;
if (ivr->eof) {
eof:;
memset(buf, 0, BLOCK_SIZE);
return 0;
}
if (ivr->initialized) {
ivr->cur_block++;
} else {
initializing = 1;
ivr->cur_block = ivr->start_byte / BLOCK_SIZE;
ivr->is_block_aligned = !(ivr->start_byte % BLOCK_SIZE);
if (ivr->flags & 1) {
if (src == NULL)
goto eof;
ret = (*src->open)(src);
if (ret < 0) {
ivr->eof = 1;
return ret;
}
ivr->src_is_open = 1;
} else {
ivr->fd = open(ivr->source_pt, O_RDONLY);
if (ivr->fd == -1) {
iso_msg_submit(-1, ISO_BAD_PARTITION_FILE, 0,
"Cannot open local file for interval reading");
ivr->eof = 1;
return ISO_BAD_PARTITION_FILE;
}
if (ivr->cur_block != 0) {
if (lseek(ivr->fd, ivr->cur_block * BLOCK_SIZE, SEEK_SET) ==
-1) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Cannot address interval start in local file");
ivr->eof = 1;
goto eof;
}
}
}
ivr->initialized = 1;
}
if (ivr->is_block_aligned) {
read_buf = buf;
} else {
process_pending:;
read_buf = ivr->read_buf;
/* Copy pending bytes from previous read */
if (ivr->pending_read_bytes > 0) {
memcpy(buf, ivr->pending_read_pt, ivr->pending_read_bytes);
*buf_fill = ivr->pending_read_bytes;
ivr->pending_read_bytes = 0;
}
}
/* Read next block */
read_done = 0;
if (ivr->cur_block * BLOCK_SIZE <= ivr->end_byte) {
if (ivr->flags & 1) {
ret = (*src->read_block)(src, (uint32_t) ivr->cur_block, read_buf);
if (ret < 0) {
if (iso_error_get_severity(ret) > 0x68000000) /* > FAILURE */
return ret;
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Premature EOF while interval reading from imported ISO");
ivr->eof = 1;
}
read_done = BLOCK_SIZE;
} else {
read_done = 0;
to_read = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
if (to_read > BLOCK_SIZE)
to_read = BLOCK_SIZE;
while (read_done < to_read) {
ret = read(ivr->fd, read_buf, to_read - read_done);
if (ret == -1) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Read error while interval reading from local file");
ivr->eof = 1;
break;
} else if (ret == 0) {
iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
"Premature EOF while interval reading from local file");
ivr->eof = 1;
break;
} else
read_done += ret;
}
}
}
if (ivr->is_block_aligned) {
*buf_fill = read_done;
} else if (initializing) {
ivr->pending_read_pt = ivr->read_buf +
(ivr->start_byte - ivr->cur_block * BLOCK_SIZE);
ivr->pending_read_bytes = (((off_t) ivr->cur_block) + 1) * BLOCK_SIZE -
ivr->start_byte;
initializing = 0;
goto process_pending;
} else if (read_done > 0) {
/* Copy bytes from new read */
to_copy = read_done > BLOCK_SIZE - *buf_fill ?
BLOCK_SIZE - *buf_fill : read_done;
memcpy(buf + *buf_fill, ivr->read_buf, to_copy);
*buf_fill += to_copy;
ivr->pending_read_pt = ivr->read_buf + to_copy;
ivr->pending_read_bytes = read_done - to_copy;
}
if (ivr->start_byte + ivr->read_count + *buf_fill - 1 > ivr->end_byte) {
*buf_fill = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
ivr->eof = 1;
}
if (*buf_fill < BLOCK_SIZE)
memset(buf + *buf_fill, 0, BLOCK_SIZE - *buf_fill);
ret = iso_ivr_zeroize(ivr, buf, *buf_fill, 0);
if (ret < 0)
return ret;
ivr->read_count += *buf_fill;
return ISO_SUCCESS;
}
/* Tells whether ivr is a reader from imported_iso in a multi-session
add-on situation, and thus to be kept in place.
*/
int iso_interval_reader_keep(Ecma119Image *target,
struct iso_interval_reader *ivr,
int flag)
{
/* Source must be "imported_iso" */
if (!(ivr->flags & 1))
return 0;
/* It must not be a new ISO */
if (!target->opts->appendable)
return 0;
/* multi-session write offset must be larger than interval end */
if (target->opts->ms_block <= ivr->end_byte / BLOCK_SIZE)
/* >>> ??? return error ??? */
return 0;
return 1;
}
int iso_interval_reader_start_size(Ecma119Image *t, char *path,
off_t *start_byte, off_t *byte_count,
int flag)
{
struct iso_interval_reader *ivr;
int keep, ret;
ret = iso_interval_reader_new(t->image, path, &ivr, byte_count, 0);
if (ret < 0)
return ret;
*start_byte = ivr->start_byte;
keep = iso_interval_reader_keep(t, ivr, 0);
iso_interval_reader_destroy(&ivr, 0);
return ISO_SUCCESS + (keep > 0);
}
int iso_write_partition_file(Ecma119Image *target, char *path,
uint32_t prepad, uint32_t blocks, int flag)
{
struct iso_interval_reader *ivr = NULL;
int buf_fill;
off_t byte_count;
FILE *fp = NULL;
uint32_t i;
uint8_t *buf = NULL;
int ret;
LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
for (i = 0; i < prepad; i++) {
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0)
goto ex;
}
if (flag & 1) {
ret = iso_interval_reader_new(target->image, path,
&ivr, &byte_count, 0);
if (ret < 0)
goto ex;
if (iso_interval_reader_keep(target, ivr, 0)) {
/* From imported_iso and for add-on session. Leave it in place. */
ret = ISO_SUCCESS;
goto ex;
}
for (i = 0; i < blocks; i++) {
ret = iso_interval_reader_read(ivr, buf, &buf_fill, 0);
if (ret < 0)
goto ex;
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0)
goto ex;
}
} else {
fp = fopen(path, "rb");
if (fp == NULL)
{ret = ISO_BAD_PARTITION_FILE; goto ex;}
for (i = 0; i < blocks; i++) {
memset(buf, 0, BLOCK_SIZE);
if (fp != NULL) {
ret = fread(buf, 1, BLOCK_SIZE, fp);
if (ret != BLOCK_SIZE) {
fclose(fp);
fp = NULL;
}
}
ret = iso_write(target, buf, BLOCK_SIZE);
if (ret < 0) {
if (fp != NULL)
fclose(fp);
goto ex;
}
}
if (fp != NULL)
fclose(fp);
}
ret = ISO_SUCCESS;
ex:;
iso_interval_reader_destroy(&ivr, 0);
LIBISO_FREE_MEM(buf);
return ret;
}
void issue_ucs2_warning_summary(size_t failures)
{
if (failures > ISO_JOLIET_UCS2_WARN_MAX) {
iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
"More filenames found which were not suitable for Joliet character set UCS-2");
}
if (failures > 0) {
iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
"Sum of filenames not suitable for Joliet character set UCS-2: %.f",
(double) failures);
}
}
static
void *write_function(void *arg)
{
int res, i;
#ifndef Libisofs_appended_partitions_inlinE
int first_partition = 1, last_partition = 0, sa_type;
#endif
IsoImageWriter *writer;
Ecma119Image *target = (Ecma119Image*)arg;
iso_msg_debug(target->image->id, "Starting image writing...");
target->bytes_written = (off_t) 0;
target->percent_written = 0;
res = write_head_part(target, 0);
if (res < 0)
goto write_error;
/* write data for each writer */
for (i = 0; i < (int) target->nwriters; ++i) {
writer = target->writers[i];
if (target->gpt_backup_outside &&
writer->write_vol_desc == gpt_tail_writer_write_vol_desc)
continue;
res = writer->write_data(writer);
if (res < 0) {
goto write_error;
}
}
#ifndef Libisofs_appended_partitions_inlinE
/* Append partition data */
sa_type = (target->system_area_options >> 2) & 0x3f;
if (sa_type == 0) { /* MBR */
first_partition = 1;
last_partition = 4;
} else if (sa_type == 3) { /* SUN Disk Label */
first_partition = 2;
last_partition = 8;
}
for (i = first_partition - 1; i <= last_partition - 1; i++) {
if (target->opts->appended_partitions[i] == NULL)
continue;
if (target->opts->appended_partitions[i][0] == 0)
continue;
res = iso_write_partition_file(target,
target->opts->appended_partitions[i],
target->appended_part_prepad[i],
target->appended_part_size[i],
target->opts->appended_part_flags[i] & 1);
if (res < 0)
goto write_error;
}
#endif /* ! Libisofs_appended_partitions_inlinE */
if (target->gpt_backup_outside) {
for (i = 0; i < (int) target->nwriters; ++i) {
writer = target->writers[i];
if (writer->write_vol_desc != gpt_tail_writer_write_vol_desc)
continue;
res = writer->write_data(writer);
if (res < 0)
goto write_error;
}
}
/* Transplant checksum buffer from Ecma119Image to IsoImage */
transplant_checksum_buffer(target, 0);
iso_ring_buffer_writer_close(target->buffer, 0);
res = finish_libjte(target);
if (res <= 0)
goto write_error;
issue_ucs2_warning_summary(target->joliet_ucs2_failures);
target->image->generator_is_running = 0;
/* Give up reference claim made in ecma119_image_new().
Eventually free target */
ecma119_image_free(target);
if (target->tree_end_block == 1) {
iso_msgs_submit(0,
"Image is most likely damaged. Calculated/written tree end address mismatch.",
0, "FATAL", 0);
}
if (target->bytes_written != target->total_size) {
iso_msg_debug(target->image->id,
"bytes_written = %.f <-> total_size = %.f",
(double) target->bytes_written, (double) target->total_size);
iso_msgs_submit(0,
"Image is most likely damaged. Calculated/written image end address mismatch.",
0, "FATAL", 0);
}
#ifdef Libisofs_with_pthread_exiT
pthread_exit(NULL);
#else
return NULL;
#endif
write_error: ;
if (res != (int) ISO_LIBJTE_END_FAILED)
finish_libjte(target);
target->eff_partition_offset = 0;
if (res == (int) ISO_CANCELED) {
/* canceled */
if (!target->opts->will_cancel)
iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED,
0, NULL);
} else {
/* image write error */
iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
"Image write error");
}
iso_ring_buffer_writer_close(target->buffer, 1);
/* Re-activate recorded cx xinfo */
process_preserved_cx(target->image->root, 1);
target->image->generator_is_running = 0;
/* Give up reference claim made in ecma119_image_new().
Eventually free target */
ecma119_image_free(target);
#ifdef Libisofs_with_pthread_exiT
pthread_exit(NULL);
#else
return NULL;
#endif
}
static
int checksum_prepare_image(IsoImage *src, int flag)
{
int ret;
/* Set provisory value of isofs.ca with
4 byte LBA, 4 byte count, size 16, name MD5 */
ret = iso_root_set_isofsca((IsoNode *) src->root, 0, 0, 0, 16, "MD5", 0);
if (ret < 0)
return ret;
return ISO_SUCCESS;
}
/*
@flag bit0= recursion
*/
static
int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag)
{
IsoNode *pos;
IsoFile *file;
IsoImage *img;
int ret, i, no_md5 = 0, has_xinfo = 0, has_attr = 0;
size_t old_cx_value_length = 0;
unsigned int idx = 0;
char *old_cx_value= NULL;
void *xipt = NULL;
img= target->image;
if (node->type == LIBISO_FILE) {
file = (IsoFile *) node;
if (file->from_old_session) {
/* Record attribute isofs.cx as xinfo before it can get overwritten
for the emerging image.
The recorded index will be used to retrieve the loaded MD5
and it will be brought back into effect if cancellation of
image production prevents that the old MD5 array gets replaced
by the new one.
*/
has_attr = iso_node_lookup_attr(node, "isofs.cx",
&old_cx_value_length, &old_cx_value, 0);
if (has_attr == 1 && old_cx_value_length == 4) {
for (i = 0; i < 4; i++)
idx = (idx << 8) | ((unsigned char *) old_cx_value)[i];
if (idx > 0 && idx < 0x8000000) {
/* xipt is an int disguised as void pointer */
for (i = 0; i < 4; i++)
((char *) &xipt)[i] = old_cx_value[i];
ret = iso_node_add_xinfo(node, checksum_cx_xinfo_func,
xipt);
if (ret < 0)
goto ex;
} else
no_md5 = 1;
}
}
if (file->from_old_session && target->opts->appendable) {
/* Save MD5 data of files from old image which will not
be copied and have an MD5 recorded in the old image. */
has_xinfo = iso_node_get_xinfo(node, checksum_md5_xinfo_func,
&xipt);
if (has_xinfo > 0) {
/* xinfo MD5 overrides everything else unless data get copied
and checksummed during that copying
*/;
} else if (has_attr == 1 && img->checksum_array == NULL) {
/* No checksum array loaded. Delete "isofs.cx" */
if (!target->opts->will_cancel)
iso_file_set_isofscx((IsoFile *) node, 0, 1);
no_md5 = 1;
} else if (!(has_attr == 1 && old_cx_value_length == 4)) {
no_md5 = 1;
}
}
/* Equip nodes with provisory isofs.cx numbers: 4 byte, all 0.
Omit those from old image which will not be copied and have no MD5.
Do not alter the nodes if this is only a will_cancel run.
*/
if (!(target->opts->will_cancel || no_md5)) {
/* Record provisory new index */
ret = iso_file_set_isofscx(file, (unsigned int) 0, 0);
if (ret < 0)
goto ex;
}
} else if (node->type == LIBISO_DIR) {
for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
ret = checksum_prepare_nodes(target, pos, 1);
if (ret < 0)
goto ex;
}
}
ret = ISO_SUCCESS;
ex:;
if (old_cx_value != NULL)
free(old_cx_value);
return ret;
}
/* Determine the alleged time of image production by predicting the volume
creation and modification timestamps and taking the maximum of both.
*/
static
void ecma119_determine_now_time(Ecma119Image *target)
{
IsoWriteOpts *o;
time_t now = 0, t, t0;
uint8_t time_text[18];
int i;
t0 = time(NULL);
o = target->opts;
if (o->vol_uuid[0]) {
for(i = 0; i < 16; i++)
if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
break;
else
time_text[i] = o->vol_uuid[i];
for(; i < 16; i++)
time_text[i] = '1';
time_text[16] = time_text[17] = 0;
t = iso_datetime_read_17(time_text);
if (t > now)
now = t;
} else {
if (o->vol_creation_time > 0) {
if (o->vol_creation_time > now)
now = o->vol_creation_time;
} else if (t0 > now) {
now = t0;
}
if (o->vol_modification_time > 0) {
if (o->vol_modification_time > now)
now = o->vol_modification_time;
} else if (t0 > now) {
now = t0;
}
}
target->now = now;
}
static
int gpt_disk_guid_setup(Ecma119Image *target)
{
if (target->opts->gpt_disk_guid_mode == 0) {
/* Random UUID production delayed until really needed */
return ISO_SUCCESS;
} else if (target->opts->gpt_disk_guid_mode == 1) {
memcpy(target->gpt_uuid_base, target->opts->gpt_disk_guid, 16);
} else if (target->opts->gpt_disk_guid_mode == 2) {
if (target->opts->vol_uuid[0] == 0)
return ISO_GPT_NO_VOL_UUID;
/* Move centi-seconds part to byte 9 and 10 */
memcpy(target->gpt_uuid_base, target->opts->vol_uuid, 9);
memcpy(target->gpt_uuid_base + 9, target->opts->vol_uuid + 14, 2);
memcpy(target->gpt_uuid_base + 11, target->opts->vol_uuid + 9, 5);
iso_mark_guid_version_4(target->gpt_uuid_base);
} else {
return ISO_BAD_GPT_GUID_MODE;
}
memcpy(target->gpt_disk_guid, target->gpt_uuid_base, 16);
target->gpt_disk_guid_set = 1;
target->gpt_uuid_counter = 1;
return ISO_SUCCESS;
}
static
int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
{
int ret, i, voldesc_size, nwriters, tag_pos;
int sa_type;
Ecma119Image *target;
IsoWriteOpts *opts;
IsoImageWriter *writer;
int file_src_writer_index = -1;
int system_area_options = 0;
char *system_area = NULL;
int write_count = 0, write_count_mem;
/* 1. Allocate target and attach a copy of in_opts there */
target = calloc(1, sizeof(Ecma119Image));
if (target == NULL) {
return ISO_OUT_OF_MEM;
}
/* This reference will be transferred to the burn_source and released by
bs_free_data.
*/
target->refcount = 1;
target->opts = NULL;
/* Record a copy of in_opts.
It is a copy because in_opts is prone to manipulations from the
application thread while the image production thread is running.
*/
ret = iso_write_opts_clone(in_opts, &(target->opts), 0);
if (ret != ISO_SUCCESS)
goto target_cleanup;
opts = target->opts;
/* create the tree for file caching */
ret = iso_rbtree_new(iso_file_src_cmp, &(target->files));
if (ret < 0) {
goto target_cleanup;
}
target->ecma119_hidden_list = NULL;
target->image = src;
iso_image_ref(src);
target->rr_reloc_node = NULL;
target->replace_uid = opts->replace_uid ? 1 : 0;
target->replace_gid = opts->replace_gid ? 1 : 0;
target->replace_dir_mode = opts->replace_dir_mode ? 1 : 0;
target->replace_file_mode = opts->replace_file_mode ? 1 : 0;
target->uid = opts->replace_uid == 2 ? opts->uid : 0;
target->gid = opts->replace_gid == 2 ? opts->gid : 0;
target->dir_mode = opts->replace_dir_mode == 2 ? opts->dir_mode : 0555;
target->file_mode = opts->replace_file_mode == 2 ? opts->file_mode : 0444;
ecma119_determine_now_time(target);
target->replace_timestamps = opts->replace_timestamps ? 1 : 0;
target->timestamp = opts->replace_timestamps == 2 ?
opts->timestamp : target->now;
/* el-torito? */
target->eltorito = (src->bootcat == NULL ? 0 : 1);
target->catalog = src->bootcat;
if (target->catalog != NULL) {
target->num_bootsrc = target->catalog->num_bootimages;
target->bootsrc = calloc(target->num_bootsrc + 1,
sizeof(IsoFileSrc *));
target->boot_appended_idx = calloc(target->num_bootsrc + 1,
sizeof(int));
target->boot_intvl_start = calloc(target->num_bootsrc + 1,
sizeof(uint32_t)