"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/ecma119.c" (26 Nov 2020, 140253 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ecma119.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 2007 Vreixo Formoso
    3  * Copyright (c) 2007 Mario Danic
    4  * Copyright (c) 2009 - 2019 Thomas Schmitt
    5  *
    6  * This file is part of the libisofs project; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License version 2 
    8  * or later as published by the Free Software Foundation. 
    9  * See COPYING file for details.
   10  */
   11 
   12 #ifdef HAVE_CONFIG_H
   13 #include "../config.h"
   14 #endif
   15 
   16 /*
   17    Use the copy of the struct burn_source definition in libisofs.h
   18 */
   19 #define LIBISOFS_WITHOUT_LIBBURN yes
   20 #include "libisofs.h"
   21 
   22 #include "ecma119.h"
   23 #include "joliet.h"
   24 #include "hfsplus.h"
   25 #include "iso1999.h"
   26 #include "eltorito.h"
   27 #include "ecma119_tree.h"
   28 #include "filesrc.h"
   29 #include "image.h"
   30 #include "writer.h"
   31 #include "messages.h"
   32 #include "rockridge.h"
   33 #include "util.h"
   34 #include "system_area.h"
   35 #include "md5.h"
   36 
   37 #include <ctype.h>
   38 #include <stdlib.h>
   39 #include <time.h>
   40 #include <string.h>
   41 #include <locale.h>
   42 #include <langinfo.h>
   43 #include <stdio.h>
   44 
   45 #ifdef Xorriso_standalonE
   46 
   47 #ifdef Xorriso_with_libjtE
   48 #include "../libjte/libjte.h"
   49 #endif
   50 
   51 #else
   52 
   53 #ifdef Libisofs_with_libjtE
   54 #include <libjte/libjte.h>
   55 #endif
   56 
   57 #endif /* ! Xorriso_standalonE */
   58 
   59 
   60 int iso_write_opts_clone(IsoWriteOpts *in, IsoWriteOpts **out, int flag);
   61 
   62 
   63 /*
   64  * TODO #00011 : guard against bad path table usage with more than 65535 dirs
   65  * image with more than 65535 directories have path_table related problems
   66  * due to 16 bits parent id. Note that this problem only affects to folders
   67  * that are parent of another folder.
   68  */
   69 
   70 static
   71 void ecma119_image_free(Ecma119Image *t)
   72 {
   73     size_t i;
   74 
   75     if (t == NULL)
   76         return;
   77 
   78     if (t->refcount > 1) {
   79         t->refcount--;
   80         return;
   81     }
   82 
   83     if (t->root != NULL)
   84         ecma119_node_free(t->root);
   85     if (t->opts != NULL)
   86         iso_write_opts_free(t->opts);
   87     if (t->image != NULL)
   88         iso_image_unref(t->image);
   89     if (t->files != NULL)
   90         iso_rbtree_destroy(t->files, iso_file_src_free);
   91     if (t->ecma119_hidden_list != NULL)
   92         iso_filesrc_list_destroy(&(t->ecma119_hidden_list));
   93     if (t->buffer != NULL)
   94         iso_ring_buffer_free(t->buffer);
   95 
   96     for (i = 0; i < t->nwriters; ++i) {
   97         IsoImageWriter *writer = t->writers[i];
   98         writer->free_data(writer);
   99         free(writer);
  100     }
  101     if (t->input_charset != NULL)
  102         free(t->input_charset);
  103     if (t->output_charset != NULL)
  104         free(t->output_charset);
  105     if (t->bootsrc != NULL)
  106         free(t->bootsrc);
  107     if (t->boot_appended_idx != NULL)
  108         free(t->boot_appended_idx);
  109     if (t->boot_intvl_start != NULL)
  110         free(t->boot_intvl_start);
  111     if (t->boot_intvl_size != NULL)
  112         free(t->boot_intvl_size);
  113     if (t->system_area_data != NULL)
  114         free(t->system_area_data);
  115     if (t->checksum_ctx != NULL) { /* dispose checksum context */
  116         char md5[16];
  117         iso_md5_end(&(t->checksum_ctx), md5);
  118     }
  119     if (t->checksum_buffer != NULL)
  120         free(t->checksum_buffer);
  121     if (t->writers != NULL)
  122         free(t->writers);
  123     if (t->partition_root != NULL)
  124         ecma119_node_free(t->partition_root);
  125     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
  126         if (t->hfsplus_blessed[i] != NULL)
  127             iso_node_unref(t->hfsplus_blessed[i]);
  128     for (i = 0; (int) i < t->apm_req_count; i++)
  129         if (t->apm_req[i] != NULL)
  130             free(t->apm_req[i]);
  131     for (i = 0; (int) i < t->mbr_req_count; i++)
  132         if (t->mbr_req[i] != NULL)
  133             free(t->mbr_req[i]);
  134     for (i = 0; (int) i < t->gpt_req_count; i++)
  135         if (t->gpt_req[i] != NULL)
  136             free(t->gpt_req[i]);
  137 
  138     free(t);
  139 }
  140 
  141 static int show_chunk_to_jte(Ecma119Image *target, char *buf, int count)
  142 {
  143 
  144 #ifdef Libisofs_with_libjtE
  145 
  146     int ret;
  147 
  148     if (target->opts->libjte_handle == NULL)
  149         return ISO_SUCCESS;
  150     ret = libjte_show_data_chunk(target->opts->libjte_handle, buf, count, 1); 
  151     if (ret <= 0) {
  152         iso_libjte_forward_msgs(target->opts->libjte_handle,
  153                                 target->image->id, ISO_LIBJTE_FILE_FAILED, 0);
  154         return ISO_LIBJTE_FILE_FAILED;
  155     }
  156 
  157 #endif /* Libisofs_with_libjtE */
  158 
  159     return ISO_SUCCESS;
  160 }
  161 
  162 /**
  163  * Check if we should add version number ";" to the given node name.
  164  */
  165 static
  166 int need_version_number(IsoWriteOpts *opts, enum ecma119_node_type node_type)
  167 {
  168     if ((opts->omit_version_numbers & 1) ||
  169         opts->max_37_char_filenames || opts->untranslated_name_len > 0) {
  170         return 0;
  171     }
  172     if (node_type == ECMA119_DIR || node_type == ECMA119_PLACEHOLDER) {
  173         return 0;
  174     } else {
  175         return 1;
  176     }
  177 }
  178 
  179 /**
  180  * Compute the size of a directory entry for a single node
  181  */
  182 static
  183 size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
  184 {
  185     int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
  186     if (need_version_number(t->opts, n->type)) {
  187         ret += 2; /* take into account version numbers */
  188     }
  189     if (ret % 2)
  190         ret++;
  191     return ret;
  192 }
  193 
  194 /**
  195  * Computes the total size of all directory entries of a single dir,
  196  * according to ECMA-119 6.8.1.1
  197  *
  198  * This also take into account the size needed for RR entries and
  199  * SUSP continuation areas (SUSP, 5.1).
  200  *
  201  * @param ce
  202  *      Will be filled with the size needed for Continuation Areas
  203  * @return
  204  *      The size needed for all dir entries of the given dir, without
  205  *      taking into account the continuation areas.
  206  */
  207 static
  208 size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
  209 {
  210     size_t i, len;
  211     size_t ce_len = 0;
  212 
  213     /* size of "." and ".." entries */
  214     len = 34 + 34;
  215     if (t->opts->rockridge) {
  216         len += rrip_calc_len(t, dir, 1, 34, &ce_len, *ce);
  217         *ce += ce_len;
  218         len += rrip_calc_len(t, dir, 2, 34, &ce_len, *ce);
  219         *ce += ce_len;
  220     }
  221 
  222     for (i = 0; i < dir->info.dir->nchildren; ++i) {
  223         size_t remaining;
  224         int section, nsections;
  225         Ecma119Node *child = dir->info.dir->children[i];
  226 
  227         nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
  228         for (section = 0; section < nsections; ++section) {
  229             size_t dirent_len = calc_dirent_len(t, child);
  230             if (t->opts->rockridge) {
  231                 dirent_len += rrip_calc_len(t, child, 0, dirent_len, &ce_len,
  232                                             *ce);
  233                 *ce += ce_len;
  234             }
  235             remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
  236             if (dirent_len > remaining) {
  237                 /* child directory entry doesn't fit on block */
  238                 len += remaining + dirent_len;
  239             } else {
  240                 len += dirent_len;
  241             }
  242         }
  243     }
  244 
  245     /*
  246      * The size of a dir is always a multiple of block size, as we must add
  247      * the size of the unused space after the last directory record
  248      * (ECMA-119, 6.8.1.3)
  249      */
  250     len = ROUND_UP(len, BLOCK_SIZE);
  251 
  252     /* cache the len */
  253     dir->info.dir->len = len;
  254     return len;
  255 }
  256 
  257 static
  258 void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir)
  259 {
  260     size_t i, len;
  261     size_t ce_len = 0;
  262 
  263     t->ndirs++;
  264     dir->info.dir->block = t->curblock;
  265     len = calc_dir_size(t, dir, &ce_len);
  266     t->curblock += DIV_UP(len, BLOCK_SIZE);
  267     if (t->opts->rockridge) {
  268         t->curblock += DIV_UP(ce_len, BLOCK_SIZE);
  269     }
  270     for (i = 0; i < dir->info.dir->nchildren; i++) {
  271         Ecma119Node *child = dir->info.dir->children[i];
  272         if (child->type == ECMA119_DIR) {
  273             calc_dir_pos(t, child);
  274         }
  275     }
  276 }
  277 
  278 /**
  279  * Compute the length of the path table, in bytes.
  280  */
  281 static
  282 uint32_t calc_path_table_size(Ecma119Node *dir)
  283 {
  284     uint32_t size;
  285     size_t i;
  286 
  287     /* size of path table for this entry */
  288     size = 8;
  289     size += dir->iso_name ? strlen(dir->iso_name) : 1;
  290     size += (size % 2);
  291 
  292     /* and recurse */
  293     for (i = 0; i < dir->info.dir->nchildren; i++) {
  294         Ecma119Node *child = dir->info.dir->children[i];
  295         if (child->type == ECMA119_DIR) {
  296             size += calc_path_table_size(child);
  297         }
  298     }
  299     return size;
  300 }
  301 
  302 static
  303 int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
  304 {
  305     Ecma119Image *target;
  306     uint32_t path_table_size;
  307     size_t ndirs;
  308 
  309     if (writer == NULL) {
  310         return ISO_ASSERT_FAILURE;
  311     }
  312 
  313     target = writer->target;
  314 
  315     /* compute position of directories */
  316     iso_msg_debug(target->image->id, "Computing position of dir structure");
  317     target->ndirs = 0;
  318     calc_dir_pos(target, target->root);
  319 
  320     /* compute length of pathlist */
  321     iso_msg_debug(target->image->id, "Computing length of pathlist");
  322     path_table_size = calc_path_table_size(target->root);
  323 
  324     /* compute location for path tables */
  325     target->l_path_table_pos = target->curblock;
  326     target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  327     target->m_path_table_pos = target->curblock;
  328     target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  329     target->path_table_size = path_table_size;
  330 
  331     if (target->opts->md5_session_checksum) {
  332         /* Account for first tree checksum tag */
  333         target->checksum_tree_tag_pos = target->curblock;
  334         target->curblock++;
  335     }
  336 
  337     if (target->opts->partition_offset > 0) {
  338         /* Take into respect the second directory tree */
  339         ndirs = target->ndirs;
  340         target->ndirs = 0;
  341         calc_dir_pos(target, target->partition_root);
  342         if (target->ndirs != ndirs) {
  343             iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0,
  344                     "Number of directories differs in ECMA-119 partiton_tree");
  345             return ISO_ASSERT_FAILURE;
  346     }
  347         /* Take into respect the second set of path tables */
  348         path_table_size = calc_path_table_size(target->partition_root);
  349         target->partition_l_table_pos = target->curblock;
  350         target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  351         target->partition_m_table_pos = target->curblock;
  352         target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
  353 
  354         /* >>> TWINTREE: >>> For now, checksum tags are only for the
  355                              image start and not for the partition */;
  356 
  357     }
  358 
  359     target->tree_end_block = target->curblock;
  360 
  361     return ISO_SUCCESS;
  362 }
  363 
  364 /**
  365  * Write a single directory record (ECMA-119, 9.1)
  366  *
  367  * @param file_id
  368  *     if >= 0, we use it instead of the filename (for "." and ".." entries).
  369  * @param len_fi
  370  *     Computed length of the file identifier. Total size of the directory
  371  *     entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
  372  * @param info
  373  *     SUSP entries for the given directory record. It will be NULL for the
  374  *     root directory record in the PVD (ECMA-119, 8.4.18) (in order to
  375  *     distinguish it from the "." entry in the root directory)
  376  */
  377 static
  378 void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
  379                           uint8_t *buf, size_t len_fi, struct susp_info *info,
  380                           int extent)
  381 {
  382     uint32_t len;
  383     uint32_t block;
  384     uint8_t len_dr; /*< size of dir entry without SUSP fields */
  385     int multi_extend = 0;
  386     uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
  387             : (uint8_t*)node->iso_name;
  388 
  389     struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
  390     IsoNode *iso;
  391 
  392     len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
  393 
  394     memcpy(rec->file_id, name, len_fi);
  395 
  396     if (need_version_number(t->opts, node->type)) {
  397         len_dr += 2;
  398         rec->file_id[len_fi++] = ';';
  399         rec->file_id[len_fi++] = '1';
  400     }
  401 
  402     if (node->type == ECMA119_DIR) {
  403         /* use the cached length */
  404         len = node->info.dir->len;
  405         block = node->info.dir->block;
  406     } else if (node->type == ECMA119_FILE) {
  407         block = node->info.file->sections[extent].block;
  408         len = node->info.file->sections[extent].size;
  409         multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
  410     } else {
  411         /*
  412          * for nodes other than files and dirs, we set len to 0, and
  413          * the content block address to a dummy value.
  414          */
  415         len = 0;
  416         if (! t->opts->old_empty)
  417             block = t->empty_file_block;
  418         else
  419             block = 0;
  420     }
  421 
  422     /*
  423      * For ".." entry we need to write the parent info!
  424      */
  425     if (file_id == 1 && node->parent)
  426         node = node->parent;
  427 
  428     rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
  429     iso_bb(rec->block, block - t->eff_partition_offset, 4);
  430     iso_bb(rec->length, len, 4);
  431     if (t->opts->dir_rec_mtime & 1) {
  432         iso= node->node;
  433         iso_datetime_7(rec->recording_time,
  434                        t->replace_timestamps ? t->timestamp : iso->mtime,
  435                        t->opts->always_gmt);
  436     } else {
  437         iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
  438     }
  439     rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
  440     iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
  441     rec->len_fi[0] = len_fi;
  442 
  443     /*
  444      * and finally write the SUSP fields.
  445      */
  446     if (info != NULL) {
  447         rrip_write_susp_fields(t, info, buf + len_dr);
  448     }
  449 }
  450 
  451 static
  452 char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
  453 {
  454     int ret;
  455     if (name == NULL) {
  456         return NULL;
  457     }
  458     if (strcmp(t->input_charset, t->output_charset)) {
  459         /* charset conversion needed */
  460         char *str;
  461         ret = strconv(name, t->input_charset, t->output_charset, &str);
  462         if (ret == ISO_SUCCESS) {
  463             return str;
  464         }
  465         iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
  466                   "Charset conversion error. Cannot convert from %s to %s",
  467                   t->input_charset, t->output_charset);
  468     }
  469     return strdup(name);
  470 }
  471 
  472 /**
  473  * Set the timestamps of Primary, Supplementary, or Enhanced Volume Descriptor.
  474  */
  475 void ecma119_set_voldescr_times(IsoImageWriter *writer,
  476                                 struct ecma119_pri_vol_desc *vol)
  477 {
  478     Ecma119Image *t = writer->target;
  479     IsoWriteOpts *o;
  480     int i;
  481 
  482     o = t->opts;
  483     if (o->vol_uuid[0]) {
  484         for(i = 0; i < 16; i++)
  485             if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
  486         break;
  487             else
  488                 vol->vol_creation_time[i] = o->vol_uuid[i];
  489        for(; i < 16; i++)
  490            vol->vol_creation_time[i] = '1';
  491        vol->vol_creation_time[16] = 0;
  492     } else if (o->vol_creation_time > 0)
  493         iso_datetime_17(vol->vol_creation_time, o->vol_creation_time,
  494                         o->always_gmt);
  495     else
  496         iso_datetime_17(vol->vol_creation_time, t->now, o->always_gmt);
  497 
  498     if (o->vol_uuid[0]) {
  499         for(i = 0; i < 16; i++)
  500             if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
  501         break;
  502             else
  503                 vol->vol_modification_time[i] = o->vol_uuid[i];
  504        for(; i < 16; i++)
  505            vol->vol_modification_time[i] = '1';
  506        vol->vol_modification_time[16] = 0;
  507     } else if (o->vol_modification_time > 0)
  508         iso_datetime_17(vol->vol_modification_time, o->vol_modification_time,
  509                         o->always_gmt);
  510     else
  511         iso_datetime_17(vol->vol_modification_time, t->now, o->always_gmt);
  512 
  513     if (o->vol_expiration_time > 0) {
  514         iso_datetime_17(vol->vol_expiration_time, o->vol_expiration_time,
  515                         o->always_gmt);
  516     } else {
  517        for(i = 0; i < 16; i++)
  518            vol->vol_expiration_time[i] = '0';
  519        vol->vol_expiration_time[16] = 0;
  520     }
  521 
  522     if (o->vol_effective_time > 0) {
  523         iso_datetime_17(vol->vol_effective_time, o->vol_effective_time,
  524                         o->always_gmt);
  525     } else {
  526        for(i = 0; i < 16; i++)
  527            vol->vol_effective_time[i] = '0';
  528        vol->vol_effective_time[16] = 0;
  529     }
  530 }
  531 
  532 /**
  533  * Write the Primary Volume Descriptor (ECMA-119, 8.4)
  534  */
  535 static
  536 int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
  537 {
  538     IsoImage *image;
  539     Ecma119Image *t;
  540     struct ecma119_pri_vol_desc vol;
  541     char *vol_id, *pub_id, *data_id, *volset_id;
  542     char *system_id, *application_id, *copyright_file_id;
  543     char *abstract_file_id, *biblio_file_id;
  544 
  545     if (writer == NULL) {
  546         return ISO_ASSERT_FAILURE;
  547     }
  548 
  549     t = writer->target;
  550     image = t->image;
  551 
  552     iso_msg_debug(image->id, "Write Primary Volume Descriptor");
  553 
  554     memset(&vol, 0, sizeof(struct ecma119_pri_vol_desc));
  555 
  556     if (t->opts->relaxed_vol_atts) {
  557         vol_id = get_relaxed_vol_id(t, image->volume_id);
  558         volset_id = get_relaxed_vol_id(t, image->volset_id);
  559     } else {
  560         str2d_char(t->input_charset, image->volume_id, &vol_id);
  561         str2d_char(t->input_charset, image->volset_id, &volset_id);
  562     }
  563     str2a_char(t->input_charset, image->publisher_id, &pub_id);
  564     str2a_char(t->input_charset, image->data_preparer_id, &data_id);
  565     str2a_char(t->input_charset, image->system_id, &system_id);
  566     str2a_char(t->input_charset, image->application_id, &application_id);
  567     str2d_char(t->input_charset, image->copyright_file_id, &copyright_file_id);
  568     str2d_char(t->input_charset, image->abstract_file_id, &abstract_file_id);
  569     str2d_char(t->input_charset, image->biblio_file_id, &biblio_file_id);
  570 
  571     vol.vol_desc_type[0] = 1;
  572     memcpy(vol.std_identifier, "CD001", 5);
  573     vol.vol_desc_version[0] = 1;
  574     strncpy_pad((char*)vol.system_id, system_id, 32);
  575     strncpy_pad((char*)vol.volume_id, vol_id, 32);
  576     if (t->pvd_size_is_total_size && t->eff_partition_offset <= 0) {
  577         iso_bb(vol.vol_space_size, t->total_size / 2048, 4);
  578     } else {
  579         iso_bb(vol.vol_space_size,
  580                t->vol_space_size - t->eff_partition_offset, 4);
  581     }
  582     iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
  583     iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
  584     iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
  585     iso_bb(vol.path_table_size, t->path_table_size, 4);
  586 
  587     if (t->eff_partition_offset > 0) {
  588         /* Point to second tables and second root */
  589         iso_lsb(vol.l_path_table_pos,
  590                 t->partition_l_table_pos - t->eff_partition_offset, 4);
  591         iso_msb(vol.m_path_table_pos,
  592                 t->partition_m_table_pos - t->eff_partition_offset, 4);
  593         write_one_dir_record(t, t->partition_root, 0,
  594                              vol.root_dir_record, 1, NULL, 0);
  595     } else {
  596         iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
  597         iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
  598         write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0);
  599     }
  600 
  601     strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
  602     strncpy_pad((char*)vol.publisher_id, pub_id, 128);
  603     strncpy_pad((char*)vol.data_prep_id, data_id, 128);
  604 
  605     strncpy_pad((char*)vol.application_id, application_id, 128);
  606     strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
  607     strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
  608     strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
  609 
  610     ecma119_set_voldescr_times(writer, &vol);
  611     vol.file_structure_version[0] = 1;
  612 
  613     memcpy(vol.app_use, image->application_use, 512);
  614 
  615     free(vol_id);
  616     free(volset_id);
  617     free(pub_id);
  618     free(data_id);
  619     free(system_id);
  620     free(application_id);
  621     free(copyright_file_id);
  622     free(abstract_file_id);
  623     free(biblio_file_id);
  624 
  625     /* Finally write the Volume Descriptor */
  626     return iso_write(t, &vol, sizeof(struct ecma119_pri_vol_desc));
  627 }
  628 
  629 static
  630 int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
  631 {
  632     int ret;
  633     uint8_t *buffer = NULL;
  634     size_t i;
  635     size_t fi_len, len;
  636     struct susp_info info;
  637 
  638     /* buf will point to current write position on buffer */
  639     uint8_t *buf;
  640 
  641     LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
  642     buf = buffer;
  643 
  644     /*
  645      * set susp_info to 0's, this way code for both plain ECMA-119 and
  646      * RR is very similar
  647      */
  648     memset(&info, 0, sizeof(struct susp_info));
  649     if (t->opts->rockridge) {
  650         /* initialize the ce_block, it might be needed */
  651         info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
  652                                                       BLOCK_SIZE);
  653         info.ce_susp_fields = NULL;
  654     }
  655 
  656     /* write the "." and ".." entries first */
  657     if (t->opts->rockridge) {
  658         ret = rrip_get_susp_fields(t, dir, 1, 34, &info);
  659         if (ret < 0) {
  660             goto ex;
  661         }
  662     }
  663     len = 34 + info.suf_len;
  664     write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
  665     buf += len;
  666 
  667     if (t->opts->rockridge) {
  668         ret = rrip_get_susp_fields(t, dir, 2, 34, &info);
  669         if (ret < 0) {
  670             goto ex;
  671         }
  672     }
  673     len = 34 + info.suf_len;
  674     write_one_dir_record(t, parent, 1, buf, 1, &info, 0);
  675     buf += len;
  676 
  677     for (i = 0; i < dir->info.dir->nchildren; i++) {
  678         int section, nsections;
  679         Ecma119Node *child = dir->info.dir->children[i];
  680 
  681         fi_len = strlen(child->iso_name);
  682 
  683         nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
  684         for (section = 0; section < nsections; ++section) {
  685 
  686             /* compute len of directory entry */
  687             len = fi_len + 33 + ((fi_len % 2) ? 0 : 1);
  688             if (need_version_number(t->opts, child->type)) {
  689                 len += 2;
  690             }
  691 
  692             /* get the SUSP fields if rockridge is enabled */
  693             if (t->opts->rockridge) {
  694                 ret = rrip_get_susp_fields(t, child, 0, len, &info);
  695                 if (ret < 0) {
  696                     goto ex;
  697                 }
  698                 len += info.suf_len;
  699             }
  700 
  701             if ( (buf + len - buffer) > BLOCK_SIZE) {
  702                 /* dir doesn't fit in current block */
  703                 ret = iso_write(t, buffer, BLOCK_SIZE);
  704                 if (ret < 0) {
  705                     goto ex;
  706                 }
  707                 memset(buffer, 0, BLOCK_SIZE);
  708                 buf = buffer;
  709             }
  710             /* write the directory entry in any case */
  711             write_one_dir_record(t, child, -1, buf, fi_len, &info, section);
  712             buf += len;
  713         }
  714     }
  715 
  716     /* write the last block */
  717     ret = iso_write(t, buffer, BLOCK_SIZE);
  718     if (ret < 0) {
  719         goto ex;
  720     }
  721 
  722     /* write the Continuation Area if needed */
  723     if (info.ce_len > 0) {
  724         ret = rrip_write_ce_fields(t, &info);
  725     }
  726 
  727 ex:;
  728     LIBISO_FREE_MEM(buffer);
  729     return ret;
  730 }
  731 
  732 static
  733 int write_dirs(Ecma119Image *t, Ecma119Node *root, Ecma119Node *parent)
  734 {
  735     int ret;
  736     size_t i;
  737 
  738     /* write all directory entries for this dir */
  739     ret = write_one_dir(t, root, parent);
  740     if (ret < 0) {
  741         return ret;
  742     }
  743 
  744     /* recurse */
  745     for (i = 0; i < root->info.dir->nchildren; i++) {
  746         Ecma119Node *child = root->info.dir->children[i];
  747         if (child->type == ECMA119_DIR) {
  748             ret = write_dirs(t, child, root);
  749             if (ret < 0) {
  750                 return ret;
  751             }
  752         }
  753     }
  754     return ISO_SUCCESS;
  755 }
  756 
  757 static
  758 int write_path_table(Ecma119Image *t, Ecma119Node **pathlist, int l_type)
  759 {
  760     size_t i, len;
  761     uint8_t buf[64]; /* 64 is just a convenient size larger enough */
  762     struct ecma119_path_table_record *rec;
  763     void (*write_int)(uint8_t*, uint32_t, int);
  764     Ecma119Node *dir;
  765     uint32_t path_table_size;
  766     int parent = 0;
  767     int ret= ISO_SUCCESS;
  768     uint8_t *zeros = NULL;
  769 
  770     path_table_size = 0;
  771     write_int = l_type ? iso_lsb : iso_msb;
  772 
  773     for (i = 0; i < t->ndirs; i++) {
  774         dir = pathlist[i];
  775 
  776         /* find the index of the parent in the table */
  777         while ((i) && pathlist[parent] != dir->parent) {
  778             parent++;
  779         }
  780 
  781         /* write the Path Table Record (ECMA-119, 9.4) */
  782         memset(buf, 0, 64);
  783         rec = (struct ecma119_path_table_record*) buf;
  784         rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1;
  785         rec->len_xa[0] = 0;
  786         write_int(rec->block, dir->info.dir->block - t->eff_partition_offset,
  787                   4);
  788         write_int(rec->parent, parent + 1, 2);
  789         if (dir->parent) {
  790             memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
  791         }
  792         len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
  793         ret = iso_write(t, buf, len);
  794         if (ret < 0) {
  795             /* error */
  796             goto ex;
  797         }
  798         path_table_size += len;
  799     }
  800 
  801     /* we need to fill the last block with zeros */
  802     path_table_size %= BLOCK_SIZE;
  803     if (path_table_size) {
  804         len = BLOCK_SIZE - path_table_size;
  805         LIBISO_ALLOC_MEM(zeros, uint8_t, len);
  806         ret = iso_write(t, zeros, len);
  807     }
  808 ex:;
  809     LIBISO_FREE_MEM(zeros);
  810     return ret;
  811 }
  812 
  813 static
  814 int write_path_tables(Ecma119Image *t)
  815 {
  816     int ret;
  817     size_t i, j, cur;
  818     Ecma119Node **pathlist;
  819 
  820     iso_msg_debug(t->image->id, "Writing ISO Path tables");
  821 
  822     /* allocate temporal pathlist */
  823     pathlist = malloc(sizeof(void*) * t->ndirs);
  824     if (pathlist == NULL) {
  825         return ISO_OUT_OF_MEM;
  826     }
  827 
  828     if (t->eff_partition_offset > 0) {
  829         pathlist[0] = t->partition_root;
  830     } else {
  831         pathlist[0] = t->root;
  832     }
  833     cur = 1;
  834 
  835     for (i = 0; i < t->ndirs; i++) {
  836         Ecma119Node *dir = pathlist[i];
  837         for (j = 0; j < dir->info.dir->nchildren; j++) {
  838             Ecma119Node *child = dir->info.dir->children[j];
  839             if (child->type == ECMA119_DIR) {
  840                 pathlist[cur++] = child;
  841             }
  842         }
  843     }
  844 
  845     /* Write L Path Table */
  846     ret = write_path_table(t, pathlist, 1);
  847     if (ret < 0) {
  848         goto write_path_tables_exit;
  849     }
  850 
  851     /* Write L Path Table */
  852     ret = write_path_table(t, pathlist, 0);
  853 
  854     write_path_tables_exit: ;
  855     free(pathlist);
  856     return ret;
  857 }
  858 
  859 
  860 /**
  861  * Write the directory structure (ECMA-119, 6.8) and the L and M
  862  * Path Tables (ECMA-119, 6.9).
  863  */
  864 static
  865 int ecma119_writer_write_dirs(IsoImageWriter *writer)
  866 {
  867     int ret, isofs_ca_changed = 0;
  868     Ecma119Image *t;
  869     Ecma119Node *root;
  870     char *value = NULL;
  871     size_t value_length;
  872 
  873     t = writer->target;
  874 
  875     /* first of all, we write the directory structure */
  876     if (t->eff_partition_offset > 0) {
  877         root = t->partition_root;
  878 
  879         if ((t->opts->md5_file_checksums & 1) ||
  880             t->opts->md5_session_checksum) {
  881             /* Take into respect the address offset in "isofs.ca" */
  882             ret = iso_node_lookup_attr((IsoNode *) t->image->root, "isofs.ca",
  883                                        &value_length, &value, 0);
  884             if (value != NULL)
  885                 free(value);
  886             if (ret == 1 && value_length == 20) {
  887                 /* "isofs.ca" does really exist and has the expected length */
  888                 ret = iso_root_set_isofsca((IsoNode *) t->image->root,
  889                              t->checksum_range_start - t->eff_partition_offset,
  890                              t->checksum_array_pos - t->eff_partition_offset,
  891                              t->checksum_idx_counter + 2, 16, "MD5", 0);
  892                 if (ret < 0)
  893                     return ret;
  894                 isofs_ca_changed = 1;
  895             }
  896         }
  897     } else {
  898         root = t->root;
  899     }
  900     ret = write_dirs(t, root, root);
  901     if (ret < 0) {
  902         return ret;
  903     }
  904 
  905     /* and write the path tables */
  906     ret = write_path_tables(t);
  907     if (ret < 0)
  908         return ret;
  909     if (t->opts->md5_session_checksum) {
  910         /* Write tree checksum tag */
  911         if (t->eff_partition_offset > 0) {
  912             /* >>> TWINTREE: >>> For now, tags are only for the
  913                                  image start and not for the partition */;
  914         } else {
  915             ret = iso_md5_write_tag(t, 3);
  916         }
  917     }
  918     if (isofs_ca_changed) {
  919         /* Restore old addresses offset in "isofs.ca" of root node */
  920         ret = iso_root_set_isofsca((IsoNode *) t->image->root,
  921                              t->checksum_range_start,
  922                              t->checksum_array_pos,
  923                              t->checksum_idx_counter + 2, 16, "MD5", 0);
  924         if (ret < 0)
  925             return ret;
  926     }
  927     return ret;
  928 }
  929 
  930 /**
  931  * Write directory structure and Path Tables of the ECMA-119 tree.
  932  * This happens eventually a second time for the duplicates which use
  933  * addresses with partition offset.
  934  */
  935 static
  936 int ecma119_writer_write_data(IsoImageWriter *writer)
  937 {
  938     int ret;
  939     Ecma119Image *t;
  940     uint32_t curblock;
  941     char *msg = NULL;
  942 
  943     if (writer == NULL)
  944         {ret = ISO_ASSERT_FAILURE; goto ex;}
  945 
  946     t = writer->target;
  947 
  948     ret = ecma119_writer_write_dirs(writer);
  949     if (ret < 0)
  950         goto ex;
  951 
  952     if (t->opts->partition_offset > 0) {
  953         t->eff_partition_offset = t->opts->partition_offset;
  954         ret = ecma119_writer_write_dirs(writer);
  955         t->eff_partition_offset = 0;
  956         if (ret < 0) 
  957             goto ex;
  958     }
  959 
  960     curblock = (t->bytes_written / 2048) + t->opts->ms_block;
  961     if (curblock != t->tree_end_block) {
  962         LIBISO_ALLOC_MEM(msg, char, 100);
  963         sprintf(msg,
  964                 "Calculated and written ECMA-119 tree end differ: %lu <> %lu",
  965                 (unsigned long) t->tree_end_block,
  966                 (unsigned long) curblock);
  967         iso_msgs_submit(0, msg, 0, "WARNING", 0);
  968 
  969         t->tree_end_block = 1;/* Mark for harsher reaction at end of writing */
  970     }
  971     ret = ISO_SUCCESS;
  972 ex:;
  973     LIBISO_FREE_MEM(msg);
  974     return ret;
  975 }
  976 
  977 static
  978 int ecma119_writer_free_data(IsoImageWriter *writer)
  979 {
  980     /* nothing to do */
  981     return ISO_SUCCESS;
  982 }
  983 
  984 int ecma119_writer_create(Ecma119Image *target)
  985 {
  986     int ret;
  987     IsoImageWriter *writer;
  988 
  989     writer = malloc(sizeof(IsoImageWriter));
  990     if (writer == NULL) {
  991         return ISO_OUT_OF_MEM;
  992     }
  993 
  994     writer->compute_data_blocks = ecma119_writer_compute_data_blocks;
  995     writer->write_vol_desc = ecma119_writer_write_vol_desc;
  996     writer->write_data = ecma119_writer_write_data;
  997     writer->free_data = ecma119_writer_free_data;
  998     writer->data = NULL;
  999     writer->target = target;
 1000 
 1001     /* add this writer to image */
 1002     target->writers[target->nwriters++] = writer;
 1003 
 1004     iso_msg_debug(target->image->id, "Creating low level ECMA-119 tree...");
 1005     ret = ecma119_tree_create(target);
 1006     if (ret < 0) {
 1007         return ret;
 1008     }
 1009 
 1010     if (target->image->sparc_core_node != NULL) {
 1011         /* Obtain a duplicate of the IsoFile's Ecma119Node->file */
 1012         ret = iso_file_src_create(target, target->image->sparc_core_node,
 1013                                   &target->sparc_core_src);
 1014         if (ret < 0)
 1015             return ret;
 1016     }
 1017 
 1018     if(target->opts->partition_offset > 0) {
 1019         /* Create second tree */
 1020         target->eff_partition_offset = target->opts->partition_offset;
 1021         ret = ecma119_tree_create(target);
 1022         target->eff_partition_offset = 0;
 1023         if (ret < 0)
 1024             return ret;
 1025     }
 1026 
 1027     /* we need the volume descriptor */
 1028     target->curblock++;
 1029     return ISO_SUCCESS;
 1030 }
 1031 
 1032 /** compute how many padding bytes are needed */
 1033 static
 1034 int mspad_writer_compute_data_blocks(IsoImageWriter *writer)
 1035 {
 1036     Ecma119Image *target;
 1037     uint32_t min_size;
 1038 
 1039     if (writer == NULL) {
 1040         return ISO_ASSERT_FAILURE;
 1041     }
 1042     target = writer->target;
 1043     min_size = 32 + target->opts->partition_offset;
 1044     if (target->curblock < min_size) {
 1045         target->mspad_blocks = min_size - target->curblock;
 1046         target->curblock = min_size;
 1047     }
 1048     return ISO_SUCCESS;
 1049 }
 1050 
 1051 static
 1052 int mspad_writer_write_vol_desc(IsoImageWriter *writer)
 1053 {
 1054     /* nothing to do */
 1055     return ISO_SUCCESS;
 1056 }
 1057 
 1058 static
 1059 int mspad_writer_write_data(IsoImageWriter *writer)
 1060 {
 1061     int ret;
 1062     Ecma119Image *t;
 1063     uint8_t *pad = NULL;
 1064     size_t i;
 1065 
 1066     if (writer == NULL) {
 1067         {ret = ISO_ASSERT_FAILURE; goto ex;}
 1068     }
 1069     t = writer->target;
 1070 
 1071     if (t->mspad_blocks == 0) {
 1072         {ret = ISO_SUCCESS; goto ex;}
 1073     }
 1074 
 1075     LIBISO_ALLOC_MEM(pad, uint8_t, BLOCK_SIZE);
 1076     for (i = 0; i < t->mspad_blocks; ++i) {
 1077         ret = iso_write(t, pad, BLOCK_SIZE);
 1078         if (ret < 0) {
 1079             goto ex;
 1080         }
 1081     }
 1082 
 1083     ret = ISO_SUCCESS;
 1084 ex:;
 1085     LIBISO_FREE_MEM(pad);
 1086     return ret;
 1087 }
 1088 
 1089 static
 1090 int mspad_writer_free_data(IsoImageWriter *writer)
 1091 {
 1092     /* nothing to do */
 1093     return ISO_SUCCESS;
 1094 }
 1095 
 1096 static
 1097 int mspad_writer_create(Ecma119Image *target)
 1098 {
 1099     IsoImageWriter *writer;
 1100 
 1101     writer = malloc(sizeof(IsoImageWriter));
 1102     if (writer == NULL) {
 1103         return ISO_OUT_OF_MEM;
 1104     }
 1105 
 1106     writer->compute_data_blocks = mspad_writer_compute_data_blocks;
 1107     writer->write_vol_desc = mspad_writer_write_vol_desc;
 1108     writer->write_data = mspad_writer_write_data;
 1109     writer->free_data = mspad_writer_free_data;
 1110     writer->data = NULL;
 1111     writer->target = target;
 1112 
 1113     /* add this writer to image */
 1114     target->writers[target->nwriters++] = writer;
 1115     return ISO_SUCCESS;
 1116 }
 1117 
 1118 
 1119 /** ----- Zero padding writer ----- */
 1120 
 1121 struct iso_zero_writer_data_struct {
 1122     uint32_t num_blocks;
 1123 };
 1124 
 1125 static
 1126 int zero_writer_compute_data_blocks(IsoImageWriter *writer)
 1127 {
 1128     Ecma119Image *target;
 1129     struct iso_zero_writer_data_struct *data;
 1130 
 1131     if (writer == NULL)
 1132         return ISO_ASSERT_FAILURE;
 1133     target = writer->target;
 1134     data = (struct iso_zero_writer_data_struct *) writer->data;
 1135     target->curblock += data->num_blocks;
 1136     return ISO_SUCCESS;
 1137 }
 1138 
 1139 static
 1140 int zero_writer_write_vol_desc(IsoImageWriter *writer)
 1141 {
 1142     /* nothing to do */
 1143     return ISO_SUCCESS;
 1144 }
 1145 
 1146 static
 1147 int zero_writer_write_data(IsoImageWriter *writer)
 1148 {
 1149     int ret;
 1150     Ecma119Image *t;
 1151     struct iso_zero_writer_data_struct *data;
 1152     uint8_t *pad = NULL;
 1153     size_t i;
 1154 
 1155     if (writer == NULL)
 1156         {ret = ISO_ASSERT_FAILURE; goto ex;}
 1157     t = writer->target;
 1158     data = (struct iso_zero_writer_data_struct *) writer->data;
 1159 
 1160     if (data->num_blocks == 0) 
 1161         {ret = ISO_SUCCESS; goto ex;}
 1162     LIBISO_ALLOC_MEM(pad, uint8_t, BLOCK_SIZE);
 1163     for (i = 0; i < data->num_blocks; ++i) {
 1164         ret = iso_write(t, pad, BLOCK_SIZE);
 1165         if (ret < 0) 
 1166             goto ex;
 1167     }
 1168     ret = ISO_SUCCESS;
 1169 ex:;
 1170     LIBISO_FREE_MEM(pad);
 1171     return ret;
 1172 }
 1173 
 1174 static
 1175 int zero_writer_free_data(IsoImageWriter *writer)
 1176 {
 1177     if (writer == NULL)
 1178         return ISO_SUCCESS;
 1179     if (writer->data == NULL)
 1180         return ISO_SUCCESS;
 1181     free(writer->data);
 1182     writer->data = NULL;
 1183     return ISO_SUCCESS;
 1184 }
 1185 
 1186 static
 1187 int tail_writer_compute_data_blocks(IsoImageWriter *writer)
 1188 {
 1189     int ret;
 1190     Ecma119Image *target;
 1191 
 1192 #ifdef Libisofs_part_align_writeR
 1193 
 1194     target = writer->target;
 1195 
 1196 #else
 1197 
 1198     struct iso_zero_writer_data_struct *data;
 1199     char msg[80];
 1200 
 1201     target = writer->target;
 1202     ret = iso_align_isohybrid(target, 0);
 1203     if (ret < 0)
 1204         return ret;
 1205     data = (struct iso_zero_writer_data_struct *) writer->data;
 1206     if (data->num_blocks != target->opts->tail_blocks) {
 1207         sprintf(msg, "Aligned image size to cylinder size by %d blocks",
 1208                      target->opts->tail_blocks - data->num_blocks);
 1209         iso_msgs_submit(0, msg, 0, "NOTE", 0);
 1210         data->num_blocks = target->opts->tail_blocks;
 1211     }
 1212 
 1213 #endif /* ! Libisofs_part_align_writeR */
 1214 
 1215     if (target->opts->tail_blocks <= 0)
 1216         return ISO_SUCCESS;
 1217     ret = zero_writer_compute_data_blocks(writer);
 1218     return ret;
 1219 }
 1220 
 1221 static
 1222 int part_align_writer_compute_data_blocks(IsoImageWriter *writer)
 1223 {
 1224     int ret;
 1225     Ecma119Image *target;
 1226     struct iso_zero_writer_data_struct *data;
 1227     char msg[80];
 1228 
 1229     target = writer->target;
 1230 
 1231     /* Default setting in case no alignment is needed */
 1232     target->alignment_end_block = target->curblock;
 1233 
 1234     ret = iso_align_isohybrid(target, 0);
 1235     if (ret < 0)
 1236         return ret;
 1237     data = (struct iso_zero_writer_data_struct *) writer->data;
 1238     if (target->part_align_blocks != 0) {
 1239         sprintf(msg, "Aligned image size to cylinder size by %d blocks",
 1240                      target->part_align_blocks);
 1241         iso_msgs_submit(0, msg, 0, "NOTE", 0);
 1242         data->num_blocks = target->part_align_blocks;
 1243     }
 1244     if (target->part_align_blocks <= 0)
 1245         return ISO_SUCCESS;
 1246     ret = zero_writer_compute_data_blocks(writer);
 1247     target->alignment_end_block = target->curblock;
 1248     return ret;
 1249 }
 1250 
 1251 /*
 1252   @param flag bit0-3= compute_data_blocks mode:
 1253                       0= zero_writer_compute_data_blocks
 1254                       1= tail_writer_compute_data_blocks
 1255                       2= part_align_writer_compute_data_blocks
 1256 */
 1257 static
 1258 int zero_writer_create(Ecma119Image *target, uint32_t num_blocks, int flag)
 1259 {
 1260     IsoImageWriter *writer;
 1261     struct iso_zero_writer_data_struct *data;
 1262     int mode;
 1263 
 1264     writer = malloc(sizeof(IsoImageWriter));
 1265     if (writer == NULL) {
 1266         return ISO_OUT_OF_MEM;
 1267     }
 1268     data = calloc(1, sizeof(struct iso_zero_writer_data_struct));
 1269     if (data == NULL) {
 1270         free(writer);
 1271         return ISO_OUT_OF_MEM;
 1272     }
 1273     data->num_blocks = num_blocks;
 1274 
 1275     mode = (flag & 15);
 1276     if (mode == 1) {
 1277         writer->compute_data_blocks = tail_writer_compute_data_blocks;
 1278     } else if (mode == 2) {
 1279         writer->compute_data_blocks = part_align_writer_compute_data_blocks;
 1280     } else {
 1281         writer->compute_data_blocks = zero_writer_compute_data_blocks;
 1282     }
 1283     writer->write_vol_desc = zero_writer_write_vol_desc;
 1284     writer->write_data = zero_writer_write_data;
 1285     writer->free_data = zero_writer_free_data;
 1286     writer->data = data;
 1287     writer->target = target;
 1288 
 1289     /* add this writer to image */
 1290     target->writers[target->nwriters++] = writer;
 1291     return ISO_SUCCESS;
 1292 }
 1293 
 1294 
 1295 /* @param flag bit0= restore preserved cx (else dispose them)
 1296 */
 1297 static
 1298 int process_preserved_cx(IsoDir *dir, int flag)
 1299 {
 1300     int ret, i;
 1301     unsigned int cx_value;
 1302     void *xipt;
 1303     IsoNode *pos;
 1304 
 1305     pos = dir->children;
 1306     for (pos = dir->children; pos != NULL; pos = pos->next) {
 1307         if (pos->type == LIBISO_FILE) {
 1308             if (flag & 1) {
 1309                 /* Restore preserved cx state of nodes */
 1310                 ret = iso_node_get_xinfo(pos, checksum_cx_xinfo_func,
 1311                                          &xipt);
 1312                 if (ret == 1) {
 1313                     /* xipt is an int disguised as void pointer */
 1314                     cx_value = 0;
 1315                     for (i = 0; i < 4; i++)
 1316                         cx_value =
 1317                             (cx_value << 8) | ((unsigned char *) &xipt)[i];
 1318                     ret = iso_file_set_isofscx((IsoFile *) pos, cx_value, 0);
 1319                     if (ret < 0)
 1320                         return ret;
 1321                 } else if (ret == 0) {
 1322                     /* Node had no cx before the write run. Delete cx. */
 1323                     iso_file_set_isofscx((IsoFile *) pos, 0, 1);
 1324                 }
 1325             }
 1326             iso_node_remove_xinfo(pos, checksum_cx_xinfo_func);
 1327         } else if (pos->type == LIBISO_DIR) {
 1328             ret = process_preserved_cx((IsoDir *) pos, flag);
 1329             if (ret != 0)
 1330                 return ret;
 1331         }
 1332     }
 1333     return 0;
 1334 }
 1335 
 1336 static
 1337 int transplant_checksum_buffer(Ecma119Image *target, int flag)
 1338 {
 1339     /* Transplant checksum buffer from Ecma119Image to IsoImage */
 1340     iso_image_set_checksums(target->image, target->checksum_buffer,
 1341                             target->checksum_range_start,
 1342                             target->checksum_array_pos,
 1343                             target->checksum_idx_counter + 2, 0);
 1344     target->checksum_buffer = NULL;
 1345     target->checksum_idx_counter = 0;
 1346 
 1347     /* Delete recorded cx xinfo */
 1348     process_preserved_cx(target->image->root, 0);
 1349 
 1350     return 1;
 1351 }
 1352 
 1353 static
 1354 int write_vol_desc_terminator(Ecma119Image *target)
 1355 {
 1356     int ret;
 1357     uint8_t *buf = NULL;
 1358     struct ecma119_vol_desc_terminator *vol;
 1359 
 1360     LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
 1361 
 1362     vol = (struct ecma119_vol_desc_terminator *) buf;
 1363 
 1364     vol->vol_desc_type[0] = 255;
 1365     memcpy(vol->std_identifier, "CD001", 5);
 1366     vol->vol_desc_version[0] = 1;
 1367 
 1368     ret = iso_write(target, buf, BLOCK_SIZE);
 1369 ex:
 1370     LIBISO_FREE_MEM(buf);
 1371     return ret;
 1372 }
 1373 
 1374 
 1375 /* @param flag bit0= initialize system area by target->opts_overwrite
 1376                bit1= fifo is not yet draining. Inquire write_count from fifo.
 1377                bit2= target->opts->ms_block is not counted in
 1378                      target->total_size
 1379 */
 1380 static
 1381 int write_head_part1(Ecma119Image *target, int *write_count, int flag)
 1382 {
 1383     int res, i, ret;
 1384     uint8_t *sa, *sa_local = NULL;
 1385     IsoImageWriter *writer;
 1386     size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0;
 1387 
 1388     if (target->sys_area_already_written) {
 1389         LIBISO_ALLOC_MEM(sa_local, uint8_t, 16 * BLOCK_SIZE);
 1390         sa = sa_local;
 1391     } else {
 1392         sa = target->sys_area_as_written;
 1393         target->sys_area_already_written = 1;
 1394     }
 1395     iso_ring_buffer_get_buf_status(target->buffer, &buffer_size,
 1396                                    &buffer_start_free);
 1397     *write_count = 0;
 1398     /* Write System Area (ECMA-119, 6.2.1) */
 1399     if ((flag & 1) && target->opts_overwrite != NULL)
 1400         memcpy(sa, target->opts_overwrite, 16 * BLOCK_SIZE);
 1401     res = iso_write_system_area(target, sa, (flag & 4) >> 2);
 1402     if (res < 0)
 1403         goto write_error;
 1404     res = iso_write(target, sa, 16 * BLOCK_SIZE);
 1405     if (res < 0)
 1406         goto write_error;
 1407     *write_count = 16;
 1408 
 1409     /* write volume descriptors, one per writer */
 1410     iso_msg_debug(target->image->id, "Write volume descriptors");
 1411     for (i = 0; i < (int) target->nwriters; ++i) {
 1412         writer = target->writers[i];
 1413         res = writer->write_vol_desc(writer);
 1414         if (res < 0) 
 1415             goto write_error;
 1416     }
 1417 
 1418     /* write Volume Descriptor Set Terminator (ECMA-119, 8.3) */
 1419     res = write_vol_desc_terminator(target);
 1420     if (res < 0)
 1421         goto write_error;
 1422 
 1423     if(flag & 2) {
 1424       iso_ring_buffer_get_buf_status(target->buffer, &buffer_size,
 1425                                      &buffer_free);
 1426       *write_count = ( buffer_start_free - buffer_free ) / BLOCK_SIZE;
 1427     } else {
 1428       *write_count = target->bytes_written / BLOCK_SIZE;
 1429     }
 1430 
 1431     ret = ISO_SUCCESS;
 1432     goto ex;
 1433 
 1434 write_error:;
 1435     ret = res;
 1436     goto ex;
 1437 
 1438 ex:
 1439     LIBISO_FREE_MEM(sa_local);
 1440     return ret;
 1441 }
 1442 
 1443 static
 1444 int write_head_part2(Ecma119Image *target, int *write_count, int flag)
 1445 {
 1446     int ret, i;
 1447     uint8_t *buf = NULL;
 1448     IsoImageWriter *writer;
 1449 
 1450     if (target->opts->partition_offset <= 0)
 1451         {ret = ISO_SUCCESS; goto ex;}
 1452 
 1453     /* Write multi-session padding up to target->opts->partition_offset + 16 */
 1454     LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
 1455     for(; *write_count < (int) target->opts->partition_offset + 16;
 1456         (*write_count)++) {
 1457         ret = iso_write(target, buf, BLOCK_SIZE);
 1458         if (ret < 0)
 1459             goto ex;
 1460     }
 1461 
 1462     /* Write volume descriptors subtracting
 1463       target->partiton_offset from any LBA pointer.
 1464     */
 1465     target->eff_partition_offset = target->opts->partition_offset;
 1466     target->pvd_size_is_total_size = 0;
 1467     for (i = 0; i < (int) target->nwriters; ++i) {
 1468         writer = target->writers[i];
 1469         /* Not all writers have an entry in the partition volume descriptor set.
 1470            It must be guaranteed that they write exactly one block.
 1471         */
 1472 
 1473         /* >>> TWINTREE: Enhance ISO1999 writer and add it here */
 1474 
 1475         if(writer->write_vol_desc != ecma119_writer_write_vol_desc &&
 1476            writer->write_vol_desc != joliet_writer_write_vol_desc)
 1477     continue;
 1478         ret = writer->write_vol_desc(writer);
 1479         if (ret < 0)
 1480             goto ex;
 1481         (*write_count)++;
 1482     }
 1483     ret = write_vol_desc_terminator(target);
 1484     if (ret < 0)
 1485         goto ex;
 1486     (*write_count)++;
 1487     target->eff_partition_offset = 0;
 1488 
 1489     /* >>> TWINTREE: Postponed for now:
 1490                      Write second superblock checksum tag */;
 1491 
 1492     ret = ISO_SUCCESS;
 1493 ex:;
 1494     if (buf != NULL)
 1495         free(buf);
 1496     return ret;
 1497 }
 1498 
 1499 static
 1500 int write_head_part(Ecma119Image *target, int flag)
 1501 {
 1502     int res, write_count = 0;
 1503 
 1504     /* System area and volume descriptors */
 1505     res = write_head_part1(target, &write_count, 4);
 1506     if (res < 0)
 1507         return res;
 1508 
 1509     /* Write superblock checksum tag */
 1510     if (target->opts->md5_session_checksum && target->checksum_ctx != NULL) {
 1511         res = iso_md5_write_tag(target, 2);
 1512         if (res < 0)
 1513             return res;
 1514         write_count++;
 1515     }
 1516 
 1517     /* Second set of system area and volume descriptors for partition_offset */
 1518     res = write_head_part2(target, &write_count, 0);
 1519     if (res < 0)
 1520         return res;
 1521     return ISO_SUCCESS;
 1522 }
 1523 
 1524 
 1525 /* Eventually end Jigdo Template Extraction */
 1526 static int finish_libjte(Ecma119Image *target)
 1527 {
 1528 #ifdef Libisofs_with_libjtE
 1529 
 1530     int ret;
 1531 
 1532     if (target->opts->libjte_handle != NULL) {
 1533         ret = libjte_write_footer(target->opts->libjte_handle);
 1534         if (ret <= 0) {
 1535             iso_libjte_forward_msgs(target->opts->libjte_handle, 
 1536                                 target->image->id, ISO_LIBJTE_END_FAILED, 0);
 1537             return ISO_LIBJTE_END_FAILED;
 1538         }
 1539     }
 1540 
 1541 #endif /* Libisofs_with_libjtE */
 1542 
 1543     return 1;
 1544 }
 1545 
 1546 
 1547 
 1548 struct iso_interval_zeroizer {
 1549     int z_type; /* 0= $zero_start"-"$zero_end ,
 1550                    1= "zero_mbrpt" , 2= "zero_gpt" , 3= "zero_apm"
 1551                 */
 1552     off_t zero_start;
 1553     off_t zero_end;
 1554 };
 1555 
 1556 struct iso_interval_reader {
 1557 
 1558     /* Setup */
 1559 
 1560     IsoImage *image;
 1561 
 1562     char *path;
 1563 
 1564     int flags; /* bit0= imported_iso, else local_fs
 1565                */
 1566 
 1567     off_t start_byte;
 1568     off_t end_byte;
 1569 
 1570     struct iso_interval_zeroizer *zeroizers;
 1571     int num_zeroizers;
 1572 
 1573     char *source_pt; /* This is a parasite pointer of path. Do not free */
 1574 
 1575     /* State information */
 1576 
 1577     int initialized;
 1578     int is_block_aligned;
 1579     off_t cur_block;
 1580     int fd;
 1581     uint8_t read_buf[BLOCK_SIZE];
 1582     uint8_t *pending_read_pt;
 1583     int pending_read_bytes;
 1584     off_t read_count;
 1585     int eof;
 1586 
 1587     int src_is_open;
 1588 
 1589     uint32_t apm_block_size;
 1590 
 1591 };
 1592 
 1593 static
 1594 int iso_ivr_next_comp(char *read_pt, char **next_pt, int flag)
 1595 {
 1596     *next_pt = NULL;
 1597     if (read_pt == NULL)
 1598         return 0;
 1599     *next_pt = strchr(read_pt, ':');
 1600     if (*next_pt != NULL)
 1601         (*next_pt)++;
 1602     return 1;
 1603 }
 1604 
 1605 /* @param flag bit1= end number requested, forward to iso_scanf_io_size()
 1606 */
 1607 static
 1608 int iso_ivr_read_number(char *start_pt, char *end_pt, off_t *result, int flag)
 1609 {
 1610     char txt[20];
 1611     off_t num;
 1612 
 1613     if (end_pt - start_pt <= 0 || end_pt - start_pt > 16) {
 1614         iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
 1615     "Number text too short or too long in interval reader description string");
 1616         return ISO_MALFORMED_READ_INTVL;
 1617     }
 1618     if (end_pt - start_pt > 0)
 1619         strncpy(txt, start_pt, end_pt - start_pt);
 1620     txt[end_pt - start_pt] = 0;
 1621 
 1622     num = iso_scanf_io_size(start_pt, 1 | (flag & 2));
 1623     if (num < 0.0 || num > 281474976710655.0) {
 1624         iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
 1625       "Negative or overly large number in interval reader description string");
 1626         return ISO_MALFORMED_READ_INTVL;
 1627     }
 1628     *result = num;
 1629     return 1;
 1630 }
 1631 
 1632 static
 1633 int iso_ivr_parse_interval(char *start_pt, char *end_pt, off_t *start_byte,
 1634                            off_t *end_byte, int flag)
 1635 {
 1636     int ret;
 1637     char *m_pt;
 1638 
 1639     m_pt = strchr(start_pt, '-');
 1640     if (m_pt == NULL) {
 1641         iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
 1642               "Malformed byte interval in interval reader description string");
 1643         return ISO_MALFORMED_READ_INTVL;
 1644     }
 1645     ret = iso_ivr_read_number(start_pt, m_pt, start_byte, 0);
 1646     if (ret < 0)
 1647         return ret;
 1648     ret = iso_ivr_read_number(m_pt + 1, end_pt - 1, end_byte, 2);
 1649     if (ret < 0)
 1650         return ret;
 1651     return ISO_SUCCESS;
 1652 }
 1653 
 1654 static
 1655 int iso_ivr_parse_zeroizers(struct iso_interval_reader *ivr,
 1656                             char *pathpt, char *end_pt, int flag)
 1657 {
 1658     int ret, num_zs = 1, idx, i;
 1659     char *rpt, *cpt;
 1660 
 1661     ivr->num_zeroizers = 0;
 1662     if (pathpt[0] == 0 || pathpt == end_pt)
 1663         return ISO_SUCCESS;
 1664     for(cpt = pathpt - 1; cpt != NULL && cpt < end_pt; num_zs++)
 1665         cpt = strchr(cpt + 1, ',');
 1666     LIBISO_ALLOC_MEM(ivr->zeroizers, struct iso_interval_zeroizer, num_zs);
 1667     for (i = 0; i < num_zs; i++)
 1668         ivr->zeroizers[i].zero_end = -1;
 1669     idx = 0;
 1670     for (rpt = pathpt; rpt != NULL && rpt < end_pt; idx++) {
 1671         cpt = strchr(rpt, ',');
 1672         if (cpt == NULL || cpt > end_pt)
 1673             cpt = end_pt;
 1674 
 1675         if (cpt == rpt) {
 1676     continue;
 1677         } else if (strncmp(rpt, "zero_mbrpt", cpt - rpt) == 0) {
 1678             ivr->zeroizers[idx].z_type = 1;
 1679         } else if (strncmp(rpt, "zero_gpt", cpt - rpt) == 0) {
 1680             ivr->zeroizers[idx].z_type = 2;
 1681         } else if (strncmp(rpt, "zero_apm", cpt - rpt) == 0) {
 1682             ivr->zeroizers[idx].z_type = 3;
 1683         } else {
 1684             ivr->zeroizers[idx].z_type = 0;
 1685             ret = iso_ivr_parse_interval(rpt, cpt,
 1686                                          &(ivr->zeroizers[idx].zero_start),
 1687                                          &(ivr->zeroizers[idx].zero_end), 0);
 1688             if (ret < 0)
 1689                 goto ex;
 1690         }
 1691         rpt = cpt + 1;
 1692         ivr->num_zeroizers++;
 1693     }
 1694     ret = ISO_SUCCESS;
 1695 ex:;
 1696     return ret;
 1697 }
 1698 
 1699 static
 1700 int iso_ivr_parse(struct iso_interval_reader *ivr, char *path, int flag)
 1701 {
 1702     int ret;
 1703     char *flags_pt, *interval_pt, *zeroize_pt;
 1704 
 1705     flags_pt = path;
 1706     iso_ivr_next_comp(flags_pt, &interval_pt, 0);
 1707     iso_ivr_next_comp(interval_pt, &zeroize_pt, 0);
 1708     iso_ivr_next_comp(zeroize_pt, &(ivr->source_pt), 0);
 1709     if (ivr->source_pt == NULL) {
 1710         iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
 1711                 "Not enough components in interval reader description string");
 1712         return ISO_MALFORMED_READ_INTVL;
 1713     }
 1714 
 1715     ivr->flags = 0;
 1716     if (strncmp(flags_pt, "imported_iso", 12) == 0) {
 1717         ivr->flags |= 1;
 1718     } else if (strncmp(flags_pt, "local_fs", 8) == 0) {
 1719         ;
 1720     } else {
 1721         iso_msg_submit(-1, ISO_MALFORMED_READ_INTVL, 0,
 1722  "Unknown flag name in first component of interval reader description string");
 1723         return ISO_MALFORMED_READ_INTVL;
 1724     }
 1725     ret = iso_ivr_parse_interval(interval_pt, zeroize_pt, &(ivr->start_byte),
 1726                                  &(ivr->end_byte), 0);
 1727     if (ret < 0)
 1728         goto ex;
 1729     ret = iso_ivr_parse_zeroizers(ivr, zeroize_pt, ivr->source_pt - 1, 0);
 1730     if (ret < 0)
 1731         goto ex;
 1732 
 1733     ret = ISO_SUCCESS;
 1734 ex:;
 1735     return ret;
 1736 }   
 1737 
 1738 int iso_interval_reader_destroy(struct iso_interval_reader **ivr, int flag)
 1739 {
 1740     struct iso_interval_reader *o;
 1741 
 1742     if (*ivr == NULL)
 1743         return 0;
 1744     o = *ivr;
 1745 
 1746     LIBISO_FREE_MEM(o->path);
 1747     LIBISO_FREE_MEM(o->zeroizers);
 1748 
 1749     if (o->fd != -1)
 1750         close(o->fd);
 1751     if (o->src_is_open)
 1752         (*o->image->import_src->close)(o->image->import_src);
 1753 
 1754     LIBISO_FREE_MEM(*ivr);
 1755     return ISO_SUCCESS;
 1756 }
 1757 
 1758 /* @param flag bit0= tolerate lack of import_src
 1759 */
 1760 int iso_interval_reader_new(IsoImage *img, char *path,
 1761                             struct iso_interval_reader **ivr,
 1762                             off_t *byte_count, int flag)
 1763 {
 1764     int ret, no_img = 0;
 1765     struct iso_interval_reader *o = NULL;
 1766 
 1767     *ivr = NULL;
 1768     *byte_count = 0;
 1769     LIBISO_ALLOC_MEM(o, struct iso_interval_reader, 1);
 1770     o->image = img;
 1771     o->path = NULL;
 1772     o->zeroizers = NULL;
 1773     o->num_zeroizers = 0;
 1774     o->source_pt = NULL;
 1775     o->initialized = 0;
 1776     o->is_block_aligned = 0;
 1777     o->fd = -1;
 1778     o->pending_read_pt = NULL;
 1779     o->pending_read_bytes = 0;
 1780     o->eof = 0;
 1781     o->read_count = 0;
 1782     o->src_is_open = 0;
 1783 
 1784     o->apm_block_size = 0;
 1785 
 1786     LIBISO_ALLOC_MEM(o->path, char, strlen(path) + 1);
 1787     strcpy(o->path, path);
 1788 
 1789     ret = iso_ivr_parse(o, path, 0);
 1790     if (ret < 0)
 1791         goto ex;
 1792 
 1793     if (o->image == NULL)
 1794         no_img = 1;
 1795     else if (o->image->import_src == NULL)
 1796         no_img = 1;
 1797     if ((o->flags & 1) && no_img) {
 1798         iso_msg_submit(-1, ISO_NO_KEPT_DATA_SRC, 0,
 1799                 "Interval reader lacks of data source object of imported ISO");
 1800         if (!(flag & 1)) {
 1801             ret = ISO_BAD_PARTITION_FILE;
 1802             goto ex;
 1803         }
 1804         o->eof = 1;
 1805     }
 1806     *byte_count = o->end_byte - o->start_byte + 1;
 1807     *ivr = o;
 1808     ret = ISO_SUCCESS;
 1809 ex:;
 1810     if (ret < 0)
 1811         iso_interval_reader_destroy(&o, 0);
 1812     return ret;
 1813 }
 1814 
 1815 static
 1816 int iso_ivr_zeroize(struct iso_interval_reader *ivr, uint8_t *buf,
 1817                              int buf_fill, int flag)
 1818 {
 1819     int i;
 1820     off_t low, high, part_start, entry_count, apm_offset = -1, map_entries;
 1821     uint8_t *apm_buf;
 1822     struct iso_interval_zeroizer *zr;
 1823 
 1824     for (i = 0; i < ivr->num_zeroizers; i++) {
 1825         zr = ivr->zeroizers + i;
 1826         if (zr->z_type == 1) { /* zero_mbrpt */
 1827             if (ivr->read_count > 0 || buf_fill < 512)
 1828     continue;
 1829             if (buf[510] != 0x55 || buf[511] != 0xaa)
 1830     continue;
 1831             memset(buf + 446, 0, 64);
 1832 
 1833         } else if (zr->z_type == 2) { /* zero_gpt */
 1834             if (zr->zero_start <= zr->zero_end)
 1835                 goto process_interval;
 1836 
 1837             if (ivr->read_count > 0 || buf_fill < 512 + 92)
 1838     continue;
 1839             if (strncmp((char *) buf + 512, "EFI PART", 8) != 0 ||
 1840                 buf[520] != 0 || buf[521] != 0  || buf[522] != 1 ||
 1841                 buf[523] != 0)
 1842     continue;
 1843             /* head_size , curr_lba , entry_size */
 1844             if (iso_read_lsb(buf + 524, 4) != 92 ||
 1845                 iso_read_lsb(buf + 536, 4) != 1 ||
 1846                 iso_read_lsb(buf + 596, 4) != 128)
 1847     continue;
 1848             part_start = iso_read_lsb(buf + 584, 4);
 1849             entry_count = iso_read_lsb(buf + 592, 4);
 1850             if (part_start < 2 || part_start + (entry_count + 3) / 4 > 64)
 1851     continue;
 1852             zr->zero_start = part_start * 512;
 1853             zr->zero_end = (part_start + (entry_count + 3) / 4) * 512 - 1;
 1854             memset(buf + 512, 0, 92);
 1855 
 1856         } else if (zr->z_type == 3) { /* zero_apm */
 1857             if (zr->zero_start <= zr->zero_end)
 1858                 goto process_interval;
 1859 
 1860             if (ivr->read_count == 0) {
 1861                 if (buf_fill < 512)
 1862     continue;
 1863                 if (buf[0] != 'E' || buf[1] != 'R')
 1864     continue;
 1865                 ivr->apm_block_size = iso_read_msb(buf + 2, 2);
 1866                 if ((ivr->apm_block_size != 512 &&
 1867                      ivr->apm_block_size != 1024 &&
 1868                      ivr->apm_block_size != 2048) ||
 1869                     ((uint32_t) buf_fill) < ivr->apm_block_size) {
 1870                     ivr->apm_block_size = 0;
 1871     continue;
 1872                 }
 1873                 if (ivr->read_count + buf_fill >= 2 * ivr->apm_block_size)
 1874                     apm_offset = ivr->apm_block_size;
 1875             } else if (ivr->read_count == 2048 &&
 1876                        ivr->apm_block_size == 2048 && buf_fill == 2048) {
 1877                 apm_offset = 0;
 1878             }
 1879             if (apm_offset < 0)
 1880     continue;
 1881 
 1882             /* Check for first APM entry */
 1883             apm_buf = buf + apm_offset;
 1884             if(apm_buf[0] != 'P' || apm_buf[1] != 'M')
 1885     continue;
 1886             if (iso_read_msb(apm_buf + 8, 4) != 1)
 1887     continue;
 1888             map_entries = iso_read_msb(apm_buf + 4, 4);
 1889             if ((1 + map_entries) * ivr->apm_block_size > 16 * 2048)
 1890     continue;
 1891             zr->zero_start = ivr->apm_block_size;
 1892             zr->zero_end = (1 + map_entries) * ivr->apm_block_size;
 1893         }
 1894 process_interval:;
 1895         /* If an interval is defined by now: zeroize its intersection with buf
 1896          */
 1897         if (zr->zero_start <= zr->zero_end) {
 1898             low = ivr->read_count >= zr->zero_start ?
 1899                   ivr->read_count : zr->zero_start;
 1900             high = ivr->read_count + buf_fill - 1 <= zr->zero_end ?
 1901                    ivr->read_count + buf_fill - 1 : zr->zero_end;
 1902             if (low <= high)
 1903                 memset(buf + low - ivr->read_count, 0, high - low + 1);
 1904         }
 1905     }
 1906 
 1907     return ISO_SUCCESS;
 1908 }
 1909 
 1910 int iso_interval_reader_read(struct iso_interval_reader *ivr, uint8_t *buf,
 1911                              int *buf_fill, int flag)
 1912 {
 1913     int ret, read_done, to_copy, initializing = 0;
 1914     IsoDataSource *src;
 1915     uint8_t *read_buf;
 1916     off_t to_read;
 1917 
 1918     *buf_fill = 0;
 1919     src = ivr->image->import_src;
 1920 
 1921     if (ivr->eof) {
 1922 eof:;
 1923         memset(buf, 0, BLOCK_SIZE);
 1924         return 0;
 1925     }
 1926 
 1927     if (ivr->initialized) {
 1928         ivr->cur_block++;
 1929     } else {
 1930         initializing = 1;
 1931         ivr->cur_block = ivr->start_byte / BLOCK_SIZE;
 1932         ivr->is_block_aligned = !(ivr->start_byte % BLOCK_SIZE);
 1933         if (ivr->flags & 1) {
 1934             if (src == NULL)
 1935                 goto eof;
 1936             ret = (*src->open)(src);
 1937             if (ret < 0) {
 1938                 ivr->eof = 1;
 1939                 return ret;
 1940             }
 1941             ivr->src_is_open = 1;
 1942         } else {
 1943             ivr->fd = open(ivr->source_pt, O_RDONLY);
 1944             if (ivr->fd == -1) {
 1945                 iso_msg_submit(-1, ISO_BAD_PARTITION_FILE, 0,
 1946                          "Cannot open local file for interval reading");
 1947                 ivr->eof = 1;
 1948                 return ISO_BAD_PARTITION_FILE;
 1949             }
 1950             if (ivr->cur_block != 0) {
 1951                 if (lseek(ivr->fd, ivr->cur_block * BLOCK_SIZE, SEEK_SET) ==
 1952                     -1) {
 1953                     iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
 1954                          "Cannot address interval start in local file");
 1955                     ivr->eof = 1;
 1956                     goto eof;
 1957                 }
 1958             }
 1959         }
 1960         ivr->initialized = 1;
 1961     }
 1962     if (ivr->is_block_aligned) {
 1963         read_buf = buf;
 1964     } else {
 1965 process_pending:;
 1966         read_buf = ivr->read_buf;
 1967         /* Copy pending bytes from previous read */
 1968         if (ivr->pending_read_bytes > 0) {
 1969             memcpy(buf, ivr->pending_read_pt, ivr->pending_read_bytes);
 1970             *buf_fill = ivr->pending_read_bytes;
 1971             ivr->pending_read_bytes = 0;
 1972         }
 1973     }
 1974 
 1975     /* Read next block */
 1976     read_done = 0;
 1977     if (ivr->cur_block * BLOCK_SIZE <= ivr->end_byte) {
 1978         if (ivr->flags & 1) {
 1979             ret = (*src->read_block)(src, (uint32_t) ivr->cur_block, read_buf);
 1980             if (ret < 0) {
 1981                 if (iso_error_get_severity(ret) > 0x68000000) /* > FAILURE */
 1982                     return ret;
 1983                 iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
 1984                      "Premature EOF while interval reading from imported ISO");
 1985                 ivr->eof = 1;
 1986             }
 1987             read_done = BLOCK_SIZE;
 1988         } else {
 1989             read_done = 0;
 1990             to_read = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
 1991             if (to_read > BLOCK_SIZE)
 1992                 to_read = BLOCK_SIZE;
 1993             while (read_done < to_read) {
 1994                 ret = read(ivr->fd, read_buf, to_read - read_done);
 1995                 if (ret == -1) {
 1996                     iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
 1997                        "Read error while interval reading from local file");
 1998                     ivr->eof = 1;
 1999             break;
 2000                 } else if (ret == 0) {
 2001                     iso_msg_submit(-1, ISO_INTVL_READ_PROBLEM, 0,
 2002                        "Premature EOF while interval reading from local file");
 2003                     ivr->eof = 1;
 2004             break;
 2005                 } else
 2006                     read_done += ret;
 2007             }
 2008         }
 2009     }
 2010     if (ivr->is_block_aligned) {
 2011         *buf_fill = read_done;
 2012     } else if (initializing) {
 2013         ivr->pending_read_pt = ivr->read_buf +
 2014                                (ivr->start_byte - ivr->cur_block * BLOCK_SIZE);
 2015         ivr->pending_read_bytes = (((off_t) ivr->cur_block) + 1) * BLOCK_SIZE -
 2016                                   ivr->start_byte;
 2017         initializing = 0;
 2018         goto process_pending;
 2019 
 2020     } else if (read_done > 0) {
 2021         /* Copy bytes from new read */
 2022         to_copy = read_done > BLOCK_SIZE - *buf_fill ?
 2023                   BLOCK_SIZE - *buf_fill : read_done;
 2024         memcpy(buf + *buf_fill, ivr->read_buf, to_copy);
 2025         *buf_fill += to_copy;
 2026         ivr->pending_read_pt = ivr->read_buf + to_copy;
 2027         ivr->pending_read_bytes = read_done - to_copy;
 2028     }
 2029     if (ivr->start_byte + ivr->read_count + *buf_fill - 1 > ivr->end_byte) {
 2030         *buf_fill = ivr->end_byte - ivr->start_byte + 1 - ivr->read_count;
 2031         ivr->eof = 1;
 2032     }
 2033 
 2034     if (*buf_fill < BLOCK_SIZE)
 2035         memset(buf + *buf_fill, 0, BLOCK_SIZE - *buf_fill);
 2036 
 2037     ret = iso_ivr_zeroize(ivr, buf, *buf_fill, 0);
 2038     if (ret < 0)
 2039         return ret;
 2040 
 2041     ivr->read_count += *buf_fill;
 2042 
 2043     return ISO_SUCCESS;
 2044 }
 2045 
 2046 
 2047 /* Tells whether ivr is a reader from imported_iso in a multi-session
 2048    add-on situation, and thus to be kept in place.
 2049 */
 2050 int iso_interval_reader_keep(Ecma119Image *target, 
 2051                              struct iso_interval_reader *ivr,
 2052                              int flag)
 2053 {
 2054     /* Source must be "imported_iso" */
 2055     if (!(ivr->flags & 1))
 2056         return 0;
 2057 
 2058     /* It must not be a new ISO */
 2059     if (!target->opts->appendable)
 2060         return 0;
 2061 
 2062     /* --- From here on return either 1 or <0 --- */
 2063 
 2064     /* multi-session write offset must be larger than interval end */
 2065     if (target->opts->ms_block <= ivr->end_byte / BLOCK_SIZE)
 2066         return ISO_MULTI_OVER_IMPORTED;
 2067 
 2068     return 1;
 2069 }
 2070 
 2071 
 2072 int iso_interval_reader_start_size(Ecma119Image *t, char *path,
 2073                                    off_t *start_byte, off_t *byte_count,
 2074                                    int flag)
 2075 {
 2076     struct iso_interval_reader *ivr;
 2077     int keep, ret;
 2078 
 2079     ret = iso_interval_reader_new(t->image, path, &ivr, byte_count, 0);
 2080     if (ret < 0)
 2081         return ret;
 2082     *start_byte = ivr->start_byte;
 2083     keep = iso_interval_reader_keep(t, ivr, 0);
 2084     if (keep < 0)
 2085         return(keep);
 2086     iso_interval_reader_destroy(&ivr, 0);
 2087     return ISO_SUCCESS + (keep > 0);
 2088 }
 2089 
 2090 
 2091 int iso_write_partition_file(Ecma119Image *target, char *path,
 2092                              uint32_t prepad, uint32_t blocks, int flag)
 2093 {
 2094 
 2095     struct iso_interval_reader *ivr = NULL;
 2096     int buf_fill;
 2097     off_t byte_count;
 2098     FILE *fp = NULL;
 2099 
 2100     uint32_t i;
 2101     uint8_t *buf = NULL;
 2102     int ret;
 2103 
 2104     LIBISO_ALLOC_MEM(buf, uint8_t, BLOCK_SIZE);
 2105     for (i = 0; i < prepad; i++) {
 2106         ret = iso_write(target, buf, BLOCK_SIZE);
 2107         if (ret < 0)
 2108             goto ex;
 2109     }
 2110 
 2111     if (flag & 1) {
 2112         ret = iso_interval_reader_new(target->image, path,
 2113                                       &ivr, &byte_count, 0);
 2114         if (ret < 0)
 2115             goto ex;
 2116         ret = iso_interval_reader_keep(target, ivr, 0);
 2117         if (ret < 0)
 2118             goto ex;
 2119         if (ret > 0) {
 2120             /* From imported_iso and for add-on session. Leave it in place. */
 2121             ret = ISO_SUCCESS;
 2122             goto ex;
 2123         }
 2124         for (i = 0; i < blocks; i++) {
 2125             ret = iso_interval_reader_read(ivr, buf, &buf_fill, 0);
 2126             if (ret < 0)
 2127                 goto ex;
 2128             ret = iso_write(target, buf, BLOCK_SIZE);
 2129             if (ret < 0)
 2130                 goto ex;
 2131         }
 2132     } else {
 2133         fp = fopen(path, "rb");
 2134         if (fp == NULL)
 2135             {ret = ISO_BAD_PARTITION_FILE; goto ex;}
 2136 
 2137         for (i = 0; i < blocks; i++) {
 2138             memset(buf, 0, BLOCK_SIZE);
 2139             if (fp != NULL) {
 2140                 ret = fread(buf, 1, BLOCK_SIZE, fp);
 2141                 if (ret != BLOCK_SIZE) {
 2142                     fclose(fp);
 2143                     fp = NULL;
 2144                 }
 2145             }
 2146             ret = iso_write(target, buf, BLOCK_SIZE);
 2147             if (ret < 0) {
 2148                 if (fp != NULL)
 2149                     fclose(fp);
 2150                 goto ex;
 2151             }
 2152         }
 2153         if (fp != NULL) 
 2154             fclose(fp);
 2155     }
 2156     ret = ISO_SUCCESS;
 2157 ex:;
 2158     iso_interval_reader_destroy(&ivr, 0);
 2159     LIBISO_FREE_MEM(buf);
 2160     return ret;
 2161 }
 2162 
 2163 
 2164 void issue_ucs2_warning_summary(size_t failures)
 2165 {
 2166     if (failures > ISO_JOLIET_UCS2_WARN_MAX) {
 2167         iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
 2168                        "More filenames found which were not suitable for Joliet character set UCS-2");
 2169     }
 2170     if (failures > 0) {
 2171         iso_msg_submit(-1, ISO_NAME_NOT_UCS2, 0,
 2172            "Sum of filenames not suitable for Joliet character set UCS-2: %.f",
 2173                        (double) failures);
 2174     }
 2175 }
 2176 
 2177 
 2178 static
 2179 void *write_function(void *arg)
 2180 {
 2181     int res, i;
 2182 #ifndef Libisofs_appended_partitions_inlinE
 2183     int first_partition = 1, last_partition = 0;
 2184 #endif
 2185     IsoImageWriter *writer;
 2186 
 2187     Ecma119Image *target = (Ecma119Image*)arg;
 2188     iso_msg_debug(target->image->id, "Starting image writing...");
 2189 
 2190     target->bytes_written = (off_t) 0;
 2191     target->percent_written = 0;
 2192 
 2193     res = write_head_part(target, 0);
 2194     if (res < 0)
 2195         goto write_error;
 2196 
 2197     /* write data for each writer */
 2198     for (i = 0; i < (int) target->nwriters; ++i) {
 2199         writer = target->writers[i];
 2200         if (target->gpt_backup_outside &&
 2201             writer->write_vol_desc == gpt_tail_writer_write_vol_desc)
 2202     continue;
 2203         res = writer->write_data(writer);
 2204         if (res < 0) {
 2205             goto write_error;
 2206         }
 2207     }
 2208 
 2209 #ifndef Libisofs_appended_partitions_inlinE
 2210 
 2211     /* Append partition data */
 2212     iso_count_appended_partitions(target, &first_partition, &last_partition);
 2213     for (i = first_partition - 1; i <= last_partition - 1; i++) {
 2214         if (target->opts->appended_partitions[i] == NULL)
 2215     continue;
 2216         if (target->opts->appended_partitions[i][0] == 0)
 2217     continue;
 2218         res = iso_write_partition_file(target,
 2219                                      target->opts->appended_partitions[i],
 2220                                      target->appended_part_prepad[i],
 2221                                      target->appended_part_size[i],
 2222                                      target->opts->appended_part_flags[i] & 1);
 2223         if (res < 0)
 2224             goto write_error;
 2225     }
 2226 
 2227 #endif /* ! Libisofs_appended_partitions_inlinE */
 2228 
 2229     if (target->gpt_backup_outside) {
 2230         for (i = 0; i < (int) target->nwriters; ++i) {
 2231             writer = target->writers[i];
 2232             if (writer->write_vol_desc != gpt_tail_writer_write_vol_desc)
 2233         continue;
 2234             res = writer->write_data(writer);
 2235             if (res < 0)
 2236                 goto write_error;
 2237         }
 2238     }
 2239 
 2240     /* Transplant checksum buffer from Ecma119Image to IsoImage */
 2241     transplant_checksum_buffer(target, 0);
 2242 
 2243     iso_ring_buffer_writer_close(target->buffer, 0);
 2244 
 2245     res = finish_libjte(target);
 2246     if (res <= 0)
 2247         goto write_error;
 2248 
 2249     issue_ucs2_warning_summary(target->joliet_ucs2_failures);
 2250 
 2251     target->image->generator_is_running = 0;
 2252 
 2253     /* Give up reference claim made in ecma119_image_new().
 2254        Eventually free target */
 2255     ecma119_image_free(target);
 2256 
 2257     if (target->tree_end_block == 1) {
 2258         iso_msgs_submit(0,
 2259  "Image is most likely damaged. Calculated/written tree end address mismatch.",
 2260                         0, "FATAL", 0);
 2261     }
 2262     if (target->bytes_written != target->total_size) {
 2263         iso_msg_debug(target->image->id,
 2264                  "bytes_written = %.f <-> total_size = %.f",
 2265                  (double) target->bytes_written, (double) target->total_size);
 2266         iso_msgs_submit(0,
 2267 "Image is most likely damaged. Calculated/written image end address mismatch.",
 2268                         0, "FATAL", 0);
 2269     }
 2270 
 2271 #ifdef Libisofs_with_pthread_exiT
 2272     pthread_exit(NULL);
 2273 #else
 2274     return NULL;
 2275 #endif
 2276 
 2277 write_error: ;
 2278     if (res != (int) ISO_LIBJTE_END_FAILED)
 2279         finish_libjte(target);
 2280     target->eff_partition_offset = 0;
 2281     if (res == (int) ISO_CANCELED) {
 2282         /* canceled */
 2283         if (!target->opts->will_cancel)
 2284             iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED,
 2285                            0, NULL);
 2286     } else {
 2287         /* image write error */
 2288         iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
 2289                    "Image write error");
 2290     }
 2291     iso_ring_buffer_writer_close(target->buffer, 1);
 2292 
 2293     /* Re-activate recorded cx xinfo */
 2294     process_preserved_cx(target->image->root, 1);
 2295     
 2296     target->image->generator_is_running = 0;
 2297 
 2298     /* Give up reference claim made in ecma119_image_new().
 2299        Eventually free target */
 2300     ecma119_image_free(target);
 2301 
 2302 #ifdef Libisofs_with_pthread_exiT
 2303     pthread_exit(NULL);
 2304 #else
 2305     return NULL;
 2306 #endif
 2307 
 2308 }
 2309 
 2310 
 2311 static
 2312 int checksum_prepare_image(IsoImage *src, int flag)
 2313 {
 2314     int ret;
 2315 
 2316     /* Set provisory value of isofs.ca with
 2317        4 byte LBA, 4 byte count, size 16, name MD5 */
 2318     ret = iso_root_set_isofsca((IsoNode *) src->root, 0, 0, 0, 16, "MD5", 0);
 2319     if (ret < 0)
 2320         return ret;
 2321     return ISO_SUCCESS;
 2322 }
 2323 
 2324 
 2325 /*
 2326   @flag bit0= recursion
 2327 */
 2328 static
 2329 int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag)
 2330 {
 2331     IsoNode *pos;
 2332     IsoFile *file;
 2333     IsoImage *img;
 2334     int ret, i, no_md5 = 0, has_xinfo = 0, has_attr = 0;
 2335     size_t old_cx_value_length = 0;
 2336     unsigned int idx = 0;
 2337     char *old_cx_value= NULL;
 2338     void *xipt = NULL;
 2339 
 2340     img= target->image;
 2341 
 2342     if (node->type == LIBISO_FILE) {
 2343         file = (IsoFile *) node;
 2344         if (file->from_old_session) {
 2345             /* Record attribute isofs.cx as xinfo before it can get overwritten
 2346                for the emerging image.
 2347                The recorded index will be used to retrieve the loaded MD5
 2348                and it will be brought back into effect if cancellation of
 2349                image production prevents that the old MD5 array gets replaced
 2350                by the new one.
 2351             */
 2352             has_attr = iso_node_lookup_attr(node, "isofs.cx",
 2353                                        &old_cx_value_length, &old_cx_value, 0);
 2354             if (has_attr == 1 && old_cx_value_length == 4) {
 2355                 for (i = 0; i < 4; i++)
 2356                     idx = (idx << 8) | ((unsigned char *) old_cx_value)[i];
 2357                 if (idx > 0 && idx < 0x8000000) {
 2358                     /* xipt is an int disguised as void pointer */
 2359                     for (i = 0; i < 4; i++)
 2360                         ((char *) &xipt)[i] = old_cx_value[i];
 2361                     ret = iso_node_add_xinfo(node, checksum_cx_xinfo_func,
 2362                                              xipt);
 2363                     if (ret < 0)
 2364                         goto ex;
 2365                 } else
 2366                     no_md5 = 1;
 2367             }
 2368         }
 2369         if (file->from_old_session && target->opts->appendable) {
 2370             /* Save MD5 data of files from old image which will not
 2371                be copied and have an MD5 recorded in the old image. */
 2372             has_xinfo = iso_node_get_xinfo(node, checksum_md5_xinfo_func,
 2373                                            &xipt);
 2374             if (has_xinfo > 0) {
 2375                 /* xinfo MD5 overrides everything else unless data get copied
 2376                    and checksummed during that copying
 2377                  */;
 2378             } else if (has_attr == 1 && img->checksum_array == NULL) {
 2379                 /* No checksum array loaded. Delete "isofs.cx" */
 2380                 if (!target->opts->will_cancel)
 2381                   iso_file_set_isofscx((IsoFile *) node, 0, 1);
 2382                 no_md5 = 1;
 2383             } else if (!(has_attr == 1 && old_cx_value_length == 4)) {
 2384                 no_md5 = 1;
 2385             }
 2386         }
 2387 
 2388         /* Equip nodes with provisory isofs.cx numbers: 4 byte, all 0.
 2389            Omit those from old image which will not be copied and have no MD5.
 2390            Do not alter the nodes if this is only a will_cancel run.
 2391          */
 2392         if (!(target->opts->will_cancel || no_md5)) {
 2393             /* Record provisory new index */
 2394             ret = iso_file_set_isofscx(file, (unsigned int) 0, 0);
 2395             if (ret < 0)
 2396                 goto ex;
 2397         }
 2398     } else if (node->type == LIBISO_DIR) {
 2399         for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
 2400             ret = checksum_prepare_nodes(target, pos, 1);
 2401             if (ret < 0)
 2402                 goto ex;
 2403         }
 2404     }
 2405     ret = ISO_SUCCESS;
 2406 ex:;
 2407     if (old_cx_value != NULL)
 2408         free(old_cx_value);
 2409     return ret;
 2410 }
 2411 
 2412 /* Determine the alleged time of image production by predicting the volume
 2413    creation and modification timestamps and taking the maximum of both.
 2414 */
 2415 static
 2416 void ecma119_determine_now_time(Ecma119Image *target)
 2417 {
 2418     IsoWriteOpts *o;
 2419     time_t now = 0, t, t0;
 2420     uint8_t time_text[18];
 2421     int i;
 2422 
 2423     iso_nowtime(&t0, 0);
 2424     o = target->opts;
 2425     if (o->vol_uuid[0]) {
 2426         for(i = 0; i < 16; i++)
 2427             if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
 2428         break;
 2429             else
 2430                 time_text[i] = o->vol_uuid[i];
 2431         for(; i < 16; i++)
 2432             time_text[i] = '1';
 2433         time_text[16] = time_text[17] = 0;
 2434         t = iso_datetime_read_17(time_text);
 2435         if (t > now)
 2436             now = t;
 2437     } else {
 2438         if (o->vol_creation_time > 0) {
 2439             if (o->vol_creation_time > now)
 2440                 now = o->vol_creation_time;
 2441         } else if (t0 > now) {
 2442             now = t0;
 2443         }
 2444         if (o->vol_modification_time > 0) {
 2445             if (o->vol_modification_time > now)
 2446                 now = o->vol_modification_time;
 2447         } else if (t0 > now) {
 2448             now = t0;
 2449         }
 2450     } 
 2451     target->now = now;
 2452 }
 2453 
 2454 static
 2455 int gpt_disk_guid_setup(Ecma119Image *target)
 2456 {
 2457     if (target->opts->gpt_disk_guid_mode == 0) {
 2458         /* Random UUID production delayed until really needed */
 2459         return ISO_SUCCESS;
 2460     } else if (target->opts->gpt_disk_guid_mode == 1) {
 2461         memcpy(target->gpt_uuid_base, target->opts->gpt_disk_guid, 16);
 2462     } else if (target->opts->gpt_disk_guid_mode == 2) {
 2463         if (target->opts->vol_uuid[0] == 0)
 2464             return ISO_GPT_NO_VOL_UUID;
 2465         /* Move centi-seconds part to byte 9 and 10 */
 2466         memcpy(target->gpt_uuid_base, target->opts->vol_uuid, 9);
 2467         memcpy(target->gpt_uuid_base + 9, target->opts->vol_uuid + 14, 2);
 2468         memcpy(target->gpt_uuid_base + 11, target->opts->vol_uuid + 9, 5);
 2469         iso_mark_guid_version_4(target->gpt_uuid_base);
 2470     } else {
 2471         return ISO_BAD_GPT_GUID_MODE;
 2472     }
 2473     memcpy(target->gpt_disk_guid, target->gpt_uuid_base, 16);
 2474     target->gpt_disk_guid_set = 1;
 2475     target->gpt_uuid_counter = 1;
 2476     return ISO_SUCCESS;
 2477 }
 2478 
 2479 static
 2480 int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
 2481 {
 2482     int ret, i, voldesc_size, nwriters, tag_pos;
 2483     int sa_type;
 2484     Ecma119Image *target;
 2485     IsoWriteOpts *opts;
 2486     IsoImageWriter *writer;
 2487     int file_src_writer_index = -1;
 2488     int system_area_options = 0;
 2489     char *system_area = NULL;
 2490     int write_count = 0, write_count_mem;
 2491     uint32_t vol_space_size_mem;
 2492     off_t total_size_mem;
 2493 
 2494 #ifdef Libisofs_appended_partitions_inlinE
 2495     int fap, lap, app_part_count;
 2496 #endif
 2497 
 2498     /* 1. Allocate target and attach a copy of in_opts there */
 2499     target = calloc(1, sizeof(Ecma119Image));
 2500     if (target == NULL) {
 2501         return ISO_OUT_OF_MEM;
 2502     }
 2503     /* This reference will be transferred to the burn_source and released by
 2504        bs_free_data.
 2505     */
 2506     target->refcount = 1;
 2507     target->opts = NULL;
 2508 
 2509     /* Record a copy of in_opts.
 2510        It is a copy because in_opts is prone to manipulations from the
 2511        application thread while the image production thread is running.
 2512     */ 
 2513     ret = iso_write_opts_clone(in_opts, &(target->opts), 0);
 2514     if (ret != ISO_SUCCESS)
 2515         goto target_cleanup;
 2516     opts = target->opts;
 2517 
 2518     /* create the tree for file caching */
 2519     ret = iso_rbtree_new(iso_file_src_cmp, &(target->files));
 2520     if (ret < 0) {
 2521         goto target_cleanup;
 2522     }
 2523     target->ecma119_hidden_list = NULL;
 2524 
 2525     target->image = src;
 2526     iso_image_ref(src);
 2527 
 2528     target->rr_reloc_node = NULL;
 2529 
 2530     target->replace_uid = opts->replace_uid ? 1 : 0;
 2531     target->replace_gid = opts->replace_gid ? 1 : 0;
 2532     target->replace_dir_mode = opts->replace_dir_mode ? 1 : 0;
 2533     target->replace_file_mode = opts->replace_file_mode ? 1 : 0;
 2534 
 2535     target->uid = opts->replace_uid == 2 ? opts->uid : 0;
 2536     target->gid = opts->replace_gid == 2 ? opts->gid : 0;
 2537     target->dir_mode = opts->replace_dir_mode == 2 ? opts->dir_mode : 0555;
 2538     target->file_mode = opts->replace_file_mode == 2 ? opts->file_mode : 0444;
 2539 
 2540     ecma119_determine_now_time(target);
 2541 
 2542     target->replace_timestamps = opts->replace_timestamps ? 1 : 0;
 2543     target->timestamp = opts->replace_timestamps == 2 ?
 2544                         opts->timestamp : target->now;
 2545 
 2546     /* el-torito? */
 2547     target->eltorito = (src->bootcat == NULL ? 0 : 1);
 2548     target->catalog = src->bootcat;
 2549     if (target->catalog != NULL) {
 2550         target->num_bootsrc = target->catalog->num_bootimages;
 2551         target->bootsrc = calloc(target->num_bootsrc + 1,
 2552                                     sizeof(IsoFileSrc *));
 2553         target->boot_appended_idx = calloc(target->num_bootsrc + 1,
 2554                                            sizeof(int));
 2555         target->boot_intvl_start = calloc(target->num_bootsrc + 1,
 2556                                              sizeof(uint32_t));
 2557         target->boot_intvl_size = calloc(target->num_bootsrc + 1,
 2558                                             sizeof(uint32_t));
 2559         if (target->bootsrc == NULL || target->boot_appended_idx == NULL ||
 2560             target->boot_intvl_start == NULL ||
 2561             target->boot_intvl_size == NULL) {
 2562             ret = ISO_OUT_OF_MEM;
 2563             goto target_cleanup;
 2564         }
 2565         for (i= 0; i < target->num_bootsrc; i++) {
 2566             target->bootsrc[i] = NULL;
 2567             target->boot_appended_idx[i] = -1;
 2568             target->boot_intvl_start[i] = 0;
 2569             target->boot_intvl_size[i] = 0;
 2570         }
 2571         /* It is not easy to predict when the node gets created and can be
 2572            manipulated. So it is better for reproducibility to derive its
 2573            timestamps from the well controllable now-time.
 2574         */
 2575         if (target->catalog->node != NULL) {
 2576             iso_node_set_mtime((IsoNode *) target->catalog->node, target->now);
 2577             iso_node_set_atime((IsoNode *) target->catalog->node, target->now);
 2578             iso_node_set_ctime((IsoNode *) target->catalog->node, target->now);
 2579         }
 2580 
 2581     } else {
 2582         target->num_bootsrc = 0;
 2583         target->bootsrc = NULL;
 2584     }
 2585 
 2586     if (opts->system_area_data != NULL) {
 2587         system_area = opts->system_area_data;
 2588         system_area_options = opts->system_area_options;
 2589     } else if (src->system_area_data != NULL) {
 2590         system_area = src->system_area_data;
 2591         system_area_options = src->system_area_options;
 2592     } else {
 2593         system_area_options = opts->system_area_options & 0xfffffffd;
 2594     }
 2595     sa_type = (system_area_options >> 2) & 0x3f;
 2596     if (sa_type != 0 && sa_type != 3)
 2597         for (i = 0; i < ISO_MAX_PARTITIONS; i++)
 2598             if (opts->appended_partitions[i] != NULL) {
 2599                 ret = ISO_NON_MBR_SYS_AREA;
 2600                 goto target_cleanup;
 2601             }
 2602     if (sa_type != 0 && opts->prep_partition != NULL) {
 2603         ret = ISO_NON_MBR_SYS_AREA;
 2604         goto target_cleanup;
 2605     }
 2606 
 2607     target->system_area_data = NULL;
 2608     if (system_area != NULL) {
 2609         target->system_area_data = calloc(32768, 1);
 2610         if (target->system_area_data == NULL) {
 2611             ret = ISO_OUT_OF_MEM;
 2612             goto target_cleanup;
 2613         }
 2614         memcpy(target->system_area_data, system_area, 32768);
 2615     }
 2616     target->system_area_options = system_area_options;
 2617 
 2618     target->partition_secs_per_head = opts->partition_secs_per_head;
 2619     target->partition_heads_per_cyl = opts->partition_heads_per_cyl;
 2620     if (target->partition_secs_per_head == 0)
 2621         target->partition_secs_per_head = 32;
 2622     if (target->partition_heads_per_cyl == 0)
 2623         target->partition_heads_per_cyl = 64;
 2624     target->eff_partition_offset = 0;
 2625     target->partition_root = NULL;
 2626     target->partition_l_table_pos = 0;
 2627     target->partition_m_table_pos = 0;
 2628     target->j_part_root = NULL;
 2629     target->j_part_l_path_table_pos = 0;
 2630     target->j_part_m_path_table_pos = 0;
 2631     target->input_charset = strdup(iso_get_local_charset(0));
 2632     if (target->input_charset == NULL) {
 2633         ret = ISO_OUT_OF_MEM;
 2634         goto target_cleanup;
 2635     }
 2636 
 2637     if (opts->output_charset != NULL) {
 2638         target->output_charset = strdup(opts->output_charset);
 2639     } else {
 2640         target->output_charset = strdup(target->input_charset);
 2641     }
 2642     if (target->output_charset == NULL) {
 2643         ret = ISO_OUT_OF_MEM;
 2644         goto target_cleanup;
 2645     }
 2646 
 2647     target->total_size = 0;
 2648     target->vol_space_size = 0;
 2649     target->pvd_size_is_total_size = 0;
 2650 
 2651     target->checksum_idx_counter = 0;
 2652     target->checksum_ctx = NULL;
 2653     target->checksum_counter = 0;
 2654     target->checksum_rlsb_tag_pos = 0;
 2655     target->checksum_sb_tag_pos = 0;
 2656     target->checksum_tree_tag_pos = 0;
 2657     target->checksum_tag_pos = 0;
 2658     target->checksum_buffer = NULL;
 2659     target->checksum_array_pos = 0;
 2660     target->checksum_range_start = 0;
 2661     target->checksum_range_size = 0;
 2662     target->opts_overwrite = NULL;
 2663 
 2664 #ifdef Libisofs_with_libjtE
 2665 
 2666     /* Eventually start Jigdo Template Extraction */
 2667     if (opts->libjte_handle != NULL) {
 2668         ret = libjte_write_header(opts->libjte_handle);
 2669         if (ret <= 0) {
 2670             iso_libjte_forward_msgs(opts->libjte_handle, 
 2671                                 target->image->id, ISO_LIBJTE_START_FAILED, 0);
 2672             ret = ISO_LIBJTE_START_FAILED;
 2673             goto target_cleanup;
 2674         }
 2675     }
 2676     
 2677 #endif /* Libisofs_with_libjtE */
 2678 
 2679     target->mipsel_e_entry = 0;
 2680     target->mipsel_p_offset = 0;
 2681     target->mipsel_p_vaddr = 0;
 2682     target->mipsel_p_filesz = 0;
 2683 
 2684     target->sparc_core_src = NULL;
 2685 
 2686     target->empty_file_block = 0;
 2687     target->tree_end_block = 0;
 2688 
 2689     target->wthread_is_running = 0;
 2690 
 2691     target->part_align_blocks = 0;
 2692     target->alignment_end_block = 0;
 2693     target->post_iso_part_pad = 0;
 2694     target->prep_part_size = 0;
 2695     target->efi_boot_part_size = 0;
 2696     target->efi_boot_part_filesrc = NULL;
 2697     for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
 2698         target->appended_part_prepad[i] = 0;
 2699         target->appended_part_start[i] = target->appended_part_size[i] = 0;
 2700     }
 2701     target->have_appended_partitions = 0;
 2702     for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++) {
 2703         target->hfsplus_blessed[i] = src->hfsplus_blessed[i];
 2704         if (target->hfsplus_blessed[i] != NULL)
 2705             iso_node_ref(target->hfsplus_blessed[i]);
 2706     }
 2707     target->hfsp_cat_node_size = 0;
 2708     target->hfsp_iso_block_fac = 0;
 2709     target->hfsp_collision_count = 0;
 2710     iso_setup_hfsplus_block_size(target);
 2711     target->apm_req_count = 0;
 2712     target->apm_req_flags = 0;
 2713     for (i = 0; i < ISO_APM_ENTRIES_MAX; i++)
 2714         target->apm_req[i] = NULL;
 2715     for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++)
 2716         target->mbr_req[i] = NULL;
 2717     target->mbr_req_count = 0;
 2718     for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++)
 2719         target->gpt_req[i] = NULL;
 2720     target->gpt_req_count = 0;
 2721     target->gpt_req_flags = 0;
 2722     target->gpt_backup_outside = 0;
 2723     memset(target->gpt_uuid_base, 0, 16);
 2724     target->gpt_uuid_counter = 0;
 2725     target->gpt_disk_guid_set = 0;
 2726     ret = gpt_disk_guid_setup(target);
 2727     if (ret < 0)
 2728         goto target_cleanup;
 2729     target->gpt_part_start = 0;
 2730     target->gpt_backup_end = 0;
 2731     target->gpt_backup_size = 0;
 2732     target->gpt_max_entries = 0;
 2733     target->gpt_is_computed = 0;
 2734 
 2735     target->sys_area_already_written = 0;
 2736 
 2737     target->filesrc_start = 0;
 2738     target->filesrc_blocks = 0;
 2739 
 2740     target->joliet_ucs2_failures = 0;
 2741 
 2742     /* If partitions get appended, then the backup GPT cannot be part of
 2743        the ISO filesystem.
 2744     */
 2745     for (i = 0; i < ISO_MAX_PARTITIONS; i++)
 2746        if (target->opts->appended_partitions[i] != NULL) {
 2747            target->gpt_backup_outside = 1;
 2748            target->have_appended_partitions = 1;
 2749     break;
 2750        }
 2751 
 2752     ret = iso_root_set_isofsnt((IsoNode *) (src->root),
 2753                                (uint32_t) src->truncate_mode,
 2754                                (uint32_t) src->truncate_length, 0);
 2755     if (ret < 0)
 2756        goto target_cleanup;
 2757 
 2758     /*
 2759      * 2. Based on those options, create needed writers: iso, joliet...
 2760      * Each writer inits its structures and stores needed info into
 2761      * target.
 2762      * If the writer needs an volume descriptor, it increments image
 2763      * current block.
 2764      * Finally, create Writer for files.
 2765      */
 2766     target->curblock = opts->ms_block + 16;
 2767 
 2768     if (opts->overwrite != NULL && opts->ms_block != 0 &&
 2769         opts->ms_block < opts->partition_offset + 32) {
 2770         /* Not enough room for superblock relocation */
 2771         ret = ISO_OVWRT_MS_TOO_SMALL;
 2772         goto target_cleanup;
 2773     }
 2774 
 2775     /* the number of writers is dependent of the extensions */
 2776     nwriters = 1 + 1 + 1; /* ECMA-119 + multi-session padding + files */
 2777 
 2778     if (target->eltorito) {
 2779         nwriters++;
 2780     }
 2781     if (opts->joliet) {
 2782         nwriters++;
 2783     }
 2784     if (opts->iso1999) {
 2785         nwriters++;
 2786     }
 2787     nwriters++; /* Partition Prepend writer */
 2788     if (opts->hfsplus || opts->fat) {
 2789         nwriters+= 2;
 2790     }
 2791 
 2792 #ifdef Libisofs_part_align_writeR
 2793 
 2794     nwriters++; /* part_align_blocks writer */
 2795 
 2796 #endif
 2797 
 2798 #ifdef Libisofs_appended_partitions_inlinE
 2799 
 2800     nwriters++; /* Inline Partition Append Writer */
 2801 
 2802 #endif
 2803 
 2804     nwriters++; /* GPT backup tail writer */
 2805     nwriters++; /* Tail padding writer */
 2806     if ((opts->md5_file_checksums & 1) || opts->md5_session_checksum) {
 2807         nwriters++;
 2808         ret = checksum_prepare_image(src, 0);
 2809         if (ret < 0)
 2810             goto target_cleanup;
 2811         if (opts->appendable) {
 2812             ret = checksum_prepare_nodes(target, (IsoNode *) src->root, 0);
 2813             if (ret < 0)
 2814                 goto target_cleanup;
 2815         }
 2816         target->checksum_idx_counter = 0;
 2817     }
 2818 
 2819     target->writers = malloc(nwriters * sizeof(void*));
 2820     if (target->writers == NULL) {
 2821         ret = ISO_OUT_OF_MEM;
 2822         goto target_cleanup;
 2823     }
 2824 
 2825     /* create writer for ECMA-119 structure */
 2826     ret = ecma119_writer_create(target);
 2827     if (ret < 0) {
 2828         goto target_cleanup;
 2829     }
 2830 
 2831     /* create writer for El-Torito */
 2832     if (target->eltorito) {
 2833         ret = eltorito_writer_create(target);
 2834         if (ret < 0) {
 2835             goto target_cleanup;
 2836         }
 2837     }
 2838 
 2839     /* create writer for Joliet structure */
 2840     if (opts->joliet) {
 2841         ret = joliet_writer_create(target);
 2842         if (ret < 0) {
 2843             goto target_cleanup;
 2844         }
 2845     }
 2846 
 2847     /* create writer for ISO 9660:1999 structure */
 2848     if (opts->iso1999) {
 2849         ret = iso1999_writer_create(target);
 2850         if (ret < 0) {
 2851             goto target_cleanup;
 2852         }
 2853     }
 2854 
 2855     voldesc_size = target->curblock - opts->ms_block - 16;
 2856 
 2857     /* Volume Descriptor Set Terminator */
 2858     target->curblock++;
 2859 
 2860     /* All empty files point to the Volume Descriptor Set Terminator
 2861      * rather than to addresses of non-empty files.
 2862      */
 2863     target->empty_file_block = target->curblock - 1;
 2864 
 2865     /*
 2866      * Create the writer for possible padding to ensure that in case of image
 2867      * growing we can safely overwrite the first 64 KiB of image.
 2868      */
 2869     ret = mspad_writer_create(target);
 2870     if (ret < 0) {
 2871         goto target_cleanup;
 2872     }
 2873 
 2874     /* The writer for MBR and GPT partitions outside iso_file_src.
 2875      * If PreP or FAT are desired, it creates MBR partition entries and
 2876      * surrounding protecting partition entries.
 2877      * If EFI boot partition is desired, it creates a GPT entry for it.
 2878      */
 2879      ret = partprepend_writer_create(target);
 2880     if (ret < 0)
 2881         goto target_cleanup;
 2882 
 2883     /* create writer for HFS+/FAT structure */
 2884     /* Impotant: It must be created directly before iso_file_src_writer_create.
 2885     */
 2886     if (opts->hfsplus || opts->fat) {
 2887         ret = hfsplus_writer_create(target);
 2888         if (ret < 0) {
 2889             goto target_cleanup;
 2890         }
 2891     }
 2892 
 2893     /* create writer for file contents */
 2894     ret = iso_file_src_writer_create(target);
 2895     if (ret < 0) {
 2896         goto target_cleanup;
 2897     }
 2898     file_src_writer_index = target->nwriters - 1;
 2899 
 2900     /* create writer for HFS+ structure */
 2901     if (opts->hfsplus || opts->fat) {
 2902         ret = hfsplus_tail_writer_create(target);
 2903         if (ret < 0) {
 2904             goto target_cleanup;
 2905         }
 2906     }
 2907 
 2908 /* >>> Decide whether the GPT tail writer can be the last of all
 2909 */
 2910 #define Libisofs_gpt_writer_lasT yes
 2911 
 2912 #ifndef Libisofs_gpt_writer_lasT
 2913     /* This writer has to be added to the list after any writer which might
 2914        request production of APM or GPT partition entries by its
 2915        compute_data_blocks() method. Its compute_data_blocks() fills the gaps
 2916        in APM requests. It determines the position of primary GPT and
 2917        backup GPT. Further it reserves blocks for the backup GPT.
 2918     */
 2919     ret = gpt_tail_writer_create(target);
 2920     if (ret < 0)
 2921         goto target_cleanup;
 2922 #endif /* ! Libisofs_gpt_writer_lasT */
 2923 
 2924     if ((opts->md5_file_checksums & 1) || opts->md5_session_checksum) {
 2925         ret = checksum_writer_create(target);
 2926         if (ret < 0)
 2927             goto target_cleanup;
 2928     }
 2929 
 2930 #ifdef Libisofs_part_align_writeR
 2931 
 2932     /* Alignment padding before appended partitions */
 2933     ret = zero_writer_create(target, 0, 2);
 2934 
 2935 #else
 2936     
 2937     ret = zero_writer_create(target, opts->tail_blocks, 1);
 2938 
 2939 #endif /* ! Libisofs_part_align_writeR */
 2940 
 2941     if (ret < 0)
 2942         goto target_cleanup;
 2943 
 2944 #ifdef Libisofs_appended_partitions_inlinE
 2945 
 2946     ret = partappend_writer_create(target);
 2947     if (ret < 0) 
 2948         goto target_cleanup;
 2949 
 2950 #endif /* Libisofs_appended_partitions_inlinE */
 2951 
 2952 #ifdef Libisofs_part_align_writeR
 2953 
 2954     ret = zero_writer_create(target, opts->tail_blocks, 0);
 2955     if (ret < 0)
 2956         goto target_cleanup;
 2957 
 2958 #endif /*  Libisofs_part_align_writeR */
 2959 
 2960 #ifdef Libisofs_gpt_writer_lasT
 2961     /* This writer shall be the last one in the list of writers of valuable
 2962        data, because it protects the image on media which are seen as GPT
 2963        partitioned.
 2964        In any case it has to come after any writer which might request
 2965        production of APM or GPT partition entries by its compute_data_blocks()
 2966        method.
 2967        gpt_tail_writer_compute_data_blocks() fills the gaps in APM requests.
 2968        It determines the position of primary GPT and backup GPT.
 2969        Further it reserves blocks for the backup GPT.
 2970     */
 2971     ret = gpt_tail_writer_create(target);
 2972     if (ret < 0)
 2973         goto target_cleanup;
 2974 #endif /* Libisofs_gpt_writer_lasT */
 2975 
 2976     if (opts->partition_offset > 0) {
 2977         /* After volume descriptors and superblock tag are accounted for:
 2978            account for second volset
 2979         */
 2980         if (opts->ms_block + opts->partition_offset + 16 < target->curblock) {
 2981             /* Overflow of partition system area */
 2982             ret = ISO_PART_OFFST_TOO_SMALL;
 2983             goto target_cleanup;
 2984         }
 2985         target->curblock = opts->ms_block + opts->partition_offset + 16;
 2986 
 2987         /* Account for partition tree volume descriptors */
 2988         for (i = 0; i < (int) target->nwriters; ++i) {
 2989             /* Not all writers have an entry in the partition
 2990                volume descriptor set.
 2991             */
 2992             writer = target->writers[i];
 2993 
 2994             /* >>> TWINTREE: Enhance ISO1999 writer and add it here */
 2995 
 2996             if(writer->write_vol_desc != ecma119_writer_write_vol_desc &&
 2997                writer->write_vol_desc != joliet_writer_write_vol_desc)
 2998         continue;
 2999             target->curblock++;
 3000         }
 3001         target->curblock++; /* + Terminator */
 3002 
 3003         /* >>> TWINTREE: eventually later : second superblock checksum tag */;
 3004 
 3005     }
 3006 
 3007 
 3008     /* At least the FAT computation needs to know the size of filesrc data
 3009        in advance. So this call produces target->filesrc_blocks and
 3010        relative extent addresses, which get absolute in
 3011        filesrc_writer_compute_data_blocks().
 3012     */
 3013     ret = filesrc_writer_pre_compute(target->writers[file_src_writer_index]);
 3014     if (ret < 0)
 3015         goto target_cleanup;
 3016 
 3017     /*
 3018      * 3.
 3019      * Call compute_data_blocks() in each Writer.
 3020      * That function computes the size needed by its structures and
 3021      * increments image current block properly.
 3022      */
 3023     for (i = 0; i < (int) target->nwriters; ++i) {
 3024         IsoImageWriter *writer = target->writers[i];
 3025 
 3026         if (target->gpt_backup_outside &&
 3027             writer->write_vol_desc == gpt_tail_writer_write_vol_desc)
 3028     continue;
 3029 
 3030         /* Exposing address of data start to IsoWriteOpts and memorizing
 3031            this address for all files which have no block address: 
 3032            symbolic links, device files, empty data files.
 3033            filesrc_writer_compute_data_blocks() and filesrc_writer_write_data()
 3034            will account resp. write this single block. 
 3035         */
 3036         if (i == file_src_writer_index) {
 3037             if (! opts->old_empty)
 3038                 target->empty_file_block = target->curblock;
 3039             in_opts->data_start_lba = opts->data_start_lba = target->curblock;
 3040         }
 3041 
 3042         ret = writer->compute_data_blocks(writer);
 3043         if (ret < 0) {
 3044             goto target_cleanup;
 3045         }
 3046 
 3047     }
 3048 
 3049     ret = iso_patch_eltoritos(target);
 3050     if (ret < 0)
 3051         goto target_cleanup;
 3052     if (((target->system_area_options & 0xfc) >> 2) == 2) {
 3053         ret = iso_read_mipsel_elf(target, 0);
 3054         if (ret < 0)
 3055             goto target_cleanup;
 3056     }
 3057 
 3058     /*
 3059      * The volume space size is just the size of the last session, in
 3060      * case of ms images.
 3061      */
 3062 
 3063 #ifdef Libisofs_appended_partitions_inlinE
 3064 
 3065     app_part_count = iso_count_appended_partitions(target, &fap, &lap);
 3066     if (app_part_count == 0)
 3067        target->vol_space_size = target->curblock - opts->ms_block;
 3068     else
 3069        target->vol_space_size = target->alignment_end_block - opts->ms_block;
 3070 
 3071     target->total_size = (off_t) (target->curblock - opts->ms_block) *
 3072                          BLOCK_SIZE;
 3073 
 3074 #else /* Libisofs_appended_partitions_inlinE */
 3075 
 3076     target->vol_space_size = target->curblock - opts->ms_block;
 3077     target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE;
 3078 
 3079     /* Add sizes of eventually appended partitions */
 3080     ret = iso_compute_append_partitions(target, 0);
 3081     if (ret < 0)
 3082         goto target_cleanup;
 3083 
 3084 #endif /* ! Libisofs_appended_partitions_inlinE */
 3085 
 3086     if (target->gpt_backup_outside) {
 3087         for (i = 0; i < (int) target->nwriters; ++i) {
 3088             IsoImageWriter *writer = target->writers[i];
 3089 
 3090             if (writer->write_vol_desc != gpt_tail_writer_write_vol_desc)
 3091         continue;
 3092             ret = writer->compute_data_blocks(writer);
 3093             if (ret < 0)
 3094                 goto target_cleanup;
 3095         }
 3096     }
 3097 
 3098     /* create the ring buffer */
 3099     if (opts->overwrite != NULL &&
 3100         opts->fifo_size < 32 + opts->partition_offset) {
 3101         /* The ring buffer must be large enough to take opts->overwrite
 3102         */
 3103         ret = ISO_OVWRT_FIFO_TOO_SMALL;
 3104         goto target_cleanup;
 3105     }
 3106     ret = iso_ring_buffer_new(opts->fifo_size, &target->buffer);
 3107     if (ret < 0) {
 3108         goto target_cleanup;
 3109     }
 3110 
 3111     /* check if we need to provide a copy of volume descriptors */
 3112     vol_space_size_mem = target->vol_space_size;
 3113     if (opts->overwrite != NULL) {
 3114 
 3115         /* opts->overwrite must be larger by partion_offset
 3116            This storage is provided by the application.
 3117         */
 3118 
 3119 
 3120         /*
 3121          * In the PVM to be written in the 16th sector of the disc, we
 3122          * need to specify the full size.
 3123          */
 3124         target->vol_space_size += opts->ms_block;
 3125 
 3126         /* System area and volume descriptors */
 3127         target->opts_overwrite = (char *) opts->overwrite;
 3128         total_size_mem = target->total_size;
 3129         target->total_size += target->opts->ms_block * BLOCK_SIZE;
 3130         ret = write_head_part1(target, &write_count, 1 | 2);
 3131         target->opts_overwrite = NULL;
 3132         target->total_size = total_size_mem;
 3133         if (ret < 0)
 3134             goto target_cleanup;
 3135 
 3136         /* copy the volume descriptors to the overwrite buffer... */
 3137         voldesc_size *= BLOCK_SIZE;
 3138         ret = iso_ring_buffer_read(target->buffer, opts->overwrite,
 3139                                    write_count * BLOCK_SIZE);
 3140         if (ret < 0) {
 3141             iso_msg_debug(target->image->id,
 3142                           "Error reading overwrite volume descriptors");
 3143             goto target_cleanup;
 3144         }
 3145 
 3146         /* Write relocated superblock checksum tag */
 3147         tag_pos = voldesc_size / BLOCK_SIZE + 16 + 1;
 3148         if (opts->md5_session_checksum) {
 3149             target->checksum_rlsb_tag_pos = tag_pos;
 3150             if (target->checksum_rlsb_tag_pos < 32) {
 3151                 ret = iso_md5_start(&(target->checksum_ctx));
 3152                 if (ret < 0)
 3153                     goto target_cleanup;
 3154                 target->opts_overwrite = (char *) opts->overwrite;
 3155                 iso_md5_compute(target->checksum_ctx, target->opts_overwrite,
 3156                                 target->checksum_rlsb_tag_pos * 2048);
 3157                 ret = iso_md5_write_tag(target, 4);
 3158                 target->opts_overwrite = NULL; /* opts might not persist */
 3159                 if (ret < 0)
 3160                     goto target_cleanup;
 3161             }
 3162             tag_pos++;
 3163             write_count++;
 3164         } 
 3165 
 3166         /* Clean out eventual obsolete checksum tags */
 3167         for (i = tag_pos; i < 32; i++) {
 3168             int tag_type;
 3169             uint32_t pos, range_start, range_size, next_tag;
 3170             char md5[16];
 3171     
 3172             ret = iso_util_decode_md5_tag((char *)(opts->overwrite + i * 2048),
 3173                                           &tag_type, &pos, &range_start,
 3174                                           &range_size, &next_tag, md5, 0);
 3175             if (ret > 0)
 3176                 opts->overwrite[i * 2048] = 0;
 3177         }
 3178 
 3179         /* Write second set of volume descriptors */
 3180         write_count_mem= write_count;
 3181         ret = write_head_part2(target, &write_count, 0);
 3182         if (ret < 0)
 3183             goto target_cleanup;
 3184 
 3185         /* Read written data into opts->overwrite */
 3186         ret = iso_ring_buffer_read(target->buffer,
 3187                                 opts->overwrite + write_count_mem * BLOCK_SIZE,
 3188                                 (write_count - write_count_mem) * BLOCK_SIZE);
 3189         if (ret < 0) {
 3190             iso_msg_debug(target->image->id,
 3191                           "Error reading overwrite volume descriptors");
 3192             goto target_cleanup;
 3193         }
 3194 
 3195         /* Delete the filler partitions of GPT and APM so that write_function()
 3196            can insert new ones for a possibly different total_size */;
 3197         iso_delete_gpt_apm_fillers(target, 0);
 3198     }
 3199 
 3200     /* This was possibly altered by above overwrite buffer production */
 3201     target->vol_space_size = vol_space_size_mem;
 3202 
 3203 /*
 3204 */
 3205 #define Libisofs_print_size_no_forK 1
 3206 
 3207 #ifdef Libisofs_print_size_no_forK
 3208     if (opts->will_cancel) {
 3209         iso_msg_debug(target->image->id,
 3210       "Will not start write thread because of iso_write_opts_set_will_cancel");
 3211         *img = target;
 3212         return ISO_SUCCESS;
 3213     }
 3214 #endif
 3215 
 3216 
 3217     /* 4. Create and start writing thread */
 3218     if (opts->md5_session_checksum) {
 3219         /* After any fake writes are done: Initialize image checksum context */
 3220         if (target->checksum_ctx != NULL)
 3221             iso_md5_end(&(target->checksum_ctx), target->image_md5);
 3222         ret = iso_md5_start(&(target->checksum_ctx));
 3223         if (ret < 0)
 3224             goto target_cleanup;
 3225     }
 3226 
 3227     if (opts->apm_block_size == 0) {
 3228         if (target->gpt_req_count)
 3229             opts->apm_block_size = 2048; /* Combinable with GPT */
 3230         else
 3231             opts->apm_block_size = 512; /* Mountable on Linux */
 3232     }
 3233 
 3234     /* ensure the thread is created joinable */
 3235     pthread_attr_init(&(target->th_attr));
 3236     pthread_attr_setdetachstate(&(target->th_attr), PTHREAD_CREATE_JOINABLE);
 3237 
 3238     /* To avoid race conditions with the caller, this mark must be set
 3239        before the thread starts. So the caller can rely on a value of 0
 3240        really meaning that the write has ended, and not that it might not have
 3241        begun yet.
 3242        In normal processing, the value will be changed to 0 at the end of
 3243        write_function().
 3244     */
 3245     target->image->generator_is_running = 1;
 3246 
 3247 
 3248     /* Claim that target may not get destroyed by bs_free_data() before
 3249        write_function() is done with it */
 3250     target->refcount++;
 3251 
 3252     ret = pthread_create(&(target->wthread), &(target->th_attr),
 3253                          write_function, (void *) target);
 3254     if (ret != 0) {
 3255         target->refcount--;
 3256         iso_msg_submit(target->image->id, ISO_THREAD_ERROR, 0,
 3257                       "Cannot create writer thread");
 3258         ret = ISO_THREAD_ERROR;
 3259         goto target_cleanup;
 3260     }
 3261     target->wthread_is_running= 1;
 3262 
 3263     /*
 3264      * Notice that once we reach this point, target belongs to the writer
 3265      * thread and should not be modified until the writer thread finished.
 3266      * There're however, specific fields in target that can be accessed, or
 3267      * even modified by the read thread (look inside bs_* functions)
 3268      */
 3269 
 3270     *img = target;
 3271     return ISO_SUCCESS;
 3272 
 3273 target_cleanup: ;
 3274     target->image->generator_is_running = 0;
 3275     ecma119_image_free(target);
 3276     return ret;
 3277 }
 3278 
 3279 static int bs_read(struct burn_source *bs, unsigned char *buf, int size)
 3280 {
 3281     int ret;
 3282     Ecma119Image *t = (Ecma119Image*)bs->data;
 3283 
 3284     ret = iso_ring_buffer_read(t->buffer, buf, size);
 3285     if (ret == ISO_SUCCESS) {
 3286         return size;
 3287     } else if (ret < 0) {
 3288         /* error */
 3289         iso_msg_submit(t->image->id, ISO_BUF_READ_ERROR, ret, NULL);
 3290         return -1;
 3291     } else {
 3292         /* EOF */
 3293         return 0;
 3294     }
 3295 }
 3296 
 3297 static off_t bs_get_size(struct burn_source *bs)
 3298 {
 3299     Ecma119Image *target = (Ecma119Image*)bs->data;
 3300     return target->total_size;
 3301 }
 3302 
 3303 static void bs_free_data(struct burn_source *bs)
 3304 {
 3305     int st;
 3306     Ecma119Image *target = (Ecma119Image*)bs->data;
 3307 
 3308     st = iso_ring_buffer_get_status(bs, NULL, NULL);
 3309 
 3310     /* was read already finished (i.e, canceled)? */
 3311     if (st < 4) {
 3312         /* forces writer to stop if it is still running */
 3313         iso_ring_buffer_reader_close(target->buffer, 0);
 3314 
 3315         /* wait until writer thread finishes */
 3316         if (target->wthread_is_running) {
 3317             pthread_join(target->wthread, NULL);
 3318             target->wthread_is_running = 0;
 3319             iso_msg_debug(target->image->id, "Writer thread joined");
 3320         }
 3321     }
 3322 
 3323     iso_msg_debug(target->image->id,
 3324                   "Ring buffer was %d times full and %d times empty",
 3325                   iso_ring_buffer_get_times_full(target->buffer),
 3326                   iso_ring_buffer_get_times_empty(target->buffer));
 3327 
 3328     /* The reference to target was inherited from ecma119_image_new() */
 3329     ecma119_image_free(target);
 3330 }
 3331 
 3332 static
 3333 int bs_cancel(struct burn_source *bs)
 3334 {
 3335     int st;
 3336     size_t cap, free;
 3337     Ecma119Image *target = (Ecma119Image*)bs->data;
 3338 
 3339     st = iso_ring_buffer_get_status(bs, &cap, &free);
 3340 
 3341     if (free == cap && (st == 2 || st == 3)) {
 3342         /* image was already consumed */
 3343         iso_ring_buffer_reader_close(target->buffer, 0);
 3344     } else {
 3345         iso_msg_debug(target->image->id, "Reader thread being cancelled");
 3346 
 3347         /* forces writer to stop if it is still running */
 3348         iso_ring_buffer_reader_close(target->buffer, ISO_CANCELED);
 3349     }
 3350 
 3351     /* wait until writer thread finishes */
 3352     if (target->wthread_is_running) {
 3353         pthread_join(target->wthread, NULL);
 3354         target->wthread_is_running = 0;
 3355         iso_msg_debug(target->image->id, "Writer thread joined");
 3356     }
 3357     return ISO_SUCCESS;
 3358 }
 3359 
 3360 static
 3361 int bs_set_size(struct burn_source *bs, off_t size)
 3362 {
 3363     Ecma119Image *target = (Ecma119Image*)bs->data;
 3364 
 3365     target->total_size = size;
 3366     return 1;
 3367 }
 3368 
 3369 static
 3370 int dive_to_depth_8(IsoDir *dir, int depth)
 3371 {
 3372     int ret;
 3373     IsoNode *pos;
 3374 
 3375     if (depth >= 8)
 3376         return 1;
 3377     pos = dir->children;
 3378     for (pos = dir->children; pos != NULL; pos = pos->next) {
 3379         if (pos->type != LIBISO_DIR)
 3380     continue;
 3381         ret = dive_to_depth_8((IsoDir *) pos, depth + 1);
 3382         if (ret != 0)
 3383             return ret;
 3384     }
 3385     return 0;
 3386 }
 3387 
 3388 static
 3389 int make_reloc_dir_if_needed(IsoImage *img, IsoWriteOpts *opts, int flag)
 3390 {
 3391     int ret;
 3392     IsoDir *dir;
 3393 
 3394     /* Two forms to express the root directory */
 3395     if (opts->rr_reloc_dir == NULL)
 3396         return 1;
 3397     if (opts->rr_reloc_dir[0] == 0)
 3398         return 1;
 3399 
 3400     if (strchr(opts->rr_reloc_dir, '/') != NULL)
 3401         return 0;
 3402 
 3403     /* Check existence of opts->rr_reloc_dir */
 3404     ret = iso_dir_get_node(img->root, opts->rr_reloc_dir, NULL);
 3405     if (ret > 0)
 3406         return 1;
 3407     if (ret < 0)
 3408         return ret;
 3409 
 3410     /* Check whether there is a directory of depth 8 (root is depth 1) */
 3411     ret = dive_to_depth_8(img->root, 1);
 3412     if (ret < 0)
 3413         return ret;
 3414     if (ret == 0)
 3415         return 1;
 3416 
 3417     /* Make IsoDir with same permissions as root directory */
 3418     ret = iso_tree_add_new_dir(img->root, opts->rr_reloc_dir, &dir);
 3419     if (ret < 0)
 3420         return ret;
 3421 
 3422     opts->rr_reloc_flags |= 2; /* Auto-created relocation directory */
 3423 
 3424     return 1;
 3425 }
 3426 
 3427 int iso_image_create_burn_source(IsoImage *image, IsoWriteOpts *opts,
 3428                                  struct burn_source **burn_src)
 3429 {
 3430     int ret;
 3431     struct burn_source *source;
 3432     Ecma119Image *target= NULL;
 3433 
 3434     if (image == NULL || opts == NULL || burn_src == NULL) {
 3435         return ISO_NULL_POINTER;
 3436     }
 3437 
 3438     source = calloc(1, sizeof(struct burn_source));
 3439     if (source == NULL) {
 3440         return ISO_OUT_OF_MEM;
 3441     }
 3442 
 3443     if (!opts->allow_deep_paths) { 
 3444         ret = make_reloc_dir_if_needed(image, opts, 0);
 3445         if (ret < 0) {
 3446             free(source);
 3447             return ret;
 3448         }
 3449     }
 3450 
 3451     ret = ecma119_image_new(image, opts, &target);
 3452     if (ret < 0) {
 3453         free(source);
 3454         return ret;
 3455     }
 3456 
 3457     source->refcount = 1;
 3458     source->version = 1;
 3459     source->read = NULL;
 3460     source->get_size = bs_get_size;
 3461     source->set_size = bs_set_size;
 3462     source->free_data = bs_free_data;
 3463     source->read_xt = bs_read;
 3464     source->cancel = bs_cancel;
 3465     source->data = target;
 3466 
 3467     *burn_src = source;
 3468     return ISO_SUCCESS;
 3469 }
 3470 
 3471 int iso_write(Ecma119Image *target, void *buf, size_t count)
 3472 {
 3473     int ret;
 3474 
 3475     if (target->bytes_written + (off_t) count > target->total_size) {
 3476         iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0,
 3477                        "ISO overwrite");
 3478         return ISO_ASSERT_FAILURE;
 3479     }
 3480 
 3481     ret = iso_ring_buffer_write(target->buffer, buf, count);
 3482     if (ret == 0) {
 3483         /* reader cancelled */
 3484         return ISO_CANCELED;
 3485     }
 3486     if (ret < 0)
 3487         return ret;
 3488     if (target->checksum_ctx != NULL) {
 3489         /* Add to image checksum */
 3490         target->checksum_counter += count;
 3491         iso_md5_compute(target->checksum_ctx, (char *) buf, (int) count);
 3492     }
 3493 
 3494     ret = show_chunk_to_jte(target, buf, count);
 3495     if (ret != ISO_SUCCESS)
 3496         return ret;
 3497 
 3498     /* total size is 0 when writing the overwrite buffer */
 3499     if (target->total_size != (off_t) 0){
 3500         unsigned int kbw, kbt;
 3501         int percent;
 3502 
 3503         target->bytes_written += (off_t) count;
 3504         kbw = (unsigned int) (target->bytes_written >> 10);
 3505         kbt = (unsigned int) (target->total_size >> 10);
 3506         percent = (kbw * 100) / kbt;
 3507 
 3508         /* only report in 5% chunks */
 3509         if (percent >= target->percent_written + 5) {
 3510             iso_msg_debug(target->image->id, "Processed %u of %u KB (%d %%)",
 3511                           kbw, kbt, percent);
 3512             target->percent_written = percent;
 3513         }
 3514     }
 3515 
 3516     return ISO_SUCCESS;
 3517 }
 3518 
 3519 int iso_write_opts_new(IsoWriteOpts **opts, int profile)
 3520 {
 3521     int i;
 3522     IsoWriteOpts *wopts;
 3523 
 3524     if (opts == NULL) {
 3525         return ISO_NULL_POINTER;
 3526     }
 3527     if (profile < 0 || profile > 2) {
 3528         return ISO_WRONG_ARG_VALUE;
 3529     }
 3530 
 3531     wopts = calloc(1, sizeof(IsoWriteOpts));
 3532     if (wopts == NULL) {
 3533         return ISO_OUT_OF_MEM;
 3534     }
 3535     wopts->scdbackup_tag_written = NULL;
 3536 
 3537     switch (profile) {
 3538     case 0:
 3539         wopts->iso_level = 1;
 3540         break;
 3541     case 1:
 3542         wopts->iso_level = 3;
 3543         wopts->rockridge = 1;
 3544         break;
 3545     case 2:
 3546         wopts->iso_level = 2;
 3547         wopts->rockridge = 1;
 3548         wopts->joliet = 1;
 3549         wopts->replace_dir_mode = 1;
 3550         wopts->replace_file_mode = 1;
 3551         wopts->replace_uid = 1;
 3552         wopts->replace_gid = 1;
 3553         wopts->replace_timestamps = 1;
 3554         wopts->always_gmt = 1;
 3555         break;
 3556     default:
 3557         /* should never happen */
 3558         free(wopts);
 3559         return ISO_ASSERT_FAILURE;
 3560         break;
 3561     }
 3562     wopts->hfsplus = 0;
 3563     wopts->fat = 0;
 3564     wopts->fifo_size = 1024; /* 2 MB buffer */
 3565     wopts->sort_files = 1; /* file sorting is always good */
 3566     wopts->joliet_utf16 = 0;
 3567     wopts->rr_reloc_dir = NULL;
 3568     wopts->rr_reloc_flags = 0;
 3569     wopts->system_area_data = NULL;
 3570     wopts->system_area_size = 0;
 3571     wopts->system_area_options = 0;
 3572     wopts->vol_creation_time = 0;
 3573     wopts->vol_modification_time = 0;
 3574     wopts->vol_expiration_time = 0;
 3575     wopts->vol_effective_time = 0;
 3576     memset(wopts->vol_uuid, 0, 17);
 3577     wopts->partition_offset = 0;
 3578     wopts->partition_secs_per_head = 0;
 3579     wopts->partition_heads_per_cyl = 0;
 3580 
 3581 #ifdef Libisofs_with_libjtE
 3582     wopts->libjte_handle = NULL;
 3583 #endif /* Libisofs_with_libjtE */
 3584 
 3585     wopts->tail_blocks = 0;
 3586     wopts->prep_partition = NULL;
 3587     wopts->prep_part_flag = 0;
 3588     wopts->efi_boot_partition = NULL;
 3589     wopts->efi_boot_part_flag = 0;
 3590     for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
 3591         wopts->appended_partitions[i] = NULL;
 3592         wopts->appended_part_types[i] = 0;
 3593         wopts->appended_part_flags[i] = 0;
 3594         memset(wopts->appended_part_type_guids[i], 0, 16);
 3595         wopts->appended_part_gpt_flags[i] = 0;
 3596     }
 3597     wopts->appended_as_gpt = 0;
 3598     wopts->appended_as_apm = 0;
 3599     wopts->part_like_isohybrid = 0;
 3600     wopts->iso_mbr_part_type = -1;
 3601     memset(wopts->iso_gpt_type_guid, 0, 16);
 3602     wopts->iso_gpt_flag= 0;
 3603     wopts->ascii_disc_label[0] = 0;
 3604     wopts->will_cancel = 0;
 3605     wopts->allow_dir_id_ext = 0;
 3606     wopts->old_empty = 0;
 3607     wopts->untranslated_name_len = 0;
 3608     for (i = 0; i < 8; i++)
 3609         wopts->hfsp_serial_number[i] = 0;
 3610     wopts->apm_block_size = 0;
 3611     wopts->hfsp_block_size = 0;
 3612     memset(wopts->gpt_disk_guid, 0, 16);
 3613     wopts->gpt_disk_guid_mode = 0;
 3614 
 3615     *opts = wopts;
 3616     return ISO_SUCCESS;
 3617 }
 3618 
 3619 int iso_write_opts_clone(IsoWriteOpts *in, IsoWriteOpts **out, int flag)
 3620 {
 3621     int ret, i;
 3622     IsoWriteOpts *o = NULL;
 3623 
 3624     ret = iso_write_opts_new(&o, 0);
 3625     if (ret != 1)
 3626         return ret;
 3627     *out = o;
 3628 
 3629     /* Provisory copy of all values and un-managed pointers */
 3630     memcpy(o, in, sizeof(IsoWriteOpts));
 3631 
 3632     /* Set managed pointers to NULL */
 3633     o->output_charset = NULL;
 3634     o->rr_reloc_dir = NULL;
 3635     o->system_area_data = NULL;
 3636     o->prep_partition = NULL;
 3637     o->efi_boot_partition = NULL;
 3638     for (i = 0; i < ISO_MAX_PARTITIONS; i++)
 3639         o->appended_partitions[i] = NULL;
 3640 
 3641     /* Clone managed objects */
 3642     if (iso_clone_mem(in->output_charset, &(o->output_charset), 0) != 1)
 3643         goto out_of_mem;
 3644     if (iso_clone_mem(in->rr_reloc_dir, &(o->rr_reloc_dir), 0) != 1)
 3645         goto out_of_mem;
 3646     if (iso_clone_mem(in->system_area_data, &(o->system_area_data),
 3647                       in->system_area_size) != 1)
 3648         goto out_of_mem;
 3649     if (iso_clone_mem(in->prep_partition, &(o->prep_partition), 0) != 1)
 3650         goto out_of_mem;
 3651     if (iso_clone_mem(in->efi_boot_partition, &(o->efi_boot_partition), 0)
 3652         != 1)
 3653         goto out_of_mem;
 3654     for (i = 0; i < ISO_MAX_PARTITIONS; i++)
 3655         if (iso_clone_mem(in->appended_partitions[i],
 3656                           &(o->appended_partitions[i]), 0) != 1)
 3657             goto out_of_mem;
 3658 
 3659     return ISO_SUCCESS;
 3660 
 3661 out_of_mem:;
 3662     iso_write_opts_free(o);
 3663     return ISO_OUT_OF_MEM;
 3664 }
 3665 
 3666 void iso_write_opts_free(IsoWriteOpts *opts)
 3667 {
 3668     int i;
 3669 
 3670     if (opts == NULL) {
 3671         return;
 3672     }
 3673     free(opts->output_charset);
 3674     if (opts->rr_reloc_dir != NULL)
 3675         free(opts->rr_reloc_dir);
 3676     if (opts->system_area_data != NULL)
 3677         free(opts->system_area_data);
 3678     if (opts->prep_partition != NULL)
 3679         free(opts->prep_partition);
 3680     if (opts->efi_boot_partition != NULL)
 3681         free(opts->efi_boot_partition);
 3682     for (i = 0; i < ISO_MAX_PARTITIONS; i++)
 3683         if (opts->appended_partitions[i] != NULL)
 3684             free(opts->appended_partitions[i]);
 3685 
 3686     free(opts);
 3687 }
 3688 
 3689 int iso_write_opts_set_will_cancel(IsoWriteOpts *opts, int will_cancel)
 3690 {
 3691     if (opts == NULL) {
 3692         return ISO_NULL_POINTER;
 3693     }
 3694     opts->will_cancel = !!will_cancel;
 3695     return ISO_SUCCESS;
 3696 }
 3697 
 3698 int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level)
 3699 {
 3700     if (opts == NULL) {
 3701         return ISO_NULL_POINTER;
 3702     }
 3703     if (level != 1 && level != 2 && level != 3) {
 3704         return ISO_WRONG_ARG_VALUE;
 3705     }
 3706     opts->iso_level = level;
 3707     return ISO_SUCCESS;
 3708 }
 3709 
 3710 int iso_write_opts_set_rockridge(IsoWriteOpts *opts, int enable)
 3711 {
 3712     if (opts == NULL) {
 3713         return ISO_NULL_POINTER;
 3714     }
 3715     opts->rockridge = enable ? 1 : 0;
 3716     return ISO_SUCCESS;
 3717 }
 3718 
 3719 int iso_write_opts_set_joliet(IsoWriteOpts *opts, int enable)
 3720 {
 3721     if (opts == NULL) {
 3722         return ISO_NULL_POINTER;
 3723     }
 3724     opts->joliet = enable ? 1 : 0;
 3725     return ISO_SUCCESS;
 3726 }
 3727 
 3728 int iso_write_opts_set_hfsplus(IsoWriteOpts *opts, int enable)
 3729 {
 3730     if (opts == NULL) {
 3731         return ISO_NULL_POINTER;
 3732     }
 3733     opts->hfsplus = enable ? 1 : 0;
 3734     return ISO_SUCCESS;
 3735 }
 3736 
 3737 int iso_write_opts_set_fat(IsoWriteOpts *opts, int enable)
 3738 {
 3739     if (opts == NULL) {
 3740         return ISO_NULL_POINTER;
 3741     }
 3742     opts->fat = enable ? 1 : 0;
 3743     return ISO_SUCCESS;
 3744 }
 3745 
 3746 int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable)
 3747 {
 3748     if (opts == NULL) {
 3749         return ISO_NULL_POINTER;
 3750     }
 3751     opts->iso1999 = enable ? 1 : 0;
 3752     return ISO_SUCCESS;
 3753 }
 3754 
 3755 int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable)
 3756 {
 3757     if (opts == NULL) {
 3758         return ISO_NULL_POINTER;
 3759     }
 3760     opts->hardlinks = enable ? 1 : 0;
 3761     return ISO_SUCCESS;
 3762 }
 3763 
 3764 int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable)
 3765 {
 3766     if (opts == NULL) {
 3767         return ISO_NULL_POINTER;
 3768     }
 3769     opts->aaip = enable ? 1 : 0;
 3770     return ISO_SUCCESS;
 3771 }
 3772 
 3773 int iso_write_opts_set_old_empty(IsoWriteOpts *opts, int enable)
 3774 {
 3775     if (opts == NULL) {
 3776         return ISO_NULL_POINTER;
 3777     }
 3778     opts->old_empty = enable ? 1 : 0;
 3779     return ISO_SUCCESS;
 3780 }
 3781 
 3782 int iso_write_opts_set_untranslated_name_len(IsoWriteOpts *opts, int len)
 3783 {
 3784     if (opts == NULL) {
 3785         return ISO_NULL_POINTER;
 3786     }
 3787     if (len == -1)
 3788         opts->untranslated_name_len = ISO_UNTRANSLATED_NAMES_MAX;
 3789     else if(len == 0)
 3790         opts->untranslated_name_len = 0;
 3791     else if(len > ISO_UNTRANSLATED_NAMES_MAX || len < 0)
 3792         return ISO_WRONG_ARG_VALUE;
 3793     else
 3794         opts->untranslated_name_len = len;
 3795     return opts->untranslated_name_len;
 3796 }
 3797 
 3798 int iso_write_opts_set_allow_dir_id_ext(IsoWriteOpts *opts, int allow)
 3799 {
 3800     if (opts == NULL) {
 3801         return ISO_NULL_POINTER;
 3802     }
 3803     opts->allow_dir_id_ext = allow ? 1 : 0;
 3804     return ISO_SUCCESS;
 3805 }
 3806 
 3807 int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit)
 3808 {
 3809     if (opts == NULL) {
 3810         return ISO_NULL_POINTER;
 3811     }
 3812     opts->omit_version_numbers = omit & 3;
 3813     return ISO_SUCCESS;
 3814 }
 3815 
 3816 int iso_write_opts_set_allow_deep_paths(IsoWriteOpts *opts, int allow)
 3817 {
 3818     if (opts == NULL) {
 3819         return ISO_NULL_POINTER;
 3820     }
 3821     opts->allow_deep_paths = allow ? 1 : 0;
 3822     return ISO_SUCCESS;
 3823 }
 3824 
 3825 int iso_write_opts_set_allow_longer_paths(IsoWriteOpts *opts, int allow)
 3826 {
 3827     if (opts == NULL) {
 3828         return ISO_NULL_POINTER;
 3829     }
 3830     opts->allow_longer_paths = allow ? 1 : 0;
 3831     return ISO_SUCCESS;
 3832 }
 3833 
 3834 int iso_write_opts_set_max_37_char_filenames(IsoWriteOpts *opts, int allow)
 3835 {
 3836     if (opts == NULL) {
 3837         return ISO_NULL_POINTER;
 3838     }
 3839     opts->max_37_char_filenames = allow ? 1 : 0;
 3840     return ISO_SUCCESS;
 3841 }
 3842 
 3843 int iso_write_opts_set_no_force_dots(IsoWriteOpts *opts, int no)
 3844 {
 3845     if (opts == NULL) {
 3846         return ISO_NULL_POINTER;
 3847     }
 3848     opts->no_force_dots = no & 3;
 3849     return ISO_SUCCESS;
 3850 }
 3851 
 3852 int iso_write_opts_set_allow_lowercase(IsoWriteOpts *opts, int allow)
 3853 {
 3854     if (opts == NULL) {
 3855         return ISO_NULL_POINTER;
 3856     }
 3857     opts->allow_lowercase = allow ? 1 : 0;
 3858     return ISO_SUCCESS;
 3859 }
 3860 
 3861 int iso_write_opts_set_allow_full_ascii(IsoWriteOpts *opts, int allow)
 3862 {
 3863     if (opts == NULL) {
 3864         return ISO_NULL_POINTER;
 3865     }
 3866     opts->allow_full_ascii = allow ? 1 : 0;
 3867     return ISO_SUCCESS;
 3868 }
 3869 
 3870 int iso_write_opts_set_allow_7bit_ascii(IsoWriteOpts *opts, int allow)
 3871 {
 3872     if (opts == NULL) {
 3873         return ISO_NULL_POINTER;
 3874     }
 3875     opts->allow_7bit_ascii = allow ? 1 : 0;
 3876     return ISO_SUCCESS;
 3877 }
 3878 
 3879 
 3880 int iso_write_opts_set_relaxed_vol_atts(IsoWriteOpts *opts, int allow)
 3881 {
 3882     if (opts == NULL) {
 3883         return ISO_NULL_POINTER;
 3884     }
 3885     opts->relaxed_vol_atts = allow ? 1 : 0;
 3886     return ISO_SUCCESS;
 3887 }
 3888 
 3889 int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow)
 3890 {
 3891     if (opts == NULL) {
 3892         return ISO_NULL_POINTER;
 3893     }
 3894     opts->joliet_longer_paths = allow ? 1 : 0;
 3895     return ISO_SUCCESS;
 3896 }
 3897 
 3898 int iso_write_opts_set_joliet_long_names(IsoWriteOpts *opts, int allow)
 3899 {
 3900     if (opts == NULL) {
 3901         return ISO_NULL_POINTER;
 3902     }
 3903     opts->joliet_long_names = allow ? 1 : 0;
 3904     return ISO_SUCCESS;
 3905 }
 3906 
 3907 int iso_write_opts_set_joliet_utf16(IsoWriteOpts *opts, int allow)
 3908 {
 3909     if (opts == NULL) {
 3910         return ISO_NULL_POINTER;
 3911     }
 3912     opts->joliet_utf16 = allow ? 1 : 0;
 3913     return ISO_SUCCESS;
 3914 }
 3915 
 3916 int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers)
 3917 {
 3918     if (opts == NULL) {
 3919         return ISO_NULL_POINTER;
 3920     }
 3921     opts->rrip_version_1_10 = oldvers ? 1 : 0;
 3922     return ISO_SUCCESS;
 3923 }
 3924 
 3925 int iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts *opts, int enable)
 3926 {
 3927     if (opts == NULL) {
 3928         return ISO_NULL_POINTER;
 3929     }
 3930     opts->rrip_1_10_px_ino = enable ? 1 : 0;
 3931     return ISO_SUCCESS;
 3932 }
 3933 
 3934 int iso_write_opts_set_aaip_susp_1_10(IsoWriteOpts *opts, int oldvers)
 3935 {
 3936     if (opts == NULL) {
 3937         return ISO_NULL_POINTER;
 3938     }
 3939     opts->aaip_susp_1_10 = oldvers ? 1 : 0;
 3940     return ISO_SUCCESS;
 3941 }
 3942 
 3943 int iso_write_opts_set_dir_rec_mtime(IsoWriteOpts *opts, int allow)
 3944 {
 3945     if (opts == NULL) {
 3946         return ISO_NULL_POINTER;
 3947     }
 3948     if (allow < 0)
 3949         allow = 1;
 3950     else if (allow & (1 << 14))
 3951         allow &= ~1;
 3952     else if (allow & 6)
 3953         allow |= 1;
 3954     opts->dir_rec_mtime = allow & 7;
 3955     return ISO_SUCCESS;
 3956 }
 3957 
 3958 int iso_write_opts_set_rr_reloc(IsoWriteOpts *opts, char *name, int flags)
 3959 {
 3960     if (opts->rr_reloc_dir != name) {
 3961         if (opts->rr_reloc_dir != NULL)
 3962             free(opts->rr_reloc_dir);
 3963         opts->rr_reloc_dir = NULL;
 3964         if (name != NULL) {
 3965             opts->rr_reloc_dir = strdup(name);
 3966             if (opts->rr_reloc_dir == NULL)
 3967                 return ISO_OUT_OF_MEM;
 3968         }
 3969     }
 3970     opts->rr_reloc_flags = flags & 1;
 3971     return ISO_SUCCESS;
 3972 }
 3973 
 3974 int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort)
 3975 {
 3976     if (opts == NULL) {
 3977         return ISO_NULL_POINTER;
 3978     }
 3979     opts->sort_files = sort ? 1 : 0;
 3980     return ISO_SUCCESS;
 3981 }
 3982 
 3983 int iso_write_opts_set_record_md5(IsoWriteOpts *opts, int session, int files)
 3984 {
 3985     opts->md5_session_checksum = session & 1;
 3986     opts->md5_file_checksums = files & 3;
 3987     return ISO_SUCCESS;
 3988 }
 3989 
 3990 int iso_write_opts_set_scdbackup_tag(IsoWriteOpts *opts,
 3991                                      char *name, char *timestamp,
 3992                                      char *tag_written)
 3993 {
 3994     char eff_name[81], eff_time[19];
 3995     int i;
 3996 
 3997     for (i = 0; name[i] != 0 && i < 80; i++)
 3998          if (isspace((int) ((unsigned char *) name)[i]))
 3999              eff_name[i] = '_';
 4000          else
 4001              eff_name[i] = name[i];
 4002     if (i == 0)
 4003         eff_name[i++] = '_';
 4004     eff_name[i] = 0;
 4005     for (i = 0; timestamp[i] != 0 && i < 18; i++)
 4006          if (isspace((int) ((unsigned char *) timestamp)[i]))
 4007              eff_time[i] = '_';
 4008          else
 4009              eff_time[i] = timestamp[i];
 4010     if (i == 0)
 4011         eff_time[i++] = '_';
 4012     eff_time[i] = 0;
 4013 
 4014     sprintf(opts->scdbackup_tag_parm, "%s %s", eff_name, eff_time);
 4015 
 4016     opts->scdbackup_tag_written = tag_written;
 4017     if (tag_written != NULL)
 4018         tag_written[0] = 0;
 4019     return ISO_SUCCESS;
 4020 }
 4021 
 4022 int iso_write_opts_set_replace_mode(IsoWriteOpts *opts, int dir_mode,
 4023                                     int file_mode, int uid, int gid)
 4024 {
 4025     if (opts == NULL) {
 4026         return ISO_NULL_POINTER;
 4027     }
 4028     if (dir_mode < 0 || dir_mode > 2) {
 4029         return ISO_WRONG_ARG_VALUE;
 4030     }
 4031     if (file_mode < 0 || file_mode > 2) {
 4032         return ISO_WRONG_ARG_VALUE;
 4033     }
 4034     if (uid < 0 || uid > 2) {
 4035         return ISO_WRONG_ARG_VALUE;
 4036     }
 4037     if (gid < 0 || gid > 2) {
 4038         return ISO_WRONG_ARG_VALUE;
 4039     }
 4040     opts->replace_dir_mode = dir_mode;
 4041     opts->replace_file_mode = file_mode;
 4042     opts->replace_uid = uid;
 4043     opts->replace_gid = gid;
 4044     return ISO_SUCCESS;
 4045 }
 4046 
 4047 int iso_write_opts_set_default_dir_mode(IsoWriteOpts *opts, mode_t dir_mode)
 4048 {
 4049     if (opts == NULL) {
 4050         return ISO_NULL_POINTER;
 4051     }
 4052     opts->dir_mode = dir_mode;
 4053     return ISO_SUCCESS;
 4054 }
 4055 
 4056 int iso_write_opts_set_default_file_mode(IsoWriteOpts *opts, mode_t file_mode)
 4057 {
 4058     if (opts == NULL) {
 4059         return ISO_NULL_POINTER;
 4060     }
 4061     opts->file_mode = file_mode;
 4062     return ISO_SUCCESS;
 4063 }
 4064 
 4065 int iso_write_opts_set_default_uid(IsoWriteOpts *opts, uid_t uid)
 4066 {
 4067     if (opts == NULL) {
 4068         return ISO_NULL_POINTER;
 4069     }
 4070     opts->uid = uid;
 4071     return ISO_SUCCESS;
 4072 }
 4073 
 4074 int iso_write_opts_set_default_gid(IsoWriteOpts *opts, gid_t gid)
 4075 {
 4076     if (opts == NULL) {
 4077         return ISO_NULL_POINTER;
 4078     }
 4079     opts->gid = gid;
 4080     return ISO_SUCCESS;
 4081 }
 4082 
 4083 int iso_write_opts_set_replace_timestamps(IsoWriteOpts *opts, int replace)
 4084 {
 4085     if (opts == NULL) {
 4086         return ISO_NULL_POINTER;
 4087     }
 4088     if (replace < 0 || replace > 2) {
 4089         return ISO_WRONG_ARG_VALUE;
 4090     }
 4091     opts->replace_timestamps = replace;
 4092     return ISO_SUCCESS;
 4093 }
 4094 
 4095 int iso_write_opts_set_default_timestamp(IsoWriteOpts *opts, time_t timestamp)
 4096 {
 4097     if (opts == NULL) {
 4098         return ISO_NULL_POINTER;
 4099     }
 4100     opts->timestamp = timestamp;
 4101     return ISO_SUCCESS;
 4102 }
 4103 
 4104 int iso_write_opts_set_always_gmt(IsoWriteOpts *opts, int gmt)
 4105 {
 4106     if (opts == NULL) {
 4107         return ISO_NULL_POINTER;
 4108     }
 4109     opts->always_gmt = gmt ? 1 : 0;
 4110     return ISO_SUCCESS;
 4111 }
 4112 
 4113 int iso_write_opts_set_output_charset(IsoWriteOpts *opts, const char *charset)
 4114 {
 4115     if (opts == NULL) {
 4116         return ISO_NULL_POINTER;
 4117     }
 4118     opts->output_charset = charset ? strdup(charset) : NULL;
 4119     return ISO_SUCCESS;
 4120 }
 4121 
 4122 int iso_write_opts_set_appendable(IsoWriteOpts *opts, int appendable)
 4123 {
 4124     if (opts == NULL) {
 4125         return ISO_NULL_POINTER;
 4126     }
 4127     opts->appendable = appendable ? 1 : 0;
 4128     return ISO_SUCCESS;
 4129 }
 4130 
 4131 int iso_write_opts_set_ms_block(IsoWriteOpts *opts, uint32_t ms_block)
 4132 {
 4133     if (opts == NULL) {
 4134         return ISO_NULL_POINTER;
 4135     }
 4136     opts->ms_block = ms_block;
 4137     return ISO_SUCCESS;
 4138 }
 4139 
 4140 int iso_write_opts_set_overwrite_buf(IsoWriteOpts *opts, uint8_t *overwrite)
 4141 {
 4142     if (opts == NULL) {
 4143         return ISO_NULL_POINTER;
 4144     }
 4145     opts->overwrite = overwrite;
 4146     return ISO_SUCCESS;
 4147 }
 4148 
 4149 int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size)
 4150 {
 4151     if (opts == NULL) {
 4152         return ISO_NULL_POINTER;
 4153     }
 4154     if (fifo_size < 32) {
 4155         return ISO_WRONG_ARG_VALUE;
 4156     }
 4157     opts->fifo_size = fifo_size;
 4158     return ISO_SUCCESS;
 4159 }
 4160 
 4161 int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start,
 4162                                   int flag)
 4163 {
 4164     if (opts->data_start_lba == 0)
 4165     return ISO_ERROR;
 4166     *data_start = opts->data_start_lba;
 4167     return ISO_SUCCESS;
 4168 }
 4169 
 4170 /*
 4171  * @param data     Either NULL or 32 kB of data. Do not submit less bytes !
 4172  * @param options 
 4173  *        Can cause manipulations of submitted data before they get written:
 4174  *        bit0= apply a --protective-msdos-label as of grub-mkisofs.
 4175  *              This means to patch bytes 446 to 512 of the system area so
 4176  *              that one partition is defined which begins at the second
 4177  *              512-byte block of the image and ends where the image ends.
 4178  *              This works with and without system_area_data.
 4179  *        bit1= apply isohybrid MBR patching to the system area.
 4180  *              This works only with system area data from SYSLINUX plus an
 4181  *              ISOLINUX boot image (see iso_image_set_boot_image()) and
 4182  *              only if not bit0 is set.
 4183  *        bit2-7= System area type
 4184  *        bit8-9= Only with System area type 0 = MBR
 4185  *                Cylinder alignment mode
 4186  *        bit10-13= System area sub type
 4187  * @param flag     bit0 = invalidate any attached system area data
 4188  *                        same as data == NULL
 4189  *                 bit1 = keep data unaltered
 4190  *                 bit2 = keep options unaltered
 4191  */
 4192 int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768],
 4193                                    int options, int flag)
 4194 {
 4195     if (data == NULL || (flag & 1)) { /* Disable */
 4196         if (opts->system_area_data != NULL)
 4197             free(opts->system_area_data);
 4198         opts->system_area_data = NULL;
 4199         opts->system_area_size = 0;
 4200     } else if (!(flag & 2)) {
 4201         if (opts->system_area_data == NULL) {
 4202             opts->system_area_data = calloc(32768, 1);
 4203             if (opts->system_area_data == NULL)
 4204                 return ISO_OUT_OF_MEM;
 4205         }
 4206         memcpy(opts->system_area_data, data, 32768);
 4207         opts->system_area_size = 32768;
 4208     }
 4209     if (!(flag & 4))
 4210         opts->system_area_options = options & 0xffff;
 4211     return ISO_SUCCESS;
 4212 }
 4213 
 4214 int iso_write_opts_set_pvd_times(IsoWriteOpts *opts, 
 4215                         time_t vol_creation_time, time_t vol_modification_time,
 4216                         time_t vol_expiration_time, time_t vol_effective_time,
 4217                         char *vol_uuid)
 4218 {
 4219     opts->vol_creation_time = vol_creation_time;
 4220     opts->vol_modification_time = vol_modification_time;
 4221     opts->vol_expiration_time = vol_expiration_time;
 4222     opts->vol_effective_time = vol_effective_time;
 4223     strncpy(opts->vol_uuid, vol_uuid, 16);
 4224     opts->vol_uuid[16] = 0;
 4225     return ISO_SUCCESS;
 4226 }
 4227 
 4228 int iso_write_opts_set_part_offset(IsoWriteOpts *opts,
 4229                                    uint32_t block_offset_2k,
 4230                                    int secs_512_per_head, int heads_per_cyl)
 4231 {
 4232     if (block_offset_2k > 0 && block_offset_2k < 16)
 4233         return ISO_PART_OFFST_TOO_SMALL;
 4234     opts->partition_offset = block_offset_2k;
 4235     opts->partition_secs_per_head = secs_512_per_head;
 4236     opts->partition_heads_per_cyl = heads_per_cyl;
 4237     return ISO_SUCCESS;
 4238 }
 4239 
 4240 int iso_write_opts_attach_jte(IsoWriteOpts *opts, void *libjte_handle)
 4241 {
 4242 #ifdef Libisofs_with_libjtE
 4243 
 4244     opts->libjte_handle = libjte_handle;
 4245     return ISO_SUCCESS;
 4246 
 4247 #else
 4248 
 4249     return ISO_LIBJTE_NOT_ENABLED;
 4250 
 4251 #endif /* Libisofs_with_libjtE */
 4252 }
 4253 
 4254 int iso_write_opts_detach_jte(IsoWriteOpts *opts, void **libjte_handle)
 4255 {
 4256 #ifdef Libisofs_with_libjtE
 4257 
 4258     if (*libjte_handle != NULL)
 4259         *libjte_handle = opts->libjte_handle;
 4260     opts->libjte_handle = NULL;
 4261     return ISO_SUCCESS;
 4262 
 4263 #else
 4264 
 4265     return ISO_LIBJTE_NOT_ENABLED;
 4266 
 4267 #endif /* Libisofs_with_libjtE */
 4268 }
 4269  
 4270 int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks)
 4271 {
 4272     opts->tail_blocks = num_blocks;
 4273     return ISO_SUCCESS;
 4274 }
 4275 
 4276 int iso_write_opts_set_prep_img(IsoWriteOpts *opts, char *image_path, int flag)
 4277 {
 4278     if (opts->prep_partition != NULL)
 4279         free(opts->prep_partition);
 4280     if (image_path == NULL)
 4281         return ISO_SUCCESS;
 4282     opts->prep_partition = strdup(image_path);
 4283     if (opts->prep_partition == NULL)
 4284         return ISO_OUT_OF_MEM;
 4285     opts->prep_part_flag = (flag & 1);
 4286     return ISO_SUCCESS;
 4287 }
 4288 
 4289 int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path, 
 4290                                  int flag)
 4291 {
 4292     if (opts->efi_boot_partition != NULL)
 4293         free(opts->efi_boot_partition);
 4294     if (image_path == NULL)
 4295         return ISO_SUCCESS;
 4296     opts->efi_boot_partition = strdup(image_path);
 4297     if (opts->efi_boot_partition == NULL)
 4298         return ISO_OUT_OF_MEM;
 4299     opts->efi_boot_part_flag = (flag & 1);
 4300     return ISO_SUCCESS;
 4301 }
 4302 
 4303 int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number,
 4304                             uint8_t partition_type, char *image_path, int flag)
 4305 {
 4306     if (partition_number < 1 || partition_number > ISO_MAX_PARTITIONS)
 4307         return ISO_BAD_PARTITION_NO;
 4308     if (opts->appended_partitions[partition_number - 1] != NULL)
 4309         free(opts->appended_partitions[partition_number - 1]);
 4310     if (image_path == NULL)
 4311         return ISO_SUCCESS;
 4312     opts->appended_partitions[partition_number - 1] = strdup(image_path);
 4313     if (opts->appended_partitions[partition_number - 1] == NULL)
 4314         return ISO_OUT_OF_MEM;
 4315     opts->appended_part_types[partition_number - 1] = partition_type;
 4316     opts->appended_part_flags[partition_number - 1] = (flag & 1);
 4317     return ISO_SUCCESS;
 4318 }
 4319 
 4320 int iso_write_opts_set_part_type_guid(IsoWriteOpts *opts, int partition_number,
 4321                                       uint8_t guid[16], int valid)
 4322 {
 4323     if (partition_number < 1 || partition_number > ISO_MAX_PARTITIONS)
 4324         return ISO_BAD_PARTITION_NO;
 4325     if (valid)
 4326         memcpy(opts->appended_part_type_guids[partition_number - 1], guid, 16);
 4327     if (valid)
 4328         opts->appended_part_gpt_flags[partition_number - 1]|= 1;
 4329     else
 4330         opts->appended_part_gpt_flags[partition_number - 1]&= ~1;
 4331     return ISO_SUCCESS;
 4332 }
 4333 
 4334 int iso_write_opts_set_appended_as_gpt(IsoWriteOpts *opts, int gpt)
 4335 {
 4336     opts->appended_as_gpt = !!gpt;
 4337     return ISO_SUCCESS;
 4338 }
 4339 
 4340 int iso_write_opts_set_appended_as_apm(IsoWriteOpts *opts, int apm)
 4341 {
 4342     opts->appended_as_apm = !!apm;
 4343     return ISO_SUCCESS;
 4344 }
 4345 
 4346 int iso_write_opts_set_part_like_isohybrid(IsoWriteOpts *opts, int alike)
 4347 {
 4348     opts->part_like_isohybrid = !!alike;
 4349     return ISO_SUCCESS;
 4350 }
 4351 
 4352 int iso_write_opts_set_iso_mbr_part_type(IsoWriteOpts *opts, int part_type)
 4353 {
 4354     if (part_type < -1 || part_type > 255)
 4355         part_type = -1;
 4356     opts->iso_mbr_part_type = part_type;
 4357     return ISO_SUCCESS;
 4358 }
 4359 
 4360 int iso_write_opts_set_iso_type_guid(IsoWriteOpts *opts, uint8_t guid[16],
 4361                                      int valid)
 4362 {
 4363     if (valid)
 4364         memcpy(opts->iso_gpt_type_guid, guid, 16);
 4365     opts->iso_gpt_flag = (opts->iso_gpt_flag & ~1) | !!valid;
 4366     return ISO_SUCCESS;
 4367 }
 4368 
 4369 int iso_write_opts_set_disc_label(IsoWriteOpts *opts, char *label)
 4370 {
 4371     strncpy(opts->ascii_disc_label, label, ISO_DISC_LABEL_SIZE - 1);
 4372     opts->ascii_disc_label[ISO_DISC_LABEL_SIZE - 1] = 0;
 4373     return ISO_SUCCESS;
 4374 }
 4375  
 4376 int iso_write_opts_set_hfsp_serial_number(IsoWriteOpts *opts,
 4377                                           uint8_t serial_number[8])
 4378 {
 4379     memcpy(opts->hfsp_serial_number, serial_number, 8);
 4380     return ISO_SUCCESS;
 4381 }
 4382  
 4383 int iso_write_opts_set_hfsp_block_size(IsoWriteOpts *opts, 
 4384                                      int hfsp_block_size, int apm_block_size)
 4385 {
 4386     if (hfsp_block_size != 0 && hfsp_block_size != 512 &&
 4387         hfsp_block_size != 2048)
 4388         return ISO_BOOT_HFSP_BAD_BSIZE;
 4389     opts->hfsp_block_size = hfsp_block_size;
 4390     if (apm_block_size != 0 && apm_block_size != 512 && apm_block_size != 2048)
 4391         return ISO_BOOT_HFSP_BAD_BSIZE;
 4392     opts->apm_block_size = apm_block_size;
 4393     return ISO_SUCCESS;
 4394 }
 4395 
 4396 int iso_write_opts_set_gpt_guid(IsoWriteOpts *opts, uint8_t guid[16], int mode)
 4397 {
 4398     if (mode < 0 || mode > 2)
 4399         return ISO_BAD_GPT_GUID_MODE;
 4400     opts->gpt_disk_guid_mode = mode;
 4401     if (opts->gpt_disk_guid_mode == 1)
 4402         memcpy(opts->gpt_disk_guid, guid, 16);
 4403     return ISO_SUCCESS;
 4404 }
 4405 
 4406 
 4407 /*
 4408  * @param flag
 4409  *      Bitfield for control purposes.
 4410  *        bit0-bit7= Name space
 4411  *                   0= generic (to_charset is valid, no reserved characters,
 4412  *                               no length limits)
 4413  *                   1= Rock Ridge (to_charset is valid)
 4414  *                   2= Joliet (to_charset gets overridden by UCS-2 or UTF-16)
 4415  *                   3= ECMA-119 (dull ISO 9660 character set)
 4416  *                   4= HFS+ (to_charset gets overridden by UTF-16BE) 
 4417  *        bit8=  Treat input text as directory name
 4418  *               (matters for Joliet and ECMA-119)
 4419  *        bit9=  Do not issue error messages
 4420  *        bit15= Reverse operation (best to be done only with results of
 4421  *               previous conversions)
 4422  */
 4423 int iso_conv_name_chars(IsoWriteOpts *opts, char *in_name, size_t name_len,
 4424                         char **result, size_t *result_len, int flag)
 4425 {
 4426     int name_space, ret, reverse;
 4427     size_t i;
 4428     size_t joliet_ucs2_failures = ISO_JOLIET_UCS2_WARN_MAX + 1;/* no warning */
 4429     size_t conved_len;
 4430     char *from_charset, *to_charset, *conved, *smashed = NULL, *name;
 4431     char *tr, *with_version = NULL;
 4432     uint16_t *ucs = NULL, *hfspcmp = NULL;
 4433     uint32_t ucs_len;
 4434     enum IsoNodeType node_type;
 4435 
 4436     *result = NULL;
 4437     *result_len = 0;
 4438 
 4439     name = in_name;
 4440     name_space = flag & 0xff;
 4441     reverse = !!(flag & (1 << 15));
 4442     node_type = (flag & 256) ? LIBISO_DIR : LIBISO_FILE;
 4443     from_charset = iso_get_local_charset(0);
 4444 
 4445     /* Note: Joliet, ECMA-119, HFS+ actually use to_charset only for the
 4446              reverse conversion case */
 4447     if (opts->output_charset != NULL)
 4448         to_charset = opts->output_charset;
 4449     else
 4450         to_charset = from_charset;
 4451     if (name_space == 1) { /* Rock Ridge */
 4452         if (!reverse) {
 4453             LIBISO_ALLOC_MEM(smashed, char, name_len + 1);
 4454             memcpy(smashed, name, name_len);
 4455             smashed[name_len] = 0;
 4456             for (i = 0; i < name_len; i++)
 4457                  if (smashed[i] == '/')
 4458                      smashed[i] = '_';
 4459             name = smashed;
 4460 
 4461             /* >>> ??? truncate to 255 chars */
 4462          }
 4463     } else if (name_space == 2) { /* Joliet */
 4464         if (opts->joliet_utf16)
 4465             to_charset = "UTF-16BE";
 4466         else
 4467             to_charset = "UCS-2BE";
 4468     } else if (name_space == 3) { /* ECMA-119 */
 4469         to_charset = "ASCII";
 4470     } else if (name_space == 4) { /* HFS+ */
 4471         to_charset= "UTF-16BE";
 4472     }
 4473     if (reverse) {
 4474         tr = from_charset;
 4475         from_charset = to_charset;
 4476         to_charset = tr;
 4477     }
 4478 
 4479     if (name_space == 0 || reverse) {
 4480         ret = strnconvl(name, from_charset, to_charset, name_len,
 4481                         &conved, &conved_len);
 4482         if (ret != ISO_SUCCESS)
 4483             goto ex;
 4484 
 4485     } else if (name_space == 1) { /* Rock Ridge */
 4486         ret = iso_get_rr_name(opts, from_charset, to_charset, -1, name,
 4487                               &conved, !!(flag & 512));
 4488         if (ret != ISO_SUCCESS)
 4489             goto ex;
 4490         conved_len = strlen(conved);
 4491 
 4492     } else if (name_space == 2) { /* Joliet */
 4493         ret = iso_get_joliet_name(opts, from_charset, -1, name, node_type,
 4494                                   &joliet_ucs2_failures, &ucs, !!(flag & 512));
 4495         if (ret != ISO_SUCCESS)
 4496             goto ex;
 4497         conved_len = ucslen(ucs) * 2;
 4498         conved = (char *) ucs; ucs = NULL;
 4499         if (node_type != LIBISO_DIR && !(opts->omit_version_numbers & 3)) {
 4500             LIBISO_ALLOC_MEM(with_version, char, conved_len + 6);
 4501             memcpy(with_version, conved, conved_len);
 4502             with_version[conved_len++] = 0;
 4503             with_version[conved_len++] = ';';
 4504             with_version[conved_len++] = 0;
 4505             with_version[conved_len++] = '1';
 4506             with_version[conved_len] = 0;
 4507             with_version[conved_len + 1] = 0;
 4508             free(conved);
 4509             conved = with_version; with_version = NULL;
 4510         }
 4511 
 4512     } else if (name_space == 3) { /* ECMA-119 */
 4513         ret = iso_get_ecma119_name(opts, from_charset, -1, name, node_type,
 4514                                    &conved, !!(flag & 512)); 
 4515         if (ret != ISO_SUCCESS)
 4516             goto ex;
 4517         conved_len = strlen(conved);
 4518         if (need_version_number(opts, node_type == LIBISO_DIR ?
 4519                                                  ECMA119_DIR : ECMA119_FILE)) {
 4520             LIBISO_ALLOC_MEM(with_version, char, conved_len + 3);
 4521             memcpy(with_version, conved, conved_len + 1);
 4522             strcat(with_version, ";1");
 4523             free(conved);
 4524             conved = with_version; with_version = NULL;
 4525             conved_len += 2;
 4526         }
 4527 
 4528     } else if (name_space == 4) { /* HFS+ */
 4529         ret = iso_get_hfsplus_name(from_charset, -1, name, &ucs, &ucs_len,
 4530                                    &hfspcmp);
 4531         if (ret != ISO_SUCCESS)
 4532             goto ex;
 4533         conved = (char *) ucs; ucs = NULL;
 4534         conved_len = ucs_len * 2;
 4535 
 4536     } else {
 4537         ret = ISO_WRONG_ARG_VALUE;
 4538         goto ex;
 4539     }
 4540 
 4541     *result = conved;
 4542     *result_len = conved_len;
 4543     ret = ISO_SUCCESS;
 4544 ex:
 4545     LIBISO_FREE_MEM(with_version);
 4546     LIBISO_FREE_MEM(smashed);
 4547     LIBISO_FREE_MEM(ucs);
 4548     LIBISO_FREE_MEM(hfspcmp);
 4549     return ret;
 4550 }
 4551 
 4552 
 4553 static
 4554 void ecma119_filesrc_array(Ecma119Node *dir,
 4555                            int (*include_item)(void *),
 4556                            IsoFileSrc **filelist, size_t *size, int just_count)
 4557 {
 4558     size_t i;
 4559     Ecma119Node *child;
 4560 
 4561     for (i = 0; i < dir->info.dir->nchildren; i++) {
 4562         child = dir->info.dir->children[i];
 4563         if (child->type == ECMA119_DIR) {
 4564             ecma119_filesrc_array(child, include_item, filelist, size,
 4565                                   just_count);
 4566         } else if (child->type == ECMA119_FILE) {
 4567             if (include_item != NULL)
 4568                 if (!include_item((void *) child->info.file))
 4569     continue;
 4570             if (just_count) {
 4571                 (*size)++;
 4572             } else {
 4573                 if (!child->info.file->taken) {
 4574                     filelist[*size] = child->info.file;
 4575                     child->info.file->taken = 1;
 4576                     (*size)++;
 4577                 }
 4578             }
 4579         }
 4580     }
 4581 }
 4582 
 4583 
 4584 static
 4585 void hidden_filesrc_array(Ecma119Image *t, 
 4586                           int (*include_item)(void *),
 4587                           IsoFileSrc **filelist, size_t *size, int just_count)
 4588 {
 4589     struct iso_filesrc_list_item *item;
 4590 
 4591     for (item = t->ecma119_hidden_list; item != NULL; item = item->next) {
 4592         if (include_item != NULL)
 4593             if (!include_item((void *) item->src))
 4594     continue;
 4595         if (just_count) {
 4596             (*size)++;
 4597         } else {
 4598             if (!item->src->taken) {
 4599                 filelist[*size] = item->src;
 4600                 item->src->taken = 1;
 4601                 (*size)++;
 4602             }
 4603         }
 4604     }
 4605 }
 4606 
 4607 
 4608 IsoFileSrc **iso_ecma119_to_filesrc_array(Ecma119Image *t,
 4609                                           int (*include_item)(void *),
 4610                                           size_t *size)
 4611 {
 4612     IsoFileSrc **filelist = NULL;
 4613 
 4614     /* Count nodes */
 4615     *size = 0;
 4616     ecma119_filesrc_array(t->root, include_item, filelist, size, 1);
 4617     hidden_filesrc_array(t, include_item, filelist, size, 1);
 4618 
 4619     LIBISO_ALLOC_MEM_VOID(filelist, IsoFileSrc *, *size + 1);
 4620 
 4621     /* Fill array */
 4622     *size = 0;
 4623     ecma119_filesrc_array(t->root, include_item, filelist, size, 0);
 4624     hidden_filesrc_array(t, include_item, filelist, size, 0);
 4625     filelist[*size] = NULL;
 4626     return filelist;
 4627 
 4628 ex: /* LIBISO_ALLOC_MEM failed */
 4629     *size = 0;
 4630     return NULL;
 4631 }
 4632 
 4633 
 4634 /* Determines the range of valid partition numbers depending on partition
 4635    table type.
 4636 */
 4637 void iso_tell_max_part_range(IsoWriteOpts *opts,
 4638                              int *first_partition, int *last_partition,
 4639                              int flag)
 4640 {
 4641     int sa_type;
 4642 
 4643     sa_type = (opts->system_area_options >> 2) & 0x3f;
 4644     if (sa_type == 3) { /* SUN Disk Label */
 4645         *first_partition = 2;
 4646         *last_partition = 8;
 4647     }  else {
 4648         *first_partition = 1;
 4649         *last_partition = 4;
 4650     }
 4651 }
 4652 
 4653 
 4654 /* Obtains start and end number of appended partition range and returns
 4655    the number of valid entries in the list of appended partitions.
 4656 */
 4657 int iso_count_appended_partitions(Ecma119Image *target,
 4658                                   int *first_partition, int *last_partition)
 4659 {
 4660     int i, count= 0;
 4661 
 4662     iso_tell_max_part_range(target->opts, first_partition, last_partition, 0);
 4663     for (i = *first_partition - 1; i <= *last_partition - 1; i++) {
 4664         if (target->opts->appended_partitions[i] == NULL)
 4665     continue;
 4666         if (target->opts->appended_partitions[i][0] == 0)
 4667     continue;
 4668         count++;
 4669     }
 4670     return(count);
 4671 }
 4672