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, ©right_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