Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * File tree.c - scan directory  tree and build memory structures for iso9660
      3  * filesystem
      4 
      5    Written by Eric Youngdale (1993).
      6 
      7    Copyright 1993 Yggdrasil Computing, Incorporated
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 2, or (at your option)
     12    any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
     22 
     23 /* ADD_FILES changes made by Ross Biro biro (at) yggdrasil.com 2/23/95 */
     24 
     25 /* APPLE_HYB James Pearson j.pearson (at) ge.ucl.ac.uk 16/3/1999 */
     26 
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <time.h>
     30 #include <errno.h>
     31 
     32 #include "config.h"
     33 #include "apple_proto.h"
     34 
     35 #ifndef VMS
     36 #if defined(MAJOR_IN_SYSMACROS)
     37 #include <sys/sysmacros.h>
     38 #endif
     39 
     40 #ifdef HAVE_UNISTD_H
     41 #include <unistd.h>
     42 #endif
     43 #include <fctldefs.h>
     44 
     45 #if defined(MAJOR_IN_MKDEV)
     46 #include <sys/types.h>
     47 #include <sys/mkdev.h>
     48 #endif
     49 #else
     50 #include <sys/file.h>
     51 #include <vms/fabdef.h>
     52 #include "vms.h"
     53 extern char * strdup(const char *);
     54 #endif
     55 
     56 /*
     57  * Autoconf should be able to figure this one out for us and let us know
     58  * whether the system has memmove or not.
     59  */
     60 # ifndef HAVE_MEMMOVE
     61 #  define memmove(d, s, n) bcopy ((s), (d), (n))
     62 # endif
     63 
     64 #include "mkisofs.h"
     65 #include "iso9660.h"
     66 #include "match.h"
     67 
     68 #include <sys/stat.h>
     69 
     70 #ifdef	DOESNT_WORK
     71 
     72 #ifdef NON_UNIXFS
     73 #define S_ISLNK(m)	(0)
     74 #define S_ISSOCK(m)	(0)
     75 #define S_ISFIFO(m)	(0)
     76 #else
     77 #ifndef S_ISLNK
     78 #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
     79 #endif
     80 #ifndef S_ISSOCK
     81 # ifdef S_IFSOCK
     82 #   define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK)
     83 # else
     84 #   define S_ISSOCK(m)	(0)
     85 # endif
     86 #endif
     87 #endif
     88 
     89 #else
     90 #include <statdefs.h>
     91 #endif
     92 
     93 
     94 #ifdef __SVR4
     95 extern char * strdup(const char *);
     96 #endif
     97 
     98 static unsigned char symlink_buff[256];
     99 
    100 static void stat_fix	__PR((struct stat * st));
    101 static void generate_reloc_directory __PR((void));
    102 
    103 static void DECL(attach_dot_entries, (struct directory * dirnode,
    104 		   struct stat * parent_stat));
    105 static void DECL(delete_directory, (struct directory * parent, struct directory * child));
    106 
    107 extern int verbose;
    108 
    109 struct stat fstatbuf = {0,};  /* We use this for the artificial entries we create */
    110 
    111 struct stat root_statbuf = {0, };  /* Stat buffer for root directory */
    112 
    113 struct directory * reloc_dir = NULL;
    114 
    115 static void
    116 FDECL1(stat_fix, struct stat *, st)
    117 {
    118   /* Remove the uid and gid, they will only be useful on the author's
    119      system.  */
    120   st->st_uid = 0;
    121   st->st_gid = 0;
    122 
    123  /*
    124   * Make sure the file modes make sense.  Turn on all read bits.  Turn
    125   * on all exec/search bits if any exec/search bit is set.  Turn off
    126   * all write bits, and all special mode bits (on a r/o fs lock bits
    127   * are useless, and with uid+gid 0 don't want set-id bits, either).
    128   */
    129   st->st_mode |= 0444;
    130 #ifndef _WIN32		/* make all file "executable" */
    131   if (st->st_mode & 0111)
    132 #endif /* _WIN32 */
    133     st->st_mode |= 0111;
    134   st->st_mode &= ~07222;
    135 }
    136 
    137 int
    138 FDECL2(stat_filter, char *, path, struct stat *, st)
    139 {
    140   int result = stat(path, st);
    141   if (result >= 0 && rationalize)
    142     stat_fix(st);
    143   return result;
    144 }
    145 
    146 int
    147 FDECL2(lstat_filter, char *, path, struct stat *, st)
    148 {
    149   int result = lstat(path, st);
    150   if (result >= 0 && rationalize)
    151     stat_fix(st);
    152   return result;
    153 }
    154 
    155 static int FDECL1(sort_n_finish, struct directory *, this_dir)
    156 {
    157   struct directory_entry  * s_entry;
    158   struct directory_entry  * s_entry1;
    159   struct directory_entry  * table;
    160   int			    count;
    161   int			    d1;
    162   int			    d2;
    163   int			    d3;
    164   int			    new_reclen;
    165   char			 *  c;
    166   int			    status = 0;
    167   int			    tablesize = 0;
    168   char			    newname[34];
    169   char			    rootname[34];
    170 
    171   /* Here we can take the opportunity to toss duplicate entries from the
    172      directory.  */
    173 
    174   /* ignore if it's hidden */
    175   if(this_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
    176     {
    177       return 0;
    178     }
    179 
    180   table = NULL;
    181 
    182   init_fstatbuf();
    183 
    184   /*
    185    * If we had artificially created this directory, then we might be
    186    * missing the required '.' entries.  Create these now if we need
    187    * them.
    188    */
    189   if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
    190       (DIR_HAS_DOT | DIR_HAS_DOTDOT) )
    191     {
    192       attach_dot_entries(this_dir, &fstatbuf);
    193     }
    194 
    195   flush_file_hash();
    196   s_entry = this_dir->contents;
    197   while(s_entry)
    198     {
    199     /* ignore if it's hidden */
    200     if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
    201       {
    202 	s_entry = s_entry->next;
    203 	continue;
    204       }
    205 
    206       /*
    207        * First assume no conflict, and handle this case
    208        */
    209       if(!(s_entry1 = find_file_hash(s_entry->isorec.name)))
    210 	{
    211 	  add_file_hash(s_entry);
    212 	  s_entry = s_entry->next;
    213 	  continue;
    214 	}
    215 
    216 #ifdef APPLE_HYB
    217       /* if the pair are associated, then skip (as they have the same name!) */
    218       if(apple_both && s_entry1->assoc && s_entry1->assoc == s_entry)
    219 	{
    220 	  s_entry = s_entry->next;
    221 	  continue;
    222 	}
    223 #endif /* APPLE_HYB */
    224 
    225       if(s_entry1 == s_entry)
    226 	{
    227 	  fprintf(stderr,"Fatal goof\n");
    228 	  exit(1);
    229 	}
    230 
    231       /*
    232        * OK, handle the conflicts.  Try substitute names until we come
    233        * up with a winner
    234        */
    235       strcpy(rootname, s_entry->isorec.name);
    236       if(full_iso9660_filenames)
    237 	{
    238 	  if(strlen(rootname) > 27) rootname[27] = 0;
    239 	}
    240 
    241       /*
    242        * Strip off the non-significant part of the name so that we are left
    243        * with a sensible root filename.  If we don't find a '.', then try
    244        * a ';'.
    245        */
    246       c  = strchr(rootname, '.');
    247       if (c)
    248 	*c = 0;
    249       else
    250 	{
    251 	  c  = strchr(rootname, ';');
    252 	  if (c) *c = 0;
    253 	}
    254       for(d1 = 0; d1 < 36; d1++)
    255 	{
    256 	  for(d2 = 0; d2 < 36; d2++)
    257 	    {
    258 	      for(d3 = 0; d3 < 36; d3++)
    259 		{
    260 		  snprintf(newname, sizeof newname, "%s.%c%c%c%s", rootname,
    261 			  (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10),
    262 			  (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10),
    263 			  (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10),
    264 			  (s_entry->isorec.flags[0] == 2 ||
    265 			   omit_version_number ? "" : ";1"));
    266 
    267 #ifdef VMS
    268 		  /* Sigh.  VAXCRTL seems to be broken here */
    269 		  {
    270 		    int ijk = 0;
    271 		    while(newname[ijk])
    272 		      {
    273 			if(newname[ijk] == ' ') newname[ijk] = '0';
    274 			ijk++;
    275 		      }
    276 		  }
    277 #endif
    278 
    279 		  if(!find_file_hash(newname)) goto got_valid_name;
    280 		}
    281 	    }
    282 	}
    283 
    284       /*
    285        * If we fell off the bottom here, we were in real trouble.
    286        */
    287       fprintf(stderr,"Unable to  generate unique  name for file %s\n", s_entry->name);
    288       exit(1);
    289 
    290 got_valid_name:
    291       /*
    292        * OK, now we have a good replacement name.  Now decide which one
    293        * of these two beasts should get the name changed
    294        */
    295       if(s_entry->priority < s_entry1->priority)
    296 	{
    297 	  if( verbose > 0 )
    298 	    {
    299 	      fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,
    300 		      this_dir->whole_name, SPATH_SEPARATOR,
    301 		      s_entry->name, s_entry1->name);
    302 	    }
    303 	  s_entry->isorec.name_len[0] =  strlen(newname);
    304 	  new_reclen =  sizeof(struct iso_directory_record) -
    305 	    sizeof(s_entry->isorec.name) +
    306 	    strlen(newname);
    307 	  if(use_RockRidge)
    308 	    {
    309 	      if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
    310 	      new_reclen += s_entry->rr_attr_size;
    311 	    }
    312 	  if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
    313 	  s_entry->isorec.length[0] = new_reclen;
    314 	  strcpy(s_entry->isorec.name, newname);
    315 #ifdef APPLE_HYB
    316 	  /* has resource fork - needs new name */
    317 	  if (apple_both && s_entry->assoc) {
    318 	    struct directory_entry  *s_entry2 = s_entry->assoc;
    319 
    320 	    /* resource fork name *should* be the same as the data fork */
    321 	    s_entry2->isorec.name_len[0] = s_entry->isorec.name_len[0];
    322 	    strcpy(s_entry2->isorec.name, s_entry->isorec.name);
    323 	    s_entry2->isorec.length[0] = new_reclen;
    324 	  }
    325 #endif /* APPLE_HYB */
    326 	}
    327       else
    328 	{
    329 	  delete_file_hash(s_entry1);
    330 	  if( verbose > 0 )
    331 	    {
    332 	      fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,
    333 		      this_dir->whole_name, SPATH_SEPARATOR,
    334 		      s_entry1->name, s_entry->name);
    335 	    }
    336 	  s_entry1->isorec.name_len[0] =  strlen(newname);
    337 	  new_reclen =  sizeof(struct iso_directory_record) -
    338 	    sizeof(s_entry1->isorec.name) +
    339 	    strlen(newname);
    340 	  if(use_RockRidge)
    341 	    {
    342 	      if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
    343 	      new_reclen += s_entry1->rr_attr_size;
    344 	    }
    345 	  if (new_reclen & 1) new_reclen++;  /* Pad to an even byte */
    346 	  s_entry1->isorec.length[0] = new_reclen;
    347 	  strcpy(s_entry1->isorec.name, newname);
    348 	  add_file_hash(s_entry1);
    349 #ifdef APPLE_HYB
    350 	  /* has resource fork - needs new name */
    351 	  if (apple_both && s_entry1->assoc) {
    352 	    struct directory_entry  *s_entry2 = s_entry1->assoc;
    353 
    354 	    /* resource fork name *should* be the same as the data fork */
    355 	    s_entry2->isorec.name_len[0] = s_entry1->isorec.name_len[0];
    356 	    strcpy(s_entry2->isorec.name, s_entry1->isorec.name);
    357 	    s_entry2->isorec.length[0] = new_reclen;
    358 	  }
    359 #endif /* APPLE_HYB */
    360 	}
    361       add_file_hash(s_entry);
    362       s_entry = s_entry->next;
    363     }
    364 
    365   if(generate_tables
    366 #ifdef APPLE_HYB
    367      && !find_file_hash(trans_tbl)
    368 #else
    369      && !find_file_hash("TRANS.TBL")
    370 #endif /* APPLE_HYB */
    371      && (reloc_dir != this_dir)
    372      && (this_dir->extent == 0) )
    373     {
    374       /*
    375        * First we need to figure out how big this table is
    376        */
    377       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
    378 	{
    379 	  if(strcmp(s_entry->name, ".") == 0  ||
    380 	     strcmp(s_entry->name, "..") == 0) continue;
    381 #ifdef APPLE_HYB
    382 	  /* skip table entry for the resource fork */
    383 	  if(apple_both && (s_entry->isorec.flags[0] & ASSOC_FLAG))
    384 	     continue;
    385 #endif /* APPLE_HYB */
    386 	  if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue;
    387 	  if(s_entry->table) tablesize += 35 + strlen(s_entry->table);
    388 	}
    389     }
    390 
    391   if( tablesize > 0 )
    392     {
    393       table = (struct directory_entry *)
    394 	e_malloc(sizeof (struct directory_entry));
    395       memset(table, 0, sizeof(struct directory_entry));
    396       table->table = NULL;
    397       table->next = this_dir->contents;
    398       this_dir->contents = table;
    399 
    400       table->filedir = root;
    401       table->isorec.flags[0] = 0;
    402       table->priority  = 32768;
    403       iso9660_date(table->isorec.date, fstatbuf.st_mtime);
    404       table->inode = TABLE_INODE;
    405       table->dev = (dev_t) UNCACHED_DEVICE;
    406       set_723(table->isorec.volume_sequence_number, volume_sequence_number);
    407       set_733((char *) table->isorec.size, tablesize);
    408       table->size = tablesize;
    409       table->filedir = this_dir;
    410       if (jhide_trans_tbl)
    411          table->de_flags    |= INHIBIT_JOLIET_ENTRY;
    412       table->name = strdup("<translation table>");
    413       table->table = (char *) e_malloc(ROUND_UP(tablesize)+1);
    414       memset(table->table, 0, ROUND_UP(tablesize)+1);
    415 #ifdef APPLE_HYB
    416       iso9660_file_length  (trans_tbl, table, 0);
    417 #else
    418       iso9660_file_length  ("TRANS.TBL", table, 0);
    419 #endif /* APPLE_HYB */
    420 
    421       if(use_RockRidge)
    422 	{
    423 	  fstatbuf.st_mode = 0444 | S_IFREG;
    424 	  fstatbuf.st_nlink = 1;
    425 	  generate_rock_ridge_attributes("",
    426 #ifdef APPLE_HYB
    427 					 trans_tbl, table,
    428 #else
    429 					 "TRANS.TBL", table,
    430 #endif /* APPLE_HYB */
    431 					 &fstatbuf, &fstatbuf, 0);
    432 	}
    433     }
    434 
    435   /*
    436    * We have now chosen the 8.3 names and we should now know the length
    437    * of every entry in the directory.
    438    */
    439   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
    440     {
    441       /* skip if it's hidden */
    442       if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
    443 	{
    444 	  continue;
    445 	}
    446 
    447       new_reclen = strlen(s_entry->isorec.name);
    448 
    449       /*
    450        * First update the path table sizes for directories.
    451        */
    452       if(s_entry->isorec.flags[0] ==  2)
    453 	{
    454 	  if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
    455 	    {
    456 	      path_table_size += new_reclen + sizeof(struct iso_path_table) - 1;
    457 	      if (new_reclen & 1) path_table_size++;
    458 	    }
    459 	  else
    460 	    {
    461 	      new_reclen = 1;
    462 	      if (this_dir == root && strlen(s_entry->name) == 1)
    463 		{
    464 		  path_table_size += sizeof(struct iso_path_table);
    465 		}
    466 	    }
    467 	}
    468       if(path_table_size & 1) path_table_size++;  /* For odd lengths we pad */
    469       s_entry->isorec.name_len[0] = new_reclen;
    470 
    471       new_reclen +=
    472 	sizeof(struct iso_directory_record) -
    473 	sizeof(s_entry->isorec.name);
    474 
    475       if (new_reclen & 1)
    476 	new_reclen++;
    477 
    478       new_reclen += s_entry->rr_attr_size;
    479 
    480       if (new_reclen & 1) new_reclen++;
    481 
    482       if(new_reclen > 0xff)
    483 	{
    484 	  fprintf(stderr,"Fatal error - RR overflow for file %s\n",
    485 		  s_entry->name);
    486 	  exit(1);
    487 	}
    488       s_entry->isorec.length[0] = new_reclen;
    489     }
    490 
    491   status = sort_directory(&this_dir->contents);
    492   if( status > 0 )
    493     {
    494       fprintf(stderr, "Unable to sort directory %s\n",
    495 	      this_dir->whole_name);
    496     }
    497 
    498   /*
    499    * If we are filling out a TRANS.TBL, generate the entries that will
    500    * go in the thing.
    501    */
    502   if(table)
    503     {
    504       count = 0;
    505       for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
    506 	if(s_entry == table) continue;
    507 	if(!s_entry->table) continue;
    508 	if(strcmp(s_entry->name, ".") == 0  ||
    509 	   strcmp(s_entry->name, "..") == 0) continue;
    510 #ifdef APPLE_HYB
    511 	/* skip table entry for the resource fork */
    512 	if(apple_both && (s_entry->isorec.flags[0] & ASSOC_FLAG))
    513 	   continue;
    514 #endif /* APPLE_HYB */
    515 	if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue;
    516 	/*
    517 	 * Warning: we cannot use the return value of sprintf because
    518 	 * old BSD based sprintf() implementations will return
    519 	 * a pointer to the result instead of a count.
    520 	 */
    521 	sprintf(table->table + count, "%c %-34s%s",
    522 		s_entry->table[0],
    523 		s_entry->isorec.name, s_entry->table+1);
    524 	count += strlen(table->table + count);
    525 	free(s_entry->table);
    526 	s_entry->table = NULL;
    527       }
    528 
    529       if(count !=  tablesize)
    530 	{
    531 	  fprintf(stderr,"Translation table size mismatch %d %d\n",
    532 		  count, tablesize);
    533 	  exit(1);
    534 	}
    535     }
    536 
    537   /*
    538    * Now go through the directory and figure out how large this one will be.
    539    * Do not split a directory entry across a sector boundary
    540    */
    541   s_entry = this_dir->contents;
    542   this_dir->ce_bytes = 0;
    543   while(s_entry)
    544     {
    545       /* skip if it's hidden */
    546       if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
    547 	s_entry = s_entry->next;
    548 	continue;
    549       }
    550 
    551       new_reclen = s_entry->isorec.length[0];
    552       if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
    553 	this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
    554 	~(SECTOR_SIZE - 1);
    555       this_dir->size += new_reclen;
    556 
    557       /* See if continuation entries were used on disc */
    558       if(use_RockRidge &&
    559 	 s_entry->rr_attr_size != s_entry->total_rr_attr_size)
    560 	{
    561 	  unsigned char * pnt;
    562 	  int len;
    563 	  int nbytes;
    564 
    565 	  pnt = s_entry->rr_attributes;
    566 	  len = s_entry->total_rr_attr_size;
    567 
    568 	  /*
    569 	   * We make sure that each continuation entry record is not
    570 	   * split across sectors, but each file could in theory have more
    571 	   * than one CE, so we scan through and figure out what we need.
    572 	   */
    573 	  while(len > 3)
    574 	    {
    575 	      if(pnt[0] == 'C' && pnt[1] == 'E')
    576 		{
    577 		  nbytes = get_733((char *) pnt+20);
    578 
    579 		  if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
    580 		     SECTOR_SIZE) this_dir->ce_bytes =
    581 				    ROUND_UP(this_dir->ce_bytes);
    582 		  /* Now store the block in the ce buffer */
    583 		  this_dir->ce_bytes += nbytes;
    584 		  if(this_dir->ce_bytes & 1) this_dir->ce_bytes++;
    585 		}
    586 	      len -= pnt[2];
    587 	      pnt += pnt[2];
    588 	    }
    589 	}
    590       s_entry = s_entry->next;
    591     }
    592   return status;
    593 }
    594 
    595 static void generate_reloc_directory()
    596 {
    597 	time_t current_time;
    598 	struct directory_entry  *s_entry;
    599 
    600 	/* Create an  entry for our internal tree */
    601 	time (&current_time);
    602 	reloc_dir = (struct directory *)
    603 		e_malloc(sizeof(struct directory));
    604 	memset(reloc_dir, 0, sizeof(struct directory));
    605 	reloc_dir->parent = root;
    606 	reloc_dir->next = root->subdir;
    607 	root->subdir = reloc_dir;
    608 	reloc_dir->depth = 1;
    609 	if (hide_rr_moved) {
    610 		reloc_dir->whole_name = strdup("./.rr_moved");
    611 		reloc_dir->de_name = strdup(".rr_moved");
    612 	} else {
    613 		reloc_dir->whole_name = strdup("./rr_moved");
    614 		reloc_dir->de_name =  strdup("rr_moved");
    615 	}
    616 	reloc_dir->extent = 0;
    617 
    618 
    619 	/* Now create an actual directory  entry */
    620 	s_entry = (struct directory_entry *)
    621 		e_malloc(sizeof (struct directory_entry));
    622 	memset(s_entry, 0, sizeof(struct directory_entry));
    623 	s_entry->next = root->contents;
    624 	reloc_dir->self = s_entry;
    625 
    626 	/*
    627 	 * The rr_moved entry will not appear in the Joliet tree.
    628 	 */
    629 	reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
    630 	s_entry->de_flags    |= INHIBIT_JOLIET_ENTRY;
    631 
    632 	root->contents = s_entry;
    633 	root->contents->name = strdup(reloc_dir->de_name);
    634 	root->contents->filedir = root;
    635 	root->contents->isorec.flags[0] = 2;
    636 	root->contents->priority  = 32768;
    637 	iso9660_date(root->contents->isorec.date, current_time);
    638 	root->contents->inode = UNCACHED_INODE;
    639 	root->contents->dev = (dev_t) UNCACHED_DEVICE;
    640 	set_723(root->contents->isorec.volume_sequence_number, volume_sequence_number);
    641 	iso9660_file_length (reloc_dir->de_name, root->contents, 1);
    642 
    643 	if(use_RockRidge){
    644 		fstatbuf.st_mode = 0555 | S_IFDIR;
    645 		fstatbuf.st_nlink = 2;
    646 		generate_rock_ridge_attributes("",
    647 			hide_rr_moved ? ".rr_moved" : "rr_moved",
    648 			s_entry, &fstatbuf, &fstatbuf, 0);
    649 	};
    650 
    651 	/* Now create the . and .. entries in rr_moved */
    652 	/* Now create an actual directory  entry */
    653 	attach_dot_entries(reloc_dir, &root_statbuf);
    654 }
    655 
    656 /*
    657  * Function:		attach_dot_entries
    658  *
    659  * Purpose:		Create . and .. entries for a new directory.
    660  *
    661  * Notes:		Only used for artificial directories that
    662  *			we are creating.
    663  */
    664 static void FDECL2(attach_dot_entries, struct directory *, dirnode,
    665 		   struct stat *, parent_stat)
    666 {
    667 	struct directory_entry  *s_entry;
    668 	struct directory_entry  *orig_contents;
    669 	int deep_flag = 0;
    670 
    671 	init_fstatbuf();
    672 
    673 	orig_contents = dirnode->contents;
    674 
    675 	if( (dirnode->dir_flags & DIR_HAS_DOTDOT) == 0 )
    676 	  {
    677 	    s_entry = (struct directory_entry *)
    678 	      e_malloc(sizeof (struct directory_entry));
    679 	    memcpy(s_entry, dirnode->self,
    680 		   sizeof(struct directory_entry));
    681 #ifdef APPLE_HYB
    682 	    if (dirnode->self->hfs_ent) {
    683 	      s_entry->hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
    684 	      memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
    685 		     sizeof (hfsdirent));
    686             }
    687 #endif
    688 	    s_entry->name = strdup("..");
    689 	    s_entry->whole_name = NULL;
    690 	    s_entry->isorec.name_len[0] = 1;
    691 	    s_entry->isorec.flags[0] = 2; /* Mark as a directory */
    692 	    iso9660_file_length ("..", s_entry, 1);
    693 	    iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
    694 	    s_entry->filedir = dirnode->parent;
    695 
    696 	    dirnode->contents = s_entry;
    697 	    dirnode->contents->next = orig_contents;
    698 	    orig_contents = s_entry;
    699 
    700 	    if(use_RockRidge)
    701 	      {
    702 		if( parent_stat == NULL )
    703 		  {
    704 		    parent_stat = &fstatbuf;
    705 		  }
    706 		generate_rock_ridge_attributes("",
    707 					       "..", s_entry,
    708 					       parent_stat,
    709 					       parent_stat, 0);
    710 	      }
    711 	    dirnode->dir_flags |= DIR_HAS_DOTDOT;
    712 	  }
    713 
    714 	if( (dirnode->dir_flags & DIR_HAS_DOT) == 0 )
    715 	  {
    716 	    s_entry = (struct directory_entry *)
    717 	      e_malloc(sizeof (struct directory_entry));
    718 	    memcpy(s_entry, dirnode->self,
    719 		   sizeof(struct directory_entry));
    720 #ifdef APPLE_HYB
    721 	    if (dirnode->self->hfs_ent) {
    722 	      s_entry->hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
    723 	      memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
    724 		     sizeof (hfsdirent));
    725 	    }
    726 #endif
    727 	    s_entry->name = strdup(".");
    728 	    s_entry->whole_name = NULL;
    729 	    s_entry->isorec.name_len[0] = 1;
    730 	    s_entry->isorec.flags[0] = 2; /* Mark as a directory */
    731 	    iso9660_file_length (".", s_entry, 1);
    732 	    iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
    733 	    s_entry->filedir = dirnode;
    734 
    735 	    dirnode->contents = s_entry;
    736 	    dirnode->contents->next = orig_contents;
    737 
    738 	    if(use_RockRidge)
    739 	      {
    740 		fstatbuf.st_mode = 0555 | S_IFDIR;
    741 		fstatbuf.st_nlink = 2;
    742 
    743 		if( dirnode == root )
    744 		  {
    745 		    deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
    746 		  }
    747 
    748 		generate_rock_ridge_attributes("",
    749 					       ".", s_entry,
    750 					       &fstatbuf, &fstatbuf, deep_flag);
    751 	      }
    752 
    753 	    dirnode->dir_flags |= DIR_HAS_DOT;
    754 	  }
    755 
    756 }
    757 
    758 static void FDECL2(update_nlink, struct directory_entry *, s_entry, int, value)
    759 {
    760     unsigned char * pnt;
    761     int len;
    762 
    763     pnt = s_entry->rr_attributes;
    764     len = s_entry->total_rr_attr_size;
    765     while(len)
    766     {
    767 	if(pnt[0] == 'P' && pnt[1] == 'X')
    768 	{
    769 	    set_733((char *) pnt+12, value);
    770 	    break;
    771 	}
    772 	len -= pnt[2];
    773 	pnt += pnt[2];
    774     }
    775 }
    776 
    777 static void FDECL1(increment_nlink, struct directory_entry *, s_entry)
    778 {
    779     unsigned char * pnt;
    780     int len, nlink;
    781 
    782     pnt = s_entry->rr_attributes;
    783     len = s_entry->total_rr_attr_size;
    784     while(len)
    785     {
    786 	if(pnt[0] == 'P' && pnt[1] == 'X')
    787 	{
    788 	    nlink =  get_733((char *) pnt+12);
    789 	    set_733((char *) pnt+12, nlink+1);
    790 	    break;
    791 	}
    792 	len -= pnt[2];
    793 	pnt += pnt[2];
    794     }
    795 }
    796 
    797 void finish_cl_pl_entries(){
    798   struct directory_entry  *s_entry, *s_entry1;
    799   struct directory *  d_entry;
    800 
    801   /* if the reloc_dir is hidden (empty), then return */
    802   if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
    803     return;
    804 
    805   s_entry = reloc_dir->contents;
    806    s_entry  = s_entry->next->next;  /* Skip past . and .. */
    807   for(; s_entry; s_entry = s_entry->next){
    808 	  /* skip if it's hidden */
    809 	  if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
    810 	    continue;
    811 	  }
    812 	  d_entry = reloc_dir->subdir;
    813 	  while(d_entry){
    814 		  if(d_entry->self == s_entry) break;
    815 		  d_entry = d_entry->next;
    816 	  };
    817 	  if(!d_entry){
    818 		  fprintf(stderr,"Unable to locate directory parent\n");
    819 		  exit(1);
    820 	  };
    821 
    822 	  /* First fix the PL pointer in the directory in the rr_reloc dir */
    823 	  s_entry1 = d_entry->contents->next;
    824 	  set_733((char *) s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
    825 		  s_entry->filedir->extent);
    826 
    827 	  /* Now fix the CL pointer */
    828 	  s_entry1 = s_entry->parent_rec;
    829 
    830 	  set_733((char *) s_entry1->rr_attributes +  s_entry1->total_rr_attr_size - 8,
    831 		  d_entry->extent);
    832 
    833 	  s_entry->filedir = reloc_dir;  /* Now we can fix this */
    834   }
    835   /* Next we need to modify the NLINK terms in the assorted root directory records
    836      to account for the presence of the RR_MOVED directory */
    837 
    838   increment_nlink(root->self);
    839   increment_nlink(root->self->next);
    840   d_entry = root->subdir;
    841   while(d_entry){
    842     increment_nlink(d_entry->contents->next);
    843     d_entry = d_entry->next;
    844   };
    845 }
    846 
    847 /*
    848  * Function:		scan_directory_tree
    849  *
    850  * Purpose:		Walk through a directory on the local machine
    851  *			filter those things we don't want to include
    852  *			and build our representation of a dir.
    853  *
    854  * Notes:
    855  */
    856 int
    857 FDECL3(scan_directory_tree,struct directory *, this_dir,
    858        char *, path,
    859        struct directory_entry *, de)
    860 {
    861   DIR				* current_dir;
    862   char				  whole_path[1024];
    863   struct dirent			* d_entry;
    864   struct directory		* parent;
    865   int				  dflag;
    866   char				* old_path;
    867 
    868     if (verbose > 1)
    869     {
    870       fprintf(stderr, "Scanning %s\n", path);
    871     }
    872 
    873   current_dir = opendir(path);
    874   d_entry = NULL;
    875 
    876   /* Apparently NFS sometimes allows you to open the directory, but
    877      then refuses to allow you to read the contents.  Allow for this */
    878 
    879   old_path = path;
    880 
    881   if(current_dir) d_entry = readdir(current_dir);
    882 
    883   if(!current_dir || !d_entry)
    884     {
    885       fprintf(stderr,"Unable to open directory %s\n", path);
    886       de->isorec.flags[0] &= ~2; /* Mark as not a directory */
    887       if(current_dir) closedir(current_dir);
    888       return 0;
    889     }
    890 
    891   parent = de->filedir;
    892   /* Set up the struct for the current directory, and insert it into the
    893      tree */
    894 
    895 #ifdef VMS
    896   vms_path_fixup(path);
    897 #endif
    898 
    899   /*
    900    * if entry for this sub-directory is hidden, then hide this directory
    901    */
    902   if (de->de_flags & INHIBIT_ISO9660_ENTRY)
    903     this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
    904 
    905   if (de->de_flags & INHIBIT_JOLIET_ENTRY)
    906     this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
    907 
    908   /*
    909    * Now we scan the directory itself, and look at what is inside of it.
    910    */
    911   dflag = 0;
    912   while(1==1){
    913 
    914     /* The first time through, skip this, since we already asked for
    915        the first entry when we opened the directory. */
    916     if(dflag) d_entry = readdir(current_dir);
    917     dflag++;
    918 
    919     if(!d_entry) break;
    920 
    921     /* OK, got a valid entry */
    922 
    923     /* If we do not want all files, then pitch the backups. */
    924     if(!all_files){
    925 	    if(   strchr(d_entry->d_name,'~')
    926 	       || strchr(d_entry->d_name,'#'))
    927 	      {
    928 		if( verbose > 0 )
    929 		  {
    930 		    fprintf(stderr, "Ignoring file %s\n", d_entry->d_name);
    931 		  }
    932 		continue;
    933 	      }
    934     }
    935 
    936 #ifdef APPLE_HYB
    937     if (apple_both) {
    938       /* exclude certain HFS type files/directories for the time being */
    939       if (hfs_exclude(d_entry->d_name))
    940 	continue;
    941     }
    942 #endif /* APPLE_HYB */
    943 
    944     if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
    945       fprintf(stderr, "Overflow of stat buffer\n");
    946       exit(1);
    947     };
    948 
    949     /* Generate the complete ASCII path for this file */
    950     strcpy(whole_path, path);
    951 #ifndef VMS
    952     if(whole_path[strlen(whole_path)-1] != '/')
    953       strcat(whole_path, "/");
    954 #endif
    955     strcat(whole_path, d_entry->d_name);
    956 
    957     /** Should we exclude this file ? */
    958     if (matches(d_entry->d_name) || matches(whole_path)) {
    959       if (verbose > 1) {
    960 	fprintf(stderr, "Excluded by match: %s\n", whole_path);
    961       }
    962       continue;
    963     }
    964 
    965     if(    generate_tables
    966 #ifdef APPLE_HYB
    967 	&& strcmp(d_entry->d_name, trans_tbl) == 0 )
    968 #else
    969 	&& strcmp(d_entry->d_name, "TRANS.TBL") == 0 )
    970 #endif /* APPLE_HYB */
    971       {
    972 	/*
    973 	 * Ignore this entry.  We are going to be generating new
    974 	 * versions of these files, and we need to ignore any
    975 	 * originals that we might have found.
    976 	 */
    977 	if (verbose > 1)
    978 	  {
    979 	    fprintf(stderr, "Excluded: %s\n",whole_path);
    980 	  }
    981 	continue;
    982       }
    983 
    984     /*
    985      * If we already have a '.' or a '..' entry, then don't
    986      * insert new ones.
    987      */
    988     if( strcmp(d_entry->d_name, ".") == 0
    989 	&& this_dir->dir_flags & DIR_HAS_DOT )
    990       {
    991 	continue;
    992       }
    993 
    994     if( strcmp(d_entry->d_name, "..") == 0
    995 	&& this_dir->dir_flags & DIR_HAS_DOTDOT )
    996       {
    997 	continue;
    998       }
    999 
   1000 #if 0
   1001     if (verbose > 1)  fprintf(stderr, "%s\n",whole_path);
   1002 #endif
   1003     /*
   1004      * This actually adds the entry to the directory in question.
   1005      */
   1006 #ifdef APPLE_HYB
   1007     insert_file_entry(this_dir, whole_path, d_entry->d_name, 0);
   1008 #else
   1009     insert_file_entry(this_dir, whole_path, d_entry->d_name);
   1010 #endif /* APPLE_HYB */
   1011   }
   1012   closedir(current_dir);
   1013 
   1014 #ifdef APPLE_HYB
   1015   /* if we cached the HFS info stuff for this directory, then delete it */
   1016   if (this_dir->hfs_info) {
   1017     del_hfs_info(this_dir->hfs_info);
   1018     this_dir->hfs_info = 0;
   1019   }
   1020 #endif /* APPLE_HYB */
   1021 
   1022   return 1;
   1023 }
   1024 
   1025 
   1026 /*
   1027  * Function:		insert_file_entry
   1028  *
   1029  * Purpose:		Insert one entry into our directory node.
   1030  *
   1031  * Note:
   1032  * This function inserts a single entry into the directory.  It
   1033  * is assumed that all filtering and decision making regarding what
   1034  * we want to include has already been made, so the purpose of this
   1035  * is to insert one entry (file, link, dir, etc), into this directory.
   1036  * Note that if the entry is a dir (or if we are following links,
   1037  * and the thing it points to is a dir), then we will scan those
   1038  * trees before we return.
   1039  */
   1040 #ifdef APPLE_HYB
   1041 int
   1042 FDECL4(insert_file_entry,struct directory *, this_dir,
   1043        char *, whole_path,
   1044        char *, short_name,
   1045        int, have_rsrc)
   1046 #else
   1047 int
   1048 FDECL3(insert_file_entry,struct directory *, this_dir,
   1049        char *, whole_path,
   1050        char *, short_name)
   1051 #endif /* APPLE_HYB */
   1052 {
   1053   struct stat			  statbuf, lstatbuf;
   1054   struct directory_entry	* s_entry, *s_entry1;
   1055   int				  lstatus;
   1056   int				  status;
   1057   int				  deep_flag;
   1058 #ifdef APPLE_HYB
   1059   int				  x_hfs = 0;
   1060   int				  htype = 0;
   1061 #endif /* APPLE_HYB */
   1062 
   1063   status = stat_filter(whole_path, &statbuf);
   1064 
   1065   lstatus = lstat_filter(whole_path, &lstatbuf);
   1066 
   1067   if( (status == -1) && (lstatus == -1) )
   1068     {
   1069       /*
   1070        * This means that the file doesn't exist, or isn't accessible.
   1071        * Sometimes this is because of NFS permissions problems.
   1072        */
   1073       fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path);
   1074       return 0;
   1075     }
   1076 
   1077   if(this_dir == root && strcmp(short_name, ".") == 0)
   1078     root_statbuf = statbuf;  /* Save this for later on */
   1079 
   1080   /* We do this to make sure that the root entries are consistent */
   1081   if(this_dir == root && strcmp(short_name, "..") == 0)
   1082     {
   1083       statbuf = root_statbuf;
   1084       lstatbuf = root_statbuf;
   1085     }
   1086 
   1087   if(S_ISLNK(lstatbuf.st_mode))
   1088     {
   1089 
   1090       /* Here we decide how to handle the symbolic links.  Here
   1091 	 we handle the general case - if we are not following
   1092 	 links or there is an error, then we must change
   1093 	 something.  If RR is in use, it is easy, we let RR
   1094 	 describe the file.  If not, then we punt the file. */
   1095 
   1096       if((status || !follow_links))
   1097 	{
   1098 	  if(use_RockRidge)
   1099 	    {
   1100 	      status = 0;
   1101 	      statbuf.st_size = 0;
   1102 	      STAT_INODE(statbuf) = UNCACHED_INODE;
   1103 	      statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
   1104 	      statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
   1105 	    } else {
   1106 	      if(follow_links)
   1107 		{
   1108 		  fprintf(stderr,
   1109 			  "Unable to stat file %s - ignoring and continuing.\n",
   1110 			  whole_path);
   1111 		}
   1112 	      else
   1113 		{
   1114 		  fprintf(stderr,
   1115 			  "Symlink %s ignored - continuing.\n",
   1116 			  whole_path);
   1117 		  return 0;  /* Non Rock Ridge discs - ignore all symlinks */
   1118 		}
   1119 	    }
   1120 	}
   1121 
   1122       /* Here we handle a different kind of case.  Here we have
   1123 	 a symlink, but we want to follow symlinks.  If we run
   1124 	 across a directory loop, then we need to pretend that
   1125 	 we are not following symlinks for this file.  If this
   1126 	 is the first time we have seen this, then make this
   1127 	 seem as if there was no symlink there in the first
   1128 	 place */
   1129 
   1130       if( follow_links
   1131 	  && S_ISDIR(statbuf.st_mode) )
   1132 	{
   1133 	  if(   strcmp(short_name, ".")
   1134 		&& strcmp(short_name, "..") )
   1135 	    {
   1136 	      if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
   1137 		{
   1138 		  if(!use_RockRidge)
   1139 		    {
   1140 		      fprintf(stderr, "Already cached directory seen (%s)\n",
   1141 			      whole_path);
   1142 		      return 0;
   1143 		    }
   1144 		  statbuf.st_size = 0;
   1145 		  STAT_INODE(statbuf) = UNCACHED_INODE;
   1146 		  statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
   1147 		  statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
   1148 		}
   1149 	      else
   1150 		{
   1151 		  lstatbuf = statbuf;
   1152 		  add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
   1153 		}
   1154 	    }
   1155 	}
   1156 
   1157       /*
   1158        * For non-directories, we just copy the stat information over
   1159        * so we correctly include this file.
   1160        */
   1161       if( follow_links
   1162 	  && !S_ISDIR(statbuf.st_mode) )
   1163 	{
   1164 	  lstatbuf = statbuf;
   1165 	}
   1166     }
   1167 
   1168   /*
   1169    * Add directories to the cache so that we don't waste space even
   1170    * if we are supposed to be following symlinks.
   1171    */
   1172   if( follow_links
   1173       && strcmp(short_name, ".")
   1174       && strcmp(short_name, "..")
   1175       && S_ISDIR(statbuf.st_mode) )
   1176     {
   1177       add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
   1178     }
   1179 #ifdef VMS
   1180   if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
   1181 				    statbuf.st_fab_rfm != FAB$C_STMLF)) {
   1182     fprintf(stderr,"Warning - file %s has an unsupported VMS record"
   1183 	    " format (%d)\n",
   1184 	    whole_path, statbuf.st_fab_rfm);
   1185   }
   1186 #endif
   1187 
   1188   if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK)))
   1189     {
   1190       fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n",
   1191 	      whole_path, errno);
   1192       return 0;
   1193     }
   1194 
   1195   /* Add this so that we can detect directory loops with hard links.
   1196      If we are set up to follow symlinks, then we skip this checking. */
   1197   if(   !follow_links
   1198 	&& S_ISDIR(lstatbuf.st_mode)
   1199 	&& strcmp(short_name, ".")
   1200 	&& strcmp(short_name, "..") )
   1201     {
   1202       if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
   1203 #ifdef APPLE_HYB
   1204 	/* NON-HFS change - print just a warning *if* this ever happens */
   1205 	fprintf(stderr,"Warning: Directory loop (%s)\n", whole_path);
   1206 #else
   1207 	fprintf(stderr,"Directory loop - fatal goof (%s %lx %llu).\n",
   1208 		whole_path, (unsigned long) statbuf.st_dev,
   1209 		(unsigned long long) STAT_INODE(statbuf));
   1210 	exit(1);
   1211 #endif
   1212       }
   1213       add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
   1214     }
   1215 
   1216   if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
   1217       !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode)
   1218       && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
   1219       !S_ISDIR(lstatbuf.st_mode)) {
   1220     fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n",
   1221 	    whole_path);
   1222     return 0;
   1223   }
   1224 
   1225   /* Who knows what trash this is - ignore and continue */
   1226 
   1227   if(status)
   1228     {
   1229       fprintf(stderr,
   1230 	      "Unable to stat file %s - ignoring and continuing.\n",
   1231 	      whole_path);
   1232       return 0;
   1233     }
   1234 
   1235   /*
   1236    * Check to see if we have already seen this directory node.
   1237    * If so, then we don't create a new entry for it, but we do want
   1238    * to recurse beneath it and add any new files we do find.
   1239    */
   1240   if (S_ISDIR(statbuf.st_mode))
   1241     {
   1242       int dflag;
   1243 
   1244       for( s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
   1245 	{
   1246 	  if( strcmp(s_entry->name, short_name) == 0 )
   1247 	    {
   1248 	      break;
   1249 	    }
   1250 	}
   1251       if ( s_entry != NULL
   1252 	   && strcmp(short_name,".")
   1253 	   && strcmp(short_name,".."))
   1254 	{
   1255 	  struct directory * child;
   1256 
   1257 	  if ( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0)
   1258 	    {
   1259 	      for( s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next)
   1260 		{
   1261 		  if( strcmp(s_entry->name, short_name) == 0 )
   1262 		    {
   1263 		      break;
   1264 		    }
   1265 		}
   1266 	      child = find_or_create_directory(reloc_dir, whole_path,
   1267 					       s_entry, 1);
   1268 	    }
   1269 	  else
   1270 	    {
   1271 	      child = find_or_create_directory(this_dir, whole_path,
   1272 					       s_entry, 1);
   1273 	      /* If unable to scan directory, mark this as a non-directory */
   1274 	    }
   1275 	  dflag = scan_directory_tree(child, whole_path, s_entry);
   1276 	  if(!dflag)
   1277 	    {
   1278 	      lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
   1279 	    }
   1280 	  return 0;
   1281 	}
   1282     }
   1283 #ifdef APPLE_HYB
   1284     /* Should we exclude this HFS file ? - only works with -hfs */
   1285     if (!have_rsrc && apple_hyb && strcmp(short_name,".") && strcmp(short_name,"..")) {
   1286       x_hfs = hfs_matches(short_name) || hfs_matches(whole_path);
   1287       if (x_hfs) {
   1288 	if (verbose > 1) {
   1289 	  fprintf(stderr, "Hidden from HFS tree: %s\n", whole_path);
   1290 	}
   1291       }
   1292     }
   1293 
   1294     /* check we are a file, using Apple extensions and have a .resource part
   1295 	and not excluded */
   1296     if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
   1297       char	rsrc_path[1024];	/* rsrc fork filename */
   1298 
   1299       /* construct the resource full path */
   1300       htype = get_hfs_rname(whole_path, short_name, rsrc_path);
   1301       /* check we can read the resouce fork */
   1302       if (htype) {
   1303 	struct stat	rstatbuf, rlstatbuf;
   1304 
   1305 	/* some further checks on the file */
   1306 	status = stat_filter(rsrc_path, &rstatbuf);
   1307 
   1308 	lstatus = lstat_filter(rsrc_path, &rlstatbuf);
   1309 
   1310 	if(!status && !lstatus && S_ISREG(rstatbuf.st_mode) && rstatbuf.st_size > 0) {
   1311 	  /* have a resource file - insert it into the current directory
   1312 	     but flag that we have a resource fork */
   1313 	  insert_file_entry(this_dir, rsrc_path, short_name, htype);
   1314 	}
   1315       }
   1316     }
   1317 #endif /* APPLE_HYB */
   1318 
   1319   s_entry = (struct directory_entry *)
   1320     e_malloc(sizeof (struct directory_entry));
   1321   /* memset the whole struct, not just the isorec.extent part JCP */
   1322   memset(s_entry, 0, sizeof (struct directory_entry));
   1323   s_entry->next = this_dir->contents;
   1324 /*memset(s_entry->isorec.extent, 0, 8); */
   1325   this_dir->contents = s_entry;
   1326   deep_flag = 0;
   1327   s_entry->table = NULL;
   1328 
   1329   s_entry->name = strdup(short_name);
   1330   s_entry->whole_name = strdup (whole_path);
   1331 
   1332   s_entry->de_flags = 0;
   1333 
   1334   /*
   1335    * If the current directory is hidden, then hide all it's members
   1336    * otherwise check if this entry needs to be hidden as well */
   1337   if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
   1338     s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
   1339   }
   1340   else if (strcmp(short_name,".") && strcmp(short_name,"..")) {
   1341     if (i_matches(short_name) || i_matches(whole_path)) {
   1342       if (verbose > 1) {
   1343 	fprintf(stderr, "Hidden from ISO9660 tree: %s\n", whole_path);
   1344       }
   1345       s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
   1346     }
   1347   }
   1348 
   1349   if (this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
   1350     s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
   1351   }
   1352   else if (strcmp(short_name,".") && strcmp(short_name,"..")) {
   1353     if (j_matches(short_name) || j_matches(whole_path)) {
   1354       if (verbose > 1) {
   1355 	fprintf(stderr, "Hidden from Joliet tree: %s\n", whole_path);
   1356       }
   1357       s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
   1358     }
   1359   }
   1360 
   1361   s_entry->filedir = this_dir;
   1362   s_entry->isorec.flags[0] = 0;
   1363   s_entry->isorec.ext_attr_length[0] = 0;
   1364   iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
   1365   s_entry->isorec.file_unit_size[0] = 0;
   1366   s_entry->isorec.interleave[0] = 0;
   1367 
   1368 #ifdef APPLE_HYB
   1369   if (apple_both && !x_hfs) {
   1370     s_entry->hfs_ent = NULL;
   1371     s_entry->assoc = NULL;
   1372     s_entry->hfs_off = 0;
   1373     s_entry->hfs_type = htype;
   1374     if (have_rsrc) {
   1375       s_entry->isorec.flags[0] = ASSOC_FLAG;	/* associated (rsrc) file */
   1376       /* set the type of HFS file */
   1377       s_entry->hfs_type = have_rsrc;
   1378       /* don't want the rsrc file to be included in any Joliet tree */
   1379       s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
   1380     }
   1381     else if (s_entry->next) {
   1382       /* if previous entry is an associated file, then "link" it
   1383 	 to this file i.e. we have a data/resource pair */
   1384       if (s_entry->next->isorec.flags[0] & ASSOC_FLAG) {
   1385 	s_entry->assoc = s_entry->next;
   1386 	/* share the same HFS parameters */
   1387 	s_entry->hfs_ent = s_entry->next->hfs_ent;
   1388 	s_entry->hfs_type = s_entry->next->hfs_type;
   1389       }
   1390     }
   1391     /* allocate HFS entry if required */
   1392     if (apple_both && strcmp(short_name, ".") && strcmp(short_name, "..")) {
   1393       if (!s_entry->hfs_ent) {
   1394 	hfsdirent *hfs_ent;
   1395 	hfs_ent = (hfsdirent *)e_malloc(sizeof(hfsdirent));
   1396 
   1397 	/* fill in the defaults */
   1398 	hfs_ent->flags = hfs_ent->fdflags = 0;
   1399 	hfs_ent->crdate = lstatbuf.st_ctime;
   1400 	hfs_ent->mddate = lstatbuf.st_mtime;
   1401 	hfs_ent->dsize = hfs_ent->rsize = 0;
   1402 	s_entry->hfs_ent = hfs_ent;
   1403       }
   1404       if (have_rsrc)
   1405 	/* set rsrc size */
   1406 	s_entry->hfs_ent->rsize = lstatbuf.st_size;
   1407       else
   1408 	/* set data size */
   1409 	s_entry->hfs_ent->dsize = lstatbuf.st_size;
   1410     }
   1411   }
   1412 #endif /* APPLE_HYB */
   1413 
   1414   if( strcmp(short_name,  ".") == 0)
   1415     {
   1416       this_dir->dir_flags |= DIR_HAS_DOT;
   1417     }
   1418 
   1419   if( strcmp(short_name,  "..") == 0)
   1420     {
   1421       this_dir->dir_flags |= DIR_HAS_DOTDOT;
   1422     }
   1423 
   1424   if(   this_dir->parent
   1425      && this_dir->parent == reloc_dir
   1426      && strcmp(short_name,  "..") == 0)
   1427     {
   1428       s_entry->inode = UNCACHED_INODE;
   1429       s_entry->dev = (dev_t) UNCACHED_DEVICE;
   1430       deep_flag  = NEED_PL;
   1431     }
   1432   else
   1433 #ifdef APPLE_HYB
   1434     if (have_rsrc) {
   1435       /* don't want rsrc files to be cached */
   1436       s_entry->inode = UNCACHED_INODE;
   1437       s_entry->dev = (dev_t) UNCACHED_DEVICE;
   1438     }
   1439   else
   1440 #endif /* APPLE_HYB */
   1441     {
   1442       s_entry->inode = STAT_INODE(statbuf);
   1443       s_entry->dev = statbuf.st_dev;
   1444     }
   1445   set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number);
   1446   iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
   1447   s_entry->rr_attr_size = 0;
   1448   s_entry->total_rr_attr_size = 0;
   1449   s_entry->rr_attributes = NULL;
   1450 
   1451   /* Directories are assigned sizes later on */
   1452   if (!S_ISDIR(statbuf.st_mode))
   1453     {
   1454       if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
   1455 	  S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode)
   1456 	  || S_ISLNK(lstatbuf.st_mode))
   1457 	{
   1458 	  s_entry->size = 0;
   1459 	  statbuf.st_size = 0;
   1460 	}
   1461       else
   1462 	{
   1463 	  s_entry->size = statbuf.st_size;
   1464 	}
   1465 
   1466       set_733((char *) s_entry->isorec.size, statbuf.st_size);
   1467     }
   1468   else
   1469     {
   1470       s_entry->isorec.flags[0] = 2;
   1471     }
   1472 #ifdef APPLE_HYB
   1473   /* if the directory is HFS excluded, then we don't have an hfs_ent */
   1474   if (apple_both && s_entry->hfs_ent && s_entry->isorec.flags[0] & 2) {
   1475     /* get the Mac directory name */
   1476     get_hfs_dir(whole_path, short_name, s_entry);
   1477 
   1478     /* if required, set ISO directory name from HFS name */
   1479     if (mac_name)
   1480       iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
   1481   }
   1482 #endif /* APPLE_HYB */
   1483 
   1484   if (strcmp(short_name,".") && strcmp(short_name,"..") &&
   1485       S_ISDIR(statbuf.st_mode) && this_dir->depth >  RR_relocation_depth)
   1486     {
   1487       struct directory * child;
   1488 
   1489       if(!reloc_dir) generate_reloc_directory();
   1490 
   1491       /*
   1492        * Replicate the entry for this directory.  The old one will stay where it
   1493        * is, and it will be neutered so that it no longer looks like a directory.
   1494        * The new one will look like a directory, and it will be put in the reloc_dir.
   1495        */
   1496       s_entry1 = (struct directory_entry *)
   1497 	e_malloc(sizeof (struct directory_entry));
   1498       memcpy(s_entry1, s_entry,  sizeof(struct directory_entry));
   1499       s_entry1->table = NULL;
   1500       s_entry1->name = strdup(this_dir->contents->name);
   1501       s_entry1->whole_name = strdup(this_dir->contents->whole_name);
   1502       s_entry1->next = reloc_dir->contents;
   1503       reloc_dir->contents = s_entry1;
   1504       s_entry1->priority  =  32768;
   1505       s_entry1->parent_rec = this_dir->contents;
   1506 
   1507       deep_flag = NEED_RE;
   1508 
   1509       if(use_RockRidge)
   1510 	{
   1511 	  generate_rock_ridge_attributes(whole_path,
   1512 					 short_name, s_entry1,
   1513 					 &statbuf, &lstatbuf, deep_flag);
   1514 	}
   1515 
   1516       deep_flag = 0;
   1517 
   1518       /* We need to set this temporarily so that the parent to this
   1519 	 is correctly determined. */
   1520       s_entry1->filedir = reloc_dir;
   1521       child = find_or_create_directory(reloc_dir, whole_path,
   1522 				       s_entry1, 0);
   1523       scan_directory_tree(child, whole_path, s_entry1);
   1524       s_entry1->filedir = this_dir;
   1525 
   1526       statbuf.st_size = 0;
   1527       statbuf.st_mode &= 0777;
   1528       set_733((char *) s_entry->isorec.size, 0);
   1529       s_entry->size = 0;
   1530       s_entry->isorec.flags[0] = 0;
   1531       s_entry->inode = UNCACHED_INODE;
   1532       s_entry->de_flags |= RELOCATED_DIRECTORY;
   1533       deep_flag = NEED_CL;
   1534     }
   1535 
   1536   if(generate_tables
   1537      && strcmp(s_entry->name, ".")
   1538      && strcmp(s_entry->name, ".."))
   1539     {
   1540       char  buffer[2048];
   1541       int nchar;
   1542       switch(lstatbuf.st_mode & S_IFMT)
   1543 	{
   1544 	case S_IFDIR:
   1545 	  snprintf(buffer, sizeof buffer, "D\t%s\n",
   1546 		  s_entry->name);
   1547 	  break;
   1548 #ifdef S_IFBLK
   1549 /* extra for WIN32 - if it doesn't have the major/minor defined, then
   1550    S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
   1551    code similar to that in rock.c */
   1552 
   1553 /* for some reason, MAJOR_IN_SYSMACROS isn't defined on a SunOS when
   1554    it should be, so see if major() is defined instead  */
   1555 /*
   1556 #if !(defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV))
   1557 */
   1558 #ifndef major
   1559 #define major(dev) (sizeof(dev_t) <= 2 ? ((dev) >> 8) : \
   1560 	(sizeof(dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
   1561 	(((dev) >> 16) >> 16)))
   1562 #define minor(dev) (sizeof(dev_t) <= 2 ? (dev) & 0xff : \
   1563 	(sizeof(dev_t) <= 4 ? (dev) & 0xffff : \
   1564 	(dev) & 0xffffffff))
   1565 #endif
   1566 	case S_IFBLK:
   1567 	  snprintf(buffer, sizeof buffer, "B\t%s\t%lu %lu\n",
   1568 		  s_entry->name,
   1569 		  (unsigned long) major(statbuf.st_rdev),
   1570 		  (unsigned long) minor(statbuf.st_rdev));
   1571 	  break;
   1572 #endif
   1573 #ifdef S_IFIFO
   1574 	case S_IFIFO:
   1575 	  snprintf(buffer, sizeof buffer, "P\t%s\n",
   1576 		  s_entry->name);
   1577 	  break;
   1578 #endif
   1579 #ifdef S_IFCHR
   1580 	case S_IFCHR:
   1581 	  snprintf(buffer, sizeof buffer, "C\t%s\t%lu %lu\n",
   1582 		  s_entry->name,
   1583 		  (unsigned long) major(statbuf.st_rdev),
   1584 		  (unsigned long) minor(statbuf.st_rdev));
   1585 	  break;
   1586 #endif
   1587 #ifdef S_IFLNK
   1588 	case S_IFLNK:
   1589 	  nchar = readlink(whole_path,
   1590 			   (char *)symlink_buff,
   1591 			   sizeof(symlink_buff)-1);
   1592 	  symlink_buff[nchar < 0 ? 0 : nchar] = 0;
   1593 	  snprintf(buffer, sizeof buffer, "L\t%s\t%s\n",
   1594 		  s_entry->name, symlink_buff);
   1595 	  break;
   1596 #endif
   1597 #ifdef S_IFSOCK
   1598 	case S_IFSOCK:
   1599 	  snprintf(buffer, sizeof buffer, "S\t%s\n",
   1600 		  s_entry->name);
   1601 	  break;
   1602 #endif
   1603 	case S_IFREG:
   1604 	default:
   1605 	  snprintf(buffer, sizeof buffer, "F\t%s\n",
   1606 		  s_entry->name);
   1607 	  break;
   1608 	};
   1609       s_entry->table = strdup(buffer);
   1610     }
   1611 
   1612   if(S_ISDIR(statbuf.st_mode))
   1613     {
   1614       int dflag;
   1615       if (strcmp(short_name,".") && strcmp(short_name,".."))
   1616 	{
   1617 	  struct directory * child;
   1618 
   1619 	  child = find_or_create_directory(this_dir, whole_path,
   1620 					   s_entry, 1);
   1621 	  dflag = scan_directory_tree(child, whole_path, s_entry);
   1622 
   1623 	  if(!dflag)
   1624 	    {
   1625 	      lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
   1626 	      if( child->contents == NULL )
   1627 		{
   1628 		  delete_directory(this_dir, child);
   1629 		}
   1630 	    }
   1631 	}
   1632       /* If unable to scan directory, mark this as a non-directory */
   1633     }
   1634 
   1635   if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")  == 0)
   1636     {
   1637       deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
   1638     }
   1639 
   1640   /* Now figure out how much room this file will take in the
   1641      directory */
   1642 
   1643 #ifdef APPLE_HYB
   1644     /* if the file is HFS excluded, then we don't have an hfs_ent */
   1645     if (apple_both && !have_rsrc && s_entry->hfs_ent) {
   1646       if (S_ISREG(lstatbuf.st_mode)) {	/* it's a regular file */
   1647 
   1648 	/* fill in the rest of the HFS entry */
   1649 	get_hfs_info(whole_path, short_name, s_entry);
   1650 
   1651 	/* if required, set ISO directory name from HFS name */
   1652 	if (mac_name)
   1653 	  iso9660_file_length(s_entry->hfs_ent->name, s_entry, 0);
   1654 
   1655 	/* print details about the HFS file */
   1656 	if (verbose > 2)
   1657 	  print_hfs_info(s_entry);
   1658 
   1659 	/* copy the new ISO9660 name to the rsrc fork - if it exists */
   1660 	if (s_entry->assoc)
   1661 	  strcpy(s_entry->assoc->isorec.name, s_entry->isorec.name);
   1662 
   1663 	/* we can't handle hard links in the hybrid case, so we "uncache"
   1664 	   the file. The downside to this is that hard linked files
   1665 	   are added to the output image more than once (we've already
   1666 	   done this for rsrc files) */
   1667 	if (apple_hyb) {
   1668 	  s_entry->inode = UNCACHED_INODE;
   1669 	  s_entry->dev = (dev_t) UNCACHED_DEVICE;
   1670 	}
   1671       }
   1672       else if (!(s_entry->isorec.flags[0] & 2)) { /* not a directory .. */
   1673 
   1674 	/* no mac equivalent, so ignore - have to be careful here, the
   1675 	   hfs_ent may be also be for a relocated directory */
   1676 	if (s_entry->hfs_ent && !(s_entry->de_flags & RELOCATED_DIRECTORY))
   1677 	    free(s_entry->hfs_ent);
   1678 	s_entry->hfs_ent = NULL;
   1679       }
   1680 
   1681       /* if the rsrc size is zero, then we don't need the entry, so we
   1682 	 might as well delete it - this will only happen if we didn't
   1683 	 know the rsrc size from the rsrc file size */
   1684       if(s_entry->assoc && s_entry->assoc->size == 0)
   1685 	 delete_rsrc_ent(s_entry);
   1686     }
   1687 
   1688     if(apple_ext && s_entry->assoc) {
   1689 	/* need Apple extensions for the resource fork as well */
   1690 	generate_rock_ridge_attributes(whole_path,
   1691 					   short_name, s_entry->assoc,
   1692 					   &statbuf, &lstatbuf, deep_flag);
   1693     }
   1694     /* leave out resource fork for the time being */
   1695     if (use_RockRidge && !have_rsrc) {
   1696 #else
   1697     if(use_RockRidge)
   1698     {
   1699 #endif /* APPLE_HYB */
   1700       generate_rock_ridge_attributes(whole_path,
   1701 				     short_name, s_entry,
   1702 				     &statbuf, &lstatbuf, deep_flag);
   1703 
   1704     }
   1705 
   1706   return 1;
   1707 }
   1708 
   1709 
   1710 void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
   1711   struct directory * dpnt;
   1712 
   1713   dpnt = node;
   1714 
   1715   while (dpnt){
   1716     if( dpnt->extent > session_start )
   1717       {
   1718 	generate_one_directory(dpnt, outfile);
   1719       }
   1720     if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
   1721     dpnt = dpnt->next;
   1722   }
   1723 }
   1724 
   1725 /*
   1726  * Function:	find_or_create_directory
   1727  *
   1728  * Purpose:	Locate a directory entry in the tree, create if needed.
   1729  *
   1730  * Arguments:
   1731  */
   1732 struct directory * FDECL4(find_or_create_directory, struct directory *, parent,
   1733 			  const char *, path,
   1734 			  struct directory_entry *, de, int, flag)
   1735 {
   1736   struct directory		* dpnt;
   1737   struct directory_entry	* orig_de;
   1738   struct directory		* next_brother;
   1739   const char                    * cpnt;
   1740   const char			* pnt;
   1741 
   1742   orig_de = de;
   1743 
   1744   pnt = strrchr(path, PATH_SEPARATOR);
   1745   if( pnt == NULL )
   1746     {
   1747       pnt = path;
   1748     }
   1749   else
   1750     {
   1751       pnt++;
   1752     }
   1753 
   1754   if( parent != NULL )
   1755     {
   1756       dpnt = parent->subdir;
   1757 
   1758       while (dpnt)
   1759 	{
   1760 	  /*
   1761 	   * Weird hack time - if there are two directories by the
   1762 	   * same name in the reloc_dir, they are not treated as the
   1763 	   * same thing unless the entire path matches completely.
   1764 	   */
   1765 	  if( flag && strcmp(dpnt->de_name, pnt) == 0 )
   1766 	    {
   1767 	      return dpnt;
   1768 	    }
   1769 	  dpnt = dpnt->next;
   1770 	}
   1771     }
   1772 
   1773   /*
   1774    * We don't know if we have a valid directory entry for this one
   1775    * yet.  If not, we need to create one.
   1776    */
   1777   if( de == NULL )
   1778     {
   1779       de = (struct directory_entry *)
   1780 	e_malloc(sizeof (struct directory_entry));
   1781       memset(de, 0, sizeof(struct directory_entry));
   1782       de->next            = parent->contents;
   1783       parent->contents    = de;
   1784       de->name            = strdup(pnt);
   1785       de->filedir         = parent;
   1786       de->isorec.flags[0] = 2;
   1787       de->priority        = 32768;
   1788       de->inode           = UNCACHED_INODE;
   1789       de->dev             = (dev_t) UNCACHED_DEVICE;
   1790       set_723(de->isorec.volume_sequence_number, volume_sequence_number);
   1791       iso9660_file_length (pnt, de, 1);
   1792 
   1793       init_fstatbuf();
   1794       /*
   1795        * It doesn't exist for real, so we cannot add any Rock Ridge.
   1796        */
   1797       if(use_RockRidge)
   1798 	{
   1799 	  fstatbuf.st_mode = 0555 | S_IFDIR;
   1800 	  fstatbuf.st_nlink = 2;
   1801 	  generate_rock_ridge_attributes("",
   1802 					 (char *) pnt, de,
   1803 					 &fstatbuf,
   1804 					 &fstatbuf, 0);
   1805 	}
   1806       iso9660_date(de->isorec.date, fstatbuf.st_mtime);
   1807 #ifdef APPLE_HYB
   1808       if (apple_both) {
   1809 	/* give the directory an HFS entry */
   1810 	hfsdirent *hfs_ent;
   1811 	hfs_ent = (hfsdirent *)e_malloc(sizeof(hfsdirent));
   1812 
   1813 	/* fill in the defaults */
   1814 	hfs_ent->flags = hfs_ent->fdflags = 0;
   1815 	hfs_ent->crdate = fstatbuf.st_ctime;
   1816 	hfs_ent->mddate = fstatbuf.st_mtime;
   1817 	hfs_ent->dsize = hfs_ent->rsize = 0;
   1818 
   1819 	de->hfs_ent = hfs_ent;
   1820 
   1821 	/* get the Mac directory name */
   1822 	get_hfs_dir(path, pnt, de);
   1823       }
   1824 #endif /* APPLE_HYB */
   1825     }
   1826 
   1827   /*
   1828    * If we don't have a directory for this one yet, then allocate it
   1829    * now, and patch it into the tree in the appropriate place.
   1830    */
   1831   dpnt             = (struct directory *) e_malloc(sizeof(struct directory));
   1832   memset(dpnt, 0, sizeof(struct directory));
   1833   dpnt->next       = NULL;
   1834   dpnt->subdir     = NULL;
   1835   dpnt->self       = de;
   1836   dpnt->contents   = NULL;
   1837   dpnt->whole_name = strdup(path);
   1838   cpnt             = strrchr(path, PATH_SEPARATOR);
   1839   if(cpnt)
   1840     cpnt++;
   1841   else
   1842     cpnt = path;
   1843   dpnt->de_name    = strdup(cpnt);
   1844   dpnt->size       = 0;
   1845   dpnt->extent     = 0;
   1846   dpnt->jextent    = 0;
   1847   dpnt->jsize      = 0;
   1848 #ifdef APPLE_HYB
   1849   dpnt->hfs_ent	   = de->hfs_ent;
   1850 #endif /*APPLE_HYB */
   1851 
   1852   if( orig_de == NULL )
   1853     {
   1854       struct stat xstatbuf;
   1855       int sts;
   1856 
   1857       /*
   1858        * Now add a . and .. entry in the directory itself.
   1859        * This is a little tricky - if the real directory
   1860        * exists, we need to stat it first.  Otherwise, we
   1861        * use the fictitious fstatbuf which points to the time
   1862        * at which mkisofs was started.
   1863        */
   1864       sts = stat_filter(parent->whole_name, &xstatbuf);
   1865       if( sts == 0 )
   1866 	{
   1867 	  attach_dot_entries(dpnt, &xstatbuf);
   1868 	}
   1869       else
   1870 	{
   1871 	  attach_dot_entries(dpnt, &fstatbuf);
   1872 	}
   1873     }
   1874 
   1875   if(!parent || parent == root)
   1876     {
   1877       if (!root)
   1878 	{
   1879 	  root = dpnt;  /* First time through for root directory only */
   1880 	  root->depth = 0;
   1881 	  root->parent = root;
   1882 	} else {
   1883 	  dpnt->depth = 1;
   1884 	  if(!root->subdir)
   1885 	    {
   1886 	      root->subdir = dpnt;
   1887 	    }
   1888 	  else
   1889 	    {
   1890 	      next_brother = root->subdir;
   1891 	      while(next_brother->next) next_brother = next_brother->next;
   1892 	      next_brother->next = dpnt;
   1893 	    }
   1894 	  dpnt->parent = parent;
   1895 	}
   1896     }
   1897   else
   1898     {
   1899       /* Come through here for  normal traversal of  tree */
   1900 #ifdef DEBUG
   1901       fprintf(stderr,"%s(%d) ", path, dpnt->depth);
   1902 #endif
   1903       if(parent->depth >  RR_relocation_depth)
   1904 	{
   1905 	  fprintf(stderr,"Directories too deep  %s\n", path);
   1906 	  exit(1);
   1907 	}
   1908 
   1909       dpnt->parent = parent;
   1910       dpnt->depth = parent->depth + 1;
   1911 
   1912       if(!parent->subdir)
   1913 	{
   1914 	  parent->subdir = dpnt;
   1915 	}
   1916       else
   1917 	{
   1918 	  next_brother = parent->subdir;
   1919 	  while(next_brother->next) next_brother = next_brother->next;
   1920 	  next_brother->next = dpnt;
   1921 	}
   1922     }
   1923 
   1924   return dpnt;
   1925 }
   1926 
   1927 /*
   1928  * Function:	delete_directory
   1929  *
   1930  * Purpose:	Locate a directory entry in the tree, create if needed.
   1931  *
   1932  * Arguments:
   1933  */
   1934 static void FDECL2(delete_directory, struct directory *, parent, struct directory *, child)
   1935 {
   1936   struct directory		* tdir;
   1937 
   1938   if( child->contents != NULL )
   1939     {
   1940       fprintf(stderr, "Unable to delete non-empty directory\n");
   1941       exit(1);
   1942     }
   1943 
   1944   free(child->whole_name);
   1945   child->whole_name = NULL;
   1946 
   1947   free(child->de_name);
   1948   child->de_name = NULL;
   1949 
   1950 #ifdef APPLE_HYB
   1951   if (apple_both && child->hfs_ent)
   1952     free(child->hfs_ent);
   1953 #endif /* APPLE_HYB */
   1954 
   1955   if( parent->subdir == child )
   1956     {
   1957       parent->subdir = child->next;
   1958     }
   1959   else
   1960     {
   1961       for( tdir = parent->subdir; tdir->next != NULL; tdir = tdir->next )
   1962 	{
   1963 	  if( tdir->next == child )
   1964 	    {
   1965 	      tdir->next = child->next;
   1966 	      break;
   1967 	    }
   1968 	}
   1969       if( tdir == NULL )
   1970 	{
   1971 	  fprintf(stderr, "Unable to locate child directory in parent list\n");
   1972 	  exit(1);
   1973 	}
   1974     }
   1975   free(child);
   1976   return;
   1977 }
   1978 
   1979 int FDECL1(sort_tree, struct directory *, node){
   1980   struct directory * dpnt;
   1981   int ret = 0;
   1982 
   1983   dpnt = node;
   1984 
   1985   while (dpnt){
   1986     ret = sort_n_finish(dpnt);
   1987     if( ret )
   1988       {
   1989 	break;
   1990       }
   1991 
   1992     if(dpnt->subdir) sort_tree(dpnt->subdir);
   1993     dpnt = dpnt->next;
   1994   }
   1995   return ret;
   1996 }
   1997 
   1998 void FDECL1(dump_tree, struct directory *, node){
   1999   struct directory * dpnt;
   2000 
   2001   dpnt = node;
   2002 
   2003   while (dpnt){
   2004     fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name);
   2005     if(dpnt->subdir) dump_tree(dpnt->subdir);
   2006     dpnt = dpnt->next;
   2007   }
   2008 }
   2009 
   2010 void FDECL1(update_nlink_field, struct directory *, node)
   2011 {
   2012     struct directory		* dpnt;
   2013     struct directory		* xpnt;
   2014     struct directory_entry	* s_entry;
   2015     int				  i;
   2016 
   2017     dpnt = node;
   2018 
   2019     while (dpnt)
   2020     {
   2021 	if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
   2022 	    dpnt = dpnt->next;
   2023 	    continue;
   2024 	}
   2025 
   2026 	/*
   2027 	 * First, count up the number of subdirectories this guy has.
   2028 	 */
   2029         for(i=0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
   2030             if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
   2031                 i++;
   2032 	/*
   2033 	 * Next check to see if we have any relocated directories
   2034 	 * in this directory.   The nlink field will include these
   2035 	 * as real directories when they are properly relocated.
   2036 	 *
   2037 	 * In the non-rockridge disk, the relocated entries appear
   2038 	 * as zero length files.
   2039 	 */
   2040 	for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
   2041 	{
   2042 		if( (s_entry->de_flags  & RELOCATED_DIRECTORY) != 0 &&
   2043 			(s_entry->de_flags  & INHIBIT_ISO9660_ENTRY) == 0)
   2044 		{
   2045 			i++;
   2046 		}
   2047 	}
   2048 	/*
   2049 	 * Now update the field in the Rock Ridge entry.
   2050 	 */
   2051 	update_nlink(dpnt->self, i + 2);
   2052 
   2053 	/*
   2054 	 * Update the '.' entry for this directory.
   2055 	 */
   2056 	update_nlink(dpnt->contents, i + 2);
   2057 
   2058 	/*
   2059 	 * Update all of the '..' entries that point to this guy.
   2060 	 */
   2061 	for(xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
   2062 	    update_nlink(xpnt->contents->next, i + 2);
   2063 
   2064 	if(dpnt->subdir) update_nlink_field(dpnt->subdir);
   2065 	dpnt = dpnt->next;
   2066     }
   2067 }
   2068 
   2069 /*
   2070  * something quick and dirty to locate a file given a path
   2071  * recursively walks down path in filename until it finds the
   2072  * directory entry for the desired file
   2073  */
   2074 struct directory_entry * FDECL2(search_tree_file, struct directory *,
   2075 				node,char *, filename)
   2076 {
   2077   struct directory_entry * depnt;
   2078   struct directory	 * dpnt;
   2079   char			 * p1;
   2080   char			 * rest;
   2081   char			 * subdir;
   2082 
   2083   /*
   2084    * strip off next directory name from filename
   2085    */
   2086   subdir = strdup(filename);
   2087 
   2088   if( (p1=strchr(subdir, '/')) == subdir )
   2089     {
   2090       fprintf(stderr,"call to search_tree_file with an absolute path, stripping\n");
   2091       fprintf(stderr,"initial path separator. Hope this was intended...\n");
   2092       memmove(subdir, subdir+1, strlen(subdir)-1);
   2093       p1 = strchr(subdir, '/');
   2094     }
   2095 
   2096   /*
   2097    * do we need to find a subdirectory
   2098    */
   2099   if (p1)
   2100     {
   2101       *p1 = '\0';
   2102 
   2103 #ifdef DEBUG_TORITO
   2104       fprintf(stderr,"Looking for subdir called %s\n",p1);
   2105 #endif
   2106 
   2107       rest = p1+1;
   2108 
   2109 #ifdef DEBUG_TORITO
   2110       fprintf(stderr,"Remainder of path name is now %s\n", rest);
   2111 #endif
   2112 
   2113       dpnt = node->subdir;
   2114      while( dpnt )
   2115        {
   2116 #ifdef DEBUG_TORITO
   2117 	 fprintf(stderr,"%4d %5d %s\n", dpnt->extent, dpnt->size,
   2118 		 dpnt->de_name);
   2119 #endif
   2120 	 if (!strcmp(subdir, dpnt->de_name))
   2121 	   {
   2122 #ifdef DEBUG_TORITO
   2123 	     fprintf(stderr,"Calling next level with filename = %s", rest);
   2124 #endif
   2125 	     return(search_tree_file( dpnt, rest ));
   2126 	   }
   2127 	 dpnt = dpnt->next;
   2128        }
   2129 
   2130      /* if we got here means we couldnt find the subdir */
   2131      return (NULL);
   2132     }
   2133   else
   2134     {
   2135       /*
   2136        * look for a normal file now
   2137        */
   2138       depnt = node->contents;
   2139       while (depnt)
   2140 	{
   2141 #ifdef DEBUG_TORITO
   2142 	  fprintf(stderr,"%4d %5d %s\n",depnt->isorec.extent,
   2143 		  depnt->size, depnt->name);
   2144 #endif
   2145 	  if (!strcmp(filename, depnt->name))
   2146 	    {
   2147 #ifdef DEBUG_TORITO
   2148 	      fprintf(stderr,"Found our file %s", filename);
   2149 #endif
   2150 	      return(depnt);
   2151 	    }
   2152 	  depnt = depnt->next;
   2153 	}
   2154       /*
   2155        * if we got here means we couldnt find the subdir
   2156        */
   2157       return (NULL);
   2158     }
   2159   fprintf(stderr,"We cant get here in search_tree_file :-/ \n");
   2160 }
   2161 
   2162 void init_fstatbuf()
   2163 {
   2164   time_t		    current_time;
   2165 
   2166   if(fstatbuf.st_ctime == 0)
   2167     {
   2168       time (&current_time);
   2169       if( rationalize )
   2170 	{
   2171 	  fstatbuf.st_uid = 0;
   2172 	  fstatbuf.st_gid = 0;
   2173 	}
   2174       else
   2175 	{
   2176 	  fstatbuf.st_uid = getuid();
   2177 	  fstatbuf.st_gid = getgid();
   2178 	}
   2179       fstatbuf.st_ctime = current_time;
   2180       fstatbuf.st_mtime = current_time;
   2181       fstatbuf.st_atime = current_time;
   2182     }
   2183 }
   2184