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
ecma119_image_free(Ecma119Image * t)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 
show_chunk_to_jte(Ecma119Image * target,char * buf,int count)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
need_version_number(IsoWriteOpts * opts,enum ecma119_node_type node_type)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
calc_dirent_len(Ecma119Image * t,Ecma119Node * n)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
calc_dir_size(Ecma119Image * t,Ecma119Node * dir,size_t * ce)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
calc_dir_pos(Ecma119Image * t,Ecma119Node * dir)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
calc_path_table_size(Ecma119Node * dir)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
ecma119_writer_compute_data_blocks(IsoImageWriter * writer)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
write_one_dir_record(Ecma119Image * t,Ecma119Node * node,int file_id,uint8_t * buf,size_t len_fi,struct susp_info * info,int extent)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
get_relaxed_vol_id(Ecma119Image * t,const char * name)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  */
ecma119_set_voldescr_times(IsoImageWriter * writer,struct ecma119_pri_vol_desc * vol)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
ecma119_writer_write_vol_desc(IsoImageWriter * writer)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
write_one_dir(Ecma119Image * t,Ecma119Node * dir,Ecma119Node * parent)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
write_dirs(Ecma119Image * t,Ecma119Node * root,Ecma119Node * parent)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
write_path_table(Ecma119Image * t,Ecma119Node ** pathlist,int l_type)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
write_path_tables(Ecma119Image * t)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
ecma119_writer_write_dirs(IsoImageWriter * writer)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
ecma119_writer_write_data(IsoImageWriter * writer)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
ecma119_writer_free_data(IsoImageWriter * writer)978 int ecma119_writer_free_data(IsoImageWriter *writer)
979 {
980     /* nothing to do */
981     return ISO_SUCCESS;
982 }
983 
ecma119_writer_create(Ecma119Image * target)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
mspad_writer_compute_data_blocks(IsoImageWriter * writer)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
mspad_writer_write_vol_desc(IsoImageWriter * writer)1052 int mspad_writer_write_vol_desc(IsoImageWriter *writer)
1053 {
1054     /* nothing to do */
1055     return ISO_SUCCESS;
1056 }
1057 
1058 static
mspad_writer_write_data(IsoImageWriter * writer)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
mspad_writer_free_data(IsoImageWriter * writer)1090 int mspad_writer_free_data(IsoImageWriter *writer)
1091 {
1092     /* nothing to do */
1093     return ISO_SUCCESS;
1094 }
1095 
1096 static
mspad_writer_create(Ecma119Image * target)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
zero_writer_compute_data_blocks(IsoImageWriter * writer)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
zero_writer_write_vol_desc(IsoImageWriter * writer)1140 int zero_writer_write_vol_desc(IsoImageWriter *writer)
1141 {
1142     /* nothing to do */
1143     return ISO_SUCCESS;
1144 }
1145 
1146 static
zero_writer_write_data(IsoImageWriter * writer)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
zero_writer_free_data(IsoImageWriter * writer)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
tail_writer_compute_data_blocks(IsoImageWriter * writer)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
part_align_writer_compute_data_blocks(IsoImageWriter * writer)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
zero_writer_create(Ecma119Image * target,uint32_t num_blocks,int flag)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
process_preserved_cx(IsoDir * dir,int flag)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
transplant_checksum_buffer(Ecma119Image * target,int flag)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
write_vol_desc_terminator(Ecma119Image * target)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
write_head_part1(Ecma119Image * target,int * write_count,int flag)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
write_head_part2(Ecma119Image * target,int * write_count,int flag)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
write_head_part(Ecma119Image * target,int flag)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 */
finish_libjte(Ecma119Image * target)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
iso_ivr_next_comp(char * read_pt,char ** next_pt,int flag)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
iso_ivr_read_number(char * start_pt,char * end_pt,off_t * result,int flag)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
iso_ivr_parse_interval(char * start_pt,char * end_pt,off_t * start_byte,off_t * end_byte,int flag)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
iso_ivr_parse_zeroizers(struct iso_interval_reader * ivr,char * pathpt,char * end_pt,int flag)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
iso_ivr_parse(struct iso_interval_reader * ivr,char * path,int flag)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 
iso_interval_reader_destroy(struct iso_interval_reader ** ivr,int flag)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 */
iso_interval_reader_new(IsoImage * img,char * path,struct iso_interval_reader ** ivr,off_t * byte_count,int flag)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
iso_ivr_zeroize(struct iso_interval_reader * ivr,uint8_t * buf,int buf_fill,int flag)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 
iso_interval_reader_read(struct iso_interval_reader * ivr,uint8_t * buf,int * buf_fill,int flag)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 */
iso_interval_reader_keep(Ecma119Image * target,struct iso_interval_reader * ivr,int flag)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 
iso_interval_reader_start_size(Ecma119Image * t,char * path,off_t * start_byte,off_t * byte_count,int flag)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 
iso_write_partition_file(Ecma119Image * target,char * path,uint32_t prepad,uint32_t blocks,int flag)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 
issue_ucs2_warning_summary(size_t failures)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
write_function(void * arg)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
checksum_prepare_image(IsoImage * src,int flag)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
checksum_prepare_nodes(Ecma119Image * target,IsoNode * node,int flag)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
ecma119_determine_now_time(Ecma119Image * target)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
gpt_disk_guid_setup(Ecma119Image * target)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
ecma119_image_new(IsoImage * src,IsoWriteOpts * in_opts,Ecma119Image ** img)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 
bs_read(struct burn_source * bs,unsigned char * buf,int size)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 
bs_get_size(struct burn_source * bs)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 
bs_free_data(struct burn_source * bs)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
bs_cancel(struct burn_source * bs)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
bs_set_size(struct burn_source * bs,off_t size)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
dive_to_depth_8(IsoDir * dir,int depth)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
make_reloc_dir_if_needed(IsoImage * img,IsoWriteOpts * opts,int flag)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 
iso_image_create_burn_source(IsoImage * image,IsoWriteOpts * opts,struct burn_source ** burn_src)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 
iso_write(Ecma119Image * target,void * buf,size_t count)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 
iso_write_opts_new(IsoWriteOpts ** opts,int profile)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 
iso_write_opts_clone(IsoWriteOpts * in,IsoWriteOpts ** out,int flag)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 
iso_write_opts_free(IsoWriteOpts * opts)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 
iso_write_opts_set_will_cancel(IsoWriteOpts * opts,int will_cancel)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 
iso_write_opts_set_iso_level(IsoWriteOpts * opts,int level)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 
iso_write_opts_set_rockridge(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_joliet(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_hfsplus(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_fat(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_iso1999(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_hardlinks(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_aaip(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_old_empty(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_untranslated_name_len(IsoWriteOpts * opts,int len)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 
iso_write_opts_set_allow_dir_id_ext(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_omit_version_numbers(IsoWriteOpts * opts,int omit)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 
iso_write_opts_set_allow_deep_paths(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_allow_longer_paths(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_max_37_char_filenames(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_no_force_dots(IsoWriteOpts * opts,int no)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 
iso_write_opts_set_allow_lowercase(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_allow_full_ascii(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_allow_7bit_ascii(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_relaxed_vol_atts(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_joliet_longer_paths(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_joliet_long_names(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_joliet_utf16(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_rrip_version_1_10(IsoWriteOpts * opts,int oldvers)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 
iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts * opts,int enable)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 
iso_write_opts_set_aaip_susp_1_10(IsoWriteOpts * opts,int oldvers)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 
iso_write_opts_set_dir_rec_mtime(IsoWriteOpts * opts,int allow)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 
iso_write_opts_set_rr_reloc(IsoWriteOpts * opts,char * name,int flags)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 
iso_write_opts_set_sort_files(IsoWriteOpts * opts,int sort)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 
iso_write_opts_set_record_md5(IsoWriteOpts * opts,int session,int files)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 
iso_write_opts_set_scdbackup_tag(IsoWriteOpts * opts,char * name,char * timestamp,char * tag_written)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 
iso_write_opts_set_replace_mode(IsoWriteOpts * opts,int dir_mode,int file_mode,int uid,int gid)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 
iso_write_opts_set_default_dir_mode(IsoWriteOpts * opts,mode_t dir_mode)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 
iso_write_opts_set_default_file_mode(IsoWriteOpts * opts,mode_t file_mode)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 
iso_write_opts_set_default_uid(IsoWriteOpts * opts,uid_t uid)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 
iso_write_opts_set_default_gid(IsoWriteOpts * opts,gid_t gid)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 
iso_write_opts_set_replace_timestamps(IsoWriteOpts * opts,int replace)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 
iso_write_opts_set_default_timestamp(IsoWriteOpts * opts,time_t timestamp)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 
iso_write_opts_set_always_gmt(IsoWriteOpts * opts,int gmt)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 
iso_write_opts_set_output_charset(IsoWriteOpts * opts,const char * charset)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 
iso_write_opts_set_appendable(IsoWriteOpts * opts,int appendable)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 
iso_write_opts_set_ms_block(IsoWriteOpts * opts,uint32_t ms_block)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 
iso_write_opts_set_overwrite_buf(IsoWriteOpts * opts,uint8_t * overwrite)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 
iso_write_opts_set_fifo_size(IsoWriteOpts * opts,size_t fifo_size)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 
iso_write_opts_get_data_start(IsoWriteOpts * opts,uint32_t * data_start,int flag)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  */
iso_write_opts_set_system_area(IsoWriteOpts * opts,char data[32768],int options,int flag)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 
iso_write_opts_set_pvd_times(IsoWriteOpts * opts,time_t vol_creation_time,time_t vol_modification_time,time_t vol_expiration_time,time_t vol_effective_time,char * vol_uuid)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 
iso_write_opts_set_part_offset(IsoWriteOpts * opts,uint32_t block_offset_2k,int secs_512_per_head,int heads_per_cyl)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 
iso_write_opts_attach_jte(IsoWriteOpts * opts,void * libjte_handle)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 
iso_write_opts_detach_jte(IsoWriteOpts * opts,void ** libjte_handle)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 
iso_write_opts_set_tail_blocks(IsoWriteOpts * opts,uint32_t num_blocks)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 
iso_write_opts_set_prep_img(IsoWriteOpts * opts,char * image_path,int flag)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 
iso_write_opts_set_efi_bootp(IsoWriteOpts * opts,char * image_path,int flag)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 
iso_write_opts_set_partition_img(IsoWriteOpts * opts,int partition_number,uint8_t partition_type,char * image_path,int flag)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 
iso_write_opts_set_part_type_guid(IsoWriteOpts * opts,int partition_number,uint8_t guid[16],int valid)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 
iso_write_opts_set_appended_as_gpt(IsoWriteOpts * opts,int gpt)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 
iso_write_opts_set_appended_as_apm(IsoWriteOpts * opts,int apm)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 
iso_write_opts_set_part_like_isohybrid(IsoWriteOpts * opts,int alike)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 
iso_write_opts_set_iso_mbr_part_type(IsoWriteOpts * opts,int part_type)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 
iso_write_opts_set_iso_type_guid(IsoWriteOpts * opts,uint8_t guid[16],int valid)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 
iso_write_opts_set_disc_label(IsoWriteOpts * opts,char * label)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 
iso_write_opts_set_hfsp_serial_number(IsoWriteOpts * opts,uint8_t serial_number[8])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 
iso_write_opts_set_hfsp_block_size(IsoWriteOpts * opts,int hfsp_block_size,int apm_block_size)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 
iso_write_opts_set_gpt_guid(IsoWriteOpts * opts,uint8_t guid[16],int mode)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  */
iso_conv_name_chars(IsoWriteOpts * opts,char * in_name,size_t name_len,char ** result,size_t * result_len,int flag)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
ecma119_filesrc_array(Ecma119Node * dir,int (* include_item)(void *),IsoFileSrc ** filelist,size_t * size,int just_count)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
hidden_filesrc_array(Ecma119Image * t,int (* include_item)(void *),IsoFileSrc ** filelist,size_t * size,int just_count)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 
iso_ecma119_to_filesrc_array(Ecma119Image * t,int (* include_item)(void *),size_t * size)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 */
iso_tell_max_part_range(IsoWriteOpts * opts,int * first_partition,int * last_partition,int flag)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 */
iso_count_appended_partitions(Ecma119Image * target,int * first_partition,int * last_partition)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 
4673