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