"Fossies" - the Fresh Open Source Software Archive 
Member "libisofs-1.5.4/libisofs/joliet.c" (8 Jul 2020, 37918 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 "joliet.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2007 Mario Danic
4 * Copyright (c) 2011-2018 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 #include "joliet.h"
17 #include "messages.h"
18 #include "writer.h"
19 #include "image.h"
20 #include "filesrc.h"
21 #include "eltorito.h"
22 #include "libisofs.h"
23 #include "util.h"
24 #include "ecma119.h"
25
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 /* @param flag bit0= Do not issue error messages
32 */
33 int iso_get_joliet_name(IsoWriteOpts *opts, char *input_charset, int imgid,
34 char *node_name, enum IsoNodeType node_type,
35 size_t *joliet_ucs2_failures,
36 uint16_t **name, int flag)
37 {
38 int ret = ISO_SUCCESS;
39 uint16_t *ucs_name = NULL, *utf16_name = NULL;
40 uint16_t *jname = NULL;
41
42 if (node_name == NULL) {
43 /* it is not necessarily an error, it can be the root */
44 *name = NULL;
45 return ISO_SUCCESS;
46 }
47
48 if (opts->joliet_utf16) {
49 ret = str2utf16be(input_charset, node_name, &ucs_name);
50 if (ret < 0) {
51 if (!(flag & 512))
52 iso_msg_debug(imgid, "Cannot convert to UTF-16 : \"%s\"",
53 node_name);
54 goto ex;
55 }
56 } else {
57 ret = str2ucs(input_charset, node_name, &ucs_name);
58 if (ret < 0) {
59 if (!(flag & 512))
60 iso_msg_debug(imgid, "Cannot convert to UCS-2 : \"%s\"",
61 node_name);
62 goto ex;
63 }
64 ret = str2utf16be(input_charset, node_name, &utf16_name);
65 if (ret == ISO_SUCCESS) {
66 if (ucscmp(ucs_name, utf16_name) != 0) {
67 (*joliet_ucs2_failures)++;
68 if (*joliet_ucs2_failures <= ISO_JOLIET_UCS2_WARN_MAX &&
69 !(flag & 512)) {
70 iso_msg_submit(imgid, ISO_NAME_NOT_UCS2, 0,
71 "Filename not suitable for Joliet character set UCS-2 : \"%s\"",
72 node_name);
73 }
74 }
75 }
76 }
77 if (node_type == LIBISO_DIR) {
78 jname = iso_j_dir_id(ucs_name, opts->joliet_long_names << 1);
79 } else {
80 jname = iso_j_file_id(ucs_name,
81 (opts->joliet_long_names << 1) | !!(opts->no_force_dots & 2));
82 }
83 ret = ISO_SUCCESS;
84 ex:;
85 if (ucs_name != NULL)
86 free(ucs_name);
87 if (utf16_name != NULL)
88 free(utf16_name);
89 if (ret != ISO_SUCCESS) {
90 if (jname != NULL)
91 free(jname);
92 return ret;
93 } else if (jname != NULL) {
94 *name = jname;
95 return ISO_SUCCESS;
96 } else {
97 /*
98 * only possible if mem error, as check for empty names is done
99 * in public tree
100 */
101 return ISO_OUT_OF_MEM;
102 }
103 }
104
105 static
106 int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
107 {
108 int ret;
109
110 ret = iso_get_joliet_name(t->opts, t->input_charset, t->image->id,
111 iso->name, iso->type, &(t->joliet_ucs2_failures),
112 name, 0);
113
114 return ret;
115 }
116
117
118 static
119 void joliet_node_free(JolietNode *node)
120 {
121 if (node == NULL) {
122 return;
123 }
124 if (node->type == JOLIET_DIR) {
125 size_t i;
126 for (i = 0; i < node->info.dir->nchildren; i++) {
127 joliet_node_free(node->info.dir->children[i]);
128 }
129 if (node->info.dir->children != NULL)
130 free(node->info.dir->children);
131 free(node->info.dir);
132 }
133 iso_node_unref(node->node);
134 free(node->name);
135 free(node);
136 }
137
138 /**
139 * Create a low level Joliet node
140 * @return
141 * 1 success, 0 ignored, < 0 error
142 */
143 static
144 int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
145 {
146 int ret;
147 JolietNode *joliet;
148
149 joliet = calloc(1, sizeof(JolietNode));
150 if (joliet == NULL) {
151 return ISO_OUT_OF_MEM;
152 }
153
154 if (iso->type == LIBISO_DIR) {
155 IsoDir *dir = (IsoDir*) iso;
156 joliet->info.dir = calloc(1, sizeof(struct joliet_dir_info));
157 if (joliet->info.dir == NULL) {
158 free(joliet);
159 return ISO_OUT_OF_MEM;
160 }
161 joliet->info.dir->children = NULL;
162 if (dir->nchildren > 0) {
163 joliet->info.dir->children = calloc(sizeof(void*), dir->nchildren);
164 if (joliet->info.dir->children == NULL) {
165 free(joliet->info.dir);
166 free(joliet);
167 return ISO_OUT_OF_MEM;
168 }
169 }
170 joliet->type = JOLIET_DIR;
171 } else if (iso->type == LIBISO_FILE) {
172 /* it's a file */
173 off_t size;
174 IsoFileSrc *src;
175 IsoFile *file = (IsoFile*) iso;
176
177 size = iso_stream_get_size(file->stream);
178 if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE &&
179 t->opts->iso_level != 3) {
180 char *ipath = iso_tree_get_node_path(iso);
181 free(joliet);
182 ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
183 "File \"%s\" can't be added to image because is "
184 "greater than 4GB", ipath);
185 free(ipath);
186 return ret;
187 }
188
189 ret = iso_file_src_create(t, file, &src);
190 if (ret < 0) {
191 free(joliet);
192 return ret;
193 }
194 joliet->info.file = src;
195 joliet->type = JOLIET_FILE;
196 } else if (iso->type == LIBISO_BOOT) {
197 /* it's a el-torito boot catalog, that we write as a file */
198 IsoFileSrc *src;
199
200 ret = el_torito_catalog_file_src_create(t, &src);
201 if (ret < 0) {
202 free(joliet);
203 return ret;
204 }
205 joliet->info.file = src;
206 joliet->type = JOLIET_FILE;
207 } else {
208 /* should never happen */
209 free(joliet);
210 return ISO_ASSERT_FAILURE;
211 }
212
213 /* take a ref to the IsoNode */
214 joliet->node = iso;
215 iso_node_ref(iso);
216
217 *node = joliet;
218 return ISO_SUCCESS;
219 }
220
221 /**
222 * Create the low level Joliet tree from the high level ISO tree.
223 *
224 * @return
225 * 1 success, 0 file ignored, < 0 error
226 */
227 static
228 int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
229 {
230 int ret, max_path;
231 JolietNode *node = NULL;
232 uint16_t *jname = NULL;
233
234 if (t == NULL || iso == NULL || tree == NULL) {
235 return ISO_NULL_POINTER;
236 }
237
238 if (iso->hidden & LIBISO_HIDE_ON_JOLIET) {
239 /* file will be ignored */
240 return 0;
241 }
242 ret = get_joliet_name(t, iso, &jname);
243 if (ret < 0) {
244 return ret;
245 }
246 max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0);
247 if (!t->opts->joliet_longer_paths && max_path > 240) {
248 char *ipath = iso_tree_get_node_path(iso);
249 /*
250 * Wow!! Joliet is even more restrictive than plain ISO-9660,
251 * that allows up to 255 bytes!!
252 */
253 ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
254 "File \"%s\" can't be added to Joliet tree, because "
255 "its path length is larger than 240", ipath);
256 free(jname);
257 free(ipath);
258 return ret;
259 }
260
261 switch (iso->type) {
262 case LIBISO_FILE:
263 ret = create_node(t, iso, &node);
264 break;
265 case LIBISO_DIR:
266 {
267 IsoNode *pos;
268 IsoDir *dir = (IsoDir*)iso;
269 ret = create_node(t, iso, &node);
270 if (ret < 0) {
271 free(jname);
272 return ret;
273 }
274 pos = dir->children;
275 while (pos) {
276 int cret;
277 JolietNode *child;
278 cret = create_tree(t, pos, &child, max_path);
279 if (cret < 0) {
280 /* error */
281 joliet_node_free(node);
282 ret = cret;
283 break;
284 } else if (cret == ISO_SUCCESS) {
285 /* add child to this node */
286 int nchildren = node->info.dir->nchildren++;
287 node->info.dir->children[nchildren] = child;
288 child->parent = node;
289 }
290 pos = pos->next;
291 }
292 }
293 break;
294 case LIBISO_BOOT:
295 if (t->eltorito) {
296 ret = create_node(t, iso, &node);
297 } else {
298 /* log and ignore */
299 ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
300 "El-Torito catalog found on a image without El-Torito.");
301 }
302 break;
303 case LIBISO_SYMLINK:
304 case LIBISO_SPECIAL:
305 {
306 char *ipath = iso_tree_get_node_path(iso);
307 ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
308 "Cannot add %s to Joliet tree. %s can only be added to a "
309 "Rock Ridge tree.", ipath, (iso->type == LIBISO_SYMLINK ?
310 "Symlinks" : "Special files"));
311 free(ipath);
312 }
313 break;
314 default:
315 /* should never happen */
316 return ISO_ASSERT_FAILURE;
317 }
318 if (ret <= 0) {
319 free(jname);
320 return ret;
321 }
322 node->name = jname;
323 *tree = node;
324 return ISO_SUCCESS;
325 }
326
327 static int
328 cmp_node(const void *f1, const void *f2)
329 {
330 JolietNode *f = *((JolietNode**)f1);
331 JolietNode *g = *((JolietNode**)f2);
332 return ucscmp(f->name, g->name);
333 }
334
335 static
336 void sort_tree(JolietNode *root)
337 {
338 size_t i;
339
340 if (root->info.dir->children == NULL)
341 return;
342 qsort(root->info.dir->children, root->info.dir->nchildren,
343 sizeof(void*), cmp_node);
344 for (i = 0; i < root->info.dir->nchildren; i++) {
345 JolietNode *child = root->info.dir->children[i];
346 if (child->type == JOLIET_DIR)
347 sort_tree(child);
348 }
349 }
350
351 static
352 int cmp_node_name(const void *f1, const void *f2)
353 {
354 JolietNode *f = *((JolietNode**)f1);
355 JolietNode *g = *((JolietNode**)f2);
356 return ucscmp(f->name, g->name);
357 }
358
359 static
360 int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits,
361 int number, uint16_t *ext)
362 {
363 int ret, pos;
364 uint16_t *ucsnumber;
365 char fmt[16];
366 char nstr[72];
367 /* was: The only caller of this function allocates dest
368 with 66 elements and limits digits to < 8
369 But this does not match the usage of nstr which has to take
370 the decimal representation of an int.
371 */
372
373 if (digits >= 8)
374 return ISO_ASSERT_FAILURE;
375
376 sprintf(fmt, "%%0%dd", digits);
377 sprintf(nstr, fmt, number);
378
379 ret = str2ucs("ASCII", nstr, &ucsnumber);
380 if (ret < 0) {
381 return ret;
382 }
383
384 /* copy name */
385 pos = ucslen(src);
386 ucsncpy(dest, src, pos);
387
388 /* copy number */
389 ucsncpy(dest + pos, ucsnumber, digits);
390 pos += digits;
391
392 if (ext[0] != (uint16_t)0) {
393 size_t extlen = ucslen(ext);
394 iso_msb((uint8_t *) (dest + pos), 0x002E, 2); /* '.' in UCS */
395 pos++;
396 ucsncpy(dest + pos, ext, extlen);
397 pos += extlen;
398 }
399 iso_msb((uint8_t *) (dest + pos), 0, 2);
400 free(ucsnumber);
401 return ISO_SUCCESS;
402 }
403
404 /*
405 * From Joliet specs:
406 * "ISO 9660 (Section 7.5.1) states that the sum of the following shall not
407 * exceed 30:
408 * - If there is a file name, the length of the file name.
409 * - If there is a file name extension, the length of the file name extension.
410 * On Joliet compliant media, however, the sum as calculated above shall not
411 * exceed 128 [bytes], to allow for longer file identifiers."
412 *
413 * I.e. the dot does not count.
414 *
415 * (We have an option to lift the limit from 64*2 to 103*2, which is the
416 * maximum to fit into an ISO 9660 directory record.)
417 */
418 static
419 int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
420 {
421 int ret;
422 int i, nchildren, maxchar = 64;
423 JolietNode **children;
424 IsoHTable *table = NULL;
425 int need_sort = 0;
426 uint16_t *full_name = NULL;
427 uint16_t *tmp = NULL;
428
429 nchildren = dir->info.dir->nchildren;
430 if (nchildren <= 0) {
431 ret = ISO_SUCCESS;
432 goto ex;
433 }
434 children = dir->info.dir->children;
435 LIBISO_ALLOC_MEM(full_name, uint16_t, LIBISO_JOLIET_NAME_MAX);
436 LIBISO_ALLOC_MEM(tmp, uint16_t, LIBISO_JOLIET_NAME_MAX);
437
438 if (t->opts->joliet_long_names)
439 maxchar = 103;
440
441 /* a hash table will temporary hold the names, for fast searching */
442 ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
443 (compare_function_t)ucscmp, &table);
444 if (ret < 0) {
445 goto ex;
446 }
447 for (i = 0; i < nchildren; ++i) {
448 uint16_t *name = children[i]->name;
449 ret = iso_htable_add(table, name, name);
450 if (ret < 0) {
451 goto mangle_cleanup;
452 }
453 }
454
455 for (i = 0; i < nchildren; ++i) {
456 uint16_t *name, *ext;
457 int max; /* computed max len for name, without extension */
458 int j = i;
459 int digits = 1; /* characters to change per name */
460
461 /* first, find all child with same name */
462 while (j + 1 < nchildren &&
463 !cmp_node_name(children + i, children + j + 1)) {
464 ++j;
465 }
466 if (j == i) {
467 /* name is unique */
468 continue;
469 }
470
471 /*
472 * A max of 7 characters is good enough, it allows handling up to
473 * 9,999,999 files with same name.
474 */
475 /* Important: joliet_create_mangled_name() relies on digits < 8 */
476
477 while (digits < 8) {
478 int ok, k;
479 uint16_t *dot;
480 int change = 0; /* number to be written */
481
482 /* copy name to buffer */
483 ucscpy(full_name, children[i]->name);
484
485 /* compute name and extension */
486 dot = ucsrchr(full_name, '.');
487 if (dot != NULL && children[i]->type != JOLIET_DIR) {
488
489 /*
490 * File (not dir) with extension
491 */
492 int extlen;
493 full_name[dot - full_name] = 0;
494 name = full_name;
495 ext = dot + 1;
496
497 extlen = ucslen(ext);
498 max = maxchar - extlen - digits;
499 if (max <= 0) {
500 /*
501 * This can happen if the extension is too long.
502 * Reduce its length, to give name at least one
503 * original character, if it has any.
504 */
505 max = (dot > full_name);
506 extlen = maxchar - max - digits;
507 if (extlen < 3) {
508 /*
509 * error, we do not reduce extensions to length < 3
510 *
511 * This cannot happen with current limit of digits
512 * because maxchar is at least 64 and digits at most 7.
513 */
514 ret = ISO_ERROR;
515 goto mangle_cleanup;
516 }
517 ext[extlen] = 0;
518 }
519 /* ok, reduce name by digits */
520 if (name + max < dot) {
521 name[max] = 0;
522 }
523 } else {
524 /* Directory, or file without extension */
525 if (children[i]->type == JOLIET_DIR) {
526 max = maxchar - digits;
527 dot = NULL; /* dots have no meaning in dirs */
528 } else {
529 max = maxchar - digits;
530 }
531 name = full_name;
532 if ((size_t) max < ucslen(name)) {
533 name[max] = 0;
534 }
535 /* let ext be an empty string */
536 ext = name + ucslen(name);
537 }
538
539 ok = 1;
540 /* change name of each file */
541 for (k = i; k <= j; ++k) {
542 while (1) {
543 ret = joliet_create_mangled_name(tmp, name, digits,
544 change, ext);
545 if (ret < 0) {
546 goto mangle_cleanup;
547 }
548 ++change;
549 if (change > int_pow(10, digits)) {
550 ok = 0;
551 break;
552 }
553 if (!iso_htable_get(table, tmp, NULL)) {
554 /* the name is unique, so it can be used */
555 break;
556 }
557 }
558 if (ok) {
559 uint16_t *new = ucsdup(tmp);
560 if (new == NULL) {
561 ret = ISO_OUT_OF_MEM;
562 goto mangle_cleanup;
563 }
564
565 iso_htable_remove_ptr(table, children[k]->name, NULL);
566 free(children[k]->name);
567 children[k]->name = new;
568 iso_htable_add(table, new, new);
569
570 /*
571 * if we change a name we need to sort again children
572 * at the end
573 */
574 need_sort = 1;
575 } else {
576 /* we need to increment digits */
577 break;
578 }
579 }
580 if (ok) {
581 break;
582 } else {
583 ++digits;
584 }
585 }
586 if (digits == 8) {
587 ret = ISO_MANGLE_TOO_MUCH_FILES;
588 goto mangle_cleanup;
589 }
590 i = j;
591 }
592
593 /*
594 * If needed, sort again the files inside dir
595 */
596 if (need_sort) {
597 qsort(children, nchildren, sizeof(void*), cmp_node_name);
598 }
599
600 ret = ISO_SUCCESS;
601
602 mangle_cleanup : ;
603 ex:;
604 iso_htable_destroy(table, NULL);
605 LIBISO_FREE_MEM(tmp);
606 LIBISO_FREE_MEM(full_name);
607 return ret;
608 }
609
610 static
611 int mangle_tree(Ecma119Image *t, JolietNode *dir)
612 {
613 int ret;
614 size_t i;
615
616 ret = mangle_single_dir(t, dir);
617 if (ret < 0) {
618 return ret;
619 }
620
621 /* recurse */
622 for (i = 0; i < dir->info.dir->nchildren; ++i) {
623 if (dir->info.dir->children[i]->type == JOLIET_DIR) {
624 ret = mangle_tree(t, dir->info.dir->children[i]);
625 if (ret < 0) {
626 /* error */
627 return ret;
628 }
629 }
630 }
631 return ISO_SUCCESS;
632 }
633
634 static
635 int joliet_tree_create(Ecma119Image *t)
636 {
637 int ret;
638 JolietNode *root;
639
640 if (t == NULL) {
641 return ISO_NULL_POINTER;
642 }
643
644 ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
645 if (ret <= 0) {
646 if (ret == 0) {
647 /* unexpected error, root ignored!! This can't happen */
648 ret = ISO_ASSERT_FAILURE;
649 }
650 return ret;
651 }
652
653 /* the Joliet tree is stored in Ecma119Image target */
654 if (t->eff_partition_offset > 0) {
655 t->j_part_root = root;
656 } else {
657 t->joliet_root = root;
658 }
659
660 iso_msg_debug(t->image->id, "Sorting the Joliet tree...");
661 sort_tree(root);
662
663 iso_msg_debug(t->image->id, "Mangling Joliet names...");
664 ret = mangle_tree(t, root);
665 if (ret < 0)
666 return ret;
667 return ISO_SUCCESS;
668 }
669
670 /**
671 * Compute the size of a directory entry for a single node
672 */
673 static
674 size_t calc_dirent_len(Ecma119Image *t, JolietNode *n)
675 {
676 /* note than name len is always even, so we always need the pad byte */
677 int ret = n->name ? ucslen(n->name) * 2 + 34 : 34;
678 if (n->type == JOLIET_FILE && !(t->opts->omit_version_numbers & 3)) {
679 /* take into account version numbers */
680 ret += 4;
681 }
682 return ret;
683 }
684
685 /**
686 * Computes the total size of all directory entries of a single joliet dir.
687 * This is like ECMA-119 6.8.1.1, but taking care that names are stored in
688 * UCS.
689 */
690 static
691 size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
692 {
693 size_t i, len;
694
695 /* size of "." and ".." entries */
696 len = 34 + 34;
697
698 for (i = 0; i < dir->info.dir->nchildren; ++i) {
699 size_t remaining;
700 int section, nsections;
701 JolietNode *child = dir->info.dir->children[i];
702 size_t dirent_len = calc_dirent_len(t, child);
703
704 nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
705 for (section = 0; section < nsections; ++section) {
706 remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
707 if (dirent_len > remaining) {
708 /* child directory entry doesn't fit on block */
709 len += remaining + dirent_len;
710 } else {
711 len += dirent_len;
712 }
713 }
714 }
715
716 /*
717 * The size of a dir is always a multiple of block size, as we must add
718 * the size of the unused space after the last directory record
719 * (ECMA-119, 6.8.1.3)
720 */
721 len = ROUND_UP(len, BLOCK_SIZE);
722
723 /* cache the len */
724 dir->info.dir->len = len;
725 return len;
726 }
727
728 static
729 void calc_dir_pos(Ecma119Image *t, JolietNode *dir)
730 {
731 size_t i, len;
732
733 t->joliet_ndirs++;
734 dir->info.dir->block = t->curblock;
735 len = calc_dir_size(t, dir);
736 t->curblock += DIV_UP(len, BLOCK_SIZE);
737 for (i = 0; i < dir->info.dir->nchildren; i++) {
738 JolietNode *child = dir->info.dir->children[i];
739 if (child->type == JOLIET_DIR) {
740 calc_dir_pos(t, child);
741 }
742 }
743 }
744
745 /**
746 * Compute the length of the joliet path table, in bytes.
747 */
748 static
749 uint32_t calc_path_table_size(JolietNode *dir)
750 {
751 uint32_t size;
752 size_t i;
753
754 /* size of path table for this entry */
755 size = 8;
756 size += dir->name ? ucslen(dir->name) * 2 : 2;
757
758 /* and recurse */
759 for (i = 0; i < dir->info.dir->nchildren; i++) {
760 JolietNode *child = dir->info.dir->children[i];
761 if (child->type == JOLIET_DIR) {
762 size += calc_path_table_size(child);
763 }
764 }
765 return size;
766 }
767
768 static
769 int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
770 {
771 Ecma119Image *t;
772 uint32_t path_table_size;
773 size_t ndirs;
774
775 if (writer == NULL) {
776 return ISO_OUT_OF_MEM;
777 }
778
779 t = writer->target;
780
781 /* compute position of directories */
782 iso_msg_debug(t->image->id, "Computing position of Joliet dir structure");
783 t->joliet_ndirs = 0;
784 calc_dir_pos(t, t->joliet_root);
785
786 /* compute length of pathlist */
787 iso_msg_debug(t->image->id, "Computing length of Joliet pathlist");
788 path_table_size = calc_path_table_size(t->joliet_root);
789
790 /* compute location for path tables */
791 t->joliet_l_path_table_pos = t->curblock;
792 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
793 t->joliet_m_path_table_pos = t->curblock;
794 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
795 t->joliet_path_table_size = path_table_size;
796
797 if (t->opts->partition_offset > 0) {
798 /* Take into respect second directory tree */
799 ndirs = t->joliet_ndirs;
800 t->joliet_ndirs = 0;
801 calc_dir_pos(t, t->j_part_root);
802 if (t->joliet_ndirs != ndirs) {
803 iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
804 "Number of directories differs in Joliet partiton_tree");
805 return ISO_ASSERT_FAILURE;
806 }
807 /* Take into respect second set of path tables */
808 path_table_size = calc_path_table_size(t->j_part_root);
809 t->j_part_l_path_table_pos = t->curblock;
810 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
811 t->j_part_m_path_table_pos = t->curblock;
812 t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
813 }
814
815 return ISO_SUCCESS;
816 }
817
818 /**
819 * Write a single directory record for Joliet. It is like (ECMA-119, 9.1),
820 * but file identifier is stored in UCS.
821 *
822 * @param file_id
823 * if >= 0, we use it instead of the filename (for "." and ".." entries).
824 * @param len_fi
825 * Computed length of the file identifier. Total size of the directory
826 * entry will be len + 34 (ECMA-119, 9.1.12), as padding is always needed
827 */
828 static
829 void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
830 uint8_t *buf, size_t len_fi, int extent)
831 {
832 uint32_t len;
833 uint32_t block;
834 uint8_t len_dr; /*< size of dir entry */
835 int multi_extend = 0;
836 uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
837 : (uint8_t*)node->name;
838
839 struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
840 IsoNode *iso;
841
842 len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
843
844 memcpy(rec->file_id, name, len_fi);
845
846 if (node->type == JOLIET_FILE && !(t->opts->omit_version_numbers & 3)) {
847 len_dr += 4;
848 rec->file_id[len_fi++] = 0;
849 rec->file_id[len_fi++] = ';';
850 rec->file_id[len_fi++] = 0;
851 rec->file_id[len_fi++] = '1';
852 }
853
854 if (node->type == JOLIET_DIR) {
855 /* use the cached length */
856 len = node->info.dir->len;
857 block = node->info.dir->block;
858 } else if (node->type == JOLIET_FILE) {
859 block = node->info.file->sections[extent].block;
860 len = node->info.file->sections[extent].size;
861 multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
862 } else {
863 /*
864 * for nodes other than files and dirs, we set both
865 * len and block to 0
866 */
867 len = 0;
868 block = 0;
869 }
870
871 /*
872 * For ".." entry we need to write the parent info!
873 */
874 if (file_id == 1 && node->parent)
875 node = node->parent;
876
877 rec->len_dr[0] = len_dr;
878 iso_bb(rec->block, block - t->eff_partition_offset, 4);
879 iso_bb(rec->length, len, 4);
880
881 /* was: iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
882 */
883 iso= node->node;
884 iso_datetime_7(rec->recording_time,
885 (t->opts->dir_rec_mtime & 2) ? ( t->replace_timestamps ?
886 t->timestamp : iso->mtime )
887 : t->now, t->opts->always_gmt);
888
889 rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
890 iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
891 rec->len_fi[0] = len_fi;
892 }
893
894 /**
895 * Copy up to \p max characters from \p src to \p dest. If \p src has less than
896 * \p max characters, we pad dest with " " characters.
897 */
898 static
899 void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max)
900 {
901 char *cdest, *csrc;
902 size_t len, i;
903
904 cdest = (char*)dest;
905 csrc = (char*)src;
906
907 if (src != NULL) {
908 len = MIN(ucslen(src) * 2, max - (max % 2));
909 } else {
910 len = 0;
911 }
912
913 for (i = 0; i < len; ++i)
914 cdest[i] = csrc[i];
915 if (len >= 2)
916 iso_handle_split_utf16(dest + (len / 2 - 1));
917
918 for (i = len; i + 1 < max; i += 2) {
919 cdest[i] = '\0';
920 cdest[i + 1] = ' ';
921 }
922 if (max % 2)
923 cdest[max - 1] = 0;
924 }
925
926 int joliet_writer_write_vol_desc(IsoImageWriter *writer)
927 {
928 IsoImage *image;
929 Ecma119Image *t;
930 struct ecma119_sup_vol_desc vol;
931
932 uint16_t *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
933 uint16_t *volset_id = NULL, *system_id = NULL, *application_id = NULL;
934 uint16_t *copyright_file_id = NULL, *abstract_file_id = NULL;
935 uint16_t *biblio_file_id = NULL;
936
937 if (writer == NULL) {
938 return ISO_OUT_OF_MEM;
939 }
940
941 t = writer->target;
942 image = t->image;
943
944 iso_msg_debug(image->id, "Write SVD for Joliet");
945
946 memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
947
948 str2ucs(t->input_charset, image->volume_id, &vol_id);
949 str2ucs(t->input_charset, image->publisher_id, &pub_id);
950 str2ucs(t->input_charset, image->data_preparer_id, &data_id);
951 str2ucs(t->input_charset, image->volset_id, &volset_id);
952
953 str2ucs(t->input_charset, image->system_id, &system_id);
954 str2ucs(t->input_charset, image->application_id, &application_id);
955 str2ucs(t->input_charset, image->copyright_file_id, ©right_file_id);
956 str2ucs(t->input_charset, image->abstract_file_id, &abstract_file_id);
957 str2ucs(t->input_charset, image->biblio_file_id, &biblio_file_id);
958
959 vol.vol_desc_type[0] = 2;
960 memcpy(vol.std_identifier, "CD001", 5);
961 vol.vol_desc_version[0] = 1;
962 ucsncpy_pad((uint16_t*)vol.volume_id, vol_id, 32);
963
964 /* make use of UCS-2 Level 3 */
965 memcpy(vol.esc_sequences, "%/E", 3);
966 iso_bb(vol.vol_space_size, t->vol_space_size - t->eff_partition_offset,
967 4);
968 iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
969 iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
970 iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
971 iso_bb(vol.path_table_size, t->joliet_path_table_size, 4);
972
973 if (t->eff_partition_offset > 0) {
974 /* Point to second tables and second root */
975 iso_lsb(vol.l_path_table_pos,
976 t->j_part_l_path_table_pos - t->eff_partition_offset, 4);
977 iso_msb(vol.m_path_table_pos,
978 t->j_part_m_path_table_pos - t->eff_partition_offset, 4);
979 write_one_dir_record(t, t->j_part_root, 0, vol.root_dir_record, 1, 0);
980 } else {
981 iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
982 iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
983 write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0);
984 }
985
986 ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
987 ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
988 ucsncpy_pad((uint16_t*)vol.data_prep_id, data_id, 128);
989
990 ucsncpy_pad((uint16_t*)vol.system_id, system_id, 32);
991
992 ucsncpy_pad((uint16_t*)vol.application_id, application_id, 128);
993 ucsncpy_pad((uint16_t*)vol.copyright_file_id, copyright_file_id, 37);
994 ucsncpy_pad((uint16_t*)vol.abstract_file_id, abstract_file_id, 37);
995 ucsncpy_pad((uint16_t*)vol.bibliographic_file_id, biblio_file_id, 37);
996
997 ecma119_set_voldescr_times(writer, (struct ecma119_pri_vol_desc *) &vol);
998 vol.file_structure_version[0] = 1;
999
1000 free(vol_id);
1001 free(volset_id);
1002 free(pub_id);
1003 free(data_id);
1004 free(system_id);
1005 free(application_id);
1006 free(copyright_file_id);
1007 free(abstract_file_id);
1008 free(biblio_file_id);
1009
1010 /* Finally write the Volume Descriptor */
1011 return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
1012 }
1013
1014 static
1015 int write_one_dir(Ecma119Image *t, JolietNode *dir)
1016 {
1017 int ret;
1018 uint8_t *buffer = NULL;
1019 size_t i;
1020 size_t fi_len, len;
1021
1022 /* buf will point to current write position on buffer */
1023 uint8_t *buf;
1024
1025 /* initialize buffer with 0s */
1026 LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
1027 buf = buffer;
1028
1029 /* write the "." and ".." entries first */
1030 write_one_dir_record(t, dir, 0, buf, 1, 0);
1031 buf += 34;
1032 write_one_dir_record(t, dir, 1, buf, 1, 0);
1033 buf += 34;
1034
1035 for (i = 0; i < dir->info.dir->nchildren; i++) {
1036 int section, nsections;
1037 JolietNode *child = dir->info.dir->children[i];
1038
1039 /* compute len of directory entry */
1040 fi_len = ucslen(child->name) * 2;
1041 len = fi_len + 34;
1042 if (child->type == JOLIET_FILE &&
1043 !(t->opts->omit_version_numbers & 3)) {
1044 len += 4;
1045 }
1046
1047 nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
1048
1049 for (section = 0; section < nsections; ++section) {
1050
1051 if ( (buf + len - buffer) > BLOCK_SIZE) {
1052 /* dir doesn't fit in current block */
1053 ret = iso_write(t, buffer, BLOCK_SIZE);
1054 if (ret < 0) {
1055 goto ex;
1056 }
1057 memset(buffer, 0, BLOCK_SIZE);
1058 buf = buffer;
1059 }
1060 /* write the directory entry in any case */
1061 write_one_dir_record(t, child, -1, buf, fi_len, section);
1062 buf += len;
1063 }
1064 }
1065
1066 /* write the last block */
1067 ret = iso_write(t, buffer, BLOCK_SIZE);
1068 ex:;
1069 LIBISO_FREE_MEM(buffer);
1070 return ret;
1071 }
1072
1073 static
1074 int write_dirs(Ecma119Image *t, JolietNode *root)
1075 {
1076 int ret;
1077 size_t i;
1078
1079 /* write all directory entries for this dir */
1080 ret = write_one_dir(t, root);
1081 if (ret < 0) {
1082 return ret;
1083 }
1084
1085 /* recurse */
1086 for (i = 0; i < root->info.dir->nchildren; i++) {
1087 JolietNode *child = root->info.dir->children[i];
1088 if (child->type == JOLIET_DIR) {
1089 ret = write_dirs(t, child);
1090 if (ret < 0) {
1091 return ret;
1092 }
1093 }
1094 }
1095 return ISO_SUCCESS;
1096 }
1097
1098 static
1099 int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
1100 {
1101 size_t i, len;
1102 uint8_t *buf = NULL;
1103 struct ecma119_path_table_record *rec;
1104 void (*write_int)(uint8_t*, uint32_t, int);
1105 JolietNode *dir;
1106 uint32_t path_table_size;
1107 int parent = 0;
1108 int ret= ISO_SUCCESS;
1109 uint8_t *zeros = NULL;
1110
1111 /* 256 is just a convenient size large enough */
1112 LIBISO_ALLOC_MEM(buf, uint8_t, 256);
1113 LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
1114 path_table_size = 0;
1115 write_int = l_type ? iso_lsb : iso_msb;
1116
1117 for (i = 0; i < t->joliet_ndirs; i++) {
1118 dir = pathlist[i];
1119
1120 /* find the index of the parent in the table */
1121 while ((i) && pathlist[parent] != dir->parent) {
1122 parent++;
1123 }
1124
1125 /* write the Path Table Record (ECMA-119, 9.4) */
1126 memset(buf, 0, 256);
1127 rec = (struct ecma119_path_table_record*) buf;
1128 rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1;
1129 rec->len_xa[0] = 0;
1130 write_int(rec->block, dir->info.dir->block - t->eff_partition_offset,
1131 4);
1132 write_int(rec->parent, parent + 1, 2);
1133 if (dir->parent) {
1134 memcpy(rec->dir_id, dir->name, rec->len_di[0]);
1135 }
1136 len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
1137 ret = iso_write(t, buf, len);
1138 if (ret < 0) {
1139 /* error */
1140 goto ex;
1141 }
1142 path_table_size += len;
1143 }
1144
1145 /* we need to fill the last block with zeros */
1146 path_table_size %= BLOCK_SIZE;
1147 if (path_table_size) {
1148 len = BLOCK_SIZE - path_table_size;
1149 memset(zeros, 0, len);
1150 ret = iso_write(t, zeros, len);
1151 }
1152 ex:;
1153 LIBISO_FREE_MEM(zeros);
1154 LIBISO_FREE_MEM(buf);
1155 return ret;
1156 }
1157
1158 static
1159 int write_path_tables(Ecma119Image *t)
1160 {
1161 int ret;
1162 size_t i, j, cur;
1163 JolietNode **pathlist;
1164
1165 iso_msg_debug(t->image->id, "Writing Joliet Path tables");
1166
1167 /* allocate temporal pathlist */
1168 pathlist = malloc(sizeof(void*) * t->joliet_ndirs);
1169 if (pathlist == NULL) {
1170 return ISO_OUT_OF_MEM;
1171 }
1172
1173 if (t->eff_partition_offset > 0) {
1174 pathlist[0] = t->j_part_root;
1175 } else {
1176 pathlist[0] = t->joliet_root;
1177 }
1178 cur = 1;
1179
1180 for (i = 0; i < t->joliet_ndirs; i++) {
1181 JolietNode *dir = pathlist[i];
1182 for (j = 0; j < dir->info.dir->nchildren; j++) {
1183 JolietNode *child = dir->info.dir->children[j];
1184 if (child->type == JOLIET_DIR) {
1185 pathlist[cur++] = child;
1186 }
1187 }
1188 }
1189
1190 /* Write L Path Table */
1191 ret = write_path_table(t, pathlist, 1);
1192 if (ret < 0) {
1193 goto write_path_tables_exit;
1194 }
1195
1196 /* Write L Path Table */
1197 ret = write_path_table(t, pathlist, 0);
1198
1199 write_path_tables_exit: ;
1200 free(pathlist);
1201 return ret;
1202 }
1203
1204 static
1205 int joliet_writer_write_dirs(IsoImageWriter *writer)
1206 {
1207 int ret;
1208 Ecma119Image *t;
1209 JolietNode *root;
1210
1211 t = writer->target;
1212
1213 /* first of all, we write the directory structure */
1214 if (t->eff_partition_offset > 0) {
1215 root = t->j_part_root;
1216 } else {
1217 root = t->joliet_root;
1218 }
1219 ret = write_dirs(t, root);
1220 if (ret < 0) {
1221 return ret;
1222 }
1223
1224 /* and write the path tables */
1225 ret = write_path_tables(t);
1226
1227 return ret;
1228 }
1229
1230 static
1231 int joliet_writer_write_data(IsoImageWriter *writer)
1232 {
1233 int ret;
1234 Ecma119Image *t;
1235
1236 if (writer == NULL) {
1237 return ISO_NULL_POINTER;
1238 }
1239 t = writer->target;
1240
1241 ret = joliet_writer_write_dirs(writer);
1242 if (ret < 0)
1243 return ret;
1244
1245 if (t->opts->partition_offset > 0) {
1246 t->eff_partition_offset = t->opts->partition_offset;
1247 ret = joliet_writer_write_dirs(writer);
1248 t->eff_partition_offset = 0;
1249 if (ret < 0)
1250 return ret;
1251 }
1252 return ISO_SUCCESS;
1253 }
1254
1255 static
1256 int joliet_writer_free_data(IsoImageWriter *writer)
1257 {
1258 /* free the Joliet tree */
1259 Ecma119Image *t = writer->target;
1260 joliet_node_free(t->joliet_root);
1261 if (t->j_part_root != NULL)
1262 joliet_node_free(t->j_part_root);
1263 t->j_part_root = NULL;
1264 return ISO_SUCCESS;
1265 }
1266
1267 int joliet_writer_create(Ecma119Image *target)
1268 {
1269 int ret;
1270 IsoImageWriter *writer;
1271
1272 writer = malloc(sizeof(IsoImageWriter));
1273 if (writer == NULL) {
1274 return ISO_OUT_OF_MEM;
1275 }
1276
1277 writer->compute_data_blocks = joliet_writer_compute_data_blocks;
1278 writer->write_vol_desc = joliet_writer_write_vol_desc;
1279 writer->write_data = joliet_writer_write_data;
1280 writer->free_data = joliet_writer_free_data;
1281 writer->data = NULL;
1282 writer->target = target;
1283
1284 iso_msg_debug(target->image->id, "Creating low level Joliet tree...");
1285 ret = joliet_tree_create(target);
1286 if (ret < 0) {
1287 free((char *) writer);
1288 return ret;
1289 }
1290
1291 /* add this writer to image */
1292 target->writers[target->nwriters++] = writer;
1293
1294 if(target->opts->partition_offset > 0) {
1295 /* Create second tree */
1296 target->eff_partition_offset = target->opts->partition_offset;
1297 ret = joliet_tree_create(target);
1298 if (ret < 0) {
1299 return ret;
1300 }
1301 target->eff_partition_offset = 0;
1302 }
1303
1304 /* we need the volume descriptor */
1305 target->curblock++;
1306 return ISO_SUCCESS;
1307 }