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 */
14 /* Parts from @(#)joliet.c>1.54 07/10/20 joerg */
16 * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
18 * Copyright 1997 Eric Youngdale.
19 * APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 22/2/2000
20 * Copyright (c) 1999,2000,2001 J. Schilling
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2, or (at your option)
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 * Joliet extensions for ISO9660. These are spottily documented by
39 * Microsoft. In their infinite stupidity, they completely ignored
40 * the possibility of using an SUSP record with the long filename
41 * in it, and instead wrote out a duplicate directory tree with the
42 * long filenames in it.
44 * I am not sure why they did this. One reason is that they get the path
45 * tables with the long filenames in them.
47 * There are two basic principles to Joliet, and the non-Unicode variant
48 * known as Romeo. Long filenames seem to be the main one, and the second
49 * is that the character set and a few other things is substantially relaxed.
51 * The SVD is identical to the PVD, except:
53 * Id is 2, not 1 (indicates SVD).
54 * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
55 * The root directory record points to a different extent (with different
57 * There are different path tables for the two sets of directory trees.
59 * The Unicode level is coded in the SVD as follows:
61 * Standard Level ASCII escape code
66 * The following fields are recorded in Unicode:
75 * bibliographic_file_id
77 * Unicode strings are always encoded in big-endian format.
79 * In a directory record, everything is the same as with iso9660, except
80 * that the name is recorded in unicode. The name length is specified in
81 * total bytes, not in number of unicode characters.
83 * The character set used for the names is different with UCS - the
84 * restrictions are that the following are not allowed:
86 * Characters (00)(00) through (00)(1f) (control chars)
95 #include "genisoimage.h"
99 #include <unls.h> /* For UNICODE translation */
108 static Uint jpath_table_index;
109 static struct directory **jpathlist;
110 static int next_jpath_index = 1;
111 static int jsort_goof;
113 static char ucs_codes[] = {
114 '\0', /* UCS-level 0 is illegal */
115 '@', /* UCS-level 1 */
116 'C', /* UCS-level 2 */
117 'E', /* UCS-level 3 */
126 convert_to_unicode(unsigned char *buffer, int size, char *source,
127 struct unls_table *inls);
128 int joliet_strlen(const char *string, struct unls_table *inls);
135 convert_to_unicode(unsigned char *buffer, int size, char *source,
136 struct unls_table *inls);
137 static int joliet_strlen(const char *string, struct nls_table *inls);
139 static void get_joliet_vol_desc(struct iso_primary_descriptor *jvol_desc);
140 static void assign_joliet_directory_addresses(struct directory *node);
141 static void build_jpathlist(struct directory *node);
142 static int joliet_compare_paths(void const *r, void const *l);
143 static int generate_joliet_path_tables(void);
144 static void generate_one_joliet_directory(struct directory *dpnt,
146 static int joliet_sort_n_finish(struct directory *this_dir);
147 static int joliet_compare_dirs(const void *rr, const void *ll);
148 static int joliet_sort_directory(struct directory_entry **sort_dir);
149 int joliet_sort_tree(struct directory *node);
150 static void generate_joliet_directories(struct directory *node, FILE *outfile);
151 static int jpathtab_write(FILE *outfile);
152 static int jdirtree_size(int starting_extent);
153 static int jroot_gen(void);
154 static int jdirtree_write(FILE *outfile);
155 static int jvd_write(FILE *outfile);
156 static int jpathtab_size(int starting_extent);
159 * conv_charset: convert to/from charsets via Unicode.
161 * Any unknown character is set to '_'
165 conv_charset(unsigned char c,
166 struct unls_table *inls,
167 struct unls_table *onls)
174 /* if we have a null mapping, just return the input character */
179 if(inls->unls_cs2uni == NULL || onls->unls_uni2cs == NULL) {
181 * This shouldn't be reached
183 static BOOL iconv_warned = FALSE;
185 fprintf(stderr, "Warning: Iconv conversion not supported in conv_charset.\n");
192 /* get high and low UNICODE bytes */
193 uh = inls->unls_cs2uni[c].unls_high;
194 ul = inls->unls_cs2uni[c].unls_low;
196 /* get the backconverted page from the output charset */
197 up = onls->unls_uni2cs[uh];
199 /* if the page exists, get the backconverted character */
205 /* return the backconverted, if it's not NULL */
206 return (uc ? uc : '_');
210 * Function: convert_to_unicode
212 * Purpose: Perform a unicode conversion on a text string
213 * using the supplied input character set.
230 convert_to_unicode(unsigned char *buffer, int size, char *source,
231 struct unls_table *inls)
233 unsigned char *tmpbuf;
242 * If we get a NULL pointer for the source, it means we have an
243 * inplace copy, and we need to make a temporary working copy first.
245 if (source == NULL) {
246 tmpbuf = (Uchar *) e_malloc(size+1);
247 memcpy(tmpbuf, buffer, size);
250 tmpbuf = (Uchar *) source;
254 if (inls->iconv_d && inls->unls_cs2uni==NULL &&
255 inls->unls_uni2cs==NULL) {
256 char *inptr = (char *)tmpbuf;
257 char *outptr = (char *)buffer;
258 size_t inleft = strlen((char *)tmpbuf);
259 size_t inlen = inleft;
260 size_t outleft = size;
262 iconv(inls->iconv_d, NULL, NULL, NULL, NULL);
263 if(iconv(inls->iconv_d, &inptr, &inleft, &outptr, &outleft) ==
264 (size_t)-1 && errno == EILSEQ) {
265 fprintf(stderr, "Incorrectly encoded string (%s) "
266 "encountered.\nPossibly creating an invalid "
267 "Joliet extension. Aborting.\n", source);
271 for (i = 0; (i + 1) < size - outleft; i += 2) { /* Size may be odd!!!*/
272 if (buffer[i]=='\0') {
273 switch (buffer[i+1]) { /* Invalid characters for Joliet */
282 if (buffer[i+1] == 0x7f ||
288 if (size & 1) { /* beautification */
289 buffer[size - 1] = 0;
291 if (source == NULL) {
294 return (inlen - inleft);
299 * Now start copying characters. If the size was specified to be 0,
300 * then assume the input was 0 terminated.
303 for (i = 0; (i + 1) < size; i += 2, j++) { /* Size may be odd! */
305 * JS integrated from: Achim_Kaiser@t-online.de
306 * SGE modified according to Linux kernel source
307 * Let all valid unicode characters pass
308 * through (according to charset). Others are set to '_' .
310 uc = tmpbuf[j]; /* temporary copy */
311 if (uc != '\0') { /* must be converted */
312 uh = inls->unls_cs2uni[uc].unls_high; /* convert forward: */
314 ul = inls->unls_cs2uni[uc].unls_low; /* ...lobyte */
315 up = inls->unls_uni2cs[uh]; /* convert backward: */
318 uc = '\0'; /* wrong unicode page */
320 uc = up[ul]; /* backconverted character */
322 uc = '\0'; /* should be identical */
323 if (uc <= 0x1f || uc == 0x7f)
324 uc = '\0'; /* control char */
325 switch (uc) { /* test special characters */
333 case '\0': /* illegal char mark */
335 * Even Joliet has some standards as to what is
336 * allowed in a pathname. Pretty tame in
337 * comparison to what DOS restricts you to.
342 buffer[i] = inls->unls_cs2uni[uc].unls_high; /* final UNICODE */
344 buffer[i + 1] = inls->unls_cs2uni[uc].unls_low;
347 if (size & 1) { /* beautification */
348 buffer[size - 1] = 0;
350 if (source == NULL) {
359 * Function: joliet_strlen
361 * Purpose: Return length in bytes of string after conversion to unicode.
363 * Notes: This is provided mainly as a convenience so that when more
364 * intelligent Unicode conversion for either Multibyte or 8-bit
365 * codes is available that we can easily adapt.
372 joliet_strlen(const char *string, struct unls_table *inls)
377 if (inls->iconv_d && inls->unls_cs2uni==NULL &&
378 inls->unls_uni2cs==NULL) {
380 * we const-cast since we're sure iconv won't change
383 char *string_ptr = (char *)string;
384 size_t string_len = strlen(string);
387 * iconv has no way of finding out the required size
392 /* we assume that the maximum length is 2 * jlen */
393 size_t tmp_len = (size_t)jlen * 2 + 1;
394 tmp = e_malloc(tmp_len);
397 iconv(inls->iconv_d, NULL, NULL, NULL, NULL);
398 iconv(inls->iconv_d, &string_ptr, &string_len, &tmp_ptr,
402 * iconv advanced the tmp pointer with as many chars
403 * as it has written to it, so we add up the delta
405 rtn = (tmp_ptr - tmp);
409 rtn = strlen(string) << 1;
412 rtn = strlen(string) << 1;
416 * We do clamp the maximum length of a Joliet string to be the
417 * maximum path size. This helps to ensure that we don't completely
418 * bolix things up with very long paths. The Joliet specs say that
419 * the maximum length is 128 bytes, or 64 unicode characters.
428 * Function: get_joliet_vol_desc
430 * Purpose: generate a Joliet compatible volume desc.
432 * Notes: Assume that we have the non-joliet vol desc
433 * already present in the buffer. Just modifiy the
434 * appropriate fields.
437 get_joliet_vol_desc(struct iso_primary_descriptor *jvol_desc)
439 jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
440 jvol_desc->version[0] = 1;
441 jvol_desc->file_structure_version[0] = 1;
444 * For now, always do Unicode level 3.
445 * I don't really know what 1 and 2 are - perhaps a more limited
447 * FIXME(eric) - how does Romeo fit in here?
449 sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
451 /* Until we have Unicode path tables, leave these unset. */
452 set_733((char *) jvol_desc->path_table_size, jpath_table_size);
453 set_731(jvol_desc->type_l_path_table, jpath_table[0]);
454 set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
455 set_732(jvol_desc->type_m_path_table, jpath_table[2]);
456 set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
458 /* Set this one up. */
459 memcpy(jvol_desc->root_directory_record, &jroot_record,
460 offsetof(struct iso_directory_record, name[0]) + 1);
463 * Finally, we have a bunch of strings to convert to Unicode.
464 * FIXME(eric) - I don't know how to do this in general,
465 * so we will just be really lazy and do a char -> short conversion.
466 * We probably will want to filter any characters >= 0x80.
468 convert_to_unicode((Uchar *) jvol_desc->system_id,
469 sizeof (jvol_desc->system_id), NULL, in_nls);
470 convert_to_unicode((Uchar *) jvol_desc->volume_id,
471 sizeof (jvol_desc->volume_id), NULL, in_nls);
472 convert_to_unicode((Uchar *) jvol_desc->volume_set_id,
473 sizeof (jvol_desc->volume_set_id), NULL, in_nls);
474 convert_to_unicode((Uchar *) jvol_desc->publisher_id,
475 sizeof (jvol_desc->publisher_id), NULL, in_nls);
476 convert_to_unicode((Uchar *) jvol_desc->preparer_id,
477 sizeof (jvol_desc->preparer_id), NULL, in_nls);
478 convert_to_unicode((Uchar *) jvol_desc->application_id,
479 sizeof (jvol_desc->application_id), NULL, in_nls);
480 convert_to_unicode((Uchar *) jvol_desc->copyright_file_id,
481 sizeof (jvol_desc->copyright_file_id), NULL, in_nls);
482 convert_to_unicode((Uchar *) jvol_desc->abstract_file_id,
483 sizeof (jvol_desc->abstract_file_id), NULL, in_nls);
484 convert_to_unicode((Uchar *) jvol_desc->bibliographic_file_id,
485 sizeof (jvol_desc->bibliographic_file_id), NULL, in_nls);
489 assign_joliet_directory_addresses(struct directory *node)
492 struct directory *dpnt;
497 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
499 * If we already have an extent for this
500 * (i.e. it came from a multisession disc), then
501 * don't reassign a new extent.
503 dpnt->jpath_index = next_jpath_index++;
504 if (dpnt->jextent == 0) {
505 dpnt->jextent = last_extent;
506 dir_size = ISO_BLOCKS(dpnt->jsize);
507 last_extent += dir_size;
510 /* skip if hidden - but not for the rr_moved dir */
512 ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
513 dpnt == reloc_dir)) {
514 assign_joliet_directory_addresses(dpnt->subdir);
521 build_jpathlist(struct directory *node)
523 struct directory *dpnt;
528 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
529 jpathlist[dpnt->jpath_index] = dpnt;
532 build_jpathlist(dpnt->subdir);
535 }/* build_jpathlist(... */
538 joliet_compare_paths(void const *r, void const *l)
540 struct directory const *ll = *(struct directory * const *) l;
541 struct directory const *rr = *(struct directory * const *) r;
546 unsigned char rtmp[2],
548 struct unls_table *rinls, *linls;
550 /* make sure root directory is first */
557 rparent = rr->parent->jpath_index;
558 lparent = ll->parent->jpath_index;
559 if (rr->parent == reloc_dir) {
560 rparent = rr->self->parent_rec->filedir->jpath_index;
562 if (ll->parent == reloc_dir) {
563 lparent = ll->self->parent_rec->filedir->jpath_index;
565 if (rparent < lparent) {
568 if (rparent > lparent) {
573 * we may be using the HFS name - so select the correct input
576 if (USE_MAC_NAME(rr->self)) {
577 rpnt = rr->self->hfs_ent->name;
580 rpnt = rr->self->name;
584 if (USE_MAC_NAME(ll->self)) {
585 lpnt = ll->self->hfs_ent->name;
588 lpnt = ll->self->name;
592 rpnt = rr->self->name;
593 lpnt = ll->self->name;
594 linls = rinls = in_nls;
595 #endif /* APPLE_HYB */
597 /* compare the Unicode names */
599 while (*rpnt && *lpnt) {
603 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
604 li = convert_to_unicode(ltmp, 2, lpnt, linls);
614 convert_to_unicode(rtmp, 2, rpnt, rinls);
615 convert_to_unicode(ltmp, 2, lpnt, linls);
618 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
620 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
636 }/* compare_paths(... */
639 generate_joliet_path_tables()
641 struct directory_entry *de;
642 struct directory *dpnt;
649 unsigned int jpindex;
651 /* First allocate memory for the tables and initialize the memory */
652 tablesize = jpath_blocks << 11;
653 jpath_table_m = (char *) e_malloc(tablesize);
654 jpath_table_l = (char *) e_malloc(tablesize);
655 memset(jpath_table_l, 0, tablesize);
656 memset(jpath_table_m, 0, tablesize);
658 /* Now start filling in the path tables. Start with root directory */
659 jpath_table_index = 0;
660 jpathlist = (struct directory **) e_malloc(sizeof (struct directory *)
662 memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
663 build_jpathlist(root);
668 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
669 (int (*) (const void *, const void *)) joliet_compare_paths);
671 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
672 joliet_compare_paths);
675 for (j = 1; j < next_jpath_index; j++) {
676 if (jpathlist[j]->jpath_index != j) {
677 jpathlist[j]->jpath_index = j;
683 for (j = 1; j < next_jpath_index; j++) {
687 comerrno(EX_BAD, "Entry %d not in path tables\n", j);
689 fprintf(stderr, "Entry %d not in path tables\n", j);
693 npnt = dpnt->de_name;
695 npnt1 = strrchr(npnt, PATH_SEPARATOR);
703 "Fatal Joliet goof - directory has amnesia\n");
706 "Fatal Joliet goof - directory has amnesia\n");
711 if (USE_MAC_NAME(de))
712 namelen = joliet_strlen(de->hfs_ent->name, hfs_inls);
714 #endif /* APPLE_HYB */
715 namelen = joliet_strlen(de->name, in_nls);
718 jpath_table_l[jpath_table_index] = 1;
719 jpath_table_m[jpath_table_index] = 1;
721 jpath_table_l[jpath_table_index] = namelen;
722 jpath_table_m[jpath_table_index] = namelen;
724 jpath_table_index += 2;
726 set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
727 set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
728 jpath_table_index += 4;
731 if (dpnt->parent != reloc_dir) {
733 set_721(jpath_table_l + jpath_table_index,
734 dpnt->parent->jpath_index);
737 "Unable to generate sane path tables - too many directories (%d)\n",
738 dpnt->parent->jpath_index);
741 set_722(jpath_table_m + jpath_table_index,
742 dpnt->parent->jpath_index);
743 jpindex = 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);
749 jpindex = dpnt->self->parent_rec->filedir->jpath_index;
752 if (jpindex > 0xffff) {
753 static int warned = 0;
758 "Unable to generate sane Joliet path tables - too many directories (%u)\n",
762 * Let it point to the root directory instead.
764 set_721(jpath_table_l + jpath_table_index, 1);
765 set_722(jpath_table_m + jpath_table_index, 1);
768 jpath_table_index += 2;
771 * The root directory is still represented in non-unicode
775 jpath_table_l[jpath_table_index] = 0;
776 jpath_table_m[jpath_table_index] = 0;
780 if (USE_MAC_NAME(de)) {
781 convert_to_unicode((Uchar *) jpath_table_l +
783 namelen, de->hfs_ent->name, hfs_inls);
784 convert_to_unicode((Uchar *) jpath_table_m +
786 namelen, de->hfs_ent->name, hfs_inls);
788 #endif /* APPLE_HYB */
789 convert_to_unicode((Uchar *) jpath_table_l +
791 namelen, de->name, in_nls);
792 convert_to_unicode((Uchar *) jpath_table_m +
794 namelen, de->name, in_nls);
797 #endif /* APPLE_HYB */
799 jpath_table_index += namelen;
802 if (jpath_table_index & 1) {
803 jpath_table_index++; /* For odd lengths we pad */
808 if (jpath_table_index != jpath_table_size) {
811 "Joliet path table lengths do not match %d expected: %d\n",
816 "Joliet path table lengths do not match %d expected: %d\n",
822 }/* generate_path_tables(... */
825 generate_one_joliet_directory(struct directory *dpnt, FILE *outfile)
827 unsigned int dir_index;
828 char *directory_buffer;
830 struct directory_entry *s_entry;
831 struct directory_entry *s_entry1;
832 struct iso_directory_record jrec;
833 unsigned int total_size;
835 struct directory *finddir;
837 total_size = ISO_ROUND_UP(dpnt->jsize);
838 directory_buffer = (char *) e_malloc(total_size);
839 memset(directory_buffer, 0, total_size);
842 s_entry = dpnt->jcontents;
844 if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
845 s_entry = s_entry->jnext;
849 * If this entry was a directory that was relocated,
850 * we have a bit of trouble here. We need to dig out the real
851 * thing and put it back here. In the Joliet tree, there is
852 * no relocated rock ridge, as there are no depth limits to a
855 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
856 for (s_entry1 = reloc_dir->contents; s_entry1;
857 s_entry1 = s_entry1->next) {
858 if (s_entry1->parent_rec == s_entry) {
862 if (s_entry1 == NULL) {
863 /* We got trouble. */
866 "Unable to locate relocated directory\n");
869 "Unable to locate relocated directory\n");
878 * We do not allow directory entries to cross sector
879 * boundaries. Simply pad, and then start the next entry at
882 new_reclen = s_entry1->jreclen;
883 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) {
884 dir_index = ISO_ROUND_UP(dir_index);
886 memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
889 /* Use the HFS name if it exists */
890 if (USE_MAC_NAME(s_entry1))
891 cvt_len = joliet_strlen(s_entry1->hfs_ent->name, hfs_inls);
893 #endif /* APPLE_HYB */
894 cvt_len = joliet_strlen(s_entry1->name, in_nls);
897 * Fix the record length
898 * - this was the non-Joliet version we were seeing.
900 jrec.name_len[0] = cvt_len;
901 jrec.length[0] = s_entry1->jreclen;
904 * If this is a directory,
905 * fix the correct size and extent number.
907 if ((jrec.flags[0] & ISO_DIRECTORY) != 0) {
908 if (strcmp(s_entry1->name, ".") == 0) {
909 jrec.name_len[0] = 1;
910 set_733((char *) jrec.extent, dpnt->jextent);
911 set_733((char *) jrec.size, ISO_ROUND_UP(dpnt->jsize));
912 } else if (strcmp(s_entry1->name, "..") == 0) {
913 jrec.name_len[0] = 1;
914 if (dpnt->parent == reloc_dir) {
915 set_733((char *)jrec.extent, dpnt->self->parent_rec->filedir->jextent);
916 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
918 set_733((char *)jrec.extent, dpnt->parent->jextent);
919 set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
922 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
923 finddir = reloc_dir->subdir;
925 finddir = dpnt->subdir;
928 if (finddir->self == s_entry1)
930 finddir = finddir->next;
933 comerrno(EX_BAD, "Fatal goof - unable to find directory location\n");
935 fprintf(stderr, "Fatal goof - unable to find directory location\n");
940 set_733((char *)jrec.extent, finddir->jextent);
941 set_733((char *)jrec.size,
942 ISO_ROUND_UP(finddir->jsize));
945 memcpy(directory_buffer + dir_index, &jrec,
946 offsetof(struct iso_directory_record, name[0]));
948 dir_index += offsetof(struct iso_directory_record, name[0]);
951 * Finally dump the Unicode version of the filename.
952 * Note - . and .. are the same as with non-Joliet discs.
954 if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
955 strcmp(s_entry1->name, ".") == 0) {
956 directory_buffer[dir_index++] = 0;
957 } else if ((jrec.flags[0] & ISO_DIRECTORY) != 0 &&
958 strcmp(s_entry1->name, "..") == 0) {
959 directory_buffer[dir_index++] = 1;
962 if (USE_MAC_NAME(s_entry1)) {
963 /* Use the HFS name if it exists */
965 (Uchar *) directory_buffer+dir_index,
967 s_entry1->hfs_ent->name, hfs_inls);
969 #endif /* APPLE_HYB */
972 (Uchar *) directory_buffer+dir_index,
974 s_entry1->name, in_nls);
976 dir_index += cvt_len;
980 directory_buffer[dir_index++] = 0;
982 s_entry = s_entry->jnext;
985 if (dpnt->jsize != dir_index) {
988 "Unexpected joliet directory length %d expected: %d '%s'\n",
990 dir_index, dpnt->de_name);
993 "Unexpected joliet directory length %d expected: %d '%s'\n",
995 dir_index, dpnt->de_name);
998 jtwrite(directory_buffer, total_size, 1, 0, FALSE);
999 xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
1000 last_extent_written += total_size >> 11;
1001 free(directory_buffer);
1002 }/* generate_one_joliet_directory(... */
1005 joliet_sort_n_finish(struct directory *this_dir)
1007 struct directory_entry *s_entry;
1011 * don't want to skip this directory if it's the reloc_dir
1014 if (this_dir != reloc_dir &&
1015 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1018 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
1019 /* skip hidden entries */
1020 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1024 * First update the path table sizes for directories.
1026 * Finally, set the length of the directory entry if Joliet is
1027 * used. The name is longer, but no Rock Ridge is ever used
1028 * here, so depending upon the options the entry size might
1029 * turn out to be about the same. The Unicode name is always
1030 * a multiple of 2 bytes, so we always add 1 to make it an
1033 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1034 if (strcmp(s_entry->name, ".") != 0 &&
1035 strcmp(s_entry->name, "..") != 0) {
1037 if (USE_MAC_NAME(s_entry))
1038 /* Use the HFS name if it exists */
1040 joliet_strlen(s_entry->hfs_ent->name, hfs_inls) +
1041 offsetof(struct iso_path_table, name[0]);
1043 #endif /* APPLE_HYB */
1045 joliet_strlen(s_entry->name, in_nls) +
1046 offsetof(struct iso_path_table, name[0]);
1047 if (jpath_table_size & 1) {
1051 if (this_dir == root &&
1052 strlen(s_entry->name) == 1) {
1054 jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
1055 if (jpath_table_size & 1)
1060 if (strcmp(s_entry->name, ".") != 0 &&
1061 strcmp(s_entry->name, "..") != 0) {
1063 if (USE_MAC_NAME(s_entry))
1064 /* Use the HFS name if it exists */
1066 offsetof(struct iso_directory_record, name[0])
1067 + joliet_strlen(s_entry->hfs_ent->name, hfs_inls)
1070 #endif /* APPLE_HYB */
1072 offsetof(struct iso_directory_record, name[0])
1073 + joliet_strlen(s_entry->name, in_nls)
1077 * Special - for '.' and '..' we generate the same
1078 * records we did for non-Joliet discs.
1081 offsetof(struct iso_directory_record, name[0])
1088 if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1091 this_dir->jcontents = this_dir->contents;
1092 status = joliet_sort_directory(&this_dir->jcontents);
1095 * Now go through the directory and figure out how large this one will
1096 * be. Do not split a directory entry across a sector boundary
1098 s_entry = this_dir->jcontents;
1100 * XXX Is it ok to comment this out?
1102 /*XXX JS this_dir->ce_bytes = 0;*/
1103 for (s_entry = this_dir->jcontents; s_entry;
1104 s_entry = s_entry->jnext) {
1107 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1110 jreclen = s_entry->jreclen;
1112 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
1114 this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
1116 this_dir->jsize += jreclen;
1122 * Similar to the iso9660 case,
1123 * except here we perform a full sort based upon the
1124 * regular name of the file, not the 8.3 version.
1127 joliet_compare_dirs(const void *rr, const void *ll)
1131 struct directory_entry **r,
1133 unsigned char rtmp[2],
1135 struct unls_table *linls, *rinls;
1137 r = (struct directory_entry **) rr;
1138 l = (struct directory_entry **) ll;
1142 * we may be using the HFS name - so select the correct input
1145 if (USE_MAC_NAME(*r)) {
1146 rpnt = (*r)->hfs_ent->name;
1153 if (USE_MAC_NAME(*l)) {
1154 lpnt = (*l)->hfs_ent->name;
1163 rinls = linls = in_nls;
1164 #endif /* APPLE_HYB */
1167 * If the entries are the same, this is an error.
1168 * Joliet specs allow for a maximum of 64 characters.
1169 * If we see different multi extent parts, it is OK to
1170 * have the same name more than once.
1172 if (strncmp(rpnt, lpnt, jlen) == 0) {
1173 #ifdef USE_LARGEFILES
1174 if ((*r)->mxpart == (*l)->mxpart)
1177 #ifdef USE_LIBSCHILY
1179 "Error: %s and %s have the same Joliet name\n",
1180 (*r)->whole_name, (*l)->whole_name);
1183 "Error: %s and %s have the same Joliet name\n",
1184 (*r)->whole_name, (*l)->whole_name);
1190 * Put the '.' and '..' entries on the head of the sorted list.
1191 * For normal ASCII, this always happens to be the case, but out of
1192 * band characters cause this not to be the case sometimes.
1194 if (strcmp(rpnt, ".") == 0)
1196 if (strcmp(lpnt, ".") == 0)
1199 if (strcmp(rpnt, "..") == 0)
1201 if (strcmp(lpnt, "..") == 0)
1206 * There're rumors claiming that some players assume VIDEO_TS.IFO
1207 * to be the first file in VIDEO_TS/ catalog. Well, it's basically
1208 * the only file a player has to actually look for, as the whole
1209 * video content can be "rolled down" from this file alone.
1210 * <appro@fy.chalmers.se>
1213 * XXX This code has to be moved from the Joliet implementation
1214 * XXX to the UDF implementation if we implement decent UDF support
1215 * XXX with a separate name space for the UDF file tree.
1218 if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
1220 if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
1225 while (*rpnt && *lpnt) {
1229 if (*rpnt == ';' && *lpnt != ';')
1231 if (*rpnt != ';' && *lpnt == ';')
1234 if (*rpnt == ';' && *lpnt == ';')
1238 * Extensions are not special here.
1239 * Don't treat the dot as something that must be bumped to
1240 * the start of the list.
1243 if (*rpnt == '.' && *lpnt != '.')
1245 if (*rpnt != '.' && *lpnt == '.')
1251 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
1252 li = convert_to_unicode(ltmp, 2, lpnt, linls);
1262 convert_to_unicode(rtmp, 2, rpnt, rinls);
1263 convert_to_unicode(ltmp, 2, lpnt, linls);
1266 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
1268 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
1280 #ifdef USE_LARGEFILES
1282 * (*r)->mxpart == (*l)->mxpart cannot happen here
1284 if ((*r)->mxpart < (*l)->mxpart)
1286 else if ((*r)->mxpart > (*l)->mxpart)
1294 * Function: sort_directory
1296 * Purpose: Sort the directory in the appropriate ISO9660
1299 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
1302 joliet_sort_directory(struct directory_entry **sort_dir)
1306 struct directory_entry *s_entry;
1307 struct directory_entry **sortlist;
1309 s_entry = *sort_dir;
1312 * only colletc non-hidden entries
1314 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1315 (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
1317 s_entry = s_entry->next;
1320 /* OK, now we know how many there are. Build a vector for sorting. */
1321 sortlist = (struct directory_entry **)
1322 e_malloc(sizeof (struct directory_entry *) * dcount);
1325 s_entry = *sort_dir;
1328 * only collect non-hidden entries
1330 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1331 (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
1332 sortlist[dcount] = s_entry;
1335 s_entry = s_entry->next;
1340 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1341 (int (*) (const void *, const void *)) joliet_compare_dirs);
1343 qsort(sortlist, dcount, sizeof (struct directory_entry *),
1344 joliet_compare_dirs);
1347 /* Now reassemble the linked list in the proper sorted order */
1348 for (i = 0; i < dcount - 1; i++) {
1349 sortlist[i]->jnext = sortlist[i + 1];
1352 sortlist[dcount - 1]->jnext = NULL;
1353 *sort_dir = sortlist[0];
1356 return (jsort_goof);
1360 joliet_sort_tree(struct directory *node)
1362 struct directory *dpnt;
1368 ret = joliet_sort_n_finish(dpnt);
1373 ret = joliet_sort_tree(dpnt->subdir);
1383 generate_joliet_directories(struct directory *node, FILE *outfile)
1385 struct directory *dpnt;
1390 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
1392 * In theory we should never reuse a directory, so this
1393 * doesn't make much sense.
1395 if (dpnt->jextent > session_start) {
1396 generate_one_joliet_directory(dpnt, outfile);
1399 /* skip if hidden - but not for the rr_moved dir */
1401 (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
1402 dpnt == reloc_dir)) {
1403 generate_joliet_directories(dpnt->subdir, outfile);
1411 * Function to write the EVD for the disc.
1414 jpathtab_write(FILE *outfile)
1416 /* Next we write the path tables */
1417 jtwrite(jpath_table_l, jpath_blocks << 11, 1, 0, FALSE);
1418 xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
1419 last_extent_written += jpath_blocks;
1420 jtwrite(jpath_table_m, jpath_blocks << 11, 1, 0, FALSE);
1421 xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
1422 last_extent_written += jpath_blocks;
1423 free(jpath_table_l);
1424 free(jpath_table_m);
1425 jpath_table_l = NULL;
1426 jpath_table_m = NULL;
1431 jdirtree_size(int starting_extent)
1433 assign_joliet_directory_addresses(root);
1440 jroot_record.length[0] =
1441 1 + offsetof(struct iso_directory_record, name[0]);
1442 jroot_record.ext_attr_length[0] = 0;
1443 set_733((char *) jroot_record.extent, root->jextent);
1444 set_733((char *) jroot_record.size, ISO_ROUND_UP(root->jsize));
1445 iso9660_date(jroot_record.date, root_statbuf.st_mtime);
1446 jroot_record.flags[0] = ISO_DIRECTORY;
1447 jroot_record.file_unit_size[0] = 0;
1448 jroot_record.interleave[0] = 0;
1449 set_723(jroot_record.volume_sequence_number, volume_sequence_number);
1450 jroot_record.name_len[0] = 1;
1455 jdirtree_write(FILE *outfile)
1457 generate_joliet_directories(root, outfile);
1462 * Function to write the EVD for the disc.
1465 jvd_write(FILE *outfile)
1467 struct iso_primary_descriptor jvol_desc;
1469 /* Next we write out the boot volume descriptor for the disc */
1470 jvol_desc = vol_desc;
1471 get_joliet_vol_desc(&jvol_desc);
1472 jtwrite(&jvol_desc, SECTOR_SIZE, 1, 0, FALSE);
1473 xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
1474 last_extent_written++;
1479 * Functions to describe padding block at the start of the disc.
1482 jpathtab_size(int starting_extent)
1484 jpath_table[0] = starting_extent;
1486 jpath_table[2] = jpath_table[0] + jpath_blocks;
1489 last_extent += 2 * jpath_blocks;
1493 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen, jvd_write, "Joliet Volume Descriptor" };
1494 struct output_fragment jpathtable_desc = {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write, "Joliet path table" };
1495 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write, "Joliet directory tree" };