1 /* @(#)joliet.c 1.71 18/04/04 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)joliet.c 1.71 18/04/04 joerg";
6 #endif
7 /*
8 * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
9 *
10 * Copyright 1997 Eric Youngdale.
11 * APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000
12 * Copyright (c) 1999-2018 J. Schilling
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*
30 * Joliet extensions for ISO9660. These are spottily documented by
31 * Microsoft. In their infinite stupidity, they completely ignored
32 * the possibility of using an SUSP record with the long filename
33 * in it, and instead wrote out a duplicate directory tree with the
34 * long filenames in it.
35 *
36 * I am not sure why they did this. One reason is that they get the path
37 * tables with the long filenames in them.
38 *
39 * There are two basic principles to Joliet, and the non-Unicode variant
40 * known as Romeo. Long filenames seem to be the main one, and the second
41 * is that the character set and a few other things is substantially relaxed.
42 *
43 * The SVD is identical to the PVD, except:
44 *
45 * Id is 2, not 1 (indicates SVD).
46 * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
47 * The root directory record points to a different extent (with different
48 * size).
49 * There are different path tables for the two sets of directory trees.
50 *
51 * The Unicode level is coded in the SVD as follows:
52 *
53 * Standard Level ASCII escape code
54 * UCS-2 Level-1 %/@
55 * UCS-2 Level-2 %/C
56 * UCS-2 Level-3 %/E
57 *
58 * The following fields are recorded in Unicode:
59 * system_id
60 * volume_id
61 * volume_set_id
62 * publisher_id
63 * preparer_id
64 * application_id
65 * copyright_file_id
66 * abstract_file_id
67 * bibliographic_file_id
68 *
69 * Unicode strings are always encoded in big-endian format.
70 *
71 * In a directory record, everything is the same as with iso9660, except
72 * that the name is recorded in unicode. The name length is specified in
73 * total bytes, not in number of unicode characters.
74 *
75 * The character set used for the names is different with UCS - the
76 * restrictions are that the following are not allowed:
77 *
78 * Characters (00)(00) through (00)(1f) (control chars)
79 * (00)(2a) '*'
80 * (00)(2f) '/'
81 * (00)(3a) ':'
82 * (00)(3b) ';'
83 * (00)(3f) '?'
84 * (00)(5c) '\'
85 */
86 #include "mkisofs.h"
87 #include <schily/time.h>
88 #include <schily/utypes.h>
89 #include <schily/intcvt.h>
90 #include <schily/schily.h>
91 #include <schily/errno.h>
92
93 LOCAL Uint jpath_table_index;
94 LOCAL struct directory **jpathlist;
95 LOCAL int next_jpath_index = 1;
96 LOCAL int jsort_goof;
97 LOCAL int jsort_glen;
98
99 LOCAL char ucs_codes[] = {
100 '\0', /* UCS-level 0 is illegal */
101 '@', /* UCS-level 1 */
102 'C', /* UCS-level 2 */
103 'E', /* UCS-level 3 */
104 };
105
106 #ifdef UDF
107 EXPORT void convert_to_unicode __PR((unsigned char *buffer,
108 int size, char *source,
109 siconvt_t *inls));
110 EXPORT int joliet_strlen __PR((const char *string, size_t maxlen,
111 siconvt_t *inls));
112 #else
113 LOCAL void convert_to_unicode __PR((unsigned char *buffer,
114 int size, char *source,
115 siconvt_t *inls));
116 LOCAL int joliet_strlen __PR((const char *string, size_t maxlen,
117 siconvt_t *inls));
118 #endif
119 LOCAL void get_joliet_vol_desc __PR((struct iso_primary_descriptor *jvol_desc));
120 LOCAL void assign_joliet_directory_addresses __PR((struct directory *node));
121 LOCAL void build_jpathlist __PR((struct directory *node));
122 LOCAL int joliet_compare_paths __PR((void const *r, void const *l));
123 LOCAL int generate_joliet_path_tables __PR((void));
124 LOCAL void generate_one_joliet_directory __PR((struct directory *dpnt,
125 FILE *outfile));
126 LOCAL int joliet_sort_n_finish __PR((struct directory *this_dir));
127
128 LOCAL int joliet_compare_dirs __PR((const void *rr, const void *ll));
129
130 LOCAL int joliet_sort_directory __PR((struct directory_entry **sort_dir));
131 EXPORT int joliet_sort_tree __PR((struct directory *node));
132 LOCAL void generate_joliet_directories __PR((struct directory *node,
133 FILE *outfile));
134 LOCAL int jpathtab_write __PR((FILE *outfile));
135 LOCAL int jdirtree_size __PR((UInt32_t starting_extent));
136 LOCAL int jroot_gen __PR((void));
137 LOCAL int jdirtree_write __PR((FILE *outfile));
138 LOCAL int jvd_write __PR((FILE *outfile));
139 LOCAL int jpathtab_size __PR((UInt32_t starting_extent));
140
141 /*
142 * conv_charset: convert to/from charsets via Unicode.
143 *
144 * Any unknown character is set to '_'
145 *
146 */
147 EXPORT void
conv_charset(to,tosizep,from,fromsizep,inls,onls)148 conv_charset(to, tosizep, from, fromsizep, inls, onls)
149 unsigned char *to;
150 size_t *tosizep;
151 unsigned char *from;
152 size_t *fromsizep;
153 siconvt_t *inls;
154 siconvt_t *onls;
155 {
156 UInt16_t unichar;
157 size_t fromsize = *fromsizep;
158 size_t tosize = *tosizep;
159 Uchar ob[2]; /* 2 octets (16 Bit) UCS-2 */
160
161 if (fromsize == 0 || tosize == 0)
162 return;
163
164 /*
165 * If we have a null mapping, just return the input character
166 */
167 if (inls->sic_name == onls->sic_name) {
168 *to = *from;
169 (*fromsizep)--;
170 (*tosizep)--;
171 return;
172 }
173 #ifdef USE_ICONV
174 #ifdef HAVE_ICONV_CONST
175 #define __IC_CONST const
176 #else
177 #define __IC_CONST
178 #endif
179 if (use_iconv(inls)) {
180 char *obuf = (char *)ob;
181 size_t osize = 2; /* UCS-2 character size */
182
183 if (iconv(inls->sic_cd2uni, (__IC_CONST char **)&from,
184 fromsizep,
185 &obuf, &osize) == -1) {
186 int err = geterrno();
187
188 if ((err == EINVAL || err == EILSEQ) &&
189 *fromsizep == fromsize) {
190 ob[0] = 0; ob[1] = '_';
191 (*fromsizep)--;
192 }
193 }
194 unichar = ob[0] * 256 + ob[1]; /* Compute 16 Bit UCS-2 char */
195 } else
196 #endif
197 {
198 unsigned char c = *from;
199
200 unichar = sic_c2uni(inls, c); /* Get the UNICODE char */
201 (*fromsizep)--;
202
203 if (unichar == 0)
204 unichar = '_';
205
206 ob[0] = unichar >> 8 & 0xFF; /* Compute 2 octet variant */
207 ob[1] = unichar & 0xFF;
208 }
209
210 #ifdef USE_ICONV
211 if (use_iconv(onls)) {
212 char *ibuf = (char *)ob;
213 size_t isize = 2; /* UCS-2 character size */
214
215 if (iconv(onls->sic_uni2cd, (__IC_CONST char **)&ibuf, &isize,
216 (char **)&to, tosizep) == -1) {
217 int err = geterrno();
218
219 if ((err == EINVAL || err == EILSEQ) &&
220 *tosizep == tosize) {
221 *to = '_';
222 (*tosizep)--;
223 }
224 }
225 } else
226 #endif
227 {
228 *to = sic_uni2c(onls, unichar); /* Get the backconverted char */
229 (*tosizep)--;
230 }
231 }
232
233
234 /*
235 * Function: convert_to_unicode
236 *
237 * Purpose: Perform a unicode conversion on a text string
238 * using the supplied input character set.
239 *
240 * Notes:
241 */
242 #ifdef UDF
243 EXPORT void
244 #else
245 LOCAL void
246 #endif
convert_to_unicode(buffer,size,source,inls)247 convert_to_unicode(buffer, size, source, inls)
248 unsigned char *buffer;
249 int size;
250 char *source;
251 siconvt_t *inls;
252 {
253 unsigned char *tmpbuf;
254 int i;
255 int j;
256 UInt16_t unichar;
257 unsigned char uc;
258 int jsize;
259
260 /*
261 * If we get a NULL pointer for the source, it means we have an
262 * inplace copy, and we need to make a temporary working copy first.
263 */
264 if (source == NULL) {
265 tmpbuf = (Uchar *) e_malloc(size);
266 memcpy(tmpbuf, buffer, size);
267 } else {
268 tmpbuf = (Uchar *) source;
269 }
270
271 /*
272 * joliet_strlen() behaves the same way: Stop at the first nul byte.
273 * Note: we cannot have 16 bit character representations in the source
274 * encoding, if we like strlen() to work correctly.
275 */
276 jsize = strlen((char *)tmpbuf);
277
278 /*
279 * Now start copying characters. If the size was specified to be 0,
280 * then assume the input was 0 terminated.
281 */
282 j = 0;
283 for (i = 0; (i + 1) < size; i += 2, j++) { /* Size may be odd! */
284 /*
285 * Let all valid unicode characters pass
286 * through (according to charset). Others are set to '_' .
287 */
288 if (j < jsize)
289 uc = tmpbuf[j]; /* temporary copy */
290 else
291 uc = '\0';
292 if (uc == '\0') {
293 jsize = j;
294 unichar = 0;
295 } else { /* must be converted */
296 #ifdef USE_ICONV
297 if (use_iconv(inls)) {
298 Uchar ob[2];
299 __IC_CONST char *inbuf = (char *)&tmpbuf[j];
300 size_t isize = 3;
301 char *obuf = (char *)ob;
302 size_t osize = 2;
303
304 /*
305 * iconv() from glibc ignores osize and thus
306 * may try to access more than a single multi
307 * byte character from the input and read from
308 * non-existent memory.
309 *
310 * Note that iconv() returns -1 and sets errno
311 * to E2BIG if there is not enough room in the
312 * target location, but correctly converts the
313 * characters before.
314 */
315 if (iconv(inls->sic_cd2uni, &inbuf, &isize,
316 &obuf, &osize) == -1) {
317 int err = geterrno();
318
319 if ((err == EINVAL || err == EILSEQ) &&
320 isize == 3) {
321 ob[0] = ob[1] = 0;
322 isize--;
323 }
324 }
325 unichar = ob[0] * 256 + ob[1];
326 j += 2 - isize;
327 } else
328 #endif
329 unichar = sic_c2uni(inls, uc); /* Get the UNICODE */
330
331 /*
332 * This code is currently also used for UDF formatting.
333 * Do not enforce silly Microsoft limitations in case
334 * that we only create UDF extensions.
335 */
336 if (!use_Joliet)
337 goto all_chars;
338
339 if (unichar <= 0x1f || unichar == 0x7f)
340 unichar = '\0'; /* control char */
341
342 switch (unichar) { /* test special characters */
343
344 case '*':
345 case '/':
346 case ':':
347 case ';':
348 case '?':
349 case '\\':
350 case '\0': /* illegal char mark */
351 /*
352 * Even Joliet has some standards as to what is
353 * allowed in a pathname. Pretty tame in
354 * comparison to what DOS restricts you to.
355 */
356 unichar = '_';
357 }
358 all_chars:
359 if (unichar == 0)
360 unichar = '_';
361 ;
362 }
363 buffer[i] = unichar >> 8 & 0xFF; /* final UNICODE */
364 buffer[i + 1] = unichar & 0xFF; /* conversion */
365 }
366
367 if (size & 1) { /* beautification */
368 buffer[size - 1] = 0;
369 }
370 if (source == NULL) {
371 free(tmpbuf);
372 }
373 }
374
375 /*
376 * Function: joliet_strlen
377 *
378 * Purpose: Return length in bytes of string after conversion to unicode.
379 *
380 * Notes: This is provided mainly as a convenience so that when more
381 * intelligent Unicode conversion for either Multibyte or 8-bit
382 * codes is available that we can easily adapt.
383 */
384 #ifdef UDF
385 EXPORT int
386 #else
387 LOCAL int
388 #endif
joliet_strlen(string,maxlen,inls)389 joliet_strlen(string, maxlen, inls)
390 const char *string;
391 size_t maxlen;
392 siconvt_t *inls;
393 {
394 int rtn = 0;
395
396 #ifdef USE_ICONV
397 if (use_iconv(inls)) {
398 int j = 0;
399
400 while (string[j] != '\0') {
401 Uchar ob[2];
402 __IC_CONST char *inbuf = (char *)&string[j];
403 size_t isize = 3;
404 char *obuf = (char *)ob;
405 size_t osize = 2;
406
407 /*
408 * iconv() from glibc ignores osize and thus
409 * may try to access more than a single multi
410 * byte character from the input and read from
411 * non-existent memory.
412 *
413 * Note that iconv() returns -1 and sets errno
414 * to E2BIG if there is not enough room in the
415 * target location, but correctly converts the
416 * characters before.
417 */
418 if (iconv(inls->sic_cd2uni, &inbuf, &isize,
419 &obuf, &osize) == -1) {
420 int err = geterrno();
421
422 if ((err == EINVAL || err == EILSEQ) &&
423 isize == 3) {
424 ob[0] = ob[1] = 0;
425 isize--;
426 }
427 }
428 j += 3 - isize;
429 rtn += 2;
430 }
431 } else
432 #endif
433 rtn = strlen(string) << 1;
434
435 /*
436 * We do clamp the maximum length of a Joliet or UDF string to be the
437 * maximum path size.
438 */
439 if (rtn > 2*maxlen) {
440 rtn = 2*maxlen;
441 }
442 return (rtn);
443 }
444
445 /*
446 * Function: get_joliet_vol_desc
447 *
448 * Purpose: generate a Joliet compatible volume desc.
449 *
450 * Notes: Assume that we have the non-joliet vol desc
451 * already present in the buffer. Just modifiy the
452 * appropriate fields.
453 */
454 LOCAL void
get_joliet_vol_desc(jvol_desc)455 get_joliet_vol_desc(jvol_desc)
456 struct iso_primary_descriptor *jvol_desc;
457 {
458 jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
459 jvol_desc->version[0] = 1;
460 jvol_desc->file_structure_version[0] = 1;
461 /*
462 * For now, always do Unicode level 3.
463 * I don't really know what 1 and 2 are - perhaps a more limited
464 * Unicode set.
465 * FIXME(eric) - how does Romeo fit in here?
466 */
467 sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
468
469 /* Until we have Unicode path tables, leave these unset. */
470 set_733((char *)jvol_desc->path_table_size, jpath_table_size);
471 set_731(jvol_desc->type_l_path_table, jpath_table[0]);
472 set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
473 set_732(jvol_desc->type_m_path_table, jpath_table[2]);
474 set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
475
476 /* Set this one up. */
477 memcpy(jvol_desc->root_directory_record, &jroot_record,
478 offsetof(struct iso_directory_record, name[0]) + 1);
479
480 /*
481 * Finally, we have a bunch of strings to convert to Unicode.
482 * FIXME(eric) - I don't know how to do this in general,
483 * so we will just be really lazy and do a char -> short conversion.
484 * We probably will want to filter any characters >= 0x80.
485 */
486 convert_to_unicode((Uchar *)jvol_desc->system_id,
487 sizeof (jvol_desc->system_id), NULL, in_nls);
488 convert_to_unicode((Uchar *)jvol_desc->volume_id,
489 sizeof (jvol_desc->volume_id), NULL, in_nls);
490 convert_to_unicode((Uchar *)jvol_desc->volume_set_id,
491 sizeof (jvol_desc->volume_set_id), NULL, in_nls);
492 convert_to_unicode((Uchar *)jvol_desc->publisher_id,
493 sizeof (jvol_desc->publisher_id), NULL, in_nls);
494 convert_to_unicode((Uchar *)jvol_desc->preparer_id,
495 sizeof (jvol_desc->preparer_id), NULL, in_nls);
496 convert_to_unicode((Uchar *)jvol_desc->application_id,
497 sizeof (jvol_desc->application_id), NULL, in_nls);
498 convert_to_unicode((Uchar *)jvol_desc->copyright_file_id,
499 sizeof (jvol_desc->copyright_file_id), NULL, in_nls);
500 convert_to_unicode((Uchar *)jvol_desc->abstract_file_id,
501 sizeof (jvol_desc->abstract_file_id), NULL, in_nls);
502 convert_to_unicode((Uchar *)jvol_desc->bibliographic_file_id,
503 sizeof (jvol_desc->bibliographic_file_id), NULL, in_nls);
504 }
505
506 /*
507 * Asssign Joliet & UDF addresses
508 * We ignore all files that are neither in the Joliet nor in the UDF tree
509 */
510 LOCAL void
assign_joliet_directory_addresses(node)511 assign_joliet_directory_addresses(node)
512 struct directory *node;
513 {
514 int dir_size;
515 struct directory *dpnt;
516
517 dpnt = node;
518
519 while (dpnt) {
520 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
521 /*
522 * If we already have an extent for this
523 * (i.e. it came from a multisession disc), then
524 * don't reassign a new extent.
525 */
526 dpnt->jpath_index = next_jpath_index++;
527 if (dpnt->jextent == 0) {
528 dpnt->jextent = last_extent;
529 dir_size = ISO_BLOCKS(dpnt->jsize);
530 last_extent += dir_size;
531 }
532 }
533 /* skip if hidden - but not for the rr_moved dir */
534 if (dpnt->subdir &&
535 ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
536 dpnt == reloc_dir)) {
537 assign_joliet_directory_addresses(dpnt->subdir);
538 }
539 dpnt = dpnt->next;
540 }
541 }
542
543 LOCAL void
build_jpathlist(node)544 build_jpathlist(node)
545 struct directory *node;
546 {
547 struct directory *dpnt;
548
549 dpnt = node;
550
551 while (dpnt) {
552 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
553 jpathlist[dpnt->jpath_index] = dpnt;
554 }
555 if (dpnt->subdir)
556 build_jpathlist(dpnt->subdir);
557 dpnt = dpnt->next;
558 }
559 } /* build_jpathlist(... */
560
561 LOCAL int
joliet_compare_paths(r,l)562 joliet_compare_paths(r, l)
563 void const *r;
564 void const *l;
565 {
566 struct directory const *ll = *(struct directory * const *) l;
567 struct directory const *rr = *(struct directory * const *) r;
568 int rparent,
569 lparent;
570 char *rpnt,
571 *lpnt;
572 unsigned char rtmp[2],
573 ltmp[2];
574 siconvt_t *rinls, *linls;
575
576 /* make sure root directory is first */
577 if (rr == root)
578 return (-1);
579
580 if (ll == root)
581 return (1);
582
583 rparent = rr->parent->jpath_index;
584 lparent = ll->parent->jpath_index;
585 if (rr->parent == reloc_dir) {
586 rparent = rr->self->parent_rec->filedir->jpath_index;
587 }
588 if (ll->parent == reloc_dir) {
589 lparent = ll->self->parent_rec->filedir->jpath_index;
590 }
591 if (rparent < lparent) {
592 return (-1);
593 }
594 if (rparent > lparent) {
595 return (1);
596 }
597 #ifdef APPLE_HYB
598 /*
599 * we may be using the HFS name - so select the correct input
600 * charset
601 */
602 if (USE_MAC_NAME(rr->self)) {
603 rpnt = rr->self->hfs_ent->name;
604 rinls = hfs_inls;
605 } else {
606 rpnt = rr->self->name;
607 rinls = in_nls;
608 }
609
610 if (USE_MAC_NAME(ll->self)) {
611 lpnt = ll->self->hfs_ent->name;
612 linls = hfs_inls;
613 } else {
614 lpnt = ll->self->name;
615 linls = in_nls;
616 }
617 #else
618 rpnt = rr->self->name;
619 lpnt = ll->self->name;
620 linls = rinls = in_nls;
621 #endif /* APPLE_HYB */
622
623 /* compare the Unicode names */
624
625 while (*rpnt && *lpnt) {
626 convert_to_unicode(rtmp, 2, rpnt, rinls);
627 convert_to_unicode(ltmp, 2, lpnt, linls);
628
629 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
630 return (-1);
631 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
632 return (1);
633
634 rpnt++;
635 lpnt++;
636 }
637
638 if (*rpnt)
639 return (1);
640 if (*lpnt)
641 return (-1);
642
643 return (0);
644
645 } /* compare_paths(... */
646
647 LOCAL int
generate_joliet_path_tables()648 generate_joliet_path_tables()
649 {
650 struct directory_entry *de;
651 struct directory *dpnt;
652 int fix;
653 int j;
654 int namelen;
655 char *npnt;
656 char *npnt1;
657 int tablesize;
658 unsigned int jpindex;
659
660 /* First allocate memory for the tables and initialize the memory */
661 tablesize = jpath_blocks << 11;
662 jpath_table_m = (char *)e_malloc(tablesize);
663 jpath_table_l = (char *)e_malloc(tablesize);
664 memset(jpath_table_l, 0, tablesize);
665 memset(jpath_table_m, 0, tablesize);
666
667 /* Now start filling in the path tables. Start with root directory */
668 jpath_table_index = 0;
669 jpathlist = (struct directory **)e_malloc(sizeof (struct directory *)
670 * next_jpath_index);
671 memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
672 build_jpathlist(root);
673
674 do {
675 fix = 0;
676 #ifdef PROTOTYPES
677 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
678 (int (*) (const void *, const void *)) joliet_compare_paths);
679 #else
680 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
681 joliet_compare_paths);
682 #endif
683
684 for (j = 1; j < next_jpath_index; j++) {
685 if (jpathlist[j]->jpath_index != j) {
686 jpathlist[j]->jpath_index = j;
687 fix++;
688 }
689 }
690 } while (fix);
691
692 for (j = 1; j < next_jpath_index; j++) {
693 dpnt = jpathlist[j];
694 if (!dpnt) {
695 comerrno(EX_BAD, _("Entry %d not in path tables\n"), j);
696 }
697 npnt = dpnt->de_name;
698
699 npnt1 = strrchr(npnt, PATH_SEPARATOR);
700 if (npnt1) {
701 npnt = npnt1 + 1;
702 }
703 de = dpnt->self;
704 if (!de) {
705 comerrno(EX_BAD,
706 _("Fatal Joliet goof - directory has amnesia\n"));
707 }
708 #ifdef APPLE_HYB
709 if (USE_MAC_NAME(de))
710 namelen = joliet_strlen(de->hfs_ent->name, jlen, hfs_inls);
711 else
712 #endif /* APPLE_HYB */
713 namelen = joliet_strlen(de->name, jlen, in_nls);
714
715 if (dpnt == root) {
716 jpath_table_l[jpath_table_index] = 1;
717 jpath_table_m[jpath_table_index] = 1;
718 } else {
719 jpath_table_l[jpath_table_index] = namelen;
720 jpath_table_m[jpath_table_index] = namelen;
721 }
722 jpath_table_index += 2;
723
724 set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
725 set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
726 jpath_table_index += 4;
727
728
729 if (dpnt->parent != reloc_dir) {
730 set_721(jpath_table_l + jpath_table_index,
731 dpnt->parent->jpath_index);
732 set_722(jpath_table_m + jpath_table_index,
733 dpnt->parent->jpath_index);
734 jpindex = dpnt->parent->jpath_index;
735 } else {
736 set_721(jpath_table_l + jpath_table_index,
737 dpnt->self->parent_rec->filedir->jpath_index);
738 set_722(jpath_table_m + jpath_table_index,
739 dpnt->self->parent_rec->filedir->jpath_index);
740 jpindex = dpnt->self->parent_rec->filedir->jpath_index;
741 }
742
743 if (jpindex > 0xffff) {
744 static int warned = 0;
745
746 if (!warned) {
747 warned++;
748 errmsgno(EX_BAD,
749 _("Unable to generate sane Joliet path tables - too many directories (%u)\n"),
750 jpindex);
751 if (!nolimitpathtables)
752 errmsgno(EX_BAD,
753 _("Try to use the option -no-limit-pathtables\n"));
754 }
755 if (!nolimitpathtables)
756 exit(EX_BAD);
757 /*
758 * Let it point to the root directory instead.
759 */
760 set_721(jpath_table_l + jpath_table_index, 1);
761 set_722(jpath_table_m + jpath_table_index, 1);
762 }
763
764 jpath_table_index += 2;
765
766 /*
767 * The root directory is still represented in non-unicode
768 * fashion.
769 */
770 if (dpnt == root) {
771 jpath_table_l[jpath_table_index] = 0;
772 jpath_table_m[jpath_table_index] = 0;
773 jpath_table_index++;
774 } else {
775 #ifdef APPLE_HYB
776 if (USE_MAC_NAME(de)) {
777 convert_to_unicode((Uchar *) jpath_table_l +
778 jpath_table_index,
779 namelen, de->hfs_ent->name, hfs_inls);
780 convert_to_unicode((Uchar *) jpath_table_m +
781 jpath_table_index,
782 namelen, de->hfs_ent->name, hfs_inls);
783 } else {
784 #endif /* APPLE_HYB */
785 convert_to_unicode((Uchar *) jpath_table_l +
786 jpath_table_index,
787 namelen, de->name, in_nls);
788 convert_to_unicode((Uchar *) jpath_table_m +
789 jpath_table_index,
790 namelen, de->name, in_nls);
791 #ifdef APPLE_HYB
792 }
793 #endif /* APPLE_HYB */
794
795 jpath_table_index += namelen;
796 }
797
798 if (jpath_table_index & 1) {
799 jpath_table_index++; /* For odd lengths we pad */
800 }
801 }
802
803 free(jpathlist);
804 if (jpath_table_index != jpath_table_size) {
805 errmsgno(EX_BAD,
806 _("Joliet path table lengths do not match %d expected: %d\n"),
807 jpath_table_index,
808 jpath_table_size);
809 }
810 return (0);
811 } /* generate_path_tables(... */
812
813 LOCAL void
generate_one_joliet_directory(dpnt,outfile)814 generate_one_joliet_directory(dpnt, outfile)
815 struct directory *dpnt;
816 FILE *outfile;
817 {
818 unsigned int dir_index;
819 char *directory_buffer;
820 int new_reclen;
821 struct directory_entry *s_entry;
822 struct directory_entry *s_entry1;
823 struct iso_directory_record jrec;
824 unsigned int total_size;
825 int cvt_len;
826 struct directory *finddir;
827
828 total_size = ISO_ROUND_UP(dpnt->jsize);
829 directory_buffer = (char *)e_malloc(total_size);
830 memset(directory_buffer, 0, total_size);
831 dir_index = 0;
832
833 s_entry = dpnt->jcontents;
834 while (s_entry) {
835 if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
836 s_entry = s_entry->jnext;
837 continue;
838 }
839 /*
840 * If this entry was a directory that was relocated,
841 * we have a bit of trouble here. We need to dig out the real
842 * thing and put it back here. In the Joliet tree, there is
843 * no relocated rock ridge, as there are no depth limits to a
844 * directory tree.
845 */
846 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
847 for (s_entry1 = reloc_dir->contents; s_entry1;
848 s_entry1 = s_entry1->next) {
849 if (s_entry1->parent_rec == s_entry) {
850 break;
851 }
852 }
853 if (s_entry1 == NULL) {
854 /* We got trouble. */
855 comerrno(EX_BAD,
856 _("Unable to locate relocated directory\n"));
857 }
858 } else {
859 s_entry1 = s_entry;
860 }
861
862 /*
863 * We do not allow directory entries to cross sector
864 * boundaries. Simply pad, and then start the next entry at
865 * the next sector
866 */
867 new_reclen = s_entry1->jreclen;
868 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) {
869 dir_index = ISO_ROUND_UP(dir_index);
870 }
871 memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
872
873 #ifdef APPLE_HYB
874 /* Use the HFS name if it exists */
875 if (USE_MAC_NAME(s_entry1))
876 cvt_len = joliet_strlen(s_entry1->hfs_ent->name, jlen, hfs_inls);
877 else
878 #endif /* APPLE_HYB */
879 cvt_len = joliet_strlen(s_entry1->name, jlen, in_nls);
880
881 /*
882 * Fix the record length
883 * - this was the non-Joliet version we were seeing.
884 */
885 jrec.name_len[0] = cvt_len;
886 jrec.length[0] = s_entry1->jreclen;
887
888 /*
889 * If this is a directory,
890 * fix the correct size and extent number.
891 */
892 if ((jrec.flags[0] & ISO_DIRECTORY) != 0) {
893 if (strcmp(s_entry1->name, ".") == 0) {
894 jrec.name_len[0] = 1;
895 set_733((char *)jrec.extent, dpnt->jextent);
896 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->jsize));
897 } else if (strcmp(s_entry1->name, "..") == 0) {
898 jrec.name_len[0] = 1;
899 if (dpnt->parent == reloc_dir) {
900 set_733((char *)jrec.extent, dpnt->self->parent_rec->filedir->jextent);
901 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
902 } else {
903 set_733((char *)jrec.extent, dpnt->parent->jextent);
904 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
905 }
906 } else {
907 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
908 finddir = reloc_dir->subdir;
909 } else {
910 finddir = dpnt->subdir;
911 }
912 while (finddir && finddir->self != s_entry1) {
913 finddir = finddir->next;
914 }
915 if (!finddir) {
916 comerrno(EX_BAD,
917 _("Fatal goof - unable to find directory location\n"));
918 }
919 set_733((char *)jrec.extent, finddir->jextent);
920 set_733((char *)jrec.size,
921 ISO_ROUND_UP(finddir->jsize));
922 }
923 }
924 memcpy(directory_buffer + dir_index, &jrec,
925 offsetof(struct iso_directory_record, name[0]));
926
927 dir_index += offsetof(struct iso_directory_record, name[0]);
928
929 /*
930 * Finally dump the Unicode version of the filename.
931 * Note - . and .. are the same as with non-Joliet discs.
932 */
933 if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
934 strcmp(s_entry1->name, ".") == 0) {
935 directory_buffer[dir_index++] = 0;
936 } else if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
937 strcmp(s_entry1->name, "..") == 0) {
938 directory_buffer[dir_index++] = 1;
939 } else {
940 #ifdef APPLE_HYB
941 if (USE_MAC_NAME(s_entry1)) {
942 /* Use the HFS name if it exists */
943 convert_to_unicode(
944 (Uchar *) directory_buffer+dir_index,
945 cvt_len,
946 s_entry1->hfs_ent->name, hfs_inls);
947 } else
948 #endif /* APPLE_HYB */
949 {
950 convert_to_unicode(
951 (Uchar *) directory_buffer+dir_index,
952 cvt_len,
953 s_entry1->name, in_nls);
954 }
955 dir_index += cvt_len;
956 }
957
958 if (dir_index & 1) {
959 directory_buffer[dir_index++] = 0;
960 }
961 s_entry = s_entry->jnext;
962 }
963
964 if (dpnt->jsize != dir_index) {
965 errmsgno(EX_BAD,
966 _("Unexpected joliet directory length %d expected: %d '%s'\n"),
967 dpnt->jsize,
968 dir_index, dpnt->de_name);
969 }
970 xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
971 last_extent_written += total_size >> 11;
972 free(directory_buffer);
973 } /* generate_one_joliet_directory(... */
974
975 LOCAL int
joliet_sort_n_finish(this_dir)976 joliet_sort_n_finish(this_dir)
977 struct directory *this_dir;
978 {
979 struct directory_entry *s_entry;
980 int status = 0;
981
982 /*
983 * don't want to skip this directory if it's the reloc_dir
984 * at the moment
985 */
986 if (this_dir != reloc_dir &&
987 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
988 return (0);
989 }
990 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
991 /* skip hidden entries */
992 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
993 continue;
994 }
995 /*
996 * First update the path table sizes for directories.
997 *
998 * Finally, set the length of the directory entry if Joliet is
999 * used. The name is longer, but no Rock Ridge is ever used
1000 * here, so depending upon the options the entry size might
1001 * turn out to be about the same. The Unicode name is always
1002 * a multiple of 2 bytes, so we always add 1 to make it an
1003 * even number.
1004 */
1005 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1006 if (strcmp(s_entry->name, ".") != 0 &&
1007 strcmp(s_entry->name, "..") != 0) {
1008 #ifdef APPLE_HYB
1009 if (USE_MAC_NAME(s_entry))
1010 /* Use the HFS name if it exists */
1011 jpath_table_size +=
1012 joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls) +
1013 offsetof(struct iso_path_table, name[0]);
1014 else
1015 #endif /* APPLE_HYB */
1016 jpath_table_size +=
1017 joliet_strlen(s_entry->name, jlen, in_nls) +
1018 offsetof(struct iso_path_table, name[0]);
1019 if (jpath_table_size & 1) {
1020 jpath_table_size++;
1021 }
1022 } else {
1023 if (this_dir == root &&
1024 strlen(s_entry->name) == 1) {
1025
1026 jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
1027 if (jpath_table_size & 1)
1028 jpath_table_size++;
1029 }
1030 }
1031 }
1032 if (strcmp(s_entry->name, ".") != 0 &&
1033 strcmp(s_entry->name, "..") != 0) {
1034 #ifdef APPLE_HYB
1035 if (USE_MAC_NAME(s_entry))
1036 /* Use the HFS name if it exists */
1037 s_entry->jreclen =
1038 offsetof(struct iso_directory_record, name[0])
1039 + joliet_strlen(s_entry->hfs_ent->name, jlen, hfs_inls)
1040 + 1;
1041 else
1042 #endif /* APPLE_HYB */
1043 s_entry->jreclen =
1044 offsetof(struct iso_directory_record, name[0])
1045 + joliet_strlen(s_entry->name, jlen, in_nls)
1046 + 1;
1047 } else {
1048 /*
1049 * Special - for '.' and '..' we generate the same
1050 * records we did for non-Joliet discs.
1051 */
1052 s_entry->jreclen =
1053 offsetof(struct iso_directory_record, name[0])
1054 + 1;
1055 }
1056
1057
1058 }
1059
1060 if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1061 return (0);
1062 }
1063 this_dir->jcontents = this_dir->contents;
1064 status = joliet_sort_directory(&this_dir->jcontents);
1065
1066 /*
1067 * Now go through the directory and figure out how large this one will
1068 * be. Do not split a directory entry across a sector boundary
1069 */
1070 s_entry = this_dir->jcontents;
1071 /*
1072 * XXX Is it ok to comment this out?
1073 */
1074 /*XXX JS this_dir->ce_bytes = 0;*/
1075 for (s_entry = this_dir->jcontents; s_entry;
1076 s_entry = s_entry->jnext) {
1077 int jreclen;
1078
1079 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1080 continue;
1081 }
1082 jreclen = s_entry->jreclen;
1083
1084 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
1085 SECTOR_SIZE) {
1086 this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
1087 }
1088 this_dir->jsize += jreclen;
1089 }
1090 return (status);
1091 }
1092
1093 /*
1094 * Similar to the iso9660 case,
1095 * except here we perform a full sort based upon the
1096 * regular name of the file, not the 8.3 version.
1097 */
1098 LOCAL int
joliet_compare_dirs(rr,ll)1099 joliet_compare_dirs(rr, ll)
1100 const void *rr;
1101 const void *ll;
1102 {
1103 char *rpnt,
1104 *lpnt;
1105 struct directory_entry **r,
1106 **l;
1107 unsigned char rtmp[2],
1108 ltmp[2];
1109 siconvt_t *linls, *rinls;
1110
1111 r = (struct directory_entry **)rr;
1112 l = (struct directory_entry **)ll;
1113
1114 #ifdef APPLE_HYB
1115 /*
1116 * we may be using the HFS name - so select the correct input
1117 * charset
1118 */
1119 if (USE_MAC_NAME(*r)) {
1120 rpnt = (*r)->hfs_ent->name;
1121 rinls = hfs_inls;
1122 } else {
1123 rpnt = (*r)->name;
1124 rinls = in_nls;
1125 }
1126
1127 if (USE_MAC_NAME(*l)) {
1128 lpnt = (*l)->hfs_ent->name;
1129 linls = hfs_inls;
1130 } else {
1131 lpnt = (*l)->name;
1132 linls = in_nls;
1133 }
1134 #else
1135 rpnt = (*r)->name;
1136 lpnt = (*l)->name;
1137 rinls = linls = in_nls;
1138 #endif /* APPLE_HYB */
1139
1140 /*
1141 * If the entries are the same, this is an error.
1142 * Joliet specs allow for a maximum of 64 characters.
1143 * If we see different multi extent parts, it is OK to
1144 * have the same name more than once.
1145 */
1146 if (strncmp(rpnt, lpnt, jlen) == 0) {
1147 #ifdef USE_LARGEFILES
1148 if ((*r)->mxpart == (*l)->mxpart)
1149 #endif
1150 {
1151 errmsgno(EX_BAD,
1152 _("Error: %s and %s have the same Joliet name\n"),
1153 (*r)->whole_name, (*l)->whole_name);
1154 jsort_goof++;
1155 {
1156 char *p1 = rpnt;
1157 char *p2 = lpnt;
1158 int len = 0;
1159
1160 for (; *p1 == *p2; p1++, p2++, len++) {
1161 if (*p1 == '\0')
1162 break;
1163 }
1164 if (len > jsort_glen)
1165 jsort_glen = len;
1166 }
1167 }
1168 }
1169 /*
1170 * Put the '.' and '..' entries on the head of the sorted list.
1171 * For normal ASCII, this always happens to be the case, but out of
1172 * band characters cause this not to be the case sometimes.
1173 */
1174 if (strcmp(rpnt, ".") == 0)
1175 return (-1);
1176 if (strcmp(lpnt, ".") == 0)
1177 return (1);
1178
1179 if (strcmp(rpnt, "..") == 0)
1180 return (-1);
1181 if (strcmp(lpnt, "..") == 0)
1182 return (1);
1183
1184 #ifdef DVD_AUD_VID
1185 /*
1186 * There're rumors claiming that some players assume VIDEO_TS.IFO
1187 * to be the first file in VIDEO_TS/ catalog. Well, it's basically
1188 * the only file a player has to actually look for, as the whole
1189 * video content can be "rolled down" from this file alone.
1190 * <appro@fy.chalmers.se>
1191 */
1192 /*
1193 * XXX This code has to be moved from the Joliet implementation
1194 * XXX to the UDF implementation if we implement decent UDF support
1195 * XXX with a separate name space for the UDF file tree.
1196 */
1197 if (dvd_aud_vid_flag & DVD_SPEC_VIDEO) {
1198 if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
1199 return (-1);
1200 if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
1201 return (1);
1202 }
1203 #endif
1204
1205 while (*rpnt && *lpnt) {
1206 if (*rpnt == ';' && *lpnt != ';')
1207 return (-1);
1208 if (*rpnt != ';' && *lpnt == ';')
1209 return (1);
1210
1211 if (*rpnt == ';' && *lpnt == ';')
1212 return (0);
1213
1214 /*
1215 * Extensions are not special here.
1216 * Don't treat the dot as something that must be bumped to
1217 * the start of the list.
1218 */
1219 #if 0
1220 if (*rpnt == '.' && *lpnt != '.')
1221 return (-1);
1222 if (*rpnt != '.' && *lpnt == '.')
1223 return (1);
1224 #endif
1225
1226 convert_to_unicode(rtmp, 2, rpnt, rinls);
1227 convert_to_unicode(ltmp, 2, lpnt, linls);
1228
1229 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
1230 return (-1);
1231 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
1232 return (1);
1233
1234 rpnt++;
1235 lpnt++;
1236 }
1237 if (*rpnt)
1238 return (1);
1239 if (*lpnt)
1240 return (-1);
1241 #ifdef USE_LARGEFILES
1242 /*
1243 * (*r)->mxpart == (*l)->mxpart cannot happen here
1244 */
1245 if ((*r)->mxpart < (*l)->mxpart)
1246 return (-1);
1247 else if ((*r)->mxpart > (*l)->mxpart)
1248 return (1);
1249 #endif
1250 return (0);
1251 }
1252
1253
1254 /*
1255 * Function: sort_directory
1256 *
1257 * Purpose: Sort the directory in the appropriate ISO9660
1258 * order.
1259 *
1260 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
1261 */
1262 LOCAL int
joliet_sort_directory(sort_dir)1263 joliet_sort_directory(sort_dir)
1264 struct directory_entry **sort_dir;
1265 {
1266 int dcount = 0;
1267 int i;
1268 struct directory_entry *s_entry;
1269 struct directory_entry **sortlist;
1270
1271 s_entry = *sort_dir;
1272 while (s_entry) {
1273 /*
1274 * only colletc non-hidden entries
1275 */
1276 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1277 (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
1278 dcount++;
1279 s_entry = s_entry->next;
1280 }
1281
1282 /* OK, now we know how many there are. Build a vector for sorting. */
1283 sortlist = (struct directory_entry **)
1284 e_malloc(sizeof (struct directory_entry *) * dcount);
1285
1286 dcount = 0;
1287 s_entry = *sort_dir;
1288 while (s_entry) {
1289 /*
1290 * only collect non-hidden entries
1291 */
1292 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1293 (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
1294 sortlist[dcount] = s_entry;
1295 dcount++;
1296 }
1297 s_entry = s_entry->next;
1298 }
1299
1300 jsort_goof = 0;
1301 jsort_glen = 0;
1302 #ifdef PROTOTYPES
1303 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1304 (int (*) (const void *, const void *)) joliet_compare_dirs);
1305 #else
1306 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1307 joliet_compare_dirs);
1308 #endif
1309
1310 if (jsort_goof) {
1311 errmsgno(EX_BAD,
1312 _("Joliet file names differ after %d chars\n"),
1313 jsort_glen);
1314 if (jsort_glen > JLONGMAX) {
1315 errmsgno(EX_BAD,
1316 _("Cannot use Joliet, please remove -J from the option list.\n"));
1317 } else if (jsort_glen > JMAX) {
1318 errmsgno(EX_BAD,
1319 _("Try to use the option -joliet-long\n"));
1320 }
1321 }
1322
1323 /* Now reassemble the linked list in the proper sorted order */
1324 for (i = 0; i < dcount - 1; i++) {
1325 sortlist[i]->jnext = sortlist[i + 1];
1326 }
1327
1328 sortlist[dcount - 1]->jnext = NULL;
1329 *sort_dir = sortlist[0];
1330
1331 free(sortlist);
1332 return (jsort_goof);
1333 }
1334
1335 EXPORT int
joliet_sort_tree(node)1336 joliet_sort_tree(node)
1337 struct directory *node;
1338 {
1339 struct directory *dpnt;
1340 int ret = 0;
1341
1342 dpnt = node;
1343
1344 while (dpnt) {
1345 ret = joliet_sort_n_finish(dpnt);
1346 if (ret) {
1347 break;
1348 }
1349 if (dpnt->subdir)
1350 ret = joliet_sort_tree(dpnt->subdir);
1351 if (ret) {
1352 break;
1353 }
1354 dpnt = dpnt->next;
1355 }
1356 return (ret);
1357 }
1358
1359 LOCAL void
generate_joliet_directories(node,outfile)1360 generate_joliet_directories(node, outfile)
1361 struct directory *node;
1362 FILE *outfile;
1363 {
1364 struct directory *dpnt;
1365
1366 dpnt = node;
1367
1368 while (dpnt) {
1369 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
1370 /*
1371 * In theory we should never reuse a directory, so this
1372 * doesn't make much sense.
1373 */
1374 if (dpnt->jextent > session_start) {
1375 generate_one_joliet_directory(dpnt, outfile);
1376 }
1377 }
1378 /* skip if hidden - but not for the rr_moved dir */
1379 if (dpnt->subdir &&
1380 (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
1381 dpnt == reloc_dir)) {
1382 generate_joliet_directories(dpnt->subdir, outfile);
1383 }
1384 dpnt = dpnt->next;
1385 }
1386 }
1387
1388
1389 /*
1390 * Function to write the EVD for the disc.
1391 */
1392 LOCAL int
jpathtab_write(outfile)1393 jpathtab_write(outfile)
1394 FILE *outfile;
1395 {
1396 /* Next we write the path tables */
1397 xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
1398 xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
1399 last_extent_written += 2 * jpath_blocks;
1400 free(jpath_table_l);
1401 free(jpath_table_m);
1402 jpath_table_l = NULL;
1403 jpath_table_m = NULL;
1404 return (0);
1405 }
1406
1407 LOCAL int
jdirtree_size(starting_extent)1408 jdirtree_size(starting_extent)
1409 UInt32_t starting_extent;
1410 {
1411 assign_joliet_directory_addresses(root);
1412 return (0);
1413 }
1414
1415 LOCAL int
jroot_gen()1416 jroot_gen()
1417 {
1418 jroot_record.length[0] =
1419 1 + offsetof(struct iso_directory_record, name[0]);
1420 jroot_record.ext_attr_length[0] = 0;
1421 set_733((char *)jroot_record.extent, root->jextent);
1422 set_733((char *)jroot_record.size, ISO_ROUND_UP(root->jsize));
1423 iso9660_date(jroot_record.date, root_statbuf.st_mtime);
1424 jroot_record.flags[0] = ISO_DIRECTORY;
1425 jroot_record.file_unit_size[0] = 0;
1426 jroot_record.interleave[0] = 0;
1427 set_723(jroot_record.volume_sequence_number, volume_sequence_number);
1428 jroot_record.name_len[0] = 1;
1429 return (0);
1430 }
1431
1432 LOCAL int
jdirtree_write(outfile)1433 jdirtree_write(outfile)
1434 FILE *outfile;
1435 {
1436 generate_joliet_directories(root, outfile);
1437 return (0);
1438 }
1439
1440 /*
1441 * Function to write the EVD for the disc.
1442 */
1443 LOCAL int
jvd_write(outfile)1444 jvd_write(outfile)
1445 FILE *outfile;
1446 {
1447 struct iso_primary_descriptor jvol_desc;
1448
1449 /* Next we write out the boot volume descriptor for the disc */
1450 jvol_desc = vol_desc;
1451 get_joliet_vol_desc(&jvol_desc);
1452 xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
1453 last_extent_written++;
1454 return (0);
1455 }
1456
1457 /*
1458 * Functions to describe padding block at the start of the disc.
1459 */
1460 LOCAL int
jpathtab_size(starting_extent)1461 jpathtab_size(starting_extent)
1462 UInt32_t starting_extent;
1463 {
1464 jpath_table[0] = starting_extent;
1465 jpath_table[1] = 0;
1466 jpath_table[2] = jpath_table[0] + jpath_blocks;
1467 jpath_table[3] = 0;
1468
1469 last_extent += 2 * jpath_blocks;
1470 return (0);
1471 }
1472
1473 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen, jvd_write, "Joliet Volume Descriptor" };
1474 struct output_fragment jpathtable_desc = {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write, "Joliet path table" };
1475 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write, "Joliet directory tree" };
1476