Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
      3 
      4    Copyright 1997 Eric Youngdale.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 2, or (at your option)
      9    any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
     19 
     20 /* APPLE_HYB James Pearson j.pearson (at) ge.ucl.ac.uk 12/3/99 */
     21 
     22 /*
     23  * Joliet extensions for ISO9660.  These are spottily documented by
     24  * Microsoft.  In their infinite stupidity, they completely ignored
     25  * the possibility of using an SUSP record with the long filename
     26  * in it, and instead wrote out a duplicate directory tree with the
     27  * long filenames in it.
     28  *
     29  * I am not sure why they did this.  One reason is that they get the path
     30  * tables with the long filenames in them.
     31  *
     32  * There are two basic principles to Joliet, and the non-Unicode variant
     33  * known as Romeo.  Long filenames seem to be the main one, and the second
     34  * is that the character set and a few other things is substantially relaxed.
     35  *
     36  * The SVD is identical to the PVD, except:
     37  *
     38  *	Id is 2, not 1 (indicates SVD).
     39  *	escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
     40  *	The root directory record points to a different extent (with different
     41  *		size).
     42  *	There are different path tables for the two sets of directory trees.
     43  *
     44  * The following fields are recorded in Unicode:
     45  *	system_id
     46  *	volume_id
     47  *	volume_set_id
     48  *	publisher_id
     49  *	preparer_id
     50  *	application_id
     51  *	copyright_file_id
     52  *	abstract_file_id
     53  *	bibliographic_file_id
     54  *
     55  * Unicode strings are always encoded in big-endian format.
     56  *
     57  * In a directory record, everything is the same as with iso9660, except
     58  * that the name is recorded in unicode.  The name length is specified in
     59  * total bytes, not in number of unicode characters.
     60  *
     61  * The character set used for the names is different with UCS - the
     62  * restrictions are that the following are not allowed:
     63  *
     64  *	Characters (00)(00) through (00)(1f) (control chars)
     65  *	(00)(2a) '*'
     66  *	(00)(2f) '/'
     67  *	(00)(3a) ':'
     68  *	(00)(3b) ';'
     69  *	(00)(3f) '?'
     70  *	(00)(5c) '\'
     71  */
     72 #include "config.h"
     73 #include "mkisofs.h"
     74 #include "iso9660.h"
     75 
     76 
     77 #include <stdlib.h>
     78 #include <time.h>
     79 
     80 static int jpath_table_index;
     81 static struct directory ** jpathlist;
     82 static int next_jpath_index  = 1;
     83 static int sort_goof;
     84 
     85 static int generate_joliet_path_tables	__PR((void));
     86 static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir));
     87 static void DECL(assign_joliet_directory_addresses, (struct directory * node));
     88 static int jroot_gen	__PR((void));
     89 
     90 /*
     91  * Function:		convert_to_unicode
     92  *
     93  * Purpose:		Perform a 1/2 assed unicode conversion on a text
     94  *			string.
     95  *
     96  * Notes:
     97  */
     98 static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char *, source )
     99 {
    100   unsigned char * tmpbuf;
    101   int i;
    102   int j;
    103 
    104   /*
    105    * If we get a NULL pointer for the source, it means we have an inplace
    106    * copy, and we need to make a temporary working copy first.
    107    */
    108   if( source == NULL )
    109     {
    110       tmpbuf = (u_char *) e_malloc(size);
    111       memcpy( tmpbuf, buffer, size);
    112     }
    113   else
    114     {
    115       tmpbuf = (u_char *)source;
    116     }
    117 
    118   /*
    119    * Now start copying characters.  If the size was specified to be 0, then
    120    * assume the input was 0 terminated.
    121    */
    122   j = 0;
    123   for(i=0; i < size ; i += 2, j++)
    124     {
    125       buffer[i]       = 0;
    126 	/*
    127 	 * JS integrated from: Achim_Kaiser (at) t-online.de
    128 	 *
    129 	 * Let all valid unicode characters pass through (assuming ISO-8859-1).
    130 	 * Others are set to '_' .
    131 	 */
    132 	if( tmpbuf[j] != 0 &&
    133 	   (tmpbuf[j] <= 0x1f || (tmpbuf[j] >= 0x7F && tmpbuf[j] <= 0xA0)) )
    134 	{
    135 	  buffer[i+1]     = '_';
    136 	}
    137       else
    138 	{
    139 	  switch(tmpbuf[j])
    140 	    {
    141 	    case '*':
    142 	    case '/':
    143 	    case ':':
    144 	    case ';':
    145 	    case '?':
    146 	    case '\\':
    147 	      /*
    148 	       * Even Joliet has some standards as to what is allowed in a pathname.
    149 	       * Pretty tame in comparison to what DOS restricts you to.
    150 	       */
    151 	      buffer[i+1]     = '_';
    152 	      break;
    153 	    default:
    154 	      buffer[i+1]     = tmpbuf[j];
    155 	      break;
    156 	    }
    157 	}
    158     }
    159 
    160   if( source == NULL )
    161     {
    162       free(tmpbuf);
    163     }
    164 }
    165 
    166 /*
    167  * Function:		joliet_strlen
    168  *
    169  * Purpose:		Return length in bytes of string after conversion to unicode.
    170  *
    171  * Notes:		This is provided mainly as a convenience so that when more intelligent
    172  *			Unicode conversion for either Multibyte or 8-bit codes is available that
    173  *			we can easily adapt.
    174  */
    175 static int FDECL1(joliet_strlen, const char *, string)
    176 {
    177   int rtn;
    178 
    179   rtn = strlen(string) << 1;
    180 
    181   /*
    182    * We do clamp the maximum length of a Joliet string to be the
    183    * maximum path size.  This helps to ensure that we don't completely
    184    * bolix things up with very long paths.    The Joliet specs say
    185    * that the maximum length is 128 bytes, or 64 unicode characters.
    186    */
    187   if( rtn > 0x80)
    188     {
    189       rtn = 0x80;
    190     }
    191   return rtn;
    192 }
    193 
    194 /*
    195  * Function:		get_joliet_vol_desc
    196  *
    197  * Purpose:		generate a Joliet compatible volume desc.
    198  *
    199  * Notes:		Assume that we have the non-joliet vol desc
    200  *			already present in the buffer.  Just modifiy the
    201  *			appropriate fields.
    202  */
    203 static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, jvol_desc)
    204 {
    205   jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
    206 
    207   /*
    208    * For now, always do Unicode level 3.  I don't really know what 1 and 2
    209    * are - perhaps a more limited Unicode set.
    210    *
    211    * FIXME(eric) - how does Romeo fit in here?  As mkisofs just
    212    * "expands" 8 bit character codes to 16 bits and does nothing
    213    * special with the Unicode characters, therefore shouldn't mkisofs
    214    * really be stating that it's using UCS-2 Level 1, not Level 3 for
    215    * the Joliet directory tree.
    216    */
    217   strcpy(jvol_desc->escape_sequences, "%/@");
    218 
    219   /*
    220    * Until we have Unicode path tables, leave these unset.
    221    */
    222   set_733((char *) jvol_desc->path_table_size, jpath_table_size);
    223   set_731(jvol_desc->type_l_path_table,     jpath_table[0]);
    224   set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]);
    225   set_732(jvol_desc->type_m_path_table,     jpath_table[2]);
    226   set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]);
    227 
    228   /*
    229    * Set this one up.
    230    */
    231   memcpy(jvol_desc->root_directory_record, &jroot_record,
    232 	 sizeof(jvol_desc->root_directory_record));
    233 
    234   /*
    235    * Finally, we have a bunch of strings to convert to Unicode.
    236    * FIXME(eric) - I don't know how to do this in general, so we will
    237    * just be really lazy and do a char -> short conversion.  We probably
    238    * will want to filter any characters >= 0x80.
    239    */
    240   convert_to_unicode((u_char *)jvol_desc->system_id, sizeof(jvol_desc->system_id), NULL);
    241   convert_to_unicode((u_char *)jvol_desc->volume_id, sizeof(jvol_desc->volume_id), NULL);
    242   convert_to_unicode((u_char *)jvol_desc->volume_set_id, sizeof(jvol_desc->volume_set_id), NULL);
    243   convert_to_unicode((u_char *)jvol_desc->publisher_id, sizeof(jvol_desc->publisher_id), NULL);
    244   convert_to_unicode((u_char *)jvol_desc->preparer_id, sizeof(jvol_desc->preparer_id), NULL);
    245   convert_to_unicode((u_char *)jvol_desc->application_id, sizeof(jvol_desc->application_id), NULL);
    246   convert_to_unicode((u_char *)jvol_desc->copyright_file_id, sizeof(jvol_desc->copyright_file_id), NULL);
    247   convert_to_unicode((u_char *)jvol_desc->abstract_file_id, sizeof(jvol_desc->abstract_file_id), NULL);
    248   convert_to_unicode((u_char *)jvol_desc->bibliographic_file_id, sizeof(jvol_desc->bibliographic_file_id), NULL);
    249 
    250 
    251 }
    252 
    253 static void FDECL1(assign_joliet_directory_addresses, struct directory *, node)
    254 {
    255      int		dir_size;
    256      struct directory * dpnt;
    257 
    258      dpnt = node;
    259 
    260      while (dpnt)
    261      {
    262 	 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
    263 	 {
    264 	     /*
    265 	      * If we already have an extent for this (i.e. it came from
    266 	      * a multisession disc), then don't reassign a new extent.
    267 	      */
    268 	     dpnt->jpath_index = next_jpath_index++;
    269 	     if( dpnt->jextent == 0 )
    270 	     {
    271 		 dpnt->jextent = last_extent;
    272 		 dir_size = (dpnt->jsize + (SECTOR_SIZE - 1)) >> 11;
    273 		 last_extent += dir_size;
    274 	     }
    275 	 }
    276 
    277 	 /* skip if hidden - but not for the rr_moved dir */
    278 	 if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir))
    279 	 {
    280 	     assign_joliet_directory_addresses(dpnt->subdir);
    281 	 }
    282 	 dpnt = dpnt->next;
    283      }
    284 }
    285 
    286 static
    287 void FDECL1(build_jpathlist, struct directory *, node)
    288 {
    289      struct directory * dpnt;
    290 
    291      dpnt = node;
    292 
    293      while (dpnt)
    294 
    295      {
    296        if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
    297 	 {
    298 	   jpathlist[dpnt->jpath_index] = dpnt;
    299 	 }
    300        if(dpnt->subdir) build_jpathlist(dpnt->subdir);
    301        dpnt = dpnt->next;
    302      }
    303 } /* build_jpathlist(... */
    304 
    305 static int FDECL2(joliet_compare_paths, void const *, r, void const *, l)
    306 {
    307   struct directory const *ll = *(struct directory * const *)l;
    308   struct directory const *rr = *(struct directory * const *)r;
    309   int rparent, lparent;
    310 
    311   rparent = rr->parent->jpath_index;
    312   lparent = ll->parent->jpath_index;
    313   if( rr->parent == reloc_dir )
    314     {
    315       rparent = rr->self->parent_rec->filedir->jpath_index;
    316     }
    317 
    318   if( ll->parent == reloc_dir )
    319     {
    320       lparent = ll->self->parent_rec->filedir->jpath_index;
    321     }
    322 
    323   if (rparent < lparent)
    324   {
    325        return -1;
    326   }
    327 
    328   if (rparent > lparent)
    329   {
    330        return 1;
    331   }
    332 #ifdef APPLE_HYB
    333   /* use Mac name for Joliet name */
    334   if (USE_MAC_NAME(mac_name, rr->self) && USE_MAC_NAME(mac_name, ll->self))
    335     return strcmp(rr->self->hfs_ent->name, ll->self->hfs_ent->name);
    336   else
    337 #endif /* APPLE_HYB */
    338     return strcmp(rr->self->name, ll->self->name);
    339 
    340 } /* compare_paths(... */
    341 
    342 static int generate_joliet_path_tables()
    343 {
    344   struct directory_entry * de;
    345   struct directory	 * dpnt;
    346   int			   fix;
    347   int			   j;
    348   int			   namelen;
    349   char			 * npnt;
    350   char			 * npnt1;
    351   int			   tablesize;
    352 
    353   /*
    354    * First allocate memory for the tables and initialize the memory
    355    */
    356   tablesize = jpath_blocks << 11;
    357   jpath_table_m = (char *) e_malloc(tablesize);
    358   jpath_table_l = (char *) e_malloc(tablesize);
    359   memset(jpath_table_l, 0, tablesize);
    360   memset(jpath_table_m, 0, tablesize);
    361 
    362   if( next_jpath_index > 0xffff )
    363   {
    364       fprintf(stderr, "Unable to generate sane path tables - too many directories (%d)\n",
    365 	      next_jpath_index);
    366       exit(1);
    367   }
    368   /*
    369    * Now start filling in the path tables.  Start with root directory
    370    */
    371   jpath_table_index = 0;
    372   jpathlist = (struct directory **) e_malloc(sizeof(struct directory *)
    373 					    * next_jpath_index);
    374   memset(jpathlist, 0, sizeof(struct directory *) * next_jpath_index);
    375   build_jpathlist(root);
    376 
    377   do
    378   {
    379        fix = 0;
    380 #ifdef	__STDC__
    381        qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *),
    382 	     (int (*)(const void *, const void *))joliet_compare_paths);
    383 #else
    384        qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *),
    385 	     joliet_compare_paths);
    386 #endif
    387 
    388        for(j=1; j<next_jpath_index; j++)
    389        {
    390 	    if(jpathlist[j]->jpath_index != j)
    391 	    {
    392 		 jpathlist[j]->jpath_index = j;
    393 		 fix++;
    394 	    }
    395        }
    396   } while(fix);
    397 
    398   for(j=1; j<next_jpath_index; j++)
    399   {
    400        dpnt = jpathlist[j];
    401        if(!dpnt)
    402        {
    403 	    fprintf(stderr,"Entry %d not in path tables\n", j);
    404 	    exit(1);
    405        }
    406        npnt = dpnt->de_name;
    407 
    408        npnt1 = strrchr(npnt, PATH_SEPARATOR);
    409        if(npnt1)
    410        {
    411 	    npnt = npnt1 + 1;
    412        }
    413 
    414        de = dpnt->self;
    415        if(!de)
    416        {
    417 	    fprintf(stderr,"Fatal goof - directory has amnesia\n");
    418 	    exit(1);
    419        }
    420 
    421 #ifdef APPLE_HYB
    422        if (USE_MAC_NAME(mac_name, de))
    423 	  namelen = joliet_strlen(de->hfs_ent->name);
    424        else
    425 #endif /* APPLE_HYB */
    426           namelen = joliet_strlen(de->name);
    427 
    428        if( dpnt == root )
    429 	 {
    430 	   jpath_table_l[jpath_table_index] = 1;
    431 	   jpath_table_m[jpath_table_index] = 1;
    432 	 }
    433        else
    434 	 {
    435 	   jpath_table_l[jpath_table_index] = namelen;
    436 	   jpath_table_m[jpath_table_index] = namelen;
    437 	 }
    438        jpath_table_index += 2;
    439 
    440        set_731(jpath_table_l + jpath_table_index, dpnt->jextent);
    441        set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
    442        jpath_table_index += 4;
    443 
    444        if( dpnt->parent != reloc_dir )
    445 	 {
    446 	   set_721(jpath_table_l + jpath_table_index,
    447 		   dpnt->parent->jpath_index);
    448 	   set_722(jpath_table_m + jpath_table_index,
    449 		   dpnt->parent->jpath_index);
    450 	 }
    451        else
    452 	 {
    453 	   set_721(jpath_table_l + jpath_table_index,
    454 		   dpnt->self->parent_rec->filedir->jpath_index);
    455 	   set_722(jpath_table_m + jpath_table_index,
    456 		   dpnt->self->parent_rec->filedir->jpath_index);
    457 	 }
    458 
    459        jpath_table_index += 2;
    460 
    461        /*
    462 	* The root directory is still represented in non-unicode fashion.
    463 	*/
    464        if( dpnt == root )
    465 	 {
    466 	   jpath_table_l[jpath_table_index] = 0;
    467 	   jpath_table_m[jpath_table_index] = 0;
    468 	   jpath_table_index ++;
    469 	 }
    470        else
    471 	 {
    472 #ifdef APPLE_HYB
    473 	   if (USE_MAC_NAME(mac_name , de)) {
    474 	      convert_to_unicode((u_char *)jpath_table_l + jpath_table_index,
    475 			      namelen, de->hfs_ent->name);
    476 	      convert_to_unicode((u_char *)jpath_table_m + jpath_table_index,
    477 			      namelen, de->hfs_ent->name);
    478 	   }
    479 	   else {
    480 #endif /* APPLE_HYB */
    481 	      convert_to_unicode((u_char *)jpath_table_l + jpath_table_index,
    482 			      namelen, de->name);
    483 	      convert_to_unicode((u_char *)jpath_table_m + jpath_table_index,
    484 			      namelen, de->name);
    485 #ifdef APPLE_HYB
    486 	   }
    487 #endif /* APPLE_HYB */
    488 
    489 	   jpath_table_index += namelen;
    490 	 }
    491 
    492        if(jpath_table_index & 1)
    493        {
    494 	    jpath_table_index++;  /* For odd lengths we pad */
    495        }
    496   }
    497 
    498   free(jpathlist);
    499   if(jpath_table_index != jpath_table_size)
    500   {
    501        fprintf(stderr,"Joliet path table lengths do not match %d %d\n",
    502 	       jpath_table_index,
    503 	       jpath_table_size);
    504   }
    505   return 0;
    506 } /* generate_path_tables(... */
    507 
    508 static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE *, outfile)
    509 {
    510      unsigned int			  dir_index;
    511      char				* directory_buffer;
    512      int				  new_reclen;
    513      struct directory_entry		* s_entry;
    514      struct directory_entry		* s_entry1;
    515      struct iso_directory_record	  jrec;
    516      unsigned int			  total_size;
    517      int				  cvt_len;
    518      struct directory			* finddir;
    519 
    520      total_size = (dpnt->jsize + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
    521      directory_buffer = (char *) e_malloc(total_size);
    522      memset(directory_buffer, 0, total_size);
    523      dir_index = 0;
    524 
    525      s_entry = dpnt->jcontents;
    526      while(s_entry)
    527      {
    528 	     if(s_entry->de_flags & INHIBIT_JOLIET_ENTRY) {
    529 		s_entry = s_entry->jnext;
    530 		continue;
    531 	     }
    532 
    533 	     /*
    534 	      * If this entry was a directory that was relocated, we have a bit
    535 	      * of trouble here.  We need to dig out the real thing and put it
    536 	      * back here.  In the Joliet tree, there is no relocated rock
    537 	      * ridge, as there are no depth limits to a directory tree.
    538 	      */
    539 	     if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
    540 	     {
    541 		 for(s_entry1 = reloc_dir->contents; s_entry1; s_entry1 = s_entry1->next)
    542 		 {
    543 		     if( s_entry1->parent_rec == s_entry )
    544 		     {
    545 			 break;
    546 		     }
    547 		 }
    548 		 if( s_entry1 == NULL )
    549 		 {
    550 		     /*
    551 		      * We got trouble.
    552 		      */
    553 		     fprintf(stderr, "Unable to locate relocated directory\n");
    554 		     exit(1);
    555 		 }
    556 	     }
    557 	     else
    558 	     {
    559 		 s_entry1 = s_entry;
    560 	     }
    561 
    562 	     /*
    563 	      * We do not allow directory entries to cross sector boundaries.
    564 	      * Simply pad, and then start the next entry at the next sector
    565 	      */
    566 	     new_reclen = s_entry1->jreclen;
    567 	     if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
    568 	     {
    569 		 dir_index = (dir_index + (SECTOR_SIZE - 1)) &
    570 		     ~(SECTOR_SIZE - 1);
    571 	     }
    572 
    573 	     memcpy(&jrec, &s_entry1->isorec, sizeof(struct iso_directory_record) -
    574 		    sizeof(s_entry1->isorec.name));
    575 
    576 #ifdef APPLE_HYB
    577 	     /* Use the HFS name if it exists */
    578 	     if (USE_MAC_NAME(mac_name, s_entry1))
    579 	       cvt_len = joliet_strlen(s_entry1->hfs_ent->name);
    580 	     else
    581 #endif /* APPLE_HYB */
    582 	       cvt_len = joliet_strlen(s_entry1->name);
    583 
    584 	     /*
    585 	      * Fix the record length - this was the non-Joliet version we
    586 	      * were seeing.
    587 	      */
    588 	     jrec.name_len[0] = cvt_len;
    589 	     jrec.length[0] = s_entry1->jreclen;
    590 
    591 	     /*
    592 	      * If this is a directory, fix the correct size and extent
    593 	      * number.
    594 	      */
    595 	     if( (jrec.flags[0] & 2) != 0 )
    596 	     {
    597 		 if(strcmp(s_entry1->name,".") == 0)
    598 		 {
    599 		     jrec.name_len[0] = 1;
    600 		     set_733((char *) jrec.extent, dpnt->jextent);
    601 		     set_733((char *) jrec.size, ROUND_UP(dpnt->jsize));
    602 		 }
    603 		 else if(strcmp(s_entry1->name,"..") == 0)
    604 		 {
    605 		     jrec.name_len[0] = 1;
    606 		     if( dpnt->parent == reloc_dir )
    607 		     {
    608 			 set_733((char *) jrec.extent, dpnt->self->parent_rec->filedir->jextent);
    609 			 set_733((char *) jrec.size, ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
    610 		     }
    611 		     else
    612 
    613 		     {
    614 			 set_733((char *) jrec.extent, dpnt->parent->jextent);
    615 			 set_733((char *) jrec.size, ROUND_UP(dpnt->parent->jsize));
    616 		     }
    617 		 }
    618 		 else
    619 		 {
    620 		     if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
    621 		     {
    622 			 finddir = reloc_dir->subdir;
    623 		     }
    624 		     else
    625 		     {
    626 			 finddir = dpnt->subdir;
    627 		     }
    628 		     while(1==1)
    629 		     {
    630 			 if(finddir->self == s_entry1) break;
    631 			 finddir = finddir->next;
    632 			 if(!finddir)
    633 			 {
    634 			     fprintf(stderr,"Fatal goof - unable to find directory location\n"); exit(1);
    635 			 }
    636 		     }
    637 		     set_733((char *) jrec.extent, finddir->jextent);
    638 		     set_733((char *) jrec.size, ROUND_UP(finddir->jsize));
    639 		 }
    640 	     }
    641 
    642 	     memcpy(directory_buffer + dir_index, &jrec,
    643 		    sizeof(struct iso_directory_record) -
    644 		    sizeof(s_entry1->isorec.name));
    645 
    646 
    647 	     dir_index += sizeof(struct iso_directory_record) -
    648 		 sizeof (s_entry1->isorec.name);
    649 
    650 	     /*
    651 	      * Finally dump the Unicode version of the filename.
    652 	      * Note - . and .. are the same as with non-Joliet discs.
    653 	      */
    654 	     if( (jrec.flags[0] & 2) != 0
    655 		 && strcmp(s_entry1->name, ".") == 0 )
    656 	     {
    657 		 directory_buffer[dir_index++] = 0;
    658 	     }
    659 	     else if( (jrec.flags[0] & 2) != 0
    660 		      && strcmp(s_entry1->name, "..") == 0 )
    661 	     {
    662 		 directory_buffer[dir_index++] = 1;
    663 	     }
    664 	     else
    665 	     {
    666 #ifdef APPLE_HYB
    667 	       if (USE_MAC_NAME(mac_name, s_entry1))
    668 		 /* Use the HFS name if it exists */
    669 		 convert_to_unicode((u_char *)directory_buffer + dir_index,
    670 				    cvt_len,
    671 				    s_entry1->hfs_ent->name);
    672 	       else
    673 #endif /* APPLE_HYB */
    674 		 convert_to_unicode((u_char *)directory_buffer + dir_index,
    675 				    cvt_len,
    676 				    s_entry1->name);
    677 		 dir_index += cvt_len;
    678 	     }
    679 
    680 	     if(dir_index & 1)
    681 	     {
    682 		 directory_buffer[dir_index++] = 0;
    683 	     }
    684 
    685 	     s_entry = s_entry->jnext;
    686      }
    687 
    688      if(dpnt->jsize != dir_index)
    689      {
    690 	 fprintf(stderr,"Unexpected joliet directory length %d %d %s\n",dpnt->jsize,
    691 		 dir_index, dpnt->de_name);
    692      }
    693 
    694      xfwrite(directory_buffer, 1, total_size, outfile);
    695      last_extent_written += total_size >> 11;
    696      free(directory_buffer);
    697 } /* generate_one_joliet_directory(... */
    698 
    699 static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir)
    700 {
    701   struct directory_entry  * s_entry;
    702   int			    status = 0;
    703 
    704   /* don't want to skip this directory if it's the reloc_dir at the moment */
    705   if(this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY)
    706     {
    707       return 0;
    708     }
    709 
    710   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
    711     {
    712       /* skip hidden entries */
    713       if(  (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
    714 	{
    715 	  continue;
    716 	}
    717 
    718       /*
    719        * First update the path table sizes for directories.
    720        *
    721        * Finally, set the length of the directory entry if Joliet is used.
    722        * The name is longer, but no Rock Ridge is ever used here, so
    723        * depending upon the options the entry size might turn out to be about
    724        * the same.  The Unicode name is always a multiple of 2 bytes, so
    725        * we always add 1 to make it an even number.
    726        */
    727       if(s_entry->isorec.flags[0] ==  2)
    728 	{
    729 	  if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
    730 	    {
    731 #ifdef APPLE_HYB
    732 	   if (USE_MAC_NAME(mac_name, s_entry))
    733 	      /* Use the HFS name if it exists */
    734 	      jpath_table_size += joliet_strlen(s_entry->hfs_ent->name) + sizeof(struct iso_path_table) - 1;
    735 	   else
    736 #endif /* APPLE_HYB */
    737 	      jpath_table_size += joliet_strlen(s_entry->name) + sizeof(struct iso_path_table) - 1;
    738 	      if (jpath_table_size & 1)
    739 		{
    740 		  jpath_table_size++;
    741 		}
    742 	    }
    743 	  else
    744 	    {
    745 	      if (this_dir == root && strlen(s_entry->name) == 1)
    746 		{
    747 		  jpath_table_size += sizeof(struct iso_path_table);
    748 		  if (jpath_table_size & 1) jpath_table_size++;
    749 		}
    750 	    }
    751 	}
    752 
    753       if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
    754 	{
    755 #ifdef APPLE_HYB
    756 	 if (USE_MAC_NAME(mac_name, s_entry))
    757 	  /* Use the HFS name if it exists */
    758 	  s_entry->jreclen = 	sizeof(struct iso_directory_record)
    759 	    - sizeof(s_entry->isorec.name)
    760 	    + joliet_strlen(s_entry->hfs_ent->name)
    761 	    + 1;
    762 	 else
    763 #endif /* APPLE_HYB */
    764 	  s_entry->jreclen = 	sizeof(struct iso_directory_record)
    765 	    - sizeof(s_entry->isorec.name)
    766 	    + joliet_strlen(s_entry->name)
    767 	    + 1;
    768 	}
    769       else
    770 	{
    771 	  /*
    772 	   * Special - for '.' and '..' we generate the same records we
    773 	   * did for non-Joliet discs.
    774 	   */
    775 	  s_entry->jreclen = 	sizeof(struct iso_directory_record)
    776 	    - sizeof(s_entry->isorec.name)
    777 	    + 1;
    778 	}
    779 
    780 
    781     }
    782 
    783   if( (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0 )
    784     {
    785       return 0;
    786     }
    787 
    788   this_dir->jcontents = this_dir->contents;
    789   status = joliet_sort_directory(&this_dir->jcontents);
    790 
    791   /*
    792    * Now go through the directory and figure out how large this one will be.
    793    * Do not split a directory entry across a sector boundary
    794    */
    795   s_entry = this_dir->jcontents;
    796 /*
    797  * XXX Is it ok to comment this out?
    798  */
    799 /*XXX JS  this_dir->ce_bytes = 0;*/
    800   for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext)
    801     {
    802       int jreclen;
    803 
    804       if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
    805 	{
    806 	  continue;
    807 	}
    808 
    809       jreclen = s_entry->jreclen;
    810 
    811       if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >= SECTOR_SIZE)
    812 	{
    813 	  this_dir->jsize = (this_dir->jsize + (SECTOR_SIZE - 1)) &
    814 	    ~(SECTOR_SIZE - 1);
    815 	}
    816       this_dir->jsize += jreclen;
    817     }
    818   return status;
    819 }
    820 
    821 /*
    822  * Similar to the iso9660 case, except here we perform a full sort based upon the
    823  * regular name of the file, not the 8.3 version.
    824  */
    825 static int FDECL2(joliet_compare_dirs, const void *, rr, const void *, ll)
    826 {
    827      char * rpnt, *lpnt;
    828      struct directory_entry ** r, **l;
    829 
    830      r = (struct directory_entry **) rr;
    831      l = (struct directory_entry **) ll;
    832      rpnt = (*r)->name;
    833      lpnt = (*l)->name;
    834 
    835      /*
    836       * If the entries are the same, this is an error.
    837       */
    838      if( strcmp(rpnt, lpnt) == 0 )
    839        {
    840 	 sort_goof++;
    841        }
    842 
    843      /*
    844       *  Put the '.' and '..' entries on the head of the sorted list.
    845       *  For normal ASCII, this always happens to be the case, but out of
    846       *  band characters cause this not to be the case sometimes.
    847       */
    848      if( strcmp(rpnt, ".") == 0 ) return -1;
    849      if( strcmp(lpnt, ".") == 0 ) return  1;
    850 
    851      if( strcmp(rpnt, "..") == 0 ) return -1;
    852      if( strcmp(lpnt, "..") == 0 ) return  1;
    853 
    854      while(*rpnt && *lpnt)
    855      {
    856 	  if(*rpnt == ';' && *lpnt != ';') return -1;
    857 	  if(*rpnt != ';' && *lpnt == ';') return 1;
    858 
    859 	  if(*rpnt == ';' && *lpnt == ';') return 0;
    860 
    861 	  /*
    862 	   * Extensions are not special here.  Don't treat the dot as something that
    863 	   * must be bumped to the start of the list.
    864 	   */
    865 #if 0
    866 	  if(*rpnt == '.' && *lpnt != '.') return -1;
    867 	  if(*rpnt != '.' && *lpnt == '.') return 1;
    868 #endif
    869 
    870 	  if(*rpnt < *lpnt) return -1;
    871 	  if(*rpnt > *lpnt) return 1;
    872 	  rpnt++;  lpnt++;
    873      }
    874      if(*rpnt) return 1;
    875      if(*lpnt) return -1;
    876      return 0;
    877 }
    878 
    879 
    880 /*
    881  * Function:		sort_directory
    882  *
    883  * Purpose:		Sort the directory in the appropriate ISO9660
    884  *			order.
    885  *
    886  * Notes:		Returns 0 if OK, returns > 0 if an error occurred.
    887  */
    888 static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir)
    889 {
    890      int dcount = 0;
    891      int i;
    892      struct directory_entry * s_entry;
    893      struct directory_entry ** sortlist;
    894 
    895      s_entry = *sort_dir;
    896      while(s_entry)
    897      {
    898 	  /* skip hidden entries */
    899 	  if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY))
    900 	    dcount++;
    901 	  s_entry = s_entry->next;
    902      }
    903 
    904      /*
    905       * OK, now we know how many there are.  Build a vector for sorting.
    906       */
    907      sortlist =   (struct directory_entry **)
    908 	  e_malloc(sizeof(struct directory_entry *) * dcount);
    909 
    910      dcount = 0;
    911      s_entry = *sort_dir;
    912      while(s_entry)
    913      {
    914 	  /* skip hidden entries */
    915 	  if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) {
    916 	    sortlist[dcount] = s_entry;
    917 	    dcount++;
    918 	  }
    919 	  s_entry = s_entry->next;
    920      }
    921 
    922      sort_goof = 0;
    923 #ifdef	__STDC__
    924      qsort(sortlist, dcount, sizeof(struct directory_entry *),
    925 	   (int (*)(const void *, const void *))joliet_compare_dirs);
    926 #else
    927      qsort(sortlist, dcount, sizeof(struct directory_entry *),
    928 	   joliet_compare_dirs);
    929 #endif
    930 
    931      /*
    932       * Now reassemble the linked list in the proper sorted order
    933       */
    934      for(i=0; i<dcount-1; i++)
    935      {
    936 	  sortlist[i]->jnext = sortlist[i+1];
    937      }
    938 
    939      sortlist[dcount-1]->jnext = NULL;
    940      *sort_dir = sortlist[0];
    941 
    942      free(sortlist);
    943      return sort_goof;
    944 }
    945 
    946 int FDECL1(joliet_sort_tree, struct directory *, node)
    947 {
    948   struct directory * dpnt;
    949   int ret = 0;
    950 
    951   dpnt = node;
    952 
    953   while (dpnt){
    954     ret = joliet_sort_n_finish(dpnt);
    955     if( ret )
    956       {
    957 	break;
    958       }
    959     if(dpnt->subdir) ret = joliet_sort_tree(dpnt->subdir);
    960     if( ret )
    961       {
    962 	break;
    963       }
    964     dpnt = dpnt->next;
    965   }
    966   return ret;
    967 }
    968 
    969 static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){
    970   struct directory * dpnt;
    971 
    972   dpnt = node;
    973 
    974   while (dpnt)
    975     {
    976       if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
    977 	{
    978 	  /*
    979 	   * In theory we should never reuse a directory, so this doesn't
    980 	   * make much sense.
    981 	   */
    982 	  if( dpnt->jextent > session_start )
    983 	    {
    984 	      generate_one_joliet_directory(dpnt, outfile);
    985 	    }
    986 	}
    987       /* skip if hidden - but not for the rr_moved dir */
    988       if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir))
    989 	generate_joliet_directories(dpnt->subdir, outfile);
    990       dpnt = dpnt->next;
    991     }
    992 }
    993 
    994 
    995 /*
    996  * Function to write the EVD for the disc.
    997  */
    998 static int FDECL1(jpathtab_write, FILE *, outfile)
    999 {
   1000   /*
   1001    * Next we write the path tables
   1002    */
   1003   xfwrite(jpath_table_l, 1, jpath_blocks << 11, outfile);
   1004   xfwrite(jpath_table_m, 1, jpath_blocks << 11, outfile);
   1005   last_extent_written += 2*jpath_blocks;
   1006   free(jpath_table_l);
   1007   free(jpath_table_m);
   1008   jpath_table_l = NULL;
   1009   jpath_table_m = NULL;
   1010   return 0;
   1011 }
   1012 
   1013 static int FDECL1(jdirtree_size, int, starting_extent)
   1014 {
   1015   assign_joliet_directory_addresses(root);
   1016   return 0;
   1017 }
   1018 
   1019 static int jroot_gen()
   1020 {
   1021      jroot_record.length[0] = 1 + sizeof(struct iso_directory_record)
   1022 	  - sizeof(jroot_record.name);
   1023      jroot_record.ext_attr_length[0] = 0;
   1024      set_733((char *) jroot_record.extent, root->jextent);
   1025      set_733((char *) jroot_record.size, ROUND_UP(root->jsize));
   1026      iso9660_date(jroot_record.date, root_statbuf.st_mtime);
   1027      jroot_record.flags[0] = 2;
   1028      jroot_record.file_unit_size[0] = 0;
   1029      jroot_record.interleave[0] = 0;
   1030      set_723(jroot_record.volume_sequence_number, volume_sequence_number);
   1031      jroot_record.name_len[0] = 1;
   1032      return 0;
   1033 }
   1034 
   1035 static int FDECL1(jdirtree_write, FILE *, outfile)
   1036 {
   1037   generate_joliet_directories(root, outfile);
   1038   return 0;
   1039 }
   1040 
   1041 /*
   1042  * Function to write the EVD for the disc.
   1043  */
   1044 static int FDECL1(jvd_write, FILE *, outfile)
   1045 {
   1046   struct iso_primary_descriptor jvol_desc;
   1047 
   1048   /*
   1049    * Next we write out the boot volume descriptor for the disc
   1050    */
   1051   jvol_desc = vol_desc;
   1052   get_joliet_vol_desc(&jvol_desc);
   1053   xfwrite(&jvol_desc, 1, 2048, outfile);
   1054   last_extent_written ++;
   1055   return 0;
   1056 }
   1057 
   1058 /*
   1059  * Functions to describe padding block at the start of the disc.
   1060  */
   1061 static int FDECL1(jpathtab_size, int, starting_extent)
   1062 {
   1063   jpath_table[0] = starting_extent;
   1064   jpath_table[1] = 0;
   1065   jpath_table[2] = jpath_table[0] + jpath_blocks;
   1066   jpath_table[3] = 0;
   1067 
   1068   last_extent += 2*jpath_blocks;
   1069   return 0;
   1070 }
   1071 
   1072 struct output_fragment joliet_desc    = {NULL, oneblock_size, jroot_gen,jvd_write};
   1073 struct output_fragment jpathtable_desc= {NULL, jpathtab_size, generate_joliet_path_tables,     jpathtab_write};
   1074 struct output_fragment jdirtree_desc  = {NULL, jdirtree_size, NULL,     jdirtree_write};
   1075