"Fossies" - the Fresh Open Source Software Archive 
Member "libisofs-1.5.4/libisofs/iso1999.c" (8 Jul 2020, 30379 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "iso1999.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2011-2014 Thomas Schmitt
4 *
5 * This file is part of the libisofs project; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * or later as published by the Free Software Foundation.
8 * See COPYING file for details.
9 */
10
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14
15 #include "iso1999.h"
16 #include "messages.h"
17 #include "writer.h"
18 #include "image.h"
19 #include "filesrc.h"
20 #include "eltorito.h"
21 #include "util.h"
22 #include "ecma119.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 static
29 int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
30 {
31 int ret;
32 char *name;
33
34 if (fname == NULL) {
35 return ISO_ASSERT_FAILURE;
36 }
37
38 if (str == NULL) {
39 /* not an error, can be root node */
40 *fname = NULL;
41 return ISO_SUCCESS;
42 }
43
44 if (!strcmp(t->input_charset, t->output_charset)) {
45 /* no conversion needed */
46 name = strdup(str);
47 } else {
48 ret = strconv(str, t->input_charset, t->output_charset, &name);
49 if (ret < 0) {
50 ret = iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
51 "Charset conversion error. Can't convert %s from %s to %s",
52 str, t->input_charset, t->output_charset);
53 if (ret < 0) {
54 return ret; /* aborted */
55 }
56
57 /* use the original name, it's the best we can do */
58 name = strdup(str);
59 }
60 }
61
62 /* ISO 9660:1999 7.5.1 */
63 if (strlen(name) > 207) {
64 name[207] = '\0';
65 }
66
67 *fname = name;
68
69 return ISO_SUCCESS;
70 }
71
72 static
73 void iso1999_node_free(Iso1999Node *node)
74 {
75 if (node == NULL) {
76 return;
77 }
78 if (node->type == ISO1999_DIR) {
79 size_t i;
80 for (i = 0; i < node->info.dir->nchildren; i++) {
81 iso1999_node_free(node->info.dir->children[i]);
82 }
83 if (node->info.dir->children != NULL)
84 free(node->info.dir->children);
85 free(node->info.dir);
86 }
87 iso_node_unref(node->node);
88 free(node->name);
89 free(node);
90 }
91
92 /**
93 * Create a low level ISO 9660:1999 node
94 * @return
95 * 1 success, 0 ignored, < 0 error
96 */
97 static
98 int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
99 {
100 int ret;
101 Iso1999Node *n;
102
103 n = calloc(1, sizeof(Iso1999Node));
104 if (n == NULL) {
105 return ISO_OUT_OF_MEM;
106 }
107
108 if (iso->type == LIBISO_DIR) {
109 IsoDir *dir = (IsoDir*) iso;
110 n->info.dir = calloc(1, sizeof(struct iso1999_dir_info));
111 if (n->info.dir == NULL) {
112 free(n);
113 return ISO_OUT_OF_MEM;
114 }
115 n->info.dir->children = NULL;
116 if (dir->nchildren > 0) {
117 n->info.dir->children = calloc(sizeof(void*), dir->nchildren);
118 if (n->info.dir->children == NULL) {
119 free(n->info.dir);
120 free(n);
121 return ISO_OUT_OF_MEM;
122 }
123 }
124 n->type = ISO1999_DIR;
125 } else if (iso->type == LIBISO_FILE) {
126 /* it's a file */
127 off_t size;
128 IsoFileSrc *src;
129 IsoFile *file = (IsoFile*) iso;
130
131 size = iso_stream_get_size(file->stream);
132 if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->opts->iso_level != 3) {
133 char *ipath = iso_tree_get_node_path(iso);
134 ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
135 "File \"%s\" can't be added to image because is "
136 "greater than 4GB", ipath);
137 free(n);
138 free(ipath);
139 return ret;
140 }
141
142 ret = iso_file_src_create(t, file, &src);
143 if (ret < 0) {
144 free(n);
145 return ret;
146 }
147 n->info.file = src;
148 n->type = ISO1999_FILE;
149 } else if (iso->type == LIBISO_BOOT) {
150 /* it's a el-torito boot catalog, that we write as a file */
151 IsoFileSrc *src;
152
153 ret = el_torito_catalog_file_src_create(t, &src);
154 if (ret < 0) {
155 free(n);
156 return ret;
157 }
158 n->info.file = src;
159 n->type = ISO1999_FILE;
160 } else {
161 /* should never happen */
162 free(n);
163 return ISO_ASSERT_FAILURE;
164 }
165
166 /* take a ref to the IsoNode */
167 n->node = iso;
168 iso_node_ref(iso);
169
170 *node = n;
171 return ISO_SUCCESS;
172 }
173
174 /**
175 * Create the low level ISO 9660:1999 tree from the high level ISO tree.
176 *
177 * @return
178 * 1 success, 0 file ignored, < 0 error
179 */
180 static
181 int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
182 {
183 int ret, max_path;
184 Iso1999Node *node = NULL;
185 char *iso_name = NULL;
186
187 if (t == NULL || iso == NULL || tree == NULL) {
188 return ISO_NULL_POINTER;
189 }
190
191 if (iso->hidden & LIBISO_HIDE_ON_1999) {
192 /* file will be ignored */
193 return 0;
194 }
195 ret = get_iso1999_name(t, iso->name, &iso_name);
196 if (ret < 0) {
197 return ret;
198 }
199
200 max_path = pathlen + 1 + (iso_name ? strlen(iso_name): 0);
201 if (!t->opts->allow_longer_paths && max_path > 255) {
202 char *ipath = iso_tree_get_node_path(iso);
203 ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
204 "File \"%s\" can't be added to ISO 9660:1999 tree, "
205 "because its path length is larger than 255", ipath);
206 free(iso_name);
207 free(ipath);
208 return ret;
209 }
210
211 switch (iso->type) {
212 case LIBISO_FILE:
213 ret = create_node(t, iso, &node);
214 break;
215 case LIBISO_DIR:
216 {
217 IsoNode *pos;
218 IsoDir *dir = (IsoDir*)iso;
219 ret = create_node(t, iso, &node);
220 if (ret < 0) {
221 free(iso_name);
222 return ret;
223 }
224 pos = dir->children;
225 while (pos) {
226 int cret;
227 Iso1999Node *child;
228 cret = create_tree(t, pos, &child, max_path);
229 if (cret < 0) {
230 /* error */
231 iso1999_node_free(node);
232 ret = cret;
233 break;
234 } else if (cret == ISO_SUCCESS) {
235 /* add child to this node */
236 int nchildren = node->info.dir->nchildren++;
237 node->info.dir->children[nchildren] = child;
238 child->parent = node;
239 }
240 pos = pos->next;
241 }
242 }
243 break;
244 case LIBISO_BOOT:
245 if (t->eltorito) {
246 ret = create_node(t, iso, &node);
247 } else {
248 /* log and ignore */
249 ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
250 "El-Torito catalog found on a image without El-Torito.");
251 }
252 break;
253 case LIBISO_SYMLINK:
254 case LIBISO_SPECIAL:
255 {
256 char *ipath = iso_tree_get_node_path(iso);
257 ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
258 "Can't add %s to ISO 9660:1999 tree. This kind of files "
259 "can only be added to a Rock Ridget tree. Skipping.",
260 ipath);
261 free(ipath);
262 }
263 break;
264 default:
265 /* should never happen */
266 return ISO_ASSERT_FAILURE;
267 }
268 if (ret <= 0) {
269 free(iso_name);
270 return ret;
271 }
272 node->name = iso_name;
273 *tree = node;
274 return ISO_SUCCESS;
275 }
276
277 static int
278 cmp_node(const void *f1, const void *f2)
279 {
280 Iso1999Node *f = *((Iso1999Node**)f1);
281 Iso1999Node *g = *((Iso1999Node**)f2);
282
283 /**
284 * TODO #00027 Follow ISO 9660:1999 specs when sorting files
285 * strcmp do not does exactly what ISO 9660:1999, 9.3, as characters
286 * < 0x20 " " are allowed, so name len must be taken into account
287 */
288 return strcmp(f->name, g->name);
289 }
290
291 /**
292 * Sort the entries inside an ISO 9660:1999 directory, according to
293 * ISO 9660:1999, 9.3
294 */
295 static
296 void sort_tree(Iso1999Node *root)
297 {
298 size_t i;
299
300 if (root->info.dir->children == NULL)
301 return;
302 qsort(root->info.dir->children, root->info.dir->nchildren,
303 sizeof(void*), cmp_node);
304 for (i = 0; i < root->info.dir->nchildren; i++) {
305 Iso1999Node *child = root->info.dir->children[i];
306 if (child->type == ISO1999_DIR)
307 sort_tree(child);
308 }
309 }
310
311 static
312 int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
313 {
314 int ret;
315 int i, nchildren;
316 Iso1999Node **children;
317 IsoHTable *table = NULL;
318 int need_sort = 0;
319 char *full_name = NULL, *tmp = NULL;
320
321 nchildren = dir->info.dir->nchildren;
322 if (nchildren <= 0) {
323 ret = ISO_SUCCESS;
324 goto ex;
325 }
326 children = dir->info.dir->children;
327 LIBISO_ALLOC_MEM(full_name, char, 208);
328 LIBISO_ALLOC_MEM(tmp, char, 208);
329
330 /* a hash table will temporary hold the names, for fast searching */
331 ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
332 (compare_function_t)strcmp, &table);
333 if (ret < 0) {
334 goto ex;
335 }
336 for (i = 0; i < nchildren; ++i) {
337 char *name = children[i]->name;
338 ret = iso_htable_add(table, name, name);
339 if (ret < 0) {
340 goto ex;
341 }
342 }
343
344 for (i = 0; i < nchildren; ++i) {
345 char *name, *ext;
346 int max; /* computed max len for name, without extension */
347 int j = i;
348 int digits = 1; /* characters to change per name */
349
350 /* first, find all child with same name */
351 while (j + 1 < nchildren &&
352 !cmp_node(children + i, children + j + 1)) {
353 ++j;
354 }
355 if (j == i) {
356 /* name is unique */
357 continue;
358 }
359
360 /*
361 * A max of 7 characters is good enough, it allows handling up to
362 * 9,999,999 files with same name.
363 */
364 while (digits < 8) {
365 int ok, k;
366 char *dot;
367 int change = 0; /* number to be written */
368
369 /* copy name to buffer */
370 strcpy(full_name, children[i]->name);
371
372 /* compute name and extension */
373 dot = strrchr(full_name, '.');
374 if (dot != NULL && children[i]->type != ISO1999_DIR) {
375
376 /*
377 * File (not dir) with extension.
378 */
379 int extlen;
380 full_name[dot - full_name] = '\0';
381 name = full_name;
382 ext = dot + 1;
383
384 extlen = strlen(ext);
385 max = 207 - extlen - 1 - digits;
386 if (max <= 0) {
387 /* this can happen if extension is too long */
388 if (extlen + max > 3) {
389 /*
390 * reduce extension len, to give name an extra char
391 * note that max is negative or 0
392 */
393 extlen = extlen + max - 1;
394 ext[extlen] = '\0';
395 max = 207 - extlen - 1 - digits;
396 } else {
397 /*
398 * error, we don't support extensions < 3
399 * This can't happen with current limit of digits.
400 */
401 ret = ISO_ERROR;
402 goto ex;
403 }
404 }
405 /* ok, reduce name by digits */
406 if (name + max < dot) {
407 name[max] = '\0';
408 }
409 } else {
410 /* Directory, or file without extension */
411 if (children[i]->type == ISO1999_DIR) {
412 dot = NULL; /* dots have no meaning in dirs */
413 }
414 max = 207 - digits;
415 name = full_name;
416 if ((size_t) max < strlen(name)) {
417 name[max] = '\0';
418 }
419 /* let ext be an empty string */
420 ext = name + strlen(name);
421 }
422
423 ok = 1;
424 /* change name of each file */
425 for (k = i; k <= j; ++k) {
426 char fmt[16];
427 if (dot != NULL) {
428 sprintf(fmt, "%%s%%0%dd.%%s", digits);
429 } else {
430 sprintf(fmt, "%%s%%0%dd%%s", digits);
431 }
432 while (1) {
433 sprintf(tmp, fmt, name, change, ext);
434 ++change;
435 if (change > int_pow(10, digits)) {
436 ok = 0;
437 break;
438 }
439 if (!iso_htable_get(table, tmp, NULL)) {
440 /* the name is unique, so it can be used */
441 break;
442 }
443 }
444 if (ok) {
445 char *new = strdup(tmp);
446 if (new == NULL) {
447 ret = ISO_OUT_OF_MEM;
448 goto ex;
449 }
450 iso_msg_debug(img->image->id, "\"%s\" renamed to \"%s\"",
451 children[k]->name, new);
452
453 iso_htable_remove_ptr(table, children[k]->name, NULL);
454 free(children[k]->name);
455 children[k]->name = new;
456 iso_htable_add(table, new, new);
457
458 /*
459 * if we change a name we need to sort again children
460 * at the end
461 */
462 need_sort = 1;
463 } else {
464 /* we need to increment digits */
465 break;
466 }
467 }
468 if (ok) {
469 break;
470 } else {
471 ++digits;
472 }
473 }
474 if (digits == 8) {
475 ret = ISO_MANGLE_TOO_MUCH_FILES;
476 goto ex;
477 }
478 i = j;
479 }
480
481 /*
482 * If needed, sort again the files inside dir
483 */
484 if (need_sort) {
485 qsort(children, nchildren, sizeof(void*), cmp_node);
486 }
487
488 ret = ISO_SUCCESS;
489
490 ex:;
491 iso_htable_destroy(table, NULL);
492 LIBISO_FREE_MEM(tmp);
493 LIBISO_FREE_MEM(full_name);
494 return ret;
495 }
496
497 static
498 int mangle_tree(Ecma119Image *t, Iso1999Node *dir)
499 {
500 int ret;
501 size_t i;
502
503 ret = mangle_single_dir(t, dir);
504 if (ret < 0) {
505 return ret;
506 }
507
508 /* recurse */
509 for (i = 0; i < dir->info.dir->nchildren; ++i) {
510 if (dir->info.dir->children[i]->type == ISO1999_DIR) {
511 ret = mangle_tree(t, dir->info.dir->children[i]);
512 if (ret < 0) {
513 /* error */
514 return ret;
515 }
516 }
517 }
518 return ISO_SUCCESS;
519 }
520
521 static
522 int iso1999_tree_create(Ecma119Image *t)
523 {
524 int ret;
525 Iso1999Node *root;
526
527 if (t == NULL) {
528 return ISO_NULL_POINTER;
529 }
530
531 ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
532 if (ret <= 0) {
533 if (ret == 0) {
534 /* unexpected error, root ignored!! This can't happen */
535 ret = ISO_ASSERT_FAILURE;
536 }
537 return ret;
538 }
539
540 /* the ISO 9660:1999 tree is stored in Ecma119Image target */
541 t->iso1999_root = root;
542
543 iso_msg_debug(t->image->id, "Sorting the ISO 9660:1999 tree...");
544 sort_tree(root);
545
546 iso_msg_debug(t->image->id, "Mangling ISO 9660:1999 names...");
547 ret = mangle_tree(t, t->iso1999_root);
548 if (ret < 0) {
549 return ret;
550 }
551
552 return ISO_SUCCESS;
553 }
554
555 /**
556 * Compute the size of a directory entry for a single node
557 */
558 static
559 size_t calc_dirent_len(Ecma119Image *t, Iso1999Node *n)
560 {
561 int ret = n->name ? strlen(n->name) + 33 : 34;
562 if (ret % 2)
563 ret++;
564 return ret;
565 }
566
567 /**
568 * Computes the total size of all directory entries of a single dir, as
569 * stated in ISO 9660:1999, 6.8.1.3
570 */
571 static
572 size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
573 {
574 size_t i, len;
575
576 /* size of "." and ".." entries */
577 len = 34 + 34;
578
579 for (i = 0; i < dir->info.dir->nchildren; ++i) {
580 size_t remaining;
581 int section, nsections;
582 Iso1999Node *child = dir->info.dir->children[i];
583 size_t dirent_len = calc_dirent_len(t, child);
584
585 nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
586 for (section = 0; section < nsections; ++section) {
587 remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
588 if (dirent_len > remaining) {
589 /* child directory entry doesn't fit on block */
590 len += remaining + dirent_len;
591 } else {
592 len += dirent_len;
593 }
594 }
595 }
596
597 /*
598 * The size of a dir is always a multiple of block size, as we must add
599 * the size of the unused space after the last directory record
600 * (ISO 9660:1999, 6.8.1.3)
601 */
602 len = ROUND_UP(len, BLOCK_SIZE);
603
604 /* cache the len */
605 dir->info.dir->len = len;
606 return len;
607 }
608
609 static
610 void calc_dir_pos(Ecma119Image *t, Iso1999Node *dir)
611 {
612 size_t i, len;
613
614 t->iso1999_ndirs++;
615 dir->info.dir->block = t->curblock;
616 len = calc_dir_size(t, dir);
617 t->curblock += DIV_UP(len, BLOCK_SIZE);
618 for (i = 0; i < dir->info.dir->nchildren; i++) {
619 Iso1999Node *child = dir->info.dir->children[i];
620 if (child->type == ISO1999_DIR) {
621 calc_dir_pos(t, child);
622 }
623 }
624 }
625
626 /**
627 * Compute the length of the path table (ISO 9660:1999, 6.9), in bytes.
628 */
629 static
630 uint32_t calc_path_table_size(Iso1999Node *dir)
631 {
632 uint32_t size;
633 size_t i;
634
635 /* size of path table for this entry */
636 size = 8;
637 size += dir->name ? strlen(dir->name) : 2;
638 size += (size % 2);
639
640 /* and recurse */
641 for (i = 0; i < dir->info.dir->nchildren; i++) {
642 Iso1999Node *child = dir->info.dir->children[i];
643 if (child->type == ISO1999_DIR) {
644 size += calc_path_table_size(child);
645 }
646 }
647 return size;
648 }
649
650 static
651 int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
652 {
653 Ecma119Image *t;
654 uint32_t path_table_size;
655
656 if (writer == NULL) {
657 return ISO_OUT_OF_MEM;
658 }
659
660 t = writer->target;
661
662 /* compute position of directories */
663 iso_msg_debug(t->image->id,
664 "Computing position of ISO 9660:1999 dir structure");
665 t->iso1999_ndirs = 0;
666 calc_dir_pos(t, t->iso1999_root);
667
668 /* compute length of pathlist */
669 iso_msg_debug(t->image->id, "Computing length of ISO 9660:1999 pathlist");
670 path_table_size = calc_path_table_size(t->iso1999_root);
671
672 /* compute location for path tables */
673 t->iso1999_l_path_table_pos = t->curblock;
674 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
675 t->iso1999_m_path_table_pos = t->curblock;
676 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
677 t->iso1999_path_table_size = path_table_size;
678
679 return ISO_SUCCESS;
680 }
681
682 /**
683 * Write a single directory record (ISO 9660:1999, 9.1).
684 *
685 * @param file_id
686 * if >= 0, we use it instead of the filename (for "." and ".." entries).
687 * @param len_fi
688 * Computed length of the file identifier.
689 */
690 static
691 void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
692 uint8_t *buf, size_t len_fi, int extent)
693 {
694 uint32_t len;
695 uint32_t block;
696 uint8_t len_dr; /*< size of dir entry */
697 int multi_extend = 0;
698 uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
699 : (uint8_t*)node->name;
700
701 struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
702 IsoNode *iso;
703
704 len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
705
706 memcpy(rec->file_id, name, len_fi);
707
708 if (node->type == ISO1999_DIR) {
709 /* use the cached length */
710 len = node->info.dir->len;
711 block = node->info.dir->block;
712 } else if (node->type == ISO1999_FILE) {
713 block = node->info.file->sections[extent].block;
714 len = node->info.file->sections[extent].size;
715 multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
716 } else {
717 /*
718 * for nodes other than files and dirs, we set both
719 * len and block to 0
720 */
721 len = 0;
722 block = 0;
723 }
724
725 /*
726 * For ".." entry we need to write the parent info!
727 */
728 if (file_id == 1 && node->parent)
729 node = node->parent;
730
731 rec->len_dr[0] = len_dr;
732 iso_bb(rec->block, block, 4);
733 iso_bb(rec->length, len, 4);
734
735 /* was: iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
736 */
737 iso= node->node;
738 iso_datetime_7(rec->recording_time,
739 (t->opts->dir_rec_mtime & 4) ? ( t->replace_timestamps ?
740 t->timestamp : iso->mtime )
741 : t->now, t->opts->always_gmt);
742
743 rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
744 iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
745 rec->len_fi[0] = len_fi;
746 }
747
748 /**
749 * Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
750 */
751 static
752 int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
753 {
754 IsoImage *image;
755 Ecma119Image *t;
756
757 /* The enhanced volume descriptor is like the sup vol desc */
758 struct ecma119_sup_vol_desc vol;
759
760 char *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
761 char *volset_id = NULL, *system_id = NULL, *application_id = NULL;
762 char *copyright_file_id = NULL, *abstract_file_id = NULL;
763 char *biblio_file_id = NULL;
764
765 if (writer == NULL) {
766 return ISO_OUT_OF_MEM;
767 }
768
769 t = writer->target;
770 image = t->image;
771
772 iso_msg_debug(image->id, "Write Enhanced Vol Desc (ISO 9660:1999)");
773
774 memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
775
776 get_iso1999_name(t, image->volume_id, &vol_id);
777 str2a_char(t->input_charset, image->publisher_id, &pub_id);
778 str2a_char(t->input_charset, image->data_preparer_id, &data_id);
779 get_iso1999_name(t, image->volset_id, &volset_id);
780
781 str2a_char(t->input_charset, image->system_id, &system_id);
782 str2a_char(t->input_charset, image->application_id, &application_id);
783 get_iso1999_name(t, image->copyright_file_id, ©right_file_id);
784 get_iso1999_name(t, image->abstract_file_id, &abstract_file_id);
785 get_iso1999_name(t, image->biblio_file_id, &biblio_file_id);
786
787 vol.vol_desc_type[0] = 2;
788 memcpy(vol.std_identifier, "CD001", 5);
789
790 /* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
791 vol.vol_desc_version[0] = 2;
792 strncpy_pad((char*)vol.volume_id, vol_id, 32);
793
794 iso_bb(vol.vol_space_size, t->vol_space_size, 4);
795 iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
796 iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
797 iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
798 iso_bb(vol.path_table_size, t->iso1999_path_table_size, 4);
799 iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4);
800 iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4);
801
802 write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1, 0);
803
804 strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
805 strncpy_pad((char*)vol.publisher_id, pub_id, 128);
806 strncpy_pad((char*)vol.data_prep_id, data_id, 128);
807
808 strncpy_pad((char*)vol.system_id, system_id, 32);
809
810 strncpy_pad((char*)vol.application_id, application_id, 128);
811 strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
812 strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
813 strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
814
815 ecma119_set_voldescr_times(writer, (struct ecma119_pri_vol_desc *) &vol);
816 vol.file_structure_version[0] = 2;
817
818 free(vol_id);
819 free(volset_id);
820 free(pub_id);
821 free(data_id);
822 free(system_id);
823 free(application_id);
824 free(copyright_file_id);
825 free(abstract_file_id);
826 free(biblio_file_id);
827
828 /* Finally write the Volume Descriptor */
829 return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
830 }
831
832 static
833 int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
834 {
835 int ret;
836 uint8_t *buffer = NULL;
837 size_t i;
838 size_t fi_len, len;
839
840 /* buf will point to current write position on buffer */
841 uint8_t *buf;
842
843 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
844 buf = buffer;
845
846 /* write the "." and ".." entries first */
847 write_one_dir_record(t, dir, 0, buf, 1, 0);
848 buf += 34;
849 write_one_dir_record(t, dir, 1, buf, 1, 0);
850 buf += 34;
851
852 for (i = 0; i < dir->info.dir->nchildren; i++) {
853 int section, nsections;
854 Iso1999Node *child = dir->info.dir->children[i];
855
856 /* compute len of directory entry */
857 fi_len = strlen(child->name);
858 len = fi_len + 33 + ((fi_len % 2) ? 0 : 1);
859
860 nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
861 for (section = 0; section < nsections; ++section) {
862 if ( (buf + len - buffer) > BLOCK_SIZE) {
863 /* dir doesn't fit in current block */
864 ret = iso_write(t, buffer, BLOCK_SIZE);
865 if (ret < 0) {
866 goto ex;
867 }
868 memset(buffer, 0, BLOCK_SIZE);
869 buf = buffer;
870 }
871 /* write the directory entry in any case */
872 write_one_dir_record(t, child, -1, buf, fi_len, section);
873 buf += len;
874 }
875 }
876
877 /* write the last block */
878 ret = iso_write(t, buffer, BLOCK_SIZE);
879 ex:;
880 LIBISO_FREE_MEM(buffer);
881 return ret;
882 }
883
884 static
885 int write_dirs(Ecma119Image *t, Iso1999Node *root)
886 {
887 int ret;
888 size_t i;
889
890 /* write all directory entries for this dir */
891 ret = write_one_dir(t, root);
892 if (ret < 0) {
893 return ret;
894 }
895
896 /* recurse */
897 for (i = 0; i < root->info.dir->nchildren; i++) {
898 Iso1999Node *child = root->info.dir->children[i];
899 if (child->type == ISO1999_DIR) {
900 ret = write_dirs(t, child);
901 if (ret < 0) {
902 return ret;
903 }
904 }
905 }
906 return ISO_SUCCESS;
907 }
908
909 static
910 int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
911 {
912 size_t i, len;
913 uint8_t *buf = NULL;
914 struct ecma119_path_table_record *rec;
915 void (*write_int)(uint8_t*, uint32_t, int);
916 Iso1999Node *dir;
917 uint32_t path_table_size;
918 int parent = 0;
919 int ret= ISO_SUCCESS;
920 uint8_t *zeros = NULL;
921
922 /* 256 is just a convenient size large enough */
923 LIBISO_ALLOC_MEM(buf, uint8_t, 256);
924
925 path_table_size = 0;
926 write_int = l_type ? iso_lsb : iso_msb;
927
928 for (i = 0; i < t->iso1999_ndirs; i++) {
929 dir = pathlist[i];
930
931 /* find the index of the parent in the table */
932 while ((i) && pathlist[parent] != dir->parent) {
933 parent++;
934 }
935
936 /* write the Path Table Record (ECMA-119, 9.4) */
937 memset(buf, 0, 256);
938 rec = (struct ecma119_path_table_record*) buf;
939 rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
940 rec->len_xa[0] = 0;
941 write_int(rec->block, dir->info.dir->block, 4);
942 write_int(rec->parent, parent + 1, 2);
943 if (dir->parent) {
944 memcpy(rec->dir_id, dir->name, rec->len_di[0]);
945 }
946 len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
947 ret = iso_write(t, buf, len);
948 if (ret < 0) {
949 /* error */
950 goto ex;
951 }
952 path_table_size += len;
953 }
954
955 /* we need to fill the last block with zeros */
956 path_table_size %= BLOCK_SIZE;
957 if (path_table_size) {
958 LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
959 len = BLOCK_SIZE - path_table_size;
960 memset(zeros, 0, len);
961 ret = iso_write(t, zeros, len);
962 }
963 ex:;
964 LIBISO_FREE_MEM(zeros);
965 LIBISO_FREE_MEM(buf);
966 return ret;
967 }
968
969 static
970 int write_path_tables(Ecma119Image *t)
971 {
972 int ret;
973 size_t i, j, cur;
974 Iso1999Node **pathlist;
975
976 iso_msg_debug(t->image->id, "Writing ISO 9660:1999 Path tables");
977
978 /* allocate temporal pathlist */
979 pathlist = malloc(sizeof(void*) * t->iso1999_ndirs);
980 if (pathlist == NULL) {
981 return ISO_OUT_OF_MEM;
982 }
983 pathlist[0] = t->iso1999_root;
984 cur = 1;
985
986 for (i = 0; i < t->iso1999_ndirs; i++) {
987 Iso1999Node *dir = pathlist[i];
988 for (j = 0; j < dir->info.dir->nchildren; j++) {
989 Iso1999Node *child = dir->info.dir->children[j];
990 if (child->type == ISO1999_DIR) {
991 pathlist[cur++] = child;
992 }
993 }
994 }
995
996 /* Write L Path Table */
997 ret = write_path_table(t, pathlist, 1);
998 if (ret < 0) {
999 goto write_path_tables_exit;
1000 }
1001
1002 /* Write L Path Table */
1003 ret = write_path_table(t, pathlist, 0);
1004
1005 write_path_tables_exit: ;
1006 free(pathlist);
1007 return ret;
1008 }
1009
1010 static
1011 int iso1999_writer_write_data(IsoImageWriter *writer)
1012 {
1013 int ret;
1014 Ecma119Image *t;
1015
1016 if (writer == NULL) {
1017 return ISO_NULL_POINTER;
1018 }
1019 t = writer->target;
1020
1021 /* first of all, we write the directory structure */
1022 ret = write_dirs(t, t->iso1999_root);
1023 if (ret < 0) {
1024 return ret;
1025 }
1026
1027 /* and write the path tables */
1028 ret = write_path_tables(t);
1029
1030 return ret;
1031 }
1032
1033 static
1034 int iso1999_writer_free_data(IsoImageWriter *writer)
1035 {
1036 /* free the ISO 9660:1999 tree */
1037 Ecma119Image *t = writer->target;
1038 iso1999_node_free(t->iso1999_root);
1039 return ISO_SUCCESS;
1040 }
1041
1042 int iso1999_writer_create(Ecma119Image *target)
1043 {
1044 int ret;
1045 IsoImageWriter *writer;
1046
1047 writer = malloc(sizeof(IsoImageWriter));
1048 if (writer == NULL) {
1049 return ISO_OUT_OF_MEM;
1050 }
1051
1052 writer->compute_data_blocks = iso1999_writer_compute_data_blocks;
1053 writer->write_vol_desc = iso1999_writer_write_vol_desc;
1054 writer->write_data = iso1999_writer_write_data;
1055 writer->free_data = iso1999_writer_free_data;
1056 writer->data = NULL;
1057 writer->target = target;
1058
1059 iso_msg_debug(target->image->id,
1060 "Creating low level ISO 9660:1999 tree...");
1061 ret = iso1999_tree_create(target);
1062 if (ret < 0) {
1063 free((char *) writer);
1064 return ret;
1065 }
1066
1067 /* add this writer to image */
1068 target->writers[target->nwriters++] = writer;
1069
1070 /* we need the volume descriptor */
1071 target->curblock++;
1072 return ISO_SUCCESS;
1073 }