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