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