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