patch: make *outfile extern
[platform/upstream/cdrkit.git] / genisoimage / joliet.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)joliet.c 1.38 05/05/01 joerg */
14 /* Parts from  @(#)joliet.c>1.54 07/10/20 joerg */
15 /*
16  * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
17  *
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
21  *
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)
25  * any later version.
26  *
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.
31  *
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.
35  */
36
37 /*
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.
43  *
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.
46  *
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.
50  *
51  * The SVD is identical to the PVD, except:
52  *
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
56  *              size).
57  *      There are different path tables for the two sets of directory trees.
58  *
59  * The Unicode level is coded in the SVD as follows:
60  *
61  *      Standard        Level   ASCII escape code
62  *      UCS-2           Level-1 %/@
63  *      UCS-2           Level-2 %/C
64  *      UCS-2           Level-3 %/E
65  *
66  * The following fields are recorded in Unicode:
67  *      system_id
68  *      volume_id
69  *      volume_set_id
70  *      publisher_id
71  *      preparer_id
72  *      application_id
73  *      copyright_file_id
74  *      abstract_file_id
75  *      bibliographic_file_id
76  *
77  * Unicode strings are always encoded in big-endian format.
78  *
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.
82  *
83  * The character set used for the names is different with UCS - the
84  * restrictions are that the following are not allowed:
85  *
86  *      Characters (00)(00) through (00)(1f) (control chars)
87  *      (00)(2a) '*'
88  *      (00)(2f) '/'
89  *      (00)(3a) ':'
90  *      (00)(3b) ';'
91  *      (00)(3f) '?'
92  *      (00)(5c) '\'
93  */
94 #include <mconfig.h>
95 #include "genisoimage.h"
96 #include <timedefs.h>
97 #include <utypes.h>
98 #include <intcvt.h>
99 #include <unls.h>       /* For UNICODE translation */
100 #include <schily.h>
101 #include <string.h>
102
103 #ifdef USE_ICONV
104 #include <iconv.h>
105 #include <errno.h>
106 #endif
107
108 static Uint     jpath_table_index;
109 static struct directory **jpathlist;
110 static int      next_jpath_index = 1;
111 static int      jsort_goof;
112
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                  */
118 };
119
120 #ifdef  UDF
121 #ifdef USE_ICONV
122 size_t
123 #else
124 void
125 #endif
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);
129 #else
130 #ifdef USE_ICONV
131 static size_t
132 #else
133 static void
134 #endif
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);
138 #endif
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, 
145                                                                                                                 FILE *outfile);
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);
157
158 /*
159  *      conv_charset: convert to/from charsets via Unicode.
160  *
161  *      Any unknown character is set to '_'
162  *
163  */
164 unsigned char
165 conv_charset(unsigned char c,
166         struct unls_table *inls,
167         struct unls_table *onls)
168 {
169         unsigned char   uh;
170         unsigned char   ul;
171         unsigned char   uc;
172         unsigned char   *up;
173
174         /* if we have a null mapping, just return the input character */
175         if (inls == onls)
176                 return (c);
177
178 #ifdef USE_ICONV
179         if(inls->unls_cs2uni == NULL || onls->unls_uni2cs == NULL) {
180                 /*
181                  * This shouldn't be reached
182                  */
183                 static BOOL iconv_warned = FALSE;
184                 if(!iconv_warned) {
185                         fprintf(stderr, "Warning: Iconv conversion not supported in conv_charset.\n");
186                         iconv_warned = TRUE;
187                 }
188                 return (c);
189         }
190 #endif
191
192         /* get high and low UNICODE bytes */
193         uh = inls->unls_cs2uni[c].unls_high;
194         ul = inls->unls_cs2uni[c].unls_low;
195
196         /* get the backconverted page from the output charset */
197         up = onls->unls_uni2cs[uh];
198
199         /* if the page exists, get the backconverted character */
200         if (up == NULL)
201                 uc = '\0';
202         else
203                 uc = up[ul];
204
205         /* return the backconverted, if it's not NULL */
206         return (uc ? uc : '_');
207 }
208
209 /*
210  * Function:            convert_to_unicode
211  *
212  * Purpose:             Perform a unicode conversion on a text string
213  *                      using the supplied input character set.
214  *
215  * Notes:
216  */
217 #ifdef USE_ICONV
218 #       if      UDF
219 size_t
220 #       else
221 static size_t
222 #       endif
223 #else
224 #       if      UDF
225 void
226 #       else
227 static void
228 #       endif
229 #endif
230 convert_to_unicode(unsigned char *buffer, int size, char *source, 
231                                                  struct unls_table *inls)
232 {
233         unsigned char   *tmpbuf;
234         int             i;
235         int             j;
236         unsigned char   uh,
237                         ul,
238                         uc,
239                         *up;
240
241         /*
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.
244          */
245         if (source == NULL) {
246                 tmpbuf = (Uchar *) e_malloc(size+1);
247                 memcpy(tmpbuf, buffer, size);
248                 tmpbuf[size] = 0;
249         } else {
250                 tmpbuf = (Uchar *) source;
251         }
252
253 #ifdef USE_ICONV
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;
261
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);
268                         exit(1);
269                 }
270
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 */
274                                         case '*':
275                                         case '/':
276                                         case ':':
277                                         case ';':
278                                         case '?':
279                                         case '\\':
280                                                 buffer[i+1]='_';
281                                         default:
282                                                 if (buffer[i+1] == 0x7f ||
283                                                             buffer[i+1] < 0x20)
284                                                         buffer[i+1]='_';
285                                 }
286                         }
287                 }
288                 if (size & 1) { /* beautification */
289                         buffer[size - 1] = 0;
290                 }
291                 if (source == NULL) {
292                         free(tmpbuf);
293                 }
294                 return (inlen - inleft);
295         }
296 #endif
297
298         /*
299          * Now start copying characters.  If the size was specified to be 0,
300          * then assume the input was 0 terminated.
301          */
302         j = 0;
303         for (i = 0; (i + 1) < size; i += 2, j++) {      /* Size may be odd! */
304                 /*
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 '_' .
309                  */
310                 uc = tmpbuf[j];                 /* temporary copy */
311                 if (uc != '\0') {               /* must be converted */
312                         uh = inls->unls_cs2uni[uc].unls_high;   /* convert forward:  */
313                                                                 /*   hibyte...  */
314                         ul = inls->unls_cs2uni[uc].unls_low;    /* ...lobyte    */
315                         up = inls->unls_uni2cs[uh];             /* convert backward: */
316                                                                 /*   page...    */
317                         if (up == NULL)
318                                 uc = '\0';      /* wrong unicode page      */
319                         else
320                                 uc = up[ul];    /* backconverted character */
321                         if (uc != tmpbuf[j])
322                                 uc = '\0';      /* should be identical */
323                         if (uc <= 0x1f || uc == 0x7f)
324                                 uc = '\0';      /* control char */
325                         switch (uc) {           /* test special characters */
326
327                         case '*':
328                         case '/':
329                         case ':':
330                         case ';':
331                         case '?':
332                         case '\\':
333                         case '\0':              /* illegal char mark */
334                                 /*
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.
338                                  */
339                                 uc = '_';
340                         }
341                 }
342                 buffer[i] = inls->unls_cs2uni[uc].unls_high; /* final UNICODE */
343                                                             /* conversion */
344                 buffer[i + 1] = inls->unls_cs2uni[uc].unls_low;
345         }
346
347         if (size & 1) { /* beautification */
348                 buffer[size - 1] = 0;
349         }
350         if (source == NULL) {
351                 free(tmpbuf);
352         }
353 #ifdef USE_ICONV
354         return j;
355 #endif
356 }
357
358 /*
359  * Function:    joliet_strlen
360  *
361  * Purpose:     Return length in bytes of string after conversion to unicode.
362  *
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.
366  */
367 #ifdef  UDF
368 int
369 #else
370 static int
371 #endif
372 joliet_strlen(const char *string, struct unls_table *inls)
373 {
374         int             rtn;
375
376 #ifdef USE_ICONV
377         if (inls->iconv_d && inls->unls_cs2uni==NULL &&
378                         inls->unls_uni2cs==NULL) {
379                 /*
380                  * we const-cast since we're sure iconv won't change
381                  * the string itself
382                  */
383                 char *string_ptr = (char *)string;
384                 size_t string_len = strlen(string);
385
386                 /*
387                  * iconv has no way of finding out the required size
388                  * in the target
389                  */
390
391                 char *tmp, *tmp_ptr;
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);
395                 tmp_ptr = tmp;
396
397                 iconv(inls->iconv_d, NULL, NULL, NULL, NULL);
398                 iconv(inls->iconv_d, &string_ptr, &string_len, &tmp_ptr,
399                         &tmp_len);
400
401                 /*
402                  * iconv advanced the tmp pointer with as many chars
403                  * as it has written to it, so we add up the delta
404                  */
405                 rtn = (tmp_ptr - tmp);
406
407                 free(tmp);
408         } else {
409                 rtn = strlen(string) << 1;
410         }
411 #else
412         rtn = strlen(string) << 1;
413 #endif
414
415         /*
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.
420          */
421         if (rtn > 2*jlen) {
422                 rtn = 2*jlen;
423         }
424         return (rtn);
425 }
426
427 /*
428  * Function:            get_joliet_vol_desc
429  *
430  * Purpose:             generate a Joliet compatible volume desc.
431  *
432  * Notes:               Assume that we have the non-joliet vol desc
433  *                      already present in the buffer.  Just modifiy the
434  *                      appropriate fields.
435  */
436 static void
437 get_joliet_vol_desc(struct iso_primary_descriptor *jvol_desc)
438 {
439         jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
440         jvol_desc->version[0] = 1;
441         jvol_desc->file_structure_version[0] = 1;
442
443         /*
444          * For now, always do Unicode level 3.
445          * I don't really know what 1 and 2 are - perhaps a more limited
446          * Unicode set.
447          * FIXME(eric) - how does Romeo fit in here?
448          */
449         sprintf(jvol_desc->escape_sequences, "%%/%c", ucs_codes[ucs_level]);
450
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]);
457
458         /* Set this one up. */
459         memcpy(jvol_desc->root_directory_record, &jroot_record,
460                 offsetof(struct iso_directory_record, name[0]) + 1);
461
462         /*
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.
467          */
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);
486 }
487
488 static void
489 assign_joliet_directory_addresses(struct directory *node)
490 {
491         int             dir_size;
492         struct directory *dpnt;
493
494         dpnt = node;
495
496         while (dpnt) {
497                 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
498                         /*
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.
502                          */
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;
508                         }
509                 }
510                 /* skip if hidden - but not for the rr_moved dir */
511                 if (dpnt->subdir &&
512                     ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
513                     dpnt == reloc_dir)) {
514                         assign_joliet_directory_addresses(dpnt->subdir);
515                 }
516                 dpnt = dpnt->next;
517         }
518 }
519
520 static void
521 build_jpathlist(struct directory *node)
522 {
523         struct directory        *dpnt;
524
525         dpnt = node;
526
527         while (dpnt) {
528                 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
529                         jpathlist[dpnt->jpath_index] = dpnt;
530                 }
531                 if (dpnt->subdir)
532                         build_jpathlist(dpnt->subdir);
533                 dpnt = dpnt->next;
534         }
535 }/* build_jpathlist(... */
536
537 static int
538 joliet_compare_paths(void const *r, void const *l)
539 {
540         struct directory const *ll = *(struct directory * const *) l;
541         struct directory const *rr = *(struct directory * const *) r;
542         int             rparent,
543                         lparent;
544         char            *rpnt,
545                         *lpnt;
546         unsigned char   rtmp[2],
547                         ltmp[2];
548         struct unls_table *rinls, *linls;
549
550         /* make sure root directory is first */
551         if (rr == root)
552                 return (-1);
553
554         if (ll == root)
555                 return (1);
556
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;
561         }
562         if (ll->parent == reloc_dir) {
563                 lparent = ll->self->parent_rec->filedir->jpath_index;
564         }
565         if (rparent < lparent) {
566                 return (-1);
567         }
568         if (rparent > lparent) {
569                 return (1);
570         }
571 #ifdef APPLE_HYB
572         /*
573          * we may be using the HFS name - so select the correct input
574          * charset
575          */
576         if (USE_MAC_NAME(rr->self)) {
577                 rpnt = rr->self->hfs_ent->name;
578                 rinls = hfs_inls;
579         } else {
580                 rpnt = rr->self->name;
581                 rinls = in_nls;
582         }
583
584         if (USE_MAC_NAME(ll->self)) {
585                 lpnt = ll->self->hfs_ent->name;
586                 linls = hfs_inls;
587         } else {
588                 lpnt = ll->self->name;
589                 linls = in_nls;
590         }
591 #else
592         rpnt = rr->self->name;
593         lpnt = ll->self->name;
594         linls = rinls = in_nls;
595 #endif  /* APPLE_HYB */
596
597         /* compare the Unicode names */
598
599         while (*rpnt && *lpnt) {
600 #ifdef USE_ICONV
601                 size_t ri, li;
602
603                 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
604                 li = convert_to_unicode(ltmp, 2, lpnt, linls);
605                 rpnt += ri;
606                 lpnt += li;
607                 if(!ri && !li)
608                         return (0);
609                 else if(ri && !li)
610                         return (1);
611                 else if(!ri && li)
612                         return (-1);
613 #else
614                 convert_to_unicode(rtmp, 2, rpnt, rinls);
615                 convert_to_unicode(ltmp, 2, lpnt, linls);
616 #endif
617
618                 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
619                         return (-1);
620                 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
621                         return (1);
622
623 #ifndef USE_ICONV
624                 rpnt++;
625                 lpnt++;
626 #endif
627         }
628
629         if (*rpnt)
630                 return (1);
631         if (*lpnt)
632                 return (-1);
633
634         return (0);
635
636 }/* compare_paths(... */
637
638 static int
639 generate_joliet_path_tables()
640 {
641         struct directory_entry *de;
642         struct directory *dpnt;
643         int             fix;
644         int             j;
645         int             namelen;
646         char            *npnt;
647         char            *npnt1;
648         int             tablesize;
649         unsigned int    jpindex;
650
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);
657
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 *)
661                 * next_jpath_index);
662         memset(jpathlist, 0, sizeof (struct directory *) * next_jpath_index);
663         build_jpathlist(root);
664
665         do {
666                 fix = 0;
667 #ifdef  PROTOTYPES
668                 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
669                         (int (*) (const void *, const void *)) joliet_compare_paths);
670 #else
671                 qsort(&jpathlist[1], next_jpath_index - 1, sizeof (struct directory *),
672                         joliet_compare_paths);
673 #endif
674
675                 for (j = 1; j < next_jpath_index; j++) {
676                         if (jpathlist[j]->jpath_index != j) {
677                                 jpathlist[j]->jpath_index = j;
678                                 fix++;
679                         }
680                 }
681         } while (fix);
682
683         for (j = 1; j < next_jpath_index; j++) {
684                 dpnt = jpathlist[j];
685                 if (!dpnt) {
686 #ifdef  USE_LIBSCHILY
687                         comerrno(EX_BAD, "Entry %d not in path tables\n", j);
688 #else
689                         fprintf(stderr, "Entry %d not in path tables\n", j);
690                         exit(1);
691 #endif
692                 }
693                 npnt = dpnt->de_name;
694
695                 npnt1 = strrchr(npnt, PATH_SEPARATOR);
696                 if (npnt1) {
697                         npnt = npnt1 + 1;
698                 }
699                 de = dpnt->self;
700                 if (!de) {
701 #ifdef  USE_LIBSCHILY
702                         comerrno(EX_BAD,
703                         "Fatal Joliet goof - directory has amnesia\n");
704 #else
705                         fprintf(stderr,
706                         "Fatal Joliet goof - directory has amnesia\n");
707                         exit(1);
708 #endif
709                 }
710 #ifdef APPLE_HYB
711                 if (USE_MAC_NAME(de))
712                         namelen = joliet_strlen(de->hfs_ent->name, hfs_inls);
713                 else
714 #endif  /* APPLE_HYB */
715                         namelen = joliet_strlen(de->name, in_nls);
716
717                 if (dpnt == root) {
718                         jpath_table_l[jpath_table_index] = 1;
719                         jpath_table_m[jpath_table_index] = 1;
720                 } else {
721                         jpath_table_l[jpath_table_index] = namelen;
722                         jpath_table_m[jpath_table_index] = namelen;
723                 }
724                 jpath_table_index += 2;
725
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;
729
730
731                 if (dpnt->parent != reloc_dir) {
732 #ifdef  USE_LIBSCHILY
733                         set_721(jpath_table_l + jpath_table_index,
734                                 dpnt->parent->jpath_index);
735 #else
736                         fprintf(stderr,
737                         "Unable to generate sane path tables - too many directories (%d)\n",
738                                 dpnt->parent->jpath_index);
739                         exit(1);
740 #endif
741                         set_722(jpath_table_m + jpath_table_index,
742                                 dpnt->parent->jpath_index);
743                         jpindex = dpnt->parent->jpath_index;
744                 } else {
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;
750                 }
751
752                 if (jpindex > 0xffff) {
753                         static int warned = 0;
754
755                         if (!warned) {
756                                 warned++;
757                                 errmsgno(EX_BAD,
758                         "Unable to generate sane Joliet path tables - too many directories (%u)\n",
759                                         jpindex);
760                         }
761                         /*
762                          * Let it point to the root directory instead.
763                          */
764                         set_721(jpath_table_l + jpath_table_index, 1);
765                         set_722(jpath_table_m + jpath_table_index, 1);
766                 }
767
768                 jpath_table_index += 2;
769
770                 /*
771                  * The root directory is still represented in non-unicode
772                  * fashion.
773                  */
774                 if (dpnt == root) {
775                         jpath_table_l[jpath_table_index] = 0;
776                         jpath_table_m[jpath_table_index] = 0;
777                         jpath_table_index++;
778                 } else {
779 #ifdef APPLE_HYB
780                         if (USE_MAC_NAME(de)) {
781                                 convert_to_unicode((Uchar *) jpath_table_l +
782                                         jpath_table_index,
783                                         namelen, de->hfs_ent->name, hfs_inls);
784                                 convert_to_unicode((Uchar *) jpath_table_m +
785                                         jpath_table_index,
786                                         namelen, de->hfs_ent->name, hfs_inls);
787                         } else {
788 #endif  /* APPLE_HYB */
789                                 convert_to_unicode((Uchar *) jpath_table_l +
790                                         jpath_table_index,
791                                         namelen, de->name, in_nls);
792                                 convert_to_unicode((Uchar *) jpath_table_m +
793                                         jpath_table_index,
794                                         namelen, de->name, in_nls);
795 #ifdef APPLE_HYB
796                         }
797 #endif  /* APPLE_HYB */
798
799                         jpath_table_index += namelen;
800                 }
801
802                 if (jpath_table_index & 1) {
803                         jpath_table_index++;    /* For odd lengths we pad */
804                 }
805         }
806
807         free(jpathlist);
808         if (jpath_table_index != jpath_table_size) {
809 #ifdef  USE_LIBSCHILY
810                 errmsgno(EX_BAD,
811                 "Joliet path table lengths do not match %d expected: %d\n",
812                         jpath_table_index,
813                         jpath_table_size);
814 #else
815                 fprintf(stderr,
816                 "Joliet path table lengths do not match %d expected: %d\n",
817                         jpath_table_index,
818                         jpath_table_size);
819 #endif
820         }
821         return (0);
822 }/* generate_path_tables(... */
823
824 static void
825 generate_one_joliet_directory(struct directory *dpnt, FILE *outfile)
826 {
827         unsigned int            dir_index;
828         char                    *directory_buffer;
829         int                     new_reclen;
830         struct directory_entry *s_entry;
831         struct directory_entry *s_entry1;
832         struct iso_directory_record jrec;
833         unsigned int    total_size;
834         int                     cvt_len;
835         struct directory        *finddir;
836
837         total_size = ISO_ROUND_UP(dpnt->jsize);
838         directory_buffer = (char *) e_malloc(total_size);
839         memset(directory_buffer, 0, total_size);
840         dir_index = 0;
841
842         s_entry = dpnt->jcontents;
843         while (s_entry) {
844                 if (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
845                         s_entry = s_entry->jnext;
846                         continue;
847                 }
848                 /*
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
853                  * directory tree.
854                  */
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) {
859                                         break;
860                                 }
861                         }
862                         if (s_entry1 == NULL) {
863                                 /* We got trouble. */
864 #ifdef  USE_LIBSCHILY
865                                 comerrno(EX_BAD,
866                                 "Unable to locate relocated directory\n");
867 #else
868                                 fprintf(stderr,
869                                 "Unable to locate relocated directory\n");
870                                 exit(1);
871 #endif
872                         }
873                 } else {
874                         s_entry1 = s_entry;
875                 }
876
877                 /*
878                  * We do not allow directory entries to cross sector
879                  * boundaries. Simply pad, and then start the next entry at
880                  * the next sector
881                  */
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);
885                 }
886                 memcpy(&jrec, &s_entry1->isorec, offsetof(struct iso_directory_record, name[0]));
887
888 #ifdef APPLE_HYB
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);
892                 else
893 #endif  /* APPLE_HYB */
894                         cvt_len = joliet_strlen(s_entry1->name, in_nls);
895
896                 /*
897                  * Fix the record length
898                  * - this was the non-Joliet version we were seeing.
899                  */
900                 jrec.name_len[0] = cvt_len;
901                 jrec.length[0] = s_entry1->jreclen;
902
903                 /*
904                  * If this is a directory,
905                  * fix the correct size and extent number.
906                  */
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));
917                                 } else {
918                                         set_733((char *)jrec.extent, dpnt->parent->jextent);
919                                         set_733((char *)jrec.size, ISO_ROUND_UP(dpnt->parent->jsize));
920                                 }
921                         } else {
922                                 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
923                                         finddir = reloc_dir->subdir;
924                                 } else {
925                                         finddir = dpnt->subdir;
926                                 }
927                                 while (1 == 1) {
928                                         if (finddir->self == s_entry1)
929                                                 break;
930                                         finddir = finddir->next;
931                                         if (!finddir) {
932 #ifdef  USE_LIBSCHILY
933                                                 comerrno(EX_BAD, "Fatal goof - unable to find directory location\n");
934 #else
935                                                 fprintf(stderr, "Fatal goof - unable to find directory location\n");
936                                                 exit(1);
937 #endif
938                                         }
939                                 }
940                                 set_733((char *)jrec.extent, finddir->jextent);
941                                 set_733((char *)jrec.size,
942                                                 ISO_ROUND_UP(finddir->jsize));
943                         }
944                 }
945                 memcpy(directory_buffer + dir_index, &jrec,
946                         offsetof(struct iso_directory_record, name[0]));
947
948                 dir_index += offsetof(struct iso_directory_record, name[0]);
949
950                 /*
951                  * Finally dump the Unicode version of the filename.
952                  * Note - . and .. are the same as with non-Joliet discs.
953                  */
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;
960                 } else {
961 #ifdef APPLE_HYB
962                         if (USE_MAC_NAME(s_entry1)) {
963                                 /* Use the HFS name if it exists */
964                                 convert_to_unicode(
965                                         (Uchar *) directory_buffer+dir_index,
966                                         cvt_len,
967                                         s_entry1->hfs_ent->name, hfs_inls);
968                         } else
969 #endif  /* APPLE_HYB */
970                         {
971                                 convert_to_unicode(
972                                         (Uchar *) directory_buffer+dir_index,
973                                         cvt_len,
974                                         s_entry1->name, in_nls);
975                         }
976                         dir_index += cvt_len;
977                 }
978
979                 if (dir_index & 1) {
980                         directory_buffer[dir_index++] = 0;
981                 }
982                 s_entry = s_entry->jnext;
983         }
984
985         if (dpnt->jsize != dir_index) {
986 #ifdef  USE_LIBSCHILY
987                 errmsgno(EX_BAD,
988                 "Unexpected joliet directory length %d expected: %d '%s'\n",
989                         dpnt->jsize,
990                         dir_index, dpnt->de_name);
991 #else
992                 fprintf(stderr,
993                 "Unexpected joliet directory length %d expected: %d '%s'\n",
994                         dpnt->jsize,
995                         dir_index, dpnt->de_name);
996 #endif
997         }
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(... */
1003
1004 static int
1005 joliet_sort_n_finish(struct directory *this_dir)
1006 {
1007         struct directory_entry  *s_entry;
1008         int                     status = 0;
1009
1010         /*
1011          * don't want to skip this directory if it's the reloc_dir
1012          * at the moment
1013          */
1014         if (this_dir != reloc_dir &&
1015                                 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1016                 return (0);
1017         }
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) {
1021                         continue;
1022                 }
1023                 /*
1024                  * First update the path table sizes for directories.
1025                  *
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
1031                  * even number.
1032                  */
1033                 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1034                         if (strcmp(s_entry->name, ".") != 0 &&
1035                                         strcmp(s_entry->name, "..") != 0) {
1036 #ifdef APPLE_HYB
1037                                 if (USE_MAC_NAME(s_entry))
1038                                         /* Use the HFS name if it exists */
1039                                         jpath_table_size +=
1040                                                 joliet_strlen(s_entry->hfs_ent->name, hfs_inls) +
1041                                                 offsetof(struct iso_path_table, name[0]);
1042                                 else
1043 #endif  /* APPLE_HYB */
1044                                         jpath_table_size +=
1045                                                 joliet_strlen(s_entry->name, in_nls) +
1046                                                 offsetof(struct iso_path_table, name[0]);
1047                                 if (jpath_table_size & 1) {
1048                                         jpath_table_size++;
1049                                 }
1050                         } else {
1051                                 if (this_dir == root &&
1052                                                 strlen(s_entry->name) == 1) {
1053
1054                                         jpath_table_size += 1 + offsetof(struct iso_path_table, name[0]);
1055                                         if (jpath_table_size & 1)
1056                                                 jpath_table_size++;
1057                                 }
1058                         }
1059                 }
1060                 if (strcmp(s_entry->name, ".") != 0 &&
1061                                         strcmp(s_entry->name, "..") != 0) {
1062 #ifdef APPLE_HYB
1063                         if (USE_MAC_NAME(s_entry))
1064                                 /* Use the HFS name if it exists */
1065                                 s_entry->jreclen =
1066                                 offsetof(struct iso_directory_record, name[0])
1067                                         + joliet_strlen(s_entry->hfs_ent->name, hfs_inls)
1068                                         + 1;
1069                         else
1070 #endif  /* APPLE_HYB */
1071                                 s_entry->jreclen =
1072                                 offsetof(struct iso_directory_record, name[0])
1073                                         + joliet_strlen(s_entry->name, in_nls)
1074                                         + 1;
1075                 } else {
1076                         /*
1077                          * Special - for '.' and '..' we generate the same
1078                          * records we did for non-Joliet discs.
1079                          */
1080                         s_entry->jreclen =
1081                         offsetof(struct iso_directory_record, name[0])
1082                                 + 1;
1083                 }
1084
1085
1086         }
1087
1088         if ((this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1089                 return (0);
1090         }
1091         this_dir->jcontents = this_dir->contents;
1092         status = joliet_sort_directory(&this_dir->jcontents);
1093
1094         /*
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
1097          */
1098         s_entry = this_dir->jcontents;
1099         /*
1100          * XXX Is it ok to comment this out?
1101          */
1102 /*XXX JS  this_dir->ce_bytes = 0;*/
1103         for (s_entry = this_dir->jcontents; s_entry;
1104                                                 s_entry = s_entry->jnext) {
1105                 int     jreclen;
1106
1107                 if ((s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0) {
1108                         continue;
1109                 }
1110                 jreclen = s_entry->jreclen;
1111
1112                 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >=
1113                                                                 SECTOR_SIZE) {
1114                         this_dir->jsize = ISO_ROUND_UP(this_dir->jsize);
1115                 }
1116                 this_dir->jsize += jreclen;
1117         }
1118         return (status);
1119 }
1120
1121 /*
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.
1125  */
1126 static int
1127 joliet_compare_dirs(const void *rr, const void *ll)
1128 {
1129         char            *rpnt,
1130                         *lpnt;
1131         struct directory_entry **r,
1132                         **l;
1133         unsigned char   rtmp[2],
1134                         ltmp[2];
1135         struct unls_table *linls, *rinls;
1136
1137         r = (struct directory_entry **) rr;
1138         l = (struct directory_entry **) ll;
1139
1140 #ifdef APPLE_HYB
1141         /*
1142          * we may be using the HFS name - so select the correct input
1143          * charset
1144          */
1145         if (USE_MAC_NAME(*r)) {
1146                 rpnt = (*r)->hfs_ent->name;
1147                 rinls = hfs_inls;
1148         } else {
1149                 rpnt = (*r)->name;
1150                 rinls = in_nls;
1151         }
1152
1153         if (USE_MAC_NAME(*l)) {
1154                 lpnt = (*l)->hfs_ent->name;
1155                 linls = hfs_inls;
1156         } else {
1157                 lpnt = (*l)->name;
1158                 linls = in_nls;
1159         }
1160 #else
1161         rpnt = (*r)->name;
1162         lpnt = (*l)->name;
1163         rinls = linls = in_nls;
1164 #endif  /* APPLE_HYB */
1165
1166         /*
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.
1171          */
1172         if (strncmp(rpnt, lpnt, jlen) == 0) {
1173 #ifdef USE_LARGEFILES
1174                 if ((*r)->mxpart == (*l)->mxpart)
1175 #endif
1176                 {
1177 #ifdef  USE_LIBSCHILY
1178                         errmsgno(EX_BAD,
1179                                 "Error: %s and %s have the same Joliet name\n",
1180                                 (*r)->whole_name, (*l)->whole_name);
1181 #else
1182                         fprintf(stderr,
1183                                 "Error: %s and %s have the same Joliet name\n",
1184                                 (*r)->whole_name, (*l)->whole_name);
1185 #endif
1186                         jsort_goof++;
1187                 }
1188         }
1189         /*
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.
1193          */
1194         if (strcmp(rpnt, ".") == 0)
1195                 return (-1);
1196         if (strcmp(lpnt, ".") == 0)
1197                 return (1);
1198
1199         if (strcmp(rpnt, "..") == 0)
1200                 return (-1);
1201         if (strcmp(lpnt, "..") == 0)
1202                 return (1);
1203
1204 #ifdef DVD_VIDEO
1205         /*
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>
1211          */
1212         /*
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.
1216          */
1217         if (dvd_video) {
1218                 if (strcmp(rpnt, "VIDEO_TS.IFO") == 0)
1219                         return (-1);
1220                 if (strcmp(lpnt, "VIDEO_TS.IFO") == 0)
1221                         return (1);
1222         }
1223 #endif
1224
1225         while (*rpnt && *lpnt) {
1226 #ifdef USE_ICONV
1227                 size_t ri, li;
1228 #endif
1229                 if (*rpnt == ';' && *lpnt != ';')
1230                         return (-1);
1231                 if (*rpnt != ';' && *lpnt == ';')
1232                         return (1);
1233
1234                 if (*rpnt == ';' && *lpnt == ';')
1235                         return (0);
1236
1237                 /*
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.
1241                  */
1242 #if 0
1243                 if (*rpnt == '.' && *lpnt != '.')
1244                         return (-1);
1245                 if (*rpnt != '.' && *lpnt == '.')
1246                         return (1);
1247 #endif
1248
1249 #ifdef USE_ICONV
1250
1251                 ri = convert_to_unicode(rtmp, 2, rpnt, rinls);
1252                 li = convert_to_unicode(ltmp, 2, lpnt, linls);
1253                 rpnt += ri;
1254                 lpnt += li;
1255                 if(!ri && !li)
1256                         return (0);
1257                 else if(ri && !li)
1258                         return (1);
1259                 else if(!ri && li)
1260                         return (-1);
1261 #else
1262                 convert_to_unicode(rtmp, 2, rpnt, rinls);
1263                 convert_to_unicode(ltmp, 2, lpnt, linls);
1264 #endif
1265
1266                 if (a_to_u_2_byte(rtmp) < a_to_u_2_byte(ltmp))
1267                         return (-1);
1268                 if (a_to_u_2_byte(rtmp) > a_to_u_2_byte(ltmp))
1269                         return (1);
1270
1271 #ifndef USE_ICONV
1272                 rpnt++;
1273                 lpnt++;
1274 #endif
1275         }
1276         if (*rpnt)
1277                 return (1);
1278         if (*lpnt)
1279                 return (-1);
1280 #ifdef USE_LARGEFILES
1281         /*
1282          * (*r)->mxpart == (*l)->mxpart cannot happen here
1283          */
1284         if ((*r)->mxpart < (*l)->mxpart)
1285                 return (-1);
1286         else if ((*r)->mxpart > (*l)->mxpart)
1287                 return (1);
1288 #endif
1289         return (0);
1290 }
1291
1292
1293 /*
1294  * Function:            sort_directory
1295  *
1296  * Purpose:             Sort the directory in the appropriate ISO9660
1297  *                      order.
1298  *
1299  * Notes:               Returns 0 if OK, returns > 0 if an error occurred.
1300  */
1301 static int
1302 joliet_sort_directory(struct directory_entry **sort_dir)
1303 {
1304         int                     dcount = 0;
1305         int                     i;
1306         struct directory_entry  *s_entry;
1307         struct directory_entry  **sortlist;
1308
1309         s_entry = *sort_dir;
1310         while (s_entry) {
1311                 /*
1312                  * only colletc non-hidden entries
1313                  */
1314                 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1315                                         (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
1316                         dcount++;
1317                 s_entry = s_entry->next;
1318         }
1319
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);
1323
1324         dcount = 0;
1325         s_entry = *sort_dir;
1326         while (s_entry) {
1327                 /*
1328                  * only collect non-hidden entries
1329                  */
1330                 if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
1331                                         (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
1332                         sortlist[dcount] = s_entry;
1333                         dcount++;
1334                 }
1335                 s_entry = s_entry->next;
1336         }
1337
1338         jsort_goof = 0;
1339 #ifdef  PROTOTYPES
1340         qsort(sortlist, dcount, sizeof (struct directory_entry *),
1341                 (int (*) (const void *, const void *)) joliet_compare_dirs);
1342 #else
1343         qsort(sortlist, dcount, sizeof (struct directory_entry *),
1344                 joliet_compare_dirs);
1345 #endif
1346
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];
1350         }
1351
1352         sortlist[dcount - 1]->jnext = NULL;
1353         *sort_dir = sortlist[0];
1354
1355         free(sortlist);
1356         return (jsort_goof);
1357 }
1358
1359 int
1360 joliet_sort_tree(struct directory *node)
1361 {
1362         struct directory        *dpnt;
1363         int                     ret = 0;
1364
1365         dpnt = node;
1366
1367         while (dpnt) {
1368                 ret = joliet_sort_n_finish(dpnt);
1369                 if (ret) {
1370                         break;
1371                 }
1372                 if (dpnt->subdir)
1373                         ret = joliet_sort_tree(dpnt->subdir);
1374                 if (ret) {
1375                         break;
1376                 }
1377                 dpnt = dpnt->next;
1378         }
1379         return (ret);
1380 }
1381
1382 static void
1383 generate_joliet_directories(struct directory *node, FILE *outfile)
1384 {
1385         struct directory *dpnt;
1386
1387         dpnt = node;
1388
1389         while (dpnt) {
1390                 if ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0) {
1391                         /*
1392                          * In theory we should never reuse a directory, so this
1393                          * doesn't make much sense.
1394                          */
1395                         if (dpnt->jextent > session_start) {
1396                                 generate_one_joliet_directory(dpnt, outfile);
1397                         }
1398                 }
1399                 /* skip if hidden - but not for the rr_moved dir */
1400                 if (dpnt->subdir &&
1401                     (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
1402                     dpnt == reloc_dir)) {
1403                         generate_joliet_directories(dpnt->subdir, outfile);
1404                 }
1405                 dpnt = dpnt->next;
1406         }
1407 }
1408
1409
1410 /*
1411  * Function to write the EVD for the disc.
1412  */
1413 static int
1414 jpathtab_write(FILE *outfile)
1415 {
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;
1427         return (0);
1428 }
1429
1430 static int
1431 jdirtree_size(int starting_extent)
1432 {
1433         assign_joliet_directory_addresses(root);
1434         return (0);
1435 }
1436
1437 static int
1438 jroot_gen()
1439 {
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;
1451         return (0);
1452 }
1453
1454 static int
1455 jdirtree_write(FILE *outfile)
1456 {
1457         generate_joliet_directories(root, outfile);
1458         return (0);
1459 }
1460
1461 /*
1462  * Function to write the EVD for the disc.
1463  */
1464 static int
1465 jvd_write(FILE *outfile)
1466 {
1467         struct iso_primary_descriptor jvol_desc;
1468
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++;
1475         return (0);
1476 }
1477
1478 /*
1479  * Functions to describe padding block at the start of the disc.
1480  */
1481 static int
1482 jpathtab_size(int starting_extent)
1483 {
1484         jpath_table[0] = starting_extent;
1485         jpath_table[1] = 0;
1486         jpath_table[2] = jpath_table[0] + jpath_blocks;
1487         jpath_table[3] = 0;
1488
1489         last_extent += 2 * jpath_blocks;
1490         return (0);
1491 }
1492
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" };