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