2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)joliet.c 1.38 05/05/01 joerg */
15 * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
17 * Copyright 1997 Eric Youngdale.
18 * APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000
19 * Copyright (c) 1999,2000,2001 J. Schilling
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2, or (at your option)
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 * Joliet extensions for ISO9660. These are spottily documented by
38 * Microsoft. In their infinite stupidity, they completely ignored
39 * the possibility of using an SUSP record with the long filename
40 * in it, and instead wrote out a duplicate directory tree with the
41 * long filenames in it.
43 * I am not sure why they did this. One reason is that they get the path
44 * tables with the long filenames in them.
46 * There are two basic principles to Joliet, and the non-Unicode variant
47 * known as Romeo. Long filenames seem to be the main one, and the second
48 * is that the character set and a few other things is substantially relaxed.
50 * The SVD is identical to the PVD, except:
52 * Id is 2, not 1 (indicates SVD).
53 * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
54 * The root directory record points to a different extent (with different
56 * There are different path tables for the two sets of directory trees.
58 * The Unicode level is coded in the SVD as follows:
60 * Standard Level ASCII escape code
65 * The following fields are recorded in Unicode:
74 * bibliographic_file_id
76 * Unicode strings are always encoded in big-endian format.
78 * In a directory record, everything is the same as with iso9660, except
79 * that the name is recorded in unicode. The name length is specified in
80 * total bytes, not in number of unicode characters.
82 * The character set used for the names is different with UCS - the
83 * restrictions are that the following are not allowed:
85 * Characters (00)(00) through (00)(1f) (control chars)
94 #include "genisoimage.h"
98 #include <unls.h> /* For UNICODE translation */
107 static Uint jpath_table_index;
108 static struct directory **jpathlist;
109 static int next_jpath_index = 1;
110 static int jsort_goof;
112 static char ucs_codes[] = {
113 '\0', /* UCS-level 0 is illegal */
114 '@', /* UCS-level 1 */
115 'C', /* UCS-level 2 */
116 'E', /* UCS-level 3 */
125 convert_to_unicode(unsigned char *buffer, int size, char *source,
126 struct unls_table *inls);
127 int joliet_strlen(const char *string, struct unls_table *inls);
134 convert_to_unicode(unsigned char *buffer, int size, char *source,
135 struct unls_table *inls);
136 static int joliet_strlen(const char *string, struct nls_table *inls);
138 static void get_joliet_vol_desc(struct iso_primary_descriptor *jvol_desc);
139 static void assign_joliet_directory_addresses(struct directory *node);
140 static void build_jpathlist(struct directory *node);
141 static int joliet_compare_paths(void const *r, void const *l);
142 static int generate_joliet_path_tables(void);
143 static void generate_one_joliet_directory(struct directory *dpnt,
145 static int joliet_sort_n_finish(struct directory *this_dir);
146 static int joliet_compare_dirs(const void *rr, const void *ll);
147 static int joliet_sort_directory(struct directory_entry **sort_dir);
148 int joliet_sort_tree(struct directory *node);
149 static void generate_joliet_directories(struct directory *node, FILE *outfile);
150 static int jpathtab_write(FILE *outfile);
151 static int jdirtree_size(int starting_extent);
152 static int jroot_gen(void);
153 static int jdirtree_write(FILE *outfile);
154 static int jvd_write(FILE *outfile);
155 static int jpathtab_size(int starting_extent);
158 * conv_charset: convert to/from charsets via Unicode.
160 * Any unknown character is set to '_'
164 conv_charset(unsigned char c,
165 struct unls_table *inls,
166 struct unls_table *onls)
173 /* if we have a null mapping, just return the input character */
178 if(inls->unls_cs2uni == NULL || onls->unls_uni2cs == NULL) {
180 * This shouldn't be reached
182 static BOOL iconv_warned = FALSE;
184 fprintf(stderr, "Warning: Iconv conversion not supported in conv_charset.\n");
191 /* get high and low UNICODE bytes */
192 uh = inls->unls_cs2uni[c].unls_high;
193 ul = inls->unls_cs2uni[c].unls_low;
195 /* get the backconverted page from the output charset */
196 up = onls->unls_uni2cs[uh];
198 /* if the page exists, get the backconverted character */
204 /* return the backconverted, if it's not NULL */
205 return (uc ? uc : '_');
209 * Function: convert_to_unicode
211 * Purpose: Perform a unicode conversion on a text string
212 * using the supplied input character set.
229 convert_to_unicode(unsigned char *buffer, int size, char *source,
230 struct unls_table *inls)
232 unsigned char *tmpbuf;
241 * If we get a NULL pointer for the source, it means we have an
242 * inplace copy, and we need to make a temporary working copy first.
244 if (source == NULL) {
245 tmpbuf = (Uchar *) e_malloc(size+1);
246 memcpy(tmpbuf, buffer, size);
249 tmpbuf = (Uchar *) source;
253 if (inls->iconv_d && inls->unls_cs2uni==NULL &&
254 inls->unls_uni2cs==NULL) {
255 char *inptr = (char *)tmpbuf;
256 char *outptr = (char *)buffer;
257 size_t inleft = strlen((char *)tmpbuf);
258 size_t inlen = inleft;
259 size_t outleft = size;
261 iconv(inls->iconv_d, NULL, NULL, NULL, NULL);
262 if(iconv(inls->iconv_d, &inptr, &inleft, &outptr, &outleft) ==
263 (size_t)-1 && errno == EILSEQ) {
264 fprintf(stderr, "Incorrectly encoded string (%s) "
265 "encountered.\nPossibly creating an invalid "
266 "Joliet extension. Aborting.\n", source);
270 for (i = 0; (i + 1) < size - outleft; i += 2) { /* Size may be odd!!!*/
271 if (buffer[i]=='\0') {
272 switch (buffer[i+1]) { /* Invalid characters for Joliet */
281 if (buffer[i+1] == 0x7f ||
287 if (size & 1) { /* beautification */
288 buffer[size - 1] = 0;
290 if (source == NULL) {
293 return (inlen - inleft);
298 * Now start copying characters. If the size was specified to be 0,
299 * then assume the input was 0 terminated.
302 for (i = 0; (i + 1) < size; i += 2, j++) { /* Size may be odd! */
304 * JS integrated from: Achim_Kaiser@t-online.de
305 * SGE modified according to Linux kernel source
306 * Let all valid unicode characters pass
307 * through (according to charset). Others are set to '_' .
309 uc = tmpbuf[j]; /* temporary copy */
310 if (uc != '\0') { /* must be converted */
311 uh = inls->unls_cs2uni[uc].unls_high; /* convert forward: */
313 ul = inls->unls_cs2uni[uc].unls_low; /* ...lobyte */
314 up = inls->unls_uni2cs[uh]; /* convert backward: */
317 uc = '\0'; /* wrong unicode page */
319 uc = up[ul]; /* backconverted character */
321 uc = '\0'; /* should be identical */
322 if (uc <= 0x1f || uc == 0x7f)
323 uc = '\0'; /* control char */
324 switch (uc) { /* test special characters */
332 case '\0': /* illegal char mark */
334 * Even Joliet has some standards as to what is
335 * allowed in a pathname. Pretty tame in
336 * comparison to what DOS restricts you to.
341 buffer[i] = inls->unls_cs2uni[uc].unls_high; /* final UNICODE */
343 buffer[i + 1] = inls->unls_cs2uni[uc].unls_low;
346 if (size & 1) { /* beautification */
347 buffer[size - 1] = 0;
349 if (source == NULL) {
358 * Function: joliet_strlen
360 * Purpose: Return length in bytes of string after conversion to unicode.
362 * Notes: This is provided mainly as a convenience so that when more
363 * intelligent Unicode conversion for either Multibyte or 8-bit
364 * codes is available that we can easily adapt.
371 joliet_strlen(const char *string, struct unls_table *inls)
376 if (inls->iconv_d && inls->unls_cs2uni==NULL &&
377 inls->unls_uni2cs==NULL) {
379 * we const-cast since we're sure iconv won't change
382 char *string_ptr = (char *)string;
383 size_t string_len = strlen(string);
386 * iconv has no way of finding out the required size
391 /* we assume that the maximum length is 2 * jlen */
392 size_t tmp_len = (size_t)jlen * 2 + 1;
393 tmp = e_malloc(tmp_len);
396 iconv(inls->iconv_d, NULL, NULL, NULL, NULL);
397 iconv(inls->iconv_d, &string_ptr, &string_len, &tmp_ptr,
401 * iconv advanced the tmp pointer with as many chars
402 * as it has written to it, so we add up the delta
404 rtn = (tmp_ptr - tmp);
408 rtn = strlen(string) << 1;
411 rtn = strlen(string) << 1;
415 * We do clamp the maximum length of a Joliet string to be the
416 * maximum path size. This helps to ensure that we don't completely
417 * bolix things up with very long paths. The Joliet specs say that
418 * the maximum length is 128 bytes, or 64 unicode characters.
427 * Function: get_joliet_vol_desc
429 * Purpose: generate a Joliet compatible volume desc.
431 * Notes: Assume that we have the non-joliet vol desc
432 * already present in the buffer. Just modifiy the
433 * appropriate fields.
436 get_joliet_vol_desc(struct iso_primary_descriptor *jvol_desc)
438 jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
439 jvol_desc->version[0] = 1;
440 jvol_desc->file_structure_version[0] = 1;
443 * For now, always do Unicode level 3.
444 * I don't really know what 1 and 2 are - perhaps a more limited
446 * FIXME(eric) - how does Romeo fit in here?
448 sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
450 /* Until we have Unicode path tables, leave these unset. */
451 set_733((char *) jvol_desc->path_table_size, jpath_table_size);
452 set_731(jvol_desc->type_l_path_table, jpath_table[0]);
453 set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
454 set_732(jvol_desc->type_m_path_table, jpath_table[2]);
455 set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
457 /* Set this one up. */
458 memcpy(jvol_desc->root_directory_record, &jroot_record,
459 offsetof(struct iso_directory_record, name[0]) + 1);
462 * Finally, we have a bunch of strings to convert to Unicode.
463 * FIXME(eric) - I don't know how to do this in general,
464 * so we will just be really lazy and do a char -> short conversion.
465 * We probably will want to filter any characters >= 0x80.
467 convert_to_unicode((Uchar *) jvol_desc->system_id,
468 sizeof (jvol_desc->system_id), NULL, in_nls);
469 convert_to_unicode((Uchar *) jvol_desc->volume_id,
470 sizeof (jvol_desc->volume_id), NULL, in_nls);
471 convert_to_unicode((Uchar *) jvol_desc->volume_set_id,
472 sizeof (jvol_desc->volume_set_id), NULL, in_nls);
473 convert_to_unicode((Uchar *) jvol_desc->publisher_id,
474 sizeof (jvol_desc->publisher_id), NULL, in_nls);
475 convert_to_unicode((Uchar *) jvol_desc->preparer_id,
476 sizeof (jvol_desc->preparer_id), NULL, in_nls);
477 convert_to_unicode((Uchar *) jvol_desc->application_id,
478 sizeof (jvol_desc->application_id), NULL, in_nls);
479 convert_to_unicode((Uchar *) jvol_desc->copyright_file_id,
480 sizeof (jvol_desc->copyright_file_id), NULL, in_nls);
481 convert_to_unicode((Uchar *) jvol_desc->abstract_file_id,
482 sizeof (jvol_desc->abstract_file_id), NULL, in_nls);
483 convert_to_unicode((Uchar *) jvol_desc->bibliographic_file_id,
484 sizeof (jvol_desc->bibliographic_file_id), NULL, in_nls);
488 assign_joliet_directory_addresses(struct directory *node)
491 struct directory *dpnt;
496 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
498 * If we already have an extent for this
499 * (i.e. it came from a multisession disc), then
500 * don't reassign a new extent.
502 dpnt->jpath_index = next_jpath_index++;
503 if (dpnt->jextent == 0) {
504 dpnt->jextent = last_extent;
505 dir_size = ISO_BLOCKS(dpnt->jsize);
506 last_extent += dir_size;
509 /* skip if hidden - but not for the rr_moved dir */
510 if (dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) {
511 assign_joliet_directory_addresses(dpnt->subdir);
518 build_jpathlist(struct directory *node)
520 struct directory *dpnt;
525 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
526 jpathlist[dpnt->jpath_index] = dpnt;
529 build_jpathlist(dpnt->subdir);
532 }/* build_jpathlist(... */
535 joliet_compare_paths(void const *r, void const *l)
537 struct directory const *ll = *(struct directory * const *) l;
538 struct directory const *rr = *(struct directory * const *) r;
543 unsigned char rtmp[2],
545 struct unls_table *rinls, *linls;
547 /* make sure root directory is first */
554 rparent = rr->parent->jpath_index;
555 lparent = ll->parent->jpath_index;
556 if (rr->parent == reloc_dir) {
557 rparent = rr->self->parent_rec->filedir->jpath_index;
559 if (ll->parent == reloc_dir) {
560 lparent = ll->self->parent_rec->filedir->jpath_index;
562 if (rparent < lparent) {
565 if (rparent > lparent) {
570 * we may be using the HFS name - so select the correct input
573 if (USE_MAC_NAME(rr->self)) {
574 rpnt = rr->self->hfs_ent->name;
577 rpnt = rr->self->name;
581 if (USE_MAC_NAME(ll->self)) {
582 lpnt = ll->self->hfs_ent->name;
585 lpnt = ll->self->name;
589 rpnt = rr->self->name;
590 lpnt = ll->self->name;
591 linls = rinls = in_nls;
592 #endif /* APPLE_HYB */
594 /* compare the Unicode names */
596 while (*rpnt && *lpnt) {
600 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
601 li = convert_to_unicode(ltmp, 2, lpnt, linls);
611 convert_to_unicode(rtmp, 2, rpnt, rinls);
612 convert_to_unicode(ltmp, 2, lpnt, linls);
615 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
617 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
633 }/* compare_paths(... */
636 generate_joliet_path_tables()
638 struct directory_entry *de;
639 struct directory *dpnt;
647 /* First allocate memory for the tables and initialize the memory */
648 tablesize = jpath_blocks << 11;
649 jpath_table_m = (char *) e_malloc(tablesize);
650 jpath_table_l = (char *) e_malloc(tablesize);
651 memset(jpath_table_l, 0, tablesize);
652 memset(jpath_table_m, 0, tablesize);
654 /* Now start filling in the path tables. Start with root directory */
655 jpath_table_index = 0;
656 jpathlist = (struct directory **) e_malloc(sizeof (struct directory *)
658 memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
659 build_jpathlist(root);
664 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
665 (int (*) (const void *, const void *)) joliet_compare_paths);
667 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
668 joliet_compare_paths);
671 for (j = 1; j < next_jpath_index; j++) {
672 if (jpathlist[j]->jpath_index != j) {
673 jpathlist[j]->jpath_index = j;
679 for (j = 1; j < next_jpath_index; j++) {
683 comerrno(EX_BAD, "Entry %d not in path tables\n", j);
685 fprintf(stderr, "Entry %d not in path tables\n", j);
689 npnt = dpnt->de_name;
691 npnt1 = strrchr(npnt, PATH_SEPARATOR);
699 "Fatal Joliet goof - directory has amnesia\n");
702 "Fatal Joliet goof - directory has amnesia\n");
707 if (USE_MAC_NAME(de))
708 namelen = joliet_strlen(de->hfs_ent->name, hfs_inls);
710 #endif /* APPLE_HYB */
711 namelen = joliet_strlen(de->name, in_nls);
714 jpath_table_l[jpath_table_index] = 1;
715 jpath_table_m[jpath_table_index] = 1;
717 jpath_table_l[jpath_table_index] = namelen;
718 jpath_table_m[jpath_table_index] = namelen;
720 jpath_table_index += 2;
722 set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
723 set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
724 jpath_table_index += 4;
726 if (dpnt->parent->jpath_index > 0xffff) {
729 "Unable to generate sane path tables - too many directories (%d)\n",
730 dpnt->parent->jpath_index);
733 "Unable to generate sane path tables - too many directories (%d)\n",
734 dpnt->parent->jpath_index);
739 if (dpnt->parent != reloc_dir) {
740 set_721(jpath_table_l + jpath_table_index,
741 dpnt->parent->jpath_index);
742 set_722(jpath_table_m + jpath_table_index,
743 dpnt->parent->jpath_index);
745 set_721(jpath_table_l + jpath_table_index,
746 dpnt->self->parent_rec->filedir->jpath_index);
747 set_722(jpath_table_m + jpath_table_index,
748 dpnt->self->parent_rec->filedir->jpath_index);
751 jpath_table_index += 2;
754 * The root directory is still represented in non-unicode
758 jpath_table_l[jpath_table_index] = 0;
759 jpath_table_m[jpath_table_index] = 0;
763 if (USE_MAC_NAME(de)) {
764 convert_to_unicode((Uchar *) jpath_table_l +
766 namelen, de->hfs_ent->name, hfs_inls);
767 convert_to_unicode((Uchar *) jpath_table_m +
769 namelen, de->hfs_ent->name, hfs_inls);
771 #endif /* APPLE_HYB */
772 convert_to_unicode((Uchar *) jpath_table_l +
774 namelen, de->name, in_nls);
775 convert_to_unicode((Uchar *) jpath_table_m +
777 namelen, de->name, in_nls);
780 #endif /* APPLE_HYB */
782 jpath_table_index += namelen;
785 if (jpath_table_index & 1) {
786 jpath_table_index++; /* For odd lengths we pad */
791 if (jpath_table_index != jpath_table_size) {
794 "Joliet path table lengths do not match %d expected: %d\n",
799 "Joliet path table lengths do not match %d expected: %d\n",
805 }/* generate_path_tables(... */
808 generate_one_joliet_directory(struct directory *dpnt, FILE *outfile)
810 unsigned int dir_index;
811 char *directory_buffer;
813 struct directory_entry *s_entry;
814 struct directory_entry *s_entry1;
815 struct iso_directory_record jrec;
816 unsigned int total_size;
818 struct directory *finddir;
820 total_size = ISO_ROUND_UP(dpnt->jsize);
821 directory_buffer = (char *) e_malloc(total_size);
822 memset(directory_buffer, 0, total_size);
825 s_entry = dpnt->jcontents;
827 if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
828 s_entry = s_entry->jnext;
832 * If this entry was a directory that was relocated,
833 * we have a bit of trouble here. We need to dig out the real
834 * thing and put it back here. In the Joliet tree, there is
835 * no relocated rock ridge, as there are no depth limits to a
838 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
839 for (s_entry1 = reloc_dir->contents; s_entry1;
840 s_entry1 = s_entry1->next) {
841 if (s_entry1->parent_rec == s_entry) {
845 if (s_entry1 == NULL) {
846 /* We got trouble. */
849 "Unable to locate relocated directory\n");
852 "Unable to locate relocated directory\n");
861 * We do not allow directory entries to cross sector
862 * boundaries. Simply pad, and then start the next entry at
865 new_reclen = s_entry1->jreclen;
866 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) {
867 dir_index = ISO_ROUND_UP(dir_index);
869 memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
872 /* Use the HFS name if it exists */
873 if (USE_MAC_NAME(s_entry1))
874 cvt_len = joliet_strlen(s_entry1->hfs_ent->name, hfs_inls);
876 #endif /* APPLE_HYB */
877 cvt_len = joliet_strlen(s_entry1->name, in_nls);
880 * Fix the record length
881 * - this was the non-Joliet version we were seeing.
883 jrec.name_len[0] = cvt_len;
884 jrec.length[0] = s_entry1->jreclen;
887 * If this is a directory,
888 * fix the correct size and extent number.
890 if ((jrec.flags[0] & ISO_DIRECTORY) != 0) {
891 if (strcmp(s_entry1->name, ".") == 0) {
892 jrec.name_len[0] = 1;
893 set_733((char *) jrec.extent, dpnt->jextent);
894 set_733((char *) jrec.size, ISO_ROUND_UP(dpnt->jsize));
895 } else if (strcmp(s_entry1->name, "..") == 0) {
896 jrec.name_len[0] = 1;
897 if (dpnt->parent == reloc_dir) {
898 set_733((char *)jrec.extent, dpnt->self->parent_rec->filedir->jextent);
899 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
901 set_733((char *)jrec.extent, dpnt->parent->jextent);
902 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
905 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
906 finddir = reloc_dir->subdir;
908 finddir = dpnt->subdir;
911 if (finddir->self == s_entry1)
913 finddir = finddir->next;
916 comerrno(EX_BAD, "Fatal goof - unable to find directory location\n");
918 fprintf(stderr, "Fatal goof - unable to find directory location\n");
923 set_733((char *)jrec.extent, finddir->jextent);
924 set_733((char *)jrec.size,
925 ISO_ROUND_UP(finddir->jsize));
928 memcpy(directory_buffer + dir_index, &jrec,
929 offsetof(struct iso_directory_record, name[0]));
931 dir_index += offsetof(struct iso_directory_record, name[0]);
934 * Finally dump the Unicode version of the filename.
935 * Note - . and .. are the same as with non-Joliet discs.
937 if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
938 strcmp(s_entry1->name, ".") == 0) {
939 directory_buffer[dir_index++] = 0;
940 } else if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
941 strcmp(s_entry1->name, "..") == 0) {
942 directory_buffer[dir_index++] = 1;
945 if (USE_MAC_NAME(s_entry1)) {
946 /* Use the HFS name if it exists */
948 (Uchar *) directory_buffer+dir_index,
950 s_entry1->hfs_ent->name, hfs_inls);
952 #endif /* APPLE_HYB */
955 (Uchar *) directory_buffer+dir_index,
957 s_entry1->name, in_nls);
959 dir_index += cvt_len;
963 directory_buffer[dir_index++] = 0;
965 s_entry = s_entry->jnext;
968 if (dpnt->jsize != dir_index) {
971 "Unexpected joliet directory length %d expected: %d '%s'\n",
973 dir_index, dpnt->de_name);
976 "Unexpected joliet directory length %d expected: %d '%s'\n",
978 dir_index, dpnt->de_name);
981 jtwrite(directory_buffer, total_size, 1, 0, FALSE);
982 xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
983 last_extent_written += total_size >> 11;
984 free(directory_buffer);
985 }/* generate_one_joliet_directory(... */
988 joliet_sort_n_finish(struct directory *this_dir)
990 struct directory_entry *s_entry;
994 * don't want to skip this directory if it's the reloc_dir
997 if (this_dir != reloc_dir &&
998 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1001 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1002 /* skip hidden entries */
1003 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1007 * First update the path table sizes for directories.
1009 * Finally, set the length of the directory entry if Joliet is
1010 * used. The name is longer, but no Rock Ridge is ever used
1011 * here, so depending upon the options the entry size might
1012 * turn out to be about the same. The Unicode name is always
1013 * a multiple of 2 bytes, so we always add 1 to make it an
1016 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1017 if (strcmp(s_entry->name, ".") != 0 &&
1018 strcmp(s_entry->name, "..") != 0) {
1020 if (USE_MAC_NAME(s_entry))
1021 /* Use the HFS name if it exists */
1023 joliet_strlen(s_entry->hfs_ent->name, hfs_inls) +
1024 offsetof(struct iso_path_table, name[0]);
1026 #endif /* APPLE_HYB */
1028 joliet_strlen(s_entry->name, in_nls) +
1029 offsetof(struct iso_path_table, name[0]);
1030 if (jpath_table_size & 1) {
1034 if (this_dir == root &&
1035 strlen(s_entry->name) == 1) {
1037 jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
1038 if (jpath_table_size & 1)
1043 if (strcmp(s_entry->name, ".") != 0 &&
1044 strcmp(s_entry->name, "..") != 0) {
1046 if (USE_MAC_NAME(s_entry))
1047 /* Use the HFS name if it exists */
1049 offsetof(struct iso_directory_record, name[0])
1050 + joliet_strlen(s_entry->hfs_ent->name, hfs_inls)
1053 #endif /* APPLE_HYB */
1055 offsetof(struct iso_directory_record, name[0])
1056 + joliet_strlen(s_entry->name, in_nls)
1060 * Special - for '.' and '..' we generate the same
1061 * records we did for non-Joliet discs.
1064 offsetof(struct iso_directory_record, name[0])
1071 if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1074 this_dir->jcontents = this_dir->contents;
1075 status = joliet_sort_directory(&this_dir->jcontents);
1078 * Now go through the directory and figure out how large this one will
1079 * be. Do not split a directory entry across a sector boundary
1081 s_entry = this_dir->jcontents;
1083 * XXX Is it ok to comment this out?
1085 /*XXX JS this_dir->ce_bytes = 0;*/
1086 for (s_entry = this_dir->jcontents; s_entry;
1087 s_entry = s_entry->jnext) {
1090 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1093 jreclen = s_entry->jreclen;
1095 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
1097 this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
1099 this_dir->jsize += jreclen;
1105 * Similar to the iso9660 case,
1106 * except here we perform a full sort based upon the
1107 * regular name of the file, not the 8.3 version.
1110 joliet_compare_dirs(const void *rr, const void *ll)
1114 struct directory_entry **r,
1116 unsigned char rtmp[2],
1118 struct unls_table *linls, *rinls;
1120 r = (struct directory_entry **) rr;
1121 l = (struct directory_entry **) ll;
1125 * we may be using the HFS name - so select the correct input
1128 if (USE_MAC_NAME(*r)) {
1129 rpnt = (*r)->hfs_ent->name;
1136 if (USE_MAC_NAME(*l)) {
1137 lpnt = (*l)->hfs_ent->name;
1146 rinls = linls = in_nls;
1147 #endif /* APPLE_HYB */
1150 * If the entries are the same, this is an error.
1151 * Joliet specs allow for a maximum of 64 characters.
1153 if (strncmp(rpnt, lpnt, jlen) == 0) {
1154 #ifdef USE_LIBSCHILY
1156 "Error: %s and %s have the same Joliet name\n",
1157 (*r)->whole_name, (*l)->whole_name);
1160 "Error: %s and %s have the same Joliet name\n",
1161 (*r)->whole_name, (*l)->whole_name);
1166 * Put the '.' and '..' entries on the head of the sorted list.
1167 * For normal ASCII, this always happens to be the case, but out of
1168 * band characters cause this not to be the case sometimes.
1170 if (strcmp(rpnt, ".") == 0)
1172 if (strcmp(lpnt, ".") == 0)
1175 if (strcmp(rpnt, "..") == 0)
1177 if (strcmp(lpnt, "..") == 0)
1182 * There're rumors claiming that some players assume VIDEO_TS.IFO
1183 * to be the first file in VIDEO_TS/ catalog. Well, it's basically
1184 * the only file a player has to actually look for, as the whole
1185 * video content can be "rolled down" from this file alone.
1186 * <appro@fy.chalmers.se>
1189 * XXX This code has to be moved from the Joliet implementation
1190 * XXX to the UDF implementation if we implement decent UDF support
1191 * XXX with a separate name space for the UDF file tree.
1194 if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
1196 if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
1201 while (*rpnt && *lpnt) {
1205 if (*rpnt == ';' && *lpnt != ';')
1207 if (*rpnt != ';' && *lpnt == ';')
1210 if (*rpnt == ';' && *lpnt == ';')
1214 * Extensions are not special here.
1215 * Don't treat the dot as something that must be bumped to
1216 * the start of the list.
1219 if (*rpnt == '.' && *lpnt != '.')
1221 if (*rpnt != '.' && *lpnt == '.')
1227 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
1228 li = convert_to_unicode(ltmp, 2, lpnt, linls);
1238 convert_to_unicode(rtmp, 2, rpnt, rinls);
1239 convert_to_unicode(ltmp, 2, lpnt, linls);
1242 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
1244 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
1261 * Function: sort_directory
1263 * Purpose: Sort the directory in the appropriate ISO9660
1266 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
1269 joliet_sort_directory(struct directory_entry **sort_dir)
1273 struct directory_entry *s_entry;
1274 struct directory_entry **sortlist;
1276 s_entry = *sort_dir;
1278 /* skip hidden entries */
1279 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY))
1281 s_entry = s_entry->next;
1284 /* OK, now we know how many there are. Build a vector for sorting. */
1285 sortlist = (struct directory_entry **)
1286 e_malloc(sizeof (struct directory_entry *) * dcount);
1289 s_entry = *sort_dir;
1291 /* skip hidden entries */
1292 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) {
1293 sortlist[dcount] = s_entry;
1296 s_entry = s_entry->next;
1301 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1302 (int (*) (const void *, const void *)) joliet_compare_dirs);
1304 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1305 joliet_compare_dirs);
1308 /* Now reassemble the linked list in the proper sorted order */
1309 for (i = 0; i < dcount - 1; i++) {
1310 sortlist[i]->jnext = sortlist[i + 1];
1313 sortlist[dcount - 1]->jnext = NULL;
1314 *sort_dir = sortlist[0];
1317 return (jsort_goof);
1321 joliet_sort_tree(struct directory *node)
1323 struct directory *dpnt;
1329 ret = joliet_sort_n_finish(dpnt);
1334 ret = joliet_sort_tree(dpnt->subdir);
1344 generate_joliet_directories(struct directory *node, FILE *outfile)
1346 struct directory *dpnt;
1351 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
1353 * In theory we should never reuse a directory, so this
1354 * doesn't make much sense.
1356 if (dpnt->jextent > session_start) {
1357 generate_one_joliet_directory(dpnt, outfile);
1360 /* skip if hidden - but not for the rr_moved dir */
1362 (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
1363 dpnt == reloc_dir)) {
1364 generate_joliet_directories(dpnt->subdir, outfile);
1372 * Function to write the EVD for the disc.
1375 jpathtab_write(FILE *outfile)
1377 /* Next we write the path tables */
1378 jtwrite(jpath_table_l, jpath_blocks << 11, 1, 0, FALSE);
1379 xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
1380 last_extent_written += jpath_blocks;
1381 jtwrite(jpath_table_m, jpath_blocks << 11, 1, 0, FALSE);
1382 xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
1383 last_extent_written += jpath_blocks;
1384 free(jpath_table_l);
1385 free(jpath_table_m);
1386 jpath_table_l = NULL;
1387 jpath_table_m = NULL;
1392 jdirtree_size(int starting_extent)
1394 assign_joliet_directory_addresses(root);
1401 jroot_record.length[0] =
1402 1 + offsetof(struct iso_directory_record, name[0]);
1403 jroot_record.ext_attr_length[0] = 0;
1404 set_733((char *) jroot_record.extent, root->jextent);
1405 set_733((char *) jroot_record.size, ISO_ROUND_UP(root->jsize));
1406 iso9660_date(jroot_record.date, root_statbuf.st_mtime);
1407 jroot_record.flags[0] = ISO_DIRECTORY;
1408 jroot_record.file_unit_size[0] = 0;
1409 jroot_record.interleave[0] = 0;
1410 set_723(jroot_record.volume_sequence_number, volume_sequence_number);
1411 jroot_record.name_len[0] = 1;
1416 jdirtree_write(FILE *outfile)
1418 generate_joliet_directories(root, outfile);
1423 * Function to write the EVD for the disc.
1426 jvd_write(FILE *outfile)
1428 struct iso_primary_descriptor jvol_desc;
1430 /* Next we write out the boot volume descriptor for the disc */
1431 jvol_desc = vol_desc;
1432 get_joliet_vol_desc(&jvol_desc);
1433 jtwrite(&jvol_desc, SECTOR_SIZE, 1, 0, FALSE);
1434 xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
1435 last_extent_written++;
1440 * Functions to describe padding block at the start of the disc.
1443 jpathtab_size(int starting_extent)
1445 jpath_table[0] = starting_extent;
1447 jpath_table[2] = jpath_table[0] + jpath_blocks;
1450 last_extent += 2 * jpath_blocks;
1454 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen, jvd_write, "Joliet Volume Descriptor" };
1455 struct output_fragment jpathtable_desc = {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write, "Joliet path table" };
1456 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write, "Joliet directory tree" };