Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / genisoimage / tree.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)tree.c   1.82 04/06/12 joerg */
14 /*
15  * File tree.c - scan directory  tree and build memory structures for iso9660
16  * filesystem
17  *
18  * Written by Eric Youngdale (1993).
19  *
20  * Copyright 1993 Yggdrasil Computing, Incorporated
21  * Copyright (c) 1999,2000-2004 J. Schilling
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 2, or (at your option)
26  * any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36  */
37 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
38
39 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
40
41 #include <mconfig.h>
42 #include "genisoimage.h"
43 #include "match.h"
44 #include "udf.h"
45 #include "exclude.h"
46 #include <timedefs.h>
47 #include <errno.h>
48 #include <fctldefs.h>
49 #include <device.h>
50 #include <schily.h>
51
52 extern int allow_limited_size;
53
54 #ifdef VMS
55 #include <sys/file.h>
56 #include <vms/fabdef.h>
57 #include "vms.h"
58 #endif
59
60 /*
61  * Autoconf should be able to figure this one out for us and let us know
62  * whether the system has memmove or not.
63  */
64 #ifndef HAVE_MEMMOVE
65 #define memmove(d, s, n)        bcopy((s), (d), (n))
66 #endif
67
68 static  Uchar   symlink_buff[PATH_MAX+1];
69
70 static  char    *filetype(int t);
71 static  char    *rstr(char *s1, char *s2);
72 static  void    stat_fix(struct stat * st);
73 int     stat_filter(char *path, struct stat *st);
74 int     lstat_filter(char *path, struct stat *st);
75 static  int     sort_n_finish(struct directory *this_dir);
76 static  void    generate_reloc_directory(void);
77 static  void    attach_dot_entries(struct directory *dirnode, struct stat *dir_stat,
78                                         struct stat *parent_stat);
79 static  void    update_nlink(struct directory_entry *s_entry, int value);
80 static  void    increment_nlink(struct directory_entry *s_entry);
81 char    *find_rr_attribute(unsigned char *pnt, int len, char *attr_type);
82 void    finish_cl_pl_entries(void);
83 int     scan_directory_tree(struct directory *this_dir, char *path,
84                                                                   struct directory_entry *de);
85 #ifdef APPLE_HYB
86 int     insert_file_entry(struct directory *this_dir,
87                                                                 char *whole_path,
88                                                                 char *short_name,
89                                                                 int have_rsrc);
90 #else
91 int     insert_file_entry(struct directory *this_dir,
92                                                                 char *whole_path,
93                                                                 char *short_name);
94 #endif
95 void    generate_iso9660_directories(struct directory *node,
96                                                                                           FILE *outfile);
97 struct directory *find_or_create_directory(struct directory *parent,
98                                                 const char *path,
99                                                 struct directory_entry *de,
100                                                 int flag,
101                                                 struct stat* stat_template);
102 static  void    delete_directory(struct directory *parent,
103                                                                                   struct directory *child);
104 int     sort_tree(struct directory *node);
105 void    dump_tree(struct directory *node);
106 void    update_nlink_field(struct directory *node);
107 struct directory_entry *search_tree_file(struct directory *node,
108                                                                                                           char *filename);
109 void    init_fstatbuf(void);
110
111 extern int      verbose;
112 struct stat     fstatbuf;               /* We use this for the artificial */
113                                         /* entries we create              */
114 struct stat     root_statbuf;           /* Stat buffer for root directory */
115 struct directory *reloc_dir;
116
117 static char *
118 filetype(int t)
119 {
120         static  char    unkn[32];
121
122         if (S_ISFIFO(t))                /* 1 */
123                 return ("fifo");
124         if (S_ISCHR(t))                 /* 2 */
125                 return ("chr");
126         if (S_ISMPC(t))                 /* 3 */
127                 return ("multiplexed chr");
128         if (S_ISDIR(t))                 /* 4 */
129                 return ("dir");
130         if (S_ISNAM(t))                 /* 5 */
131                 return ("named file");
132         if (S_ISBLK(t))                 /* 6 */
133                 return ("blk");
134         if (S_ISMPB(t))                 /* 7 */
135                 return ("multiplexed blk");
136         if (S_ISREG(t))                 /* 8 */
137                 return ("regular file");
138         if (S_ISCNT(t))                 /* 9 */
139                 return ("contiguous file");
140         if (S_ISLNK(t))                 /* 10 */
141                 return ("symlink");
142         if (S_ISSHAD(t))                /* 11 */
143                 return ("Solaris shadow inode");
144         if (S_ISSOCK(t))                /* 12 */
145                 return ("socket");
146         if (S_ISDOOR(t))                /* 13 */
147                 return ("door");
148         if (S_ISWHT(t))                 /* 14 */
149                 return ("whiteout");
150         if (S_ISEVC(t))                 /* 15 */
151                 return ("event count");
152
153         /*
154          * Needs to be last in case somebody makes this
155          * a supported file type.
156          */
157         if ((t & S_IFMT) == 0)          /* 0 (unallocated) */
158                 return ("unallocated");
159
160         sprintf(unkn, "octal '%o'", t & S_IFMT);
161         return (unkn);
162 }
163
164 /*
165  * Check if s1 ends in strings s2
166  */
167 static char *
168 rstr(char *s1, char *s2)
169 {
170         int     l1;
171         int     l2;
172
173         l1 = strlen(s1);
174         l2 = strlen(s2);
175         if (l2 > l1)
176                 return ((char *) NULL);
177
178         if (strcmp(&s1[l1 - l2], s2) == 0)
179                 return (&s1[l1 - l2]);
180         return ((char *) NULL);
181 }
182
183 static void
184 stat_fix(struct stat *st)
185 {
186         int adjust_modes = 0;
187
188         if (S_ISREG(st->st_mode))
189                 adjust_modes = rationalize_filemode;
190         else if (S_ISDIR(st->st_mode))
191                 adjust_modes = rationalize_dirmode;
192         else
193                 adjust_modes = (rationalize_filemode || rationalize_dirmode);
194
195         /*
196          * If rationalizing, override the uid and gid, since the
197          * originals will only be useful on the author's system.
198          */
199         if (rationalize_uid)
200                 st->st_uid = uid_to_use;
201         if (rationalize_gid)
202                 st->st_gid = gid_to_use;
203
204         if (adjust_modes) {
205
206                 if (S_ISREG(st->st_mode) && (filemode_to_use != 0)) {
207                         st->st_mode = filemode_to_use | S_IFREG;
208                 } else if (S_ISDIR(st->st_mode) && (dirmode_to_use != 0)) {
209                         st->st_mode = dirmode_to_use | S_IFDIR;
210                 } else {
211                         /*
212                          * Make sure the file modes make sense.  Turn
213                          * on all read bits.  Turn on all exec/search
214                          * bits if any exec/search bit is set.  Turn
215                          * off all write bits, and all special mode
216                          * bits (on a r/o fs lock bits are useless,
217                          * and with uid+gid 0 don't want set-id bits,
218                          * either).
219                          */
220
221                         st->st_mode |= 0444;
222 #if !defined(_WIN32) && !defined(__DJGPP__)     /* make all file "executable" */
223                         if (st->st_mode & 0111)
224 #endif
225                                 st->st_mode |= 0111;
226                         st->st_mode &= ~07222;
227                 }
228         }
229 }
230
231 int
232 stat_filter(char *path, struct stat *st)
233 {
234         int     result = stat(path, st);
235
236         if (result >= 0 && rationalize)
237                 stat_fix(st);
238         return (result);
239 }
240
241 int
242 lstat_filter(char *path, struct stat *st)
243 {
244         int     result = lstat(path, st);
245
246         if (result >= 0 && rationalize)
247                 stat_fix(st);
248         return (result);
249 }
250
251 static int
252 sort_n_finish(struct directory *this_dir)
253 {
254         struct directory_entry *s_entry;
255         struct directory_entry *s_entry1;
256         struct directory_entry *table;
257         int             count;
258         int             d1;
259         int             d2;
260         int             d3;
261         register int    new_reclen;
262         char            *c;
263         int             status = 0;
264         int             tablesize = 0;
265         char            newname[MAX_ISONAME+1];
266         char            rootname[MAX_ISONAME+1];
267         char            extname[MAX_ISONAME+1];
268
269         /*
270          * Here we can take the opportunity to toss duplicate entries from the
271          * directory.
272          */
273         /* ignore if it's hidden */
274         if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
275                 return (0);
276         }
277         table = NULL;
278
279         init_fstatbuf();
280
281         /*
282          * If we had artificially created this directory, then we might be
283          * missing the required '.' entries.  Create these now if we need
284          * them.
285          */
286         if ((this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
287                 (DIR_HAS_DOT | DIR_HAS_DOTDOT)) {
288                 fstatbuf.st_mode = new_dir_mode | S_IFDIR;
289                 fstatbuf.st_nlink = 2;
290                 attach_dot_entries(this_dir, &fstatbuf, &fstatbuf);
291         }
292         flush_file_hash();
293         s_entry = this_dir->contents;
294         while (s_entry) {
295                 /* ignore if it's hidden */
296                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
297                         s_entry = s_entry->next;
298                         continue;
299                 }
300                 /* First assume no conflict, and handle this case */
301                 if (!(s_entry1 = find_file_hash(s_entry->isorec.name))) {
302                         add_file_hash(s_entry);
303                         s_entry = s_entry->next;
304                         continue;
305                 }
306 #ifdef APPLE_HYB
307                 /*
308                  * if the pair are associated, then skip (as they have the
309                  * same name!)
310                  */
311                 if (apple_both && s_entry1->assoc &&
312                                                 s_entry1->assoc == s_entry) {
313                         s_entry = s_entry->next;
314                         continue;
315                 }
316 #endif  /* APPLE_HYB */
317
318                 if (s_entry1 == s_entry) {
319 #ifdef  USE_LIBSCHILY
320                         comerrno(EX_BAD,
321                         "Fatal goof, file '%s' already in hash table.\n",
322                         s_entry->isorec.name);
323 #else
324                         fprintf(stderr,
325                         "Fatal goof, file '%s' already in hash table.\n",
326                         s_entry->isorec.name);
327                         exit(1);
328 #endif
329                 }
330                 /*
331                  * OK, handle the conflicts.  Try substitute names until we
332                  * come up with a winner
333                  */
334                 strcpy(rootname, s_entry->isorec.name);
335                 /*
336                  * Strip off the non-significant part of the name so that we
337                  * are left with a sensible root filename.  If we don't find
338                  * a '.', then try a ';'.
339                  */
340                 c = strchr(rootname, '.');
341                 /*
342                  * In case we ever allow more than on dot, only modify the
343                  * section past the last dot if the file name starts with a
344                  * dot.
345                  */
346                 if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
347                         c = strrchr(rootname, '.');
348                 }
349                 extname[0] = '\0';              /* In case we have no ext.  */
350                 if (c) {
351                         strcpy(extname, c);
352                         *c = 0;                 /* Cut off complete ext.    */
353                 } else {
354                         /*
355                          * Could not find any '.'.
356                          */
357                         c = strchr(rootname, ';');
358                         if (c) {
359                                 *c = 0;         /* Cut off version number    */
360                         }
361                 }
362                 c = strchr(extname, ';');
363                 if (c) {
364                         *c = 0;                 /* Cut off version number    */
365                 }
366                 d1 = strlen(rootname);
367                 if (full_iso9660_filenames || iso9660_level > 1) {
368                         d2 = strlen(extname);
369                         /*
370                          * 31/37 chars minus the 3 characters we are
371                          * appending below to create unique filenames.
372                          */
373                         if ((d1 + d2) > (iso9660_namelen - 3))
374                                 rootname[iso9660_namelen - 3 - d2] = 0;
375                 } else {
376                         if (d1 > 5)
377                                 rootname[5] = 0;
378                 }
379                 new_reclen = strlen(rootname);
380                 sprintf(newname, "%s000%s%s",
381                                 rootname,
382                                 extname,
383                                 ((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
384                                 omit_version_number ? "" : ";1"));
385
386                 for (d1 = 0; d1 < 36; d1++) {
387                         for (d2 = 0; d2 < 36; d2++) {
388                                 for (d3 = 0; d3 < 36; d3++) {
389                                         newname[new_reclen + 0] =
390                                             (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10);
391                                         newname[new_reclen + 1] =
392                                             (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10);
393                                         newname[new_reclen + 2] =
394                                             (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10);
395                                         if (debug)
396                                                 fprintf(stderr, "NEW name '%s'\n", newname);
397
398 #ifdef VMS
399                                         /* Sigh.  VAXCRTL seems to be broken here */
400                                         {
401                                                 int     ijk = 0;
402
403                                                 while (newname[ijk]) {
404                                                         if (newname[ijk] == ' ')
405                                                                 newname[ijk] = '0';
406                                                         ijk++;
407                                                 }
408                                         }
409 #endif
410
411                                         if (!find_file_hash(newname))
412                                                 goto got_valid_name;
413                                 }
414                         }
415                 }
416
417                 /* If we fell off the bottom here, we were in real trouble. */
418 #ifdef  USE_LIBSCHILY
419                 comerrno(EX_BAD,
420                         "Unable to generate unique name for file %s\n",
421                         s_entry->name);
422 #else
423                 fprintf(stderr,
424                         "Unable to generate unique name for file %s\n",
425                         s_entry->name);
426                 exit(1);
427 #endif
428
429 got_valid_name:
430                 /*
431                  * OK, now we have a good replacement name.  Now decide which
432                  * one of these two beasts should get the name changed
433                  */
434                 if (s_entry->priority < s_entry1->priority) {
435                         if (verbose > 0) {
436                                 fprintf(stderr, "Using %s for  %s%s%s (%s)\n",
437                                         newname,
438                                         this_dir->whole_name, SPATH_SEPARATOR,
439                                         s_entry->name, s_entry1->name);
440                         }
441                         s_entry->isorec.name_len[0] = strlen(newname);
442                         new_reclen = offsetof(struct iso_directory_record,
443                                 name[0]) +
444                                 strlen(newname);
445                         if (use_XA || use_RockRidge) {
446                                 if (new_reclen & 1)
447                                         new_reclen++; /* Pad to an even byte */
448                                 new_reclen += s_entry->rr_attr_size;
449                         }
450                         if (new_reclen & 1)
451                                 new_reclen++;   /* Pad to an even byte */
452                         s_entry->isorec.length[0] = new_reclen;
453                         strcpy(s_entry->isorec.name, newname);
454 #ifdef APPLE_HYB
455                         /* has resource fork - needs new name */
456                         if (apple_both && s_entry->assoc) {
457                                 struct directory_entry *s_entry2 =
458                                                                 s_entry->assoc;
459
460                                 /*
461                                  * resource fork name *should* be the same as
462                                  * the data fork
463                                  */
464                                 s_entry2->isorec.name_len[0] =
465                                                 s_entry->isorec.name_len[0];
466                                 strcpy(s_entry2->isorec.name,
467                                                 s_entry->isorec.name);
468                                 s_entry2->isorec.length[0] = new_reclen;
469                         }
470 #endif  /* APPLE_HYB */
471                 } else {
472                         delete_file_hash(s_entry1);
473                         if (verbose > 0) {
474                                 fprintf(stderr, "Using %s for  %s%s%s (%s)\n",
475                                         newname,
476                                         this_dir->whole_name, SPATH_SEPARATOR,
477                                         s_entry1->name, s_entry->name);
478                         }
479                         s_entry1->isorec.name_len[0] = strlen(newname);
480                         new_reclen = offsetof(struct iso_directory_record,
481                                         name[0]) +
482                                         strlen(newname);
483                         if (use_XA || use_RockRidge) {
484                                 if (new_reclen & 1)
485                                         new_reclen++; /* Pad to an even byte */
486                                 new_reclen += s_entry1->rr_attr_size;
487                         }
488                         if (new_reclen & 1)
489                                 new_reclen++;   /* Pad to an even byte */
490                         s_entry1->isorec.length[0] = new_reclen;
491                         strcpy(s_entry1->isorec.name, newname);
492                         add_file_hash(s_entry1);
493 #ifdef APPLE_HYB
494                         /* has resource fork - needs new name */
495                         if (apple_both && s_entry1->assoc) {
496                                 struct directory_entry *s_entry2 =
497                                                         s_entry1->assoc;
498
499                                 /*
500                                  * resource fork name *should* be the same as
501                                  * the data fork
502                                  */
503                                 s_entry2->isorec.name_len[0] =
504                                                 s_entry1->isorec.name_len[0];
505                                 strcpy(s_entry2->isorec.name,
506                                                         s_entry1->isorec.name);
507                                 s_entry2->isorec.length[0] = new_reclen;
508                         }
509 #endif  /* APPLE_HYB */
510                 }
511                 add_file_hash(s_entry);
512                 s_entry = s_entry->next;
513         }
514
515         if (generate_tables &&
516             !find_file_hash(trans_tbl) &&
517             (reloc_dir != this_dir) &&
518             (this_dir->extent == 0)) {
519                 /* First we need to figure out how big this table is */
520                 for (s_entry = this_dir->contents; s_entry;
521                                                 s_entry = s_entry->next) {
522                         if (strcmp(s_entry->name, ".") == 0 ||
523                                 strcmp(s_entry->name, "..") == 0)
524                                 continue;
525 #ifdef APPLE_HYB
526                         /* skip table entry for the resource fork */
527                         if (apple_both &&
528                             (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
529                                 continue;
530 #endif  /* APPLE_HYB */
531                         if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
532                                 continue;
533                         if (s_entry->table) {
534                                 /*
535                                  * Max namelen, a space before and a space
536                                  * after the iso filename.
537                                  */
538                                 tablesize += MAX_ISONAME + 2 +
539                                                 strlen(s_entry->table);
540                         }
541                 }
542         }
543         if (tablesize > 0) {
544                 table = (struct directory_entry *)
545                         e_malloc(sizeof (struct directory_entry));
546                 memset(table, 0, sizeof (struct directory_entry));
547                 table->table = NULL;
548                 table->next = this_dir->contents;
549                 this_dir->contents = table;
550
551                 table->filedir = root;
552                 table->isorec.flags[0] = ISO_FILE;
553                 table->priority = 32768;
554                 iso9660_date(table->isorec.date, fstatbuf.st_mtime);
555                 table->inode = TABLE_INODE;
556                 table->dev = (dev_t) UNCACHED_DEVICE;
557                 set_723(table->isorec.volume_sequence_number,
558                                                 volume_sequence_number);
559                 set_733((char *) table->isorec.size, tablesize);
560                 table->realsize = tablesize;
561                 table->size = tablesize;
562                 table->filedir = this_dir;
563                 if (jhide_trans_tbl)
564                         table->de_flags |= INHIBIT_JOLIET_ENTRY;
565 /*              table->name = strdup("<translation table>");*/
566                 table->name = strdup(trans_tbl);
567                 /*
568                  * We use sprintf() to create the strings, for this reason
569                  * we need to add one byte for the null character at the
570                  * end of the string even though we don't use it.
571                  */
572                 table->table = (char *) e_malloc(ISO_ROUND_UP(tablesize)+1);
573                 memset(table->table, 0, ISO_ROUND_UP(tablesize)+1);
574                 iso9660_file_length(trans_tbl, table, 0);
575
576                 if (use_XA || use_RockRidge) {
577                         fstatbuf.st_mode = 0444 | S_IFREG;
578                         fstatbuf.st_nlink = 1;
579                         generate_xa_rr_attributes("",
580                                 trans_tbl, table,
581                                 &fstatbuf, &fstatbuf, 0);
582                 }
583         }
584         /*
585          * We have now chosen the 8.3 names and we should now know the length
586          * of every entry in the directory.
587          */
588         for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
589                 /* skip if it's hidden */
590                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
591                         continue;
592                 }
593                 new_reclen = strlen(s_entry->isorec.name);
594
595                 /* First update the path table sizes for directories. */
596                 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
597                         if (strcmp(s_entry->name, ".") != 0 &&
598                                         strcmp(s_entry->name, "..") != 0) {
599                                 path_table_size += new_reclen +
600                                                 offsetof(struct iso_path_table,
601                                                 name[0]);
602                                 if (new_reclen & 1)
603                                         path_table_size++;
604                         } else {
605                                 new_reclen = 1;
606                                 if (this_dir == root && strlen(s_entry->name)
607                                                                         == 1) {
608                                         path_table_size += new_reclen +
609                                                 offsetof(struct iso_path_table,
610                                                 name[0]);
611                                 }
612                         }
613                 }
614                 if (path_table_size & 1)
615                         path_table_size++;      /* For odd lengths we pad */
616                 s_entry->isorec.name_len[0] = new_reclen;
617
618                 new_reclen += offsetof(struct iso_directory_record, name[0]);
619
620                 if (new_reclen & 1)
621                         new_reclen++;
622
623                 new_reclen += s_entry->rr_attr_size;
624
625                 if (new_reclen & 1)
626                         new_reclen++;
627
628                 if (new_reclen > 0xff) {
629 #ifdef  USE_LIBSCHILY
630                         comerrno(EX_BAD,
631                                 "Fatal error - RR overflow (reclen %d) for file %s\n",
632                                 new_reclen,
633                                 s_entry->name);
634 #else
635                         fprintf(stderr,
636                                 "Fatal error - RR overflow (reclen %d) for file %s\n",
637                                 new_reclen,
638                                 s_entry->name);
639                         exit(1);
640 #endif
641                 }
642                 s_entry->isorec.length[0] = new_reclen;
643         }
644
645         status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
646         if (status > 0) {
647      fprintf(stderr, "Unable to sort directory %s\n",
648            this_dir->whole_name);
649      if(merge_warn_msg)
650         fprintf(stderr, merge_warn_msg);
651      exit(1);
652         }
653         /*
654          * If we are filling out a TRANS.TBL, generate the entries that will
655          * go in the thing.
656          */
657         if (table) {
658                 count = 0;
659                 for (s_entry = this_dir->contents; s_entry;
660                                                 s_entry = s_entry->next) {
661                         if (s_entry == table)
662                                 continue;
663                         if (!s_entry->table)
664                                 continue;
665                         if (strcmp(s_entry->name, ".") == 0 ||
666                                 strcmp(s_entry->name, "..") == 0)
667                                 continue;
668 #ifdef APPLE_HYB
669                         /* skip table entry for the resource fork */
670                         if (apple_both &&
671                             (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
672                                 continue;
673 #endif  /* APPLE_HYB */
674                         if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
675                                 continue;
676                         /*
677                          * Warning: we cannot use the return value of sprintf
678                          * because old BSD based sprintf() implementations
679                          * will return a pointer to the result instead of a
680                          * count.
681                          * Old mkiofs introduced a space after the iso
682                          * filename to make parsing TRANS.TBL easier.
683                          */
684                         sprintf(table->table + count, "%c %-*s%s",
685                                 s_entry->table[0],
686                                 MAX_ISONAME + 1,
687                                 s_entry->isorec.name, s_entry->table + 1);
688                         count += strlen(table->table + count);
689                         free(s_entry->table);
690                         /*
691                          * for a memory file, set s_entry->table to the
692                          * correct data - which is stored in
693                          * s_entry->whole_name
694                          */
695                         if (s_entry->de_flags & MEMORY_FILE) {
696                                 s_entry->table = s_entry->whole_name;
697                                 s_entry->whole_name = NULL;
698                         } else {
699                                 s_entry->table = NULL;
700                         }
701                 }
702
703                 if (count != tablesize) {
704 #ifdef  USE_LIBSCHILY
705                         comerrno(EX_BAD,
706                                 "Translation table size mismatch %d %d\n",
707                                 count, tablesize);
708 #else
709                         fprintf(stderr,
710                                 "Translation table size mismatch %d %d\n",
711                                 count, tablesize);
712                         exit(1);
713 #endif
714                 }
715         }
716         /*
717          * Now go through the directory and figure out how large this one will
718          * be. Do not split a directory entry across a sector boundary
719          */
720         s_entry = this_dir->contents;
721         this_dir->ce_bytes = 0;
722         while (s_entry) {
723                 /* skip if it's hidden */
724                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
725                         s_entry = s_entry->next;
726                         continue;
727                 }
728                 new_reclen = s_entry->isorec.length[0];
729                 if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
730                                                                 >= SECTOR_SIZE)
731
732                         this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
733                                 ~(SECTOR_SIZE - 1);
734                 this_dir->size += new_reclen;
735
736                 /* See if continuation entries were used on disc */
737                 if (use_RockRidge &&
738                         s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
739                         unsigned char   *pnt;
740                         int             len;
741                         int             nbytes;
742
743                         pnt = s_entry->rr_attributes;
744                         len = s_entry->total_rr_attr_size;
745                         pnt = parse_xa(pnt, &len, 0);
746 /*                      pnt = parse_xa(pnt, &len, s_entry);*/
747
748                         /*
749                          * We make sure that each continuation entry record is
750                          * not split across sectors, but each file could in
751                          * theory have more than one CE, so we scan through
752                          * and figure out what we need.
753                          */
754                         while (len > 3) {
755                                 if (pnt[0] == 'C' && pnt[1] == 'E') {
756                                         nbytes = get_733((char *) pnt + 20);
757
758                                         if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
759                                                 SECTOR_SIZE)
760                                                 this_dir->ce_bytes =
761                                                         ISO_ROUND_UP(this_dir->ce_bytes);
762                                         /*
763                                          * Now store the block in the
764                                          * ce buffer
765                                          */
766                                         this_dir->ce_bytes += nbytes;
767                                         if (this_dir->ce_bytes & 1)
768                                                 this_dir->ce_bytes++;
769                                 }
770                                 len -= pnt[2];
771                                 pnt += pnt[2];
772                         }
773                 }
774                 s_entry = s_entry->next;
775         }
776         return (status);
777 }
778
779 static void
780 generate_reloc_directory()
781 {
782         time_t          current_time;
783         struct directory_entry *s_entry;
784
785         /* Create an  entry for our internal tree */
786         time(&current_time);
787         reloc_dir = (struct directory *)
788                 e_malloc(sizeof (struct directory));
789         memset(reloc_dir, 0, sizeof (struct directory));
790         reloc_dir->parent = root;
791         reloc_dir->next = root->subdir;
792         root->subdir = reloc_dir;
793         reloc_dir->depth = 1;
794         if (hide_rr_moved) {
795                 reloc_dir->whole_name = strdup("./.rr_moved");
796                 reloc_dir->de_name = strdup(".rr_moved");
797         } else {
798                 reloc_dir->whole_name = strdup("./rr_moved");
799                 reloc_dir->de_name = strdup("rr_moved");
800         }
801         reloc_dir->extent = 0;
802
803
804         /* Now create an actual directory  entry */
805         s_entry = (struct directory_entry *)
806                 e_malloc(sizeof (struct directory_entry));
807         memset(s_entry, 0, sizeof (struct directory_entry));
808         s_entry->next = root->contents;
809         reloc_dir->self = s_entry;
810
811         /* The rr_moved entry will not appear in the Joliet tree. */
812         reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
813         s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
814
815         /* Hiding RR_MOVED seems not to be possible..... */
816 #ifdef  HIDE_RR
817         reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
818         s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
819 #endif
820
821         root->contents = s_entry;
822         root->contents->name = strdup(reloc_dir->de_name);
823         root->contents->filedir = root;
824         root->contents->isorec.flags[0] = ISO_DIRECTORY;
825         root->contents->priority = 32768;
826         iso9660_date(root->contents->isorec.date, current_time);
827         root->contents->inode = UNCACHED_INODE;
828         root->contents->dev = (dev_t) UNCACHED_DEVICE;
829         set_723(root->contents->isorec.volume_sequence_number,
830                                                 volume_sequence_number);
831         iso9660_file_length(reloc_dir->de_name, root->contents, 1);
832
833         init_fstatbuf();
834
835         if (use_XA || use_RockRidge) {
836                 fstatbuf.st_mode = 0555 | S_IFDIR;
837                 fstatbuf.st_nlink = 2;
838                 generate_xa_rr_attributes("",
839                         hide_rr_moved ? ".rr_moved" : "rr_moved",
840                         s_entry, &fstatbuf, &fstatbuf, 0);
841         };
842
843         /* Now create the . and .. entries in rr_moved */
844         /* Now create an actual directory  entry */
845         memset(&root_statbuf, 0x0, sizeof(struct stat)); /* be sure */
846         attach_dot_entries(reloc_dir, &fstatbuf, &root_statbuf);
847 }
848
849 /*
850  * Function:            attach_dot_entries
851  *
852  * Purpose:             Create . and .. entries for a new directory.
853  *
854  * Arguments:           dir_stat contains the ownership/permission information
855  *                      for dirnode, and parent_stat contains 
856  *                      ownership/permission information for its parent
857  *
858  *
859  * Notes:               Only used for artificial directories that
860  *                      we are creating.
861  */
862 static void
863 attach_dot_entries(struct directory *dirnode, struct stat *dir_stat,
864                         struct stat *parent_stat)
865 {
866         struct directory_entry *s_entry;
867         struct directory_entry *orig_contents;
868         int             deep_flag = 0;
869
870         init_fstatbuf();
871
872         orig_contents = dirnode->contents;
873
874         if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 0) {
875                 s_entry = (struct directory_entry *)
876                         e_malloc(sizeof (struct directory_entry));
877                 memcpy(s_entry, dirnode->self,
878                         sizeof (struct directory_entry));
879 #ifdef  APPLE_HYB
880                 if (dirnode->self->hfs_ent) {
881                         s_entry->hfs_ent = (hfsdirent *)
882                                 e_malloc(sizeof (hfsdirent));
883                         memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
884                                 sizeof (hfsdirent));
885                 }
886 #endif
887                 s_entry->name = strdup("..");
888                 s_entry->whole_name = NULL;
889                 s_entry->isorec.name_len[0] = 1;
890                 s_entry->isorec.flags[0] = ISO_DIRECTORY;
891                 iso9660_file_length("..", s_entry, 1);
892                 iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
893                 set_723(s_entry->isorec.volume_sequence_number,
894                                                 volume_sequence_number);
895                 set_733(s_entry->isorec.size, SECTOR_SIZE);
896                 s_entry->realsize = SECTOR_SIZE;
897                 memset(s_entry->isorec.extent, 0, 8);
898                 s_entry->filedir = dirnode->parent;
899
900                 dirnode->contents = s_entry;
901                 dirnode->contents->next = orig_contents;
902                 orig_contents = s_entry;
903
904                 if (use_XA || use_RockRidge) {
905                         generate_xa_rr_attributes("",
906                                 "..", s_entry,
907                                 parent_stat,
908                                 parent_stat, 0);
909                 }
910                 dirnode->dir_flags |= DIR_HAS_DOTDOT;
911         }
912         if ((dirnode->dir_flags & DIR_HAS_DOT) == 0) {
913                 s_entry = (struct directory_entry *)
914                         e_malloc(sizeof (struct directory_entry));
915                 memcpy(s_entry, dirnode->self,
916                         sizeof (struct directory_entry));
917 #ifdef  APPLE_HYB
918                 if (dirnode->self->hfs_ent) {
919                         s_entry->hfs_ent = (hfsdirent *)
920                                 e_malloc(sizeof (hfsdirent));
921                         memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
922                                 sizeof (hfsdirent));
923                 }
924 #endif
925                 s_entry->name = strdup(".");
926                 s_entry->whole_name = NULL;
927                 s_entry->isorec.name_len[0] = 1;
928                 s_entry->isorec.flags[0] = ISO_DIRECTORY;
929                 iso9660_file_length(".", s_entry, 1);
930                 iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
931                 set_723(s_entry->isorec.volume_sequence_number,
932                                                 volume_sequence_number);
933                 set_733(s_entry->isorec.size, SECTOR_SIZE);
934                 s_entry->realsize=SECTOR_SIZE;
935                 memset(s_entry->isorec.extent, 0, 8);
936                 s_entry->filedir = dirnode;
937
938                 dirnode->contents = s_entry;
939                 dirnode->contents->next = orig_contents;
940
941                 if (use_XA || use_RockRidge) {
942
943                         if (dirnode == root) {
944                                 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
945                         }
946                         generate_xa_rr_attributes("", ".", s_entry,
947                                 dir_stat, dir_stat, deep_flag);
948                 }
949                 dirnode->dir_flags |= DIR_HAS_DOT;
950         }
951 }
952
953 static void
954 update_nlink(struct directory_entry *s_entry, int value)
955 {
956         unsigned char   *pnt;
957         int             len;
958
959         pnt = s_entry->rr_attributes;
960         len = s_entry->total_rr_attr_size;
961         pnt = parse_xa(pnt, &len, 0);
962         while (len >= 4) {
963                 if (pnt[3] != 1 && pnt[3] != 2) {
964 #ifdef USE_LIBSCHILY
965                         errmsgno(EX_BAD,
966                                 "**BAD RRVERSION (%d) for %c%c\n",
967                                 pnt[3], pnt[0], pnt[1]);
968 #else
969                         fprintf(stderr,
970                                 "**BAD RRVERSION (%d) for %c%c\n",
971                                 pnt[3], pnt[0], pnt[1]);
972 #endif
973                 }
974                 if (pnt[0] == 'P' && pnt[1] == 'X') {
975                         set_733((char *) pnt + 12, value);
976                         break;
977                 }
978                 len -= pnt[2];
979                 pnt += pnt[2];
980         }
981 }
982
983 static void
984 increment_nlink(struct directory_entry *s_entry)
985 {
986         unsigned char   *pnt;
987         int             len,
988                         nlink;
989
990         pnt = s_entry->rr_attributes;
991         len = s_entry->total_rr_attr_size;
992         pnt = parse_xa(pnt, &len, 0);
993         while (len >= 4) {
994                 if (pnt[3] != 1 && pnt[3] != 2) {
995 #ifdef USE_LIBSCHILY
996                         errmsgno(EX_BAD,
997                                 "**BAD RRVERSION (%d) for %c%c\n",
998                                 pnt[3], pnt[0], pnt[1]);
999 #else
1000                         fprintf(stderr,
1001                                 "**BAD RRVERSION (%d) for %c%c\n",
1002                                 pnt[3], pnt[0], pnt[1]);
1003 #endif
1004                 }
1005                 if (pnt[0] == 'P' && pnt[1] == 'X') {
1006                         nlink = get_733((char *) pnt + 12);
1007                         set_733((char *) pnt + 12, nlink + 1);
1008                         break;
1009                 }
1010                 len -= pnt[2];
1011                 pnt += pnt[2];
1012         }
1013 }
1014
1015 char *
1016 find_rr_attribute(unsigned char *pnt, int len, char *attr_type)
1017 {
1018         pnt = parse_xa(pnt, &len, 0);
1019         while (len >= 4) {
1020                 if (pnt[3] != 1 && pnt[3] != 2) {
1021 #ifdef USE_LIBSCHILY
1022                         errmsgno(EX_BAD,
1023                                 "**BAD RRVERSION (%d) for %c%c\n",
1024                                 pnt[3], pnt[0], pnt[1]);
1025 #else
1026                         fprintf(stderr,
1027                                 "**BAD RRVERSION (%d) for %c%c\n",
1028                                 pnt[3], pnt[0], pnt[1]);
1029 #endif
1030                 }
1031                 if (strncmp((char *) pnt, attr_type, 2) == 0)
1032                         return ((char *) pnt);
1033                 else if (strncmp((char *) pnt, "ST", 2) == 0)
1034                         return (NULL);
1035                 len -= pnt[2];
1036                 pnt += pnt[2];
1037         }
1038         return (NULL);
1039 }
1040
1041 void
1042 finish_cl_pl_entries()
1043 {
1044         struct directory_entry  *s_entry;
1045         struct directory_entry  *s_entry1;
1046         struct directory        *d_entry;
1047
1048         /* if the reloc_dir is hidden (empty), then return */
1049         if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
1050                 return;
1051
1052         s_entry = reloc_dir->contents;
1053         s_entry = s_entry->next->next;  /* Skip past . and .. */
1054         for (; s_entry; s_entry = s_entry->next) {
1055                 /* skip if it's hidden */
1056                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1057                         continue;
1058                 }
1059                 d_entry = reloc_dir->subdir;
1060                 while (d_entry) {
1061                         if (d_entry->self == s_entry)
1062                                 break;
1063                         d_entry = d_entry->next;
1064                 };
1065                 if (!d_entry) {
1066 #ifdef  USE_LIBSCHILY
1067                         comerrno(EX_BAD,
1068                                         "Unable to locate directory parent\n");
1069 #else
1070                         fprintf(stderr, "Unable to locate directory parent\n");
1071                         exit(1);
1072 #endif
1073                 };
1074
1075                 if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
1076                         char    *rr_attr;
1077
1078                         /*
1079                          * First fix the PL pointer in the directory in the
1080                          * rr_reloc dir
1081                          */
1082                         s_entry1 = d_entry->contents->next;
1083
1084 /*                      set_733((char *) s_entry1->rr_attributes +*/
1085 /*                              s_entry1->total_rr_attr_size - 8,*/
1086 /*                              s_entry->filedir->extent); */
1087                         /*
1088                          * The line above won't work when entry was read from
1089                          * the previous session, because if total_rr_attr_size
1090                          * was odd when recording previous session, now we have
1091                          * total_rr_attr_size off by 1 due to padding.
1092                          *
1093                          * So, just search for the attributes by name
1094                          */
1095                         rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1096                                 s_entry1->total_rr_attr_size, "PL");
1097                         if (rr_attr != NULL)
1098                                 set_733(rr_attr + 4, s_entry->filedir->extent);
1099
1100
1101                         /* Now fix the CL pointer */
1102                         s_entry1 = s_entry->parent_rec;
1103
1104 /*                      set_733((char *) s_entry1->rr_attributes +*/
1105 /*                      s_entry1->total_rr_attr_size - 8, d_entry->extent); */
1106                         rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1107                                 s_entry1->total_rr_attr_size, "CL");
1108                         if (rr_attr != NULL)
1109                                 set_733(rr_attr + 4, d_entry->extent);
1110                 }
1111                 s_entry->filedir = reloc_dir;   /* Now we can fix this */
1112         }
1113         /*
1114          * Next we need to modify the NLINK terms in the assorted root
1115          * directory records to account for the presence of the RR_MOVED
1116          * directory
1117          */
1118         increment_nlink(root->self);
1119         increment_nlink(root->self->next);
1120         d_entry = root->subdir;
1121         while (d_entry) {
1122                 increment_nlink(d_entry->contents->next);
1123                 d_entry = d_entry->next;
1124         };
1125
1126         finish_cl_pl_for_prev_session();
1127 }
1128
1129 /*
1130  * Function:            scan_directory_tree
1131  *
1132  * Purpose:             Walk through a directory on the local machine
1133  *                      filter those things we don't want to include
1134  *                      and build our representation of a dir.
1135  *
1136  * Notes:
1137  */
1138 int
1139 scan_directory_tree(struct directory *this_dir, char *path, 
1140                                                   struct directory_entry *de)
1141 {
1142         DIR             *current_dir;
1143         char            whole_path[PATH_MAX];
1144         struct dirent   *d_entry;
1145         struct directory *parent;
1146         int             dflag;
1147         char            *old_path;
1148
1149         if (verbose > 1) {
1150                 fprintf(stderr, "Scanning %s\n", path);
1151         }
1152 /*#define       check_needed*/
1153 #ifdef  check_needed
1154         /*
1155          * Trying to use this to avoid directory loops from hard links
1156          * or followed symlinks does not work. It would prevent us from
1157          * implementing merge directories.
1158          */
1159         if (this_dir->dir_flags & DIR_WAS_SCANNED) {
1160                 fprintf(stderr, "Already scanned directory %s\n", path);
1161                 return (1);     /* It's a directory */
1162         }
1163 #endif
1164         this_dir->dir_flags |= DIR_WAS_SCANNED;
1165
1166         errno = 0;      /* Paranoia */
1167         current_dir = opendir(path);
1168         d_entry = NULL;
1169
1170         /*
1171          * Apparently NFS sometimes allows you to open the directory, but then
1172          * refuses to allow you to read the contents.  Allow for this
1173          */
1174         old_path = path;
1175
1176         if (current_dir) {
1177                 errno = 0;
1178                 d_entry = readdir(current_dir);
1179         }
1180
1181         if (!current_dir || !d_entry) {
1182                 int     ret = 1;
1183
1184 #ifdef  USE_LIBSCHILY
1185                 errmsg("Unable to open directory %s\n", path);
1186 #else
1187                 fprintf(stderr, "Unable to open directory %s\n", path);
1188 #endif
1189                 if (errno == ENOTDIR) {
1190                         /* Mark as not a directory */
1191                         de->isorec.flags[0] &= ~ISO_DIRECTORY;
1192                         ret = 0;
1193                 }
1194                 if (current_dir)
1195                         closedir(current_dir);
1196                 return (ret);
1197         }
1198 #ifdef  ABORT_DEEP_ISO_ONLY
1199         if ((this_dir->depth > RR_relocation_depth) && !use_RockRidge) {
1200                 static  BOOL    did_hint = FALSE;
1201
1202                 errmsgno(EX_BAD,
1203                         "Directories too deep for '%s' (%d) max is %d; ignored - continuing.\n",
1204                         path, this_dir->depth, RR_relocation_depth);
1205                 if (!did_hint) {
1206                         did_hint = TRUE;
1207                         errmsgno(EX_BAD, "To include the complete directory tree,\n");
1208                         errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n");
1209                         errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n");
1210                 }
1211                 closedir(current_dir);
1212                 return (1);
1213         }
1214 #endif
1215
1216         parent = de->filedir;
1217         /*
1218          * Set up the struct for the current directory, and insert it into
1219          * the tree
1220          */
1221 #ifdef VMS
1222         vms_path_fixup(path);
1223 #endif
1224
1225         /*
1226          * if entry for this sub-directory is hidden, then hide this directory
1227          */
1228         if (de->de_flags & INHIBIT_ISO9660_ENTRY)
1229                 this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
1230
1231         if (de->de_flags & INHIBIT_JOLIET_ENTRY)
1232                 this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
1233
1234 #ifdef SORTING
1235         /*
1236          * set any sort weighting from it's own directory entry - if a
1237          * directory is given a weighting, then all the contents will use
1238          * this as the default weighting
1239          */
1240         this_dir->sort = de->sort;
1241 #endif /* SORTING */
1242
1243         /*
1244          * Now we scan the directory itself, and look at what is inside of it.
1245          */
1246         dflag = 0;
1247         while (1 == 1) {
1248
1249                 /*
1250                  * The first time through, skip this, since we already asked
1251                  * for the first entry when we opened the directory.
1252                  */
1253                 if (dflag)
1254                         d_entry = readdir(current_dir);
1255                 dflag++;
1256
1257                 if (!d_entry)
1258                         break;
1259
1260                 /* OK, got a valid entry */
1261
1262                 /* If we do not want all files, then pitch the backups. */
1263                 if (!all_files) {
1264                         if (strchr(d_entry->d_name, '~') ||
1265                             strchr(d_entry->d_name, '#') ||
1266                             rstr(d_entry->d_name, ".bak")) {
1267                                 if (verbose > 0) {
1268                                         fprintf(stderr,
1269                                                 "Ignoring file %s\n",
1270                                                 d_entry->d_name);
1271                                 }
1272                                 continue;
1273                         }
1274                 }
1275 #ifdef APPLE_HYB
1276                 if (apple_both) {
1277                         /*
1278                          * exclude certain HFS type files/directories for the
1279                          * time being
1280                          */
1281                         if (hfs_exclude(d_entry->d_name))
1282                                 continue;
1283                 }
1284 #endif  /* APPLE_HYB */
1285
1286                 if (strlen(path) + strlen(d_entry->d_name) + 2 >
1287                                                         sizeof (whole_path)) {
1288 #ifdef  USE_LIBSCHILY
1289                         errmsgno(EX_BAD, "Path name %s/%s too long.\n",
1290                                         path, d_entry->d_name);
1291                         comerrno(EX_BAD, "Overflow of stat buffer\n");
1292 #else
1293                         fprintf(stderr, "Path name %s/%s too long.\n",
1294                                         path, d_entry->d_name);
1295                         fprintf(stderr, "Overflow of stat buffer\n");
1296                         exit(1);
1297 #endif
1298                 };
1299
1300                 /* Generate the complete ASCII path for this file */
1301                 strcpy(whole_path, path);
1302 #ifndef VMS
1303                 if (whole_path[strlen(whole_path) - 1] != '/')
1304                         strcat(whole_path, "/");
1305 #endif
1306                 strcat(whole_path, d_entry->d_name);
1307
1308                 /** Should we exclude this file ? */
1309                 if (matches(d_entry->d_name) || matches(whole_path)) {
1310                         if (verbose > 1) {
1311                                 fprintf(stderr,
1312                                         "Excluded by match: %s\n", whole_path);
1313                         }
1314                         continue;
1315                 }
1316                 if (generate_tables &&
1317                     strcmp(d_entry->d_name, trans_tbl) == 0) {
1318                         /*
1319                          * Ignore this entry.  We are going to be generating
1320                          * new versions of these files, and we need to ignore
1321                          * any originals that we might have found.
1322                          */
1323                         if (verbose > 1) {
1324                                 fprintf(stderr, "Excluded: %s\n", whole_path);
1325                         }
1326                         continue;
1327                 }
1328                 /*
1329                  * If we already have a '.' or a '..' entry, then don't insert
1330                  * new ones.
1331                  */
1332                 if (strcmp(d_entry->d_name, ".") == 0 &&
1333                     this_dir->dir_flags & DIR_HAS_DOT) {
1334                         continue;
1335                 }
1336                 if (strcmp(d_entry->d_name, "..") == 0 &&
1337                     this_dir->dir_flags & DIR_HAS_DOTDOT) {
1338                         continue;
1339                 }
1340 #if 0
1341                 if (verbose > 1)
1342                         fprintf(stderr, "%s\n", whole_path);
1343 #endif
1344                 /* This actually adds the entry to the directory in question.*/
1345 #ifdef APPLE_HYB
1346                 insert_file_entry(this_dir, whole_path, d_entry->d_name, 0);
1347 #else
1348                 insert_file_entry(this_dir, whole_path, d_entry->d_name);
1349 #endif  /* APPLE_HYB */
1350         }
1351         closedir(current_dir);
1352
1353 #ifdef APPLE_HYB
1354         /*
1355          * if we cached the HFS info stuff for this directory, then delete it
1356          */
1357         if (this_dir->hfs_info) {
1358                 del_hfs_info(this_dir->hfs_info);
1359                 this_dir->hfs_info = 0;
1360         }
1361 #endif  /* APPLE_HYB */
1362
1363         return (1);
1364 }
1365
1366
1367 /*
1368  * Function:            insert_file_entry
1369  *
1370  * Purpose:             Insert one entry into our directory node.
1371  *
1372  * Note:
1373  * This function inserts a single entry into the directory.  It
1374  * is assumed that all filtering and decision making regarding what
1375  * we want to include has already been made, so the purpose of this
1376  * is to insert one entry (file, link, dir, etc), into this directory.
1377  * Note that if the entry is a dir (or if we are following links,
1378  * and the thing it points to is a dir), then we will scan those
1379  * trees before we return.
1380  */
1381 #ifdef APPLE_HYB
1382 int
1383 insert_file_entry(struct directory *this_dir, char *whole_path, 
1384                                                 char *short_name, int have_rsrc)
1385 #else
1386 int
1387 insert_file_entry(struct directory *this_dir, char *whole_path, 
1388                                                 char *short_name)
1389 #endif  /* APPLE_HYB */
1390 {
1391         struct stat     statbuf,
1392                         lstatbuf;
1393         struct directory_entry *s_entry,
1394                         *s_entry1;
1395         int             lstatus;
1396         int             status;
1397         int             deep_flag;
1398         int             no_scandir = 0;
1399
1400 #ifdef APPLE_HYB
1401         int             x_hfs = 0;
1402         int             htype = TYPE_NONE;
1403
1404 #endif  /* APPLE_HYB */
1405
1406         status = stat_filter(whole_path, &statbuf);
1407
1408         lstatus = lstat_filter(whole_path, &lstatbuf);
1409
1410         if ((status == -1) && (lstatus == -1)) {
1411                 /*
1412                  * This means that the file doesn't exist, or isn't accessible.
1413                  * Sometimes this is because of NFS permissions problems.
1414                  */
1415 #ifdef  USE_LIBSCHILY
1416                 errmsg("Non-existent or inaccessible: %s\n", whole_path);
1417 #else
1418                 fprintf(stderr, "Non-existent or inaccessible: %s\n",
1419                                                                 whole_path);
1420 #endif
1421                 return (0);
1422         }
1423         if (this_dir == root && strcmp(short_name, ".") == 0)
1424                 root_statbuf = statbuf; /* Save this for later on */
1425
1426         /* We do this to make sure that the root entries are consistent */
1427         if (this_dir == root && strcmp(short_name, "..") == 0) {
1428                 statbuf = root_statbuf;
1429                 lstatbuf = root_statbuf;
1430         }
1431         if (S_ISLNK(lstatbuf.st_mode)) {
1432
1433                 /*
1434                  * Here we decide how to handle the symbolic links.  Here we
1435                  * handle the general case - if we are not following links or
1436                  * there is an error, then we must change something.  If RR
1437                  * is in use, it is easy, we let RR describe the file.  If
1438                  * not, then we punt the file.
1439                  */
1440                 if ((status || !follow_links)) {
1441                         if (use_RockRidge) {
1442                                 status = 0;
1443                                 statbuf.st_size = (off_t)0;
1444                                 STAT_INODE(statbuf) = UNCACHED_INODE;
1445                                 statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
1446                                 statbuf.st_mode =
1447                                         (statbuf.st_mode & ~S_IFMT) | S_IFREG;
1448                         } else {
1449                                 if (follow_links) {
1450 #ifdef  USE_LIBSCHILY
1451                                         /* XXX errno may be wrong! */
1452                                         errmsg("Unable to stat file %s - ignoring and continuing.\n",
1453                                                 whole_path);
1454 #else
1455                                         fprintf(stderr,
1456                                                 "Unable to stat file %s - ignoring and continuing.\n",
1457                                                 whole_path);
1458 #endif
1459                                 } else {
1460 #ifdef  USE_LIBSCHILY
1461                                         errmsgno(EX_BAD,
1462                                                 "Symlink %s ignored - continuing.\n",
1463                                                 whole_path);
1464 #else
1465                                         fprintf(stderr,
1466                                                 "Symlink %s ignored - continuing.\n",
1467                                                 whole_path);
1468 #endif
1469                                         return (0); /* Non Rock Ridge discs */
1470                                                     /* - ignore all symlinks */
1471                                 }
1472                         }
1473                 }
1474                 /*
1475                  * Here we handle a different kind of case.  Here we have a
1476                  * symlink, but we want to follow symlinks.  If we run across
1477                  * a directory loop, then we need to pretend that we are not
1478                  * following symlinks for this file.  If this is the first
1479                  * time we have seen this, then make this seem as if there was
1480                  * no symlink there in the first place
1481                  */
1482                 if (follow_links &&
1483                     S_ISDIR(statbuf.st_mode)) {
1484                         if (strcmp(short_name, ".") &&
1485                             strcmp(short_name, "..")) {
1486                                 if (find_directory_hash(statbuf.st_dev,
1487                                                         STAT_INODE(statbuf))) {
1488                                         if (!use_RockRidge) {
1489                                                 fprintf(stderr,
1490                                                 "Already cached directory seen (%s)\n",
1491                                                         whole_path);
1492                                                 return (0);
1493                                         }
1494                                         lstatbuf = statbuf;
1495                                         /*
1496                                          * XXX when this line was active,
1497                                          * XXX genisoimage did not include all
1498                                          * XXX files if it was called with '-f'
1499                                          * XXX (follow symlinks).
1500                                          * XXX Now scan_directory_tree()
1501                                          * XXX checks if the directory has
1502                                          * XXX already been scanned via the
1503                                          * XXX DIR_WAS_SCANNED flag.
1504                                          */
1505 /*                                      no_scandir = 1;*/
1506                                 } else {
1507                                         lstatbuf = statbuf;
1508                                         add_directory_hash(statbuf.st_dev,
1509                                                         STAT_INODE(statbuf));
1510                                 }
1511                         }
1512                 }
1513                 /*
1514                  * For non-directories, we just copy the stat information over
1515                  * so we correctly include this file.
1516                  */
1517                 if (follow_links &&
1518                     !S_ISDIR(statbuf.st_mode)) {
1519                         lstatbuf = statbuf;
1520                 }
1521         }
1522         /*
1523          * Add directories to the cache so that we don't waste space even if
1524          * we are supposed to be following symlinks.
1525          */
1526         if (follow_links &&
1527             strcmp(short_name, ".") &&
1528             strcmp(short_name, "..") &&
1529             S_ISDIR(statbuf.st_mode)) {
1530                 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1531         }
1532 #ifdef VMS
1533         if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
1534                         statbuf.st_fab_rfm != FAB$C_STMLF)) {
1535                 fprintf(stderr,
1536                         "Warning - file %s has an unsupported VMS record"
1537                         " format (%d)\n",
1538                         whole_path, statbuf.st_fab_rfm);
1539         }
1540 #endif
1541
1542         if (S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))) {
1543 #ifdef  USE_LIBSCHILY
1544                 errmsg("File %s is not readable - ignoring\n",
1545                         whole_path);
1546 #else
1547                 fprintf(stderr,
1548                         "File %s is not readable (errno = %d) - ignoring\n",
1549                         whole_path, errno);
1550 #endif
1551                 return (0);
1552         }
1553         /* print a warning but don't spam too much */
1554         if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0xFFFFFFFF)) {
1555                 static int udf_warned;
1556
1557                 if( !allow_limited_size || verbose>1)
1558                         fprintf(stderr, "File %s is larger than 4GiB-1.\n", whole_path);
1559                 if( !allow_limited_size)
1560                 {
1561                         fprintf(stderr, "-allow-limited-size was not specified. There is no way do represent this file size. Aborting.\n");
1562                         exit(1);
1563                 }
1564                 if(verbose>=1 && ! udf_warned ) {
1565                         udf_warned++;
1566                         fprintf(stderr, "This size can only be represented in the UDF filesystem.\n"
1567                                         "Make sure that your clients support and use it.\n"
1568                                         "ISO9660, Joliet, RockRidge, HFS will display incorrect size.\n");
1569                 }
1570         }
1571         /*
1572          * Add this so that we can detect directory loops with hard links.
1573          * If we are set up to follow symlinks, then we skip this checking.
1574          */
1575         if (!follow_links &&
1576             S_ISDIR(lstatbuf.st_mode) &&
1577             strcmp(short_name, ".") &&
1578             strcmp(short_name, "..")) {
1579                 if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
1580 #ifdef  USE_LIBSCHILY
1581 /*                      comerrno(EX_BAD,*/
1582 /*                      "Directory loop - fatal goof (%s %lx %lu).\n",*/
1583                         errmsgno(EX_BAD,
1584                         "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1585                                 whole_path, (unsigned long) statbuf.st_dev,
1586                                 (unsigned long) STAT_INODE(statbuf));
1587 #else
1588 /*                      fprintf(stderr,*/
1589 /*                      "Directory loop - fatal goof (%s %lx %lu).\n",*/
1590                         fprintf(stderr,
1591                         "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1592                                 whole_path, (unsigned long) statbuf.st_dev,
1593                                 (unsigned long) STAT_INODE(statbuf));
1594 #endif
1595                 }
1596                 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1597         }
1598         if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
1599                 !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) &&
1600                 !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
1601                 !S_ISDIR(lstatbuf.st_mode)) {
1602                 if ( ! (this_dir == root && strcmp(short_name, "..") == 0)) {
1603                         fprintf(stderr,
1604                         "Unknown file type (%s) %s - ignoring and continuing.\n",
1605                                 filetype((int) lstatbuf.st_mode), whole_path);
1606                 }
1607                 return (0);
1608         }
1609         /* Who knows what trash this is - ignore and continue */
1610
1611         if (status) {
1612 #ifdef  USE_LIBSCHILY
1613                 errmsg("Unable to stat file %s - ignoring and continuing.\n",
1614                         whole_path);
1615 #else
1616                 fprintf(stderr,
1617                         "Unable to stat file %s - ignoring and continuing.\n",
1618                         whole_path);
1619 #endif
1620                 return (0);
1621         }
1622         /*
1623          * Check to see if we have already seen this directory node. If so,
1624          * then we don't create a new entry for it, but we do want to recurse
1625          * beneath it and add any new files we do find.
1626          */
1627         if (S_ISDIR(statbuf.st_mode)) {
1628                 int     dflag;
1629
1630                 for (s_entry = this_dir->contents; s_entry;
1631                                                 s_entry = s_entry->next) {
1632                         if (strcmp(s_entry->name, short_name) == 0) {
1633                                 break;
1634                         }
1635                 }
1636                 if (s_entry != NULL &&
1637                     strcmp(short_name, ".") &&
1638                     strcmp(short_name, "..")) {
1639                         struct directory *child;
1640
1641                         if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
1642                                 for (s_entry = reloc_dir->contents; s_entry;
1643                                                 s_entry = s_entry->next) {
1644                                         if (strcmp(s_entry->name, short_name)
1645                                                                         == 0) {
1646                                                 break;
1647                                         }
1648                                 }
1649                                 child = find_or_create_directory(reloc_dir,
1650                                         whole_path,
1651                                         s_entry, 1, NULL);
1652                         } else {
1653                                 child = find_or_create_directory(this_dir,
1654                                         whole_path,
1655                                         s_entry, 1, NULL);
1656                                 /*
1657                                  * If unable to scan directory, mark this as a
1658                                  * non-directory
1659                                  */
1660                         }
1661 /*                      if (no_scandir)*/
1662                         if (0)
1663                                 dflag = 1;
1664                         else
1665                                 dflag = scan_directory_tree(child,
1666                                                         whole_path, s_entry);
1667                         if (!dflag) {
1668                                 lstatbuf.st_mode =
1669                                         (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
1670                         }
1671                         return (0);
1672                 }
1673         }
1674 #ifdef APPLE_HYB
1675         /* Should we exclude this HFS file ? - only works with -hfs */
1676         if (!have_rsrc && apple_hyb && strcmp(short_name, ".") &&
1677                                                 strcmp(short_name, "..")) {
1678                 if ((x_hfs = (hfs_matches(short_name) ||
1679                                         hfs_matches(whole_path))) == 1) {
1680                         if (verbose > 1) {
1681                                 fprintf(stderr, "Hidden from HFS tree: %s\n",
1682                                                         whole_path);
1683                         }
1684                 }
1685         }
1686         /*
1687          * check we are a file, using Apple extensions and have a .resource
1688          * part and not excluded
1689          */
1690         if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
1691                 char    rsrc_path[PATH_MAX];    /* rsrc fork filename */
1692
1693                 /* construct the resource full path */
1694                 htype = get_hfs_rname(whole_path, short_name, rsrc_path);
1695                 /* check we can read the resouce fork */
1696                 if (htype) {
1697                         struct stat     rstatbuf,
1698                                         rlstatbuf;
1699
1700                         /* some further checks on the file */
1701                         status = stat_filter(rsrc_path, &rstatbuf);
1702
1703                         lstatus = lstat_filter(rsrc_path, &rlstatbuf);
1704
1705 /*                      if (!status && !lstatus && S_ISREG(rlstatbuf.st_mode)*/
1706 /*                                      && rlstatbuf.st_size > (off_t)0) { */
1707                         if (!status && !lstatus && S_ISREG(rstatbuf.st_mode) &&
1708                                         rstatbuf.st_size > (off_t)0) {
1709
1710                                 /*
1711                                  * have a resource file - insert it into the
1712                                  * current directory but flag that we have a
1713                                  * resource fork
1714                                  */
1715                                 insert_file_entry(this_dir, rsrc_path,
1716                                                         short_name, htype);
1717                         }
1718                 }
1719         }
1720 #endif  /* APPLE_HYB */
1721
1722         s_entry = (struct directory_entry *)
1723                 e_malloc(sizeof (struct directory_entry));
1724         /* memset the whole struct, not just the isorec.extent part JCP */
1725         memset(s_entry, 0, sizeof (struct directory_entry));
1726         s_entry->next = this_dir->contents;
1727 /*      memset(s_entry->isorec.extent, 0, 8); */
1728         this_dir->contents = s_entry;
1729         deep_flag = 0;
1730         s_entry->table = NULL;
1731
1732         s_entry->name = strdup(short_name);
1733         s_entry->whole_name = strdup(whole_path);
1734
1735         s_entry->de_flags = 0;
1736
1737         /*
1738          * If the current directory is hidden, then hide all it's members
1739          * otherwise check if this entry needs to be hidden as well
1740          */
1741         if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
1742                 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1743         } else if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
1744                                                                         != 0) {
1745                 if (i_matches(short_name) || i_matches(whole_path)) {
1746                         if (verbose > 1) {
1747                                 fprintf(stderr,
1748                                         "Hidden from ISO9660 tree: %s\n",
1749                                         whole_path);
1750                         }
1751                         s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1752                 }
1753                 if (h_matches(short_name) || h_matches(whole_path)) {
1754                         if (verbose > 1) {
1755                                 fprintf(stderr,
1756                                         "Hidden ISO9660 attribute: %s\n",
1757                                         whole_path);
1758                         }
1759                         s_entry->de_flags |= HIDDEN_FILE;
1760                 }
1761         }
1762         if (this_dir != reloc_dir &&
1763                                 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1764                 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1765         } else if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
1766                                                                         != 0) {
1767                 if (j_matches(short_name) || j_matches(whole_path)) {
1768                         if (verbose > 1) {
1769                                 fprintf(stderr,
1770                                         "Hidden from Joliet tree: %s\n",
1771                                         whole_path);
1772                         }
1773                         s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1774                 }
1775         }
1776
1777 #ifdef SORTING
1778         /* inherit any sort weight from parent directory */
1779         s_entry->sort = this_dir->sort;
1780
1781 #ifdef  DVD_VIDEO
1782         /*
1783          * No use at all to do a sort if we don't make a dvd video/audio
1784          */
1785         /*
1786          * Assign special weights to VIDEO_TS and AUDIO_TS files.
1787          * This can't be done with sort_matches for two reasons:
1788          * first, we need to match against the destination (DVD)
1789          * path rather than the source path, and second, there are
1790          * about 2400 different file names to check, each needing
1791          * a different priority, and adding that many patterns to
1792          * sort_matches would slow things to a crawl.
1793          */
1794
1795         if (dvd_video) {
1796                 s_entry->sort = assign_dvd_weights(s_entry->name, this_dir, s_entry->sort);
1797                 /* turn on sorting if necessary, regardless of cmd-line options */
1798                 if ((s_entry->sort != this_dir->sort) && do_sort == 0)
1799                         do_sort++;
1800         }
1801 #endif
1802
1803         /* see if this entry should have a new weighting */
1804         if (do_sort && strcmp(short_name, ".") != 0 &&
1805                         strcmp(short_name, "..") != 0) {
1806                 s_entry->sort = sort_matches(whole_path, s_entry->sort);
1807         }
1808 #endif /* SORTING */
1809
1810         s_entry->filedir = this_dir;
1811         s_entry->isorec.flags[0] = ISO_FILE;
1812         if (s_entry->de_flags & HIDDEN_FILE)
1813                 s_entry->isorec.flags[0] |= ISO_EXISTENCE;
1814         s_entry->isorec.ext_attr_length[0] = 0;
1815         iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
1816         s_entry->isorec.file_unit_size[0] = 0;
1817         s_entry->isorec.interleave[0] = 0;
1818
1819 #ifdef APPLE_HYB
1820         if (apple_both && !x_hfs) {
1821                 s_entry->hfs_ent = NULL;
1822                 s_entry->assoc = NULL;
1823                 s_entry->hfs_off = (off_t)0;
1824                 s_entry->hfs_type = htype;
1825                 if (have_rsrc) {
1826                         /* associated (rsrc) file */
1827                         s_entry->isorec.flags[0] |= ISO_ASSOCIATED;
1828                         /* set the type of HFS file */
1829                         s_entry->hfs_type = have_rsrc;
1830                         /*
1831                          * don't want the rsrc file to be included in any
1832                          * Joliet tree
1833                          */
1834                         s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1835                 } else if (s_entry->next) {
1836                         /*
1837                          * if previous entry is an associated file,
1838                          * then "link" it to this file i.e. we have a
1839                          * data/resource pair
1840                          */
1841                         if (s_entry->next->isorec.flags[0] & ISO_ASSOCIATED) {
1842                                 s_entry->assoc = s_entry->next;
1843                                 /* share the same HFS parameters */
1844                                 s_entry->hfs_ent = s_entry->next->hfs_ent;
1845                                 s_entry->hfs_type = s_entry->next->hfs_type;
1846                         }
1847                 }
1848                 /* allocate HFS entry if required */
1849                 if (apple_both && strcmp(short_name, ".") &&
1850                                                 strcmp(short_name, "..")) {
1851                         if (!s_entry->hfs_ent) {
1852                                 hfsdirent       *hfs_ent;
1853
1854                                 hfs_ent =
1855                                 (hfsdirent *) e_malloc(sizeof (hfsdirent));
1856
1857                                 /* fill in the defaults */
1858                                 memset(hfs_ent, 0, sizeof (hfsdirent));
1859
1860                                 s_entry->hfs_ent = hfs_ent;
1861                         }
1862                         /*
1863                          * the resource fork is processed first, but the
1864                          * data fork's time info is used in preference
1865                          * i.e. time info is set from the resource fork
1866                          * initially, then it is set from the data fork
1867                          */
1868                         if (have_rsrc) {
1869                                 /* set rsrc size */
1870                                 s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
1871                                 /*
1872                                  * this will be overwritten - but might as
1873                                  * well set it here ...
1874                                  */
1875                                 s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
1876                                 s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
1877                         } else {
1878                                 /* set data size */
1879                                 s_entry->hfs_ent->u.file.dsize = lstatbuf.st_size;
1880                                 s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
1881                                 s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
1882                         }
1883                 }
1884         }
1885 #endif  /* APPLE_HYB */
1886
1887         if (strcmp(short_name, ".") == 0) {
1888                 this_dir->dir_flags |= DIR_HAS_DOT;
1889         }
1890         if (strcmp(short_name, "..") == 0) {
1891                 this_dir->dir_flags |= DIR_HAS_DOTDOT;
1892         }
1893         if (this_dir->parent &&
1894             this_dir->parent == reloc_dir &&
1895             strcmp(short_name, "..") == 0) {
1896                 s_entry->inode = UNCACHED_INODE;
1897                 s_entry->dev = (dev_t) UNCACHED_DEVICE;
1898                 deep_flag = NEED_PL;
1899         } else
1900 #ifdef APPLE_HYB
1901         if (have_rsrc) {
1902                 /* don't want rsrc files to be cached */
1903                 s_entry->inode = UNCACHED_INODE;
1904                 s_entry->dev = (dev_t) UNCACHED_DEVICE;
1905         } else
1906 #endif  /* APPLE_HYB */
1907         {
1908                 s_entry->inode = STAT_INODE(statbuf);
1909                 s_entry->dev = statbuf.st_dev;
1910         }
1911         set_723(s_entry->isorec.volume_sequence_number,
1912                                                 volume_sequence_number);
1913         iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
1914         s_entry->rr_attr_size = 0;
1915         s_entry->total_rr_attr_size = 0;
1916         s_entry->rr_attributes = NULL;
1917
1918         /* Directories are assigned sizes later on */
1919         if (!S_ISDIR(statbuf.st_mode)) {
1920                 if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
1921                         S_ISFIFO(lstatbuf.st_mode) ||
1922                                 S_ISSOCK(lstatbuf.st_mode) ||
1923                                 S_ISLNK(lstatbuf.st_mode)) {
1924                         s_entry->size = (off_t)0;
1925                         statbuf.st_size = (off_t)0;
1926                 } else {
1927                         s_entry->size = statbuf.st_size;
1928                 }
1929
1930                 set_733((char *) s_entry->isorec.size, statbuf.st_size);
1931                 s_entry->realsize = statbuf.st_size;
1932         } else {
1933                 s_entry->isorec.flags[0] |= ISO_DIRECTORY;
1934         }
1935 #ifdef APPLE_HYB
1936         /* if the directory is HFS excluded, then we don't have an hfs_ent */
1937         if (apple_both && s_entry->hfs_ent &&
1938                                 (s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
1939                 /* get the Mac directory name */
1940                 get_hfs_dir(whole_path, short_name, s_entry);
1941
1942                 /* if required, set ISO directory name from HFS name */
1943                 if (use_mac_name)
1944                         iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
1945         }
1946 #endif  /* APPLE_HYB */
1947
1948         if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0 &&
1949                 S_ISDIR(statbuf.st_mode) &&
1950                                 this_dir->depth > RR_relocation_depth) {
1951                 struct directory *child;
1952
1953                 if (!reloc_dir)
1954                         generate_reloc_directory();
1955
1956                 /*
1957                  * Replicate the entry for this directory.  The old one will
1958                  * stay where it is, and it will be neutered so that it no
1959                  * longer looks like a directory. The new one will look like
1960                  * a directory, and it will be put in the reloc_dir.
1961                  */
1962                 s_entry1 = (struct directory_entry *)
1963                         e_malloc(sizeof (struct directory_entry));
1964                 memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
1965                 s_entry1->table = NULL;
1966                 s_entry1->name = strdup(this_dir->contents->name);
1967                 s_entry1->whole_name = strdup(this_dir->contents->whole_name);
1968                 s_entry1->next = reloc_dir->contents;
1969                 reloc_dir->contents = s_entry1;
1970                 s_entry1->priority = 32768;
1971                 s_entry1->parent_rec = this_dir->contents;
1972                 set_723(s_entry1->isorec.volume_sequence_number,
1973                                                 volume_sequence_number);
1974
1975                 deep_flag = NEED_RE;
1976
1977                 if (use_XA || use_RockRidge) {
1978                         generate_xa_rr_attributes(whole_path,
1979                                 short_name, s_entry1,
1980                                 &statbuf, &lstatbuf, deep_flag);
1981                 }
1982                 deep_flag = 0;
1983
1984                 /*
1985                  * We need to set this temporarily so that the parent to this
1986                  * is correctly determined.
1987                  */
1988                 s_entry1->filedir = reloc_dir;
1989                 child = find_or_create_directory(reloc_dir, whole_path,
1990                         s_entry1, 0, NULL);
1991 /*              if (!no_scandir)*/
1992                 if (!0)
1993                         scan_directory_tree(child, whole_path, s_entry1);
1994                 s_entry1->filedir = this_dir;
1995
1996                 statbuf.st_size = (off_t)0;
1997                 statbuf.st_mode &= 0777;
1998                 set_733((char *) s_entry->isorec.size, 0);
1999                 s_entry->realsize=0;
2000                 s_entry->size = 0;
2001                 s_entry->isorec.flags[0] = ISO_FILE;
2002                 s_entry->inode = UNCACHED_INODE;
2003                 s_entry->de_flags |= RELOCATED_DIRECTORY;
2004                 deep_flag = NEED_CL;
2005         }
2006         if (generate_tables &&
2007             strcmp(s_entry->name, ".") != 0 &&
2008             strcmp(s_entry->name, "..") != 0) {
2009
2010                 char    buffer[SECTOR_SIZE];
2011                 int     nchar;
2012
2013                 switch (lstatbuf.st_mode & S_IFMT) {
2014                 case S_IFDIR:
2015                         sprintf(buffer, "D\t%s\n",
2016                                 s_entry->name);
2017                         break;
2018
2019 /*
2020  * extra for WIN32 - if it doesn't have the major/minor defined, then
2021  * S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
2022  * code similar to that in rock.c
2023  */
2024 #if 0
2025 /*
2026  * Use the device handling code from <device.h>
2027  */
2028 #ifndef major
2029 #define major(dev) (sizeof (dev_t) <= 2 ? ((dev) >> 8) : \
2030         (sizeof (dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
2031         (((dev) >> 16) >> 16)))
2032 #define minor(dev) (sizeof (dev_t) <= 2 ? (dev) & 0xff : \
2033         (sizeof (dev_t) <= 4 ? (dev) & 0xffff : \
2034         (dev) & 0xffffffff))
2035 #endif
2036 #endif
2037
2038 #ifdef S_IFBLK
2039                 case S_IFBLK:
2040                         sprintf(buffer, "B\t%s\t%lu %lu\n",
2041                                 s_entry->name,
2042                                 (unsigned long) major(statbuf.st_rdev),
2043                                 (unsigned long) minor(statbuf.st_rdev));
2044                         break;
2045 #endif
2046 #ifdef S_IFIFO
2047                 case S_IFIFO:
2048                         sprintf(buffer, "P\t%s\n",
2049                                 s_entry->name);
2050                         break;
2051 #endif
2052 #ifdef S_IFCHR
2053                 case S_IFCHR:
2054                         sprintf(buffer, "C\t%s\t%lu %lu\n",
2055                                 s_entry->name,
2056                                 (unsigned long) major(statbuf.st_rdev),
2057                                 (unsigned long) minor(statbuf.st_rdev));
2058                         break;
2059 #endif
2060 #ifdef S_IFLNK
2061                 case S_IFLNK:
2062 #ifdef  HAVE_READLINK
2063                         nchar = readlink(whole_path,
2064                                 (char *) symlink_buff,
2065                                 sizeof (symlink_buff)-1);
2066 #else
2067                         nchar = -1;
2068 #endif
2069                         symlink_buff[nchar < 0 ? 0 : nchar] = 0;
2070                         sprintf(buffer, "L\t%s\t%s\n",
2071                                 s_entry->name, symlink_buff);
2072                         break;
2073 #endif
2074 #ifdef S_IFSOCK
2075                 case S_IFSOCK:
2076                         sprintf(buffer, "S\t%s\n",
2077                                 s_entry->name);
2078                         break;
2079 #endif
2080                 case S_IFREG:
2081                 default:
2082                         sprintf(buffer, "F\t%s\n",
2083                                 s_entry->name);
2084                         break;
2085                 };
2086                 s_entry->table = strdup(buffer);
2087         }
2088         if (S_ISDIR(statbuf.st_mode)) {
2089                 int     dflag;
2090
2091                 if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
2092                                                                         != 0) {
2093                         struct directory *child;
2094
2095                         child = find_or_create_directory(this_dir, whole_path,
2096                                 s_entry, 1, NULL);
2097                         if (no_scandir)
2098                                 dflag = 1;
2099                         else
2100                                 dflag = scan_directory_tree(child, whole_path,
2101                                                                 s_entry);
2102
2103                         if (!dflag) {
2104                                 lstatbuf.st_mode =
2105                                         (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
2106                                 if (child->contents == NULL) {
2107                                         delete_directory(this_dir, child);
2108                                 }
2109                         }
2110                 }
2111                 /* If unable to scan directory, mark this as a non-directory */
2112         }
2113         if (use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")
2114                                                                         == 0) {
2115                 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
2116         }
2117         /* Now figure out how much room this file will take in the directory */
2118
2119 #ifdef APPLE_HYB
2120         /* if the file is HFS excluded, then we don't have an hfs_ent */
2121         if (apple_both && !have_rsrc && s_entry->hfs_ent) {
2122                 if (S_ISREG(lstatbuf.st_mode)) { /* it's a regular file */
2123
2124                         /* fill in the rest of the HFS entry */
2125                         get_hfs_info(whole_path, short_name, s_entry);
2126
2127                         /* if required, set ISO directory name from HFS name */
2128                         if (use_mac_name)
2129                                 iso9660_file_length(s_entry->hfs_ent->name,
2130                                                                 s_entry, 0);
2131
2132                         /* print details about the HFS file */
2133                         if (verbose > 2)
2134                                 print_hfs_info(s_entry);
2135
2136                         /*
2137                          * copy the new ISO9660 name to the rsrc fork
2138                          * - if it exists
2139                          */
2140                         if (s_entry->assoc)
2141                                 strcpy(s_entry->assoc->isorec.name,
2142                                                         s_entry->isorec.name);
2143
2144                         /*
2145                          * we can't handle hard links in the hybrid case, so we
2146                          * "uncache" the file. The downside to this is that
2147                          * hard linked files are added to the output image
2148                          * more than once (we've already done this for rsrc
2149                          * files)
2150                          */
2151                         if (apple_hyb) {
2152                                 s_entry->inode = UNCACHED_INODE;
2153                                 s_entry->dev = (dev_t) UNCACHED_DEVICE;
2154                         }
2155                 } else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
2156                         /* not a directory .. */
2157
2158                         /*
2159                          * no mac equivalent, so ignore - have to be careful
2160                          * here, the hfs_ent may be also be for a relocated
2161                          * directory
2162                          */
2163                         if (s_entry->hfs_ent &&
2164                                 !(s_entry->de_flags & RELOCATED_DIRECTORY))
2165                                 free(s_entry->hfs_ent);
2166                         s_entry->hfs_ent = NULL;
2167                 }
2168                 /*
2169                  * if the rsrc size is zero, then we don't need the entry, so
2170                  * we might as well delete it - this will only happen if we
2171                  * didn't know the rsrc size from the rsrc file size
2172                  */
2173                 if (s_entry->assoc && s_entry->assoc->size == 0)
2174                         delete_rsrc_ent(s_entry);
2175         }
2176         if (apple_ext && s_entry->assoc) {
2177                 /* need Apple extensions for the resource fork as well */
2178                 generate_xa_rr_attributes(whole_path,
2179                         short_name, s_entry->assoc,
2180                         &statbuf, &lstatbuf, deep_flag);
2181         }
2182         /* leave out resource fork for the time being */
2183         /*
2184          * XXX This is most likely wrong and should just be:
2185          * XXX if (use_XA || use_RockRidge) {
2186          */
2187 /*      if ((use_XA || use_RockRidge) && !have_rsrc) {*/
2188         if (use_XA || use_RockRidge) {
2189 #else
2190         if (use_XA || use_RockRidge) {
2191 #endif  /* APPLE_HYB */
2192                 generate_xa_rr_attributes(whole_path,
2193                         short_name, s_entry,
2194                         &statbuf, &lstatbuf, deep_flag);
2195
2196         }
2197         return (1);
2198 }
2199
2200
2201 void
2202 generate_iso9660_directories(struct directory *node, FILE *outfile)
2203 {
2204         struct directory *dpnt;
2205
2206         dpnt = node;
2207
2208         while (dpnt) {
2209                 if (dpnt->extent > session_start) {
2210                         generate_one_directory(dpnt, outfile);
2211                 }
2212                 if (dpnt->subdir)
2213                         generate_iso9660_directories(dpnt->subdir, outfile);
2214                 dpnt = dpnt->next;
2215         }
2216 }
2217
2218 /*
2219  * Function:    find_or_create_directory
2220  *
2221  * Purpose:     Locate a directory entry in the tree, create if needed.
2222  *              If a directory is created and stat_template is non-null,
2223  *              create the directory with ownership, permissions, etc.,
2224  *              from stat_template, otherwise use fallback defaults.
2225  *
2226  * Arguments:   parent & de are never NULL at the same time.
2227  */
2228 struct directory *
2229 find_or_create_directory(struct directory *parent,
2230                          const char *path, 
2231                          struct directory_entry *de,
2232                          int flag,
2233                          struct stat *stat_template)
2234 {
2235         struct directory *dpnt;
2236         struct directory_entry *orig_de;
2237         struct directory *next_brother;
2238         const char      *cpnt;
2239         const char      *pnt;
2240         struct stat     my_statbuf;
2241
2242         orig_de = de;
2243
2244         /*
2245          * XXX It seems that the tree that has been read from the
2246          * XXX previous session does not carry whole_name entries.
2247          * XXX We provide a hack in multi.c:find_or_create_directory()
2248          * XXX that should be removed when a reasonable method could
2249          * XXX be found.
2250          */
2251         if (path == NULL) {
2252                 fprintf(stderr, "Warning: missing whole name for: '%s'\n", de->name);
2253                 path = de->name;
2254         }
2255         pnt = strrchr(path, PATH_SEPARATOR);
2256         if (pnt == NULL) {
2257                 pnt = path;
2258         } else {
2259                 pnt++;
2260         }
2261
2262         if (parent != NULL) {
2263                 dpnt = parent->subdir;
2264
2265                 while (dpnt) {
2266                         /*
2267                          * Weird hack time - if there are two directories by
2268                          * the same name in the reloc_dir, they are not
2269                          * treated as the same thing unless the entire path
2270                          * matches completely.
2271                          */
2272                         if (flag && strcmp(dpnt->de_name, pnt) == 0) {
2273                                 return (dpnt);
2274                         }
2275                         dpnt = dpnt->next;
2276                 }
2277         }
2278         /*
2279          * We don't know if we have a valid directory entry for this one yet.
2280          * If not, we need to create one.
2281          */
2282         if (de == NULL) {
2283                 de = (struct directory_entry *)
2284                         e_malloc(sizeof (struct directory_entry));
2285                 memset(de, 0, sizeof (struct directory_entry));
2286                 de->next = parent->contents;
2287                 parent->contents = de;
2288                 de->name = strdup(pnt);
2289                 de->whole_name = strdup(path);
2290                 de->filedir = parent;
2291                 de->isorec.flags[0] = ISO_DIRECTORY;
2292                 de->priority = 32768;
2293                 de->inode = UNCACHED_INODE;
2294                 de->dev = (dev_t) UNCACHED_DEVICE;
2295                 set_723(de->isorec.volume_sequence_number,
2296                                                 volume_sequence_number);
2297                 iso9660_file_length(pnt, de, 1);
2298
2299                 /*
2300                  * If we were given a stat template, use it for
2301                  * ownership/permissions, otherwise use fallback defaults.
2302                  */
2303                 init_fstatbuf();
2304                 if (stat_template) {
2305                         my_statbuf = *stat_template;
2306                 } else {
2307                         my_statbuf = fstatbuf; /* defaults */
2308                         my_statbuf.st_mode = new_dir_mode;
2309                 }
2310                 my_statbuf.st_mode &= ~S_IFMT; /* zero out file type */
2311                 my_statbuf.st_mode |= S_IFDIR; /* force to be a directory */
2312                 my_statbuf.st_nlink = 2;
2313                 
2314                 /*
2315                  * Apply attributes from my_statbuf to the new directory.
2316                  */
2317                 if (use_XA || use_RockRidge) {
2318                         generate_xa_rr_attributes("", (char *) pnt, de,
2319                                 &my_statbuf, &my_statbuf, 0);
2320                 }
2321                 iso9660_date(de->isorec.date, fstatbuf.st_mtime);
2322 #ifdef APPLE_HYB
2323                 if (apple_both) {
2324                         /* give the directory an HFS entry */
2325                         hfsdirent       *hfs_ent;
2326
2327                         hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
2328
2329                         /* fill in the defaults */
2330                         memset(hfs_ent, 0, sizeof (hfsdirent));
2331                         hfs_ent->crdate = my_statbuf.st_ctime;
2332                         hfs_ent->mddate = my_statbuf.st_mtime;
2333
2334                         de->hfs_ent = hfs_ent;
2335
2336                         /* get the Mac directory name */
2337                         get_hfs_dir((char *) path, (char *) pnt, de);
2338                 }
2339 #endif  /* APPLE_HYB */
2340         }
2341         /*
2342          * If we don't have a directory for this one yet, then allocate it now,
2343          * and patch it into the tree in the appropriate place.
2344          */
2345         dpnt = (struct directory *) e_malloc(sizeof (struct directory));
2346         memset(dpnt, 0, sizeof (struct directory));
2347         dpnt->next = NULL;
2348         dpnt->subdir = NULL;
2349         dpnt->self = de;
2350         dpnt->contents = NULL;
2351         dpnt->whole_name = strdup(path);
2352         cpnt = strrchr(path, PATH_SEPARATOR);
2353         if (cpnt)
2354                 cpnt++;
2355         else
2356                 cpnt = path;
2357         dpnt->de_name = strdup(cpnt);
2358         dpnt->size = 0;
2359         dpnt->extent = 0;
2360         dpnt->jextent = 0;
2361         dpnt->jsize = 0;
2362 #ifdef APPLE_HYB
2363         dpnt->hfs_ent = de->hfs_ent;
2364 #endif  /* APPLE_HYB */
2365
2366         if (orig_de == NULL) {
2367                 struct stat     xstatbuf;
2368                 struct stat     parent_statbuf;
2369                 int             sts;
2370
2371                 /*
2372                  * Now add a . and .. entry in the directory itself. This is a
2373                  * little tricky - if the real directory exists, we need to
2374                  * stat it first. Otherwise, we use the fictitious fstatbuf
2375                  * which points to the time at which genisoimage was started.
2376                  */
2377                 if (parent == NULL || parent->whole_name[0] == '\0')
2378                         sts = -1;
2379                 else
2380                         sts = stat_filter(parent->whole_name, &parent_statbuf);
2381                 
2382                 if (sts != 0) {
2383                         parent_statbuf = fstatbuf;
2384                         parent_statbuf.st_mode = new_dir_mode | S_IFDIR;
2385                         parent_statbuf.st_nlink = 2;
2386                 }
2387                 
2388                 if (debug && parent) {
2389                         fprintf(stderr, "stat parent->whole_name: '%s' -> %d.\n",
2390                                 parent->whole_name, sts);
2391                 }
2392                 attach_dot_entries(dpnt, &my_statbuf, &parent_statbuf);
2393         }
2394         if (!parent || parent == root) {
2395                 if (!root) {
2396                         root = dpnt;    /* First time through for root  */
2397                                         /* directory only               */
2398                         root->depth = 0;
2399                         root->parent = root;
2400                 } else {
2401                         dpnt->depth = 1;
2402                         if (!root->subdir) {
2403                                 root->subdir = dpnt;
2404                         } else {
2405                                 next_brother = root->subdir;
2406                                 while (next_brother->next)
2407                                         next_brother = next_brother->next;
2408                                 next_brother->next = dpnt;
2409                         }
2410                         dpnt->parent = parent;
2411                 }
2412         } else {
2413                 /* Come through here for  normal traversal of  tree */
2414 #ifdef DEBUG
2415                 fprintf(stderr, "%s(%d) ", path, dpnt->depth);
2416 #endif
2417                 if (parent->depth > RR_relocation_depth) {
2418                         /*
2419                          * XXX to prevent this, we would need to add
2420                          * XXX support for RR directory relocation
2421                          * XXX to find_or_create_directory()
2422                          */
2423 #ifdef  USE_LIBSCHILY
2424                         comerrno(EX_BAD,
2425                         "Directories too deep for '%s' (%d) max is %d.\n",
2426                                 path, parent->depth, RR_relocation_depth);
2427 #else
2428                         fprintf(stderr,
2429                         "Directories too deep for '%s' (%d) max is %d.\n",
2430                                 path, parent->depth, RR_relocation_depth);
2431                         exit(1);
2432 #endif
2433                 }
2434                 dpnt->parent = parent;
2435                 dpnt->depth = parent->depth + 1;
2436
2437                 if (!parent->subdir) {
2438                         parent->subdir = dpnt;
2439                 } else {
2440                         next_brother = parent->subdir;
2441                         while (next_brother->next)
2442                                 next_brother = next_brother->next;
2443                         next_brother->next = dpnt;
2444                 }
2445         }
2446
2447         return (dpnt);
2448 }
2449
2450 /*
2451  * Function:    delete_directory
2452  *
2453  * Purpose:     Locate a directory entry in the tree, create if needed.
2454  *
2455  * Arguments:
2456  */
2457 static void
2458 delete_directory(parent, child)
2459         struct directory        *parent;
2460         struct directory        *child;
2461 {
2462         struct directory *tdir;
2463
2464         if (child->contents != NULL) {
2465 #ifdef  USE_LIBSCHILY
2466                 comerrno(EX_BAD, "Unable to delete non-empty directory\n");
2467 #else
2468                 fprintf(stderr, "Unable to delete non-empty directory\n");
2469                 exit(1);
2470 #endif
2471         }
2472         free(child->whole_name);
2473         child->whole_name = NULL;
2474
2475         free(child->de_name);
2476         child->de_name = NULL;
2477
2478 #ifdef APPLE_HYB
2479         if (apple_both && child->hfs_ent)
2480                 free(child->hfs_ent);
2481 #endif  /* APPLE_HYB */
2482
2483         if (parent->subdir == child) {
2484                 parent->subdir = child->next;
2485         } else {
2486                 for (tdir = parent->subdir; tdir->next != NULL;
2487                                                         tdir = tdir->next) {
2488                         if (tdir->next == child) {
2489                                 tdir->next = child->next;
2490                                 break;
2491                         }
2492                 }
2493                 if (tdir == NULL) {
2494 #ifdef  USE_LIBSCHILY
2495                         comerrno(EX_BAD,
2496                         "Unable to locate child directory in parent list\n");
2497 #else
2498                         fprintf(stderr,
2499                         "Unable to locate child directory in parent list\n");
2500                         exit(1);
2501 #endif
2502                 }
2503         }
2504         free(child);
2505 }
2506
2507 int
2508 sort_tree(struct directory *node)
2509 {
2510         struct directory *dpnt;
2511         int             ret = 0;
2512
2513         dpnt = node;
2514
2515         while (dpnt) {
2516                 ret = sort_n_finish(dpnt);
2517                 if (ret) {
2518                         break;
2519                 }
2520                 if (dpnt->subdir)
2521                         sort_tree(dpnt->subdir);
2522                 dpnt = dpnt->next;
2523         }
2524         return (ret);
2525 }
2526
2527 void
2528 dump_tree(struct directory *node)
2529 {
2530         struct directory *dpnt;
2531
2532         dpnt = node;
2533
2534         while (dpnt) {
2535                 fprintf(stderr, "%4d %5d %s\n",
2536                                 dpnt->extent, dpnt->size, dpnt->de_name);
2537                 if (dpnt->subdir)
2538                         dump_tree(dpnt->subdir);
2539                 dpnt = dpnt->next;
2540         }
2541 }
2542
2543 void
2544 update_nlink_field(struct directory *node)
2545 {
2546         struct directory *dpnt;
2547         struct directory *xpnt;
2548         struct directory_entry *s_entry;
2549         int             i;
2550
2551         dpnt = node;
2552
2553         while (dpnt) {
2554                 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
2555                         dpnt = dpnt->next;
2556                         continue;
2557                 }
2558                 /*
2559                  * First, count up the number of subdirectories this guy has.
2560                  */
2561                 for (i = 0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
2562                         if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
2563                                 i++;
2564                 /*
2565                  * Next check to see if we have any relocated directories in
2566                  * this directory. The nlink field will include these as
2567                  * real directories when they are properly relocated.
2568                  * In the non-rockridge disk, the relocated entries appear as
2569                  * zero length files.
2570                  */
2571                 for (s_entry = dpnt->contents; s_entry;
2572                                                 s_entry = s_entry->next) {
2573                         if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0 &&
2574                                 (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) ==
2575                                                                         0) {
2576                                 i++;
2577                         }
2578                 }
2579                 /* Now update the field in the Rock Ridge entry. */
2580                 update_nlink(dpnt->self, i + 2);
2581
2582                 /* Update the '.' entry for this directory. */
2583                 update_nlink(dpnt->contents, i + 2);
2584
2585                 /* Update all of the '..' entries that point to this guy. */
2586                 for (xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
2587                         update_nlink(xpnt->contents->next, i + 2);
2588
2589                 if (dpnt->subdir)
2590                         update_nlink_field(dpnt->subdir);
2591                 dpnt = dpnt->next;
2592         }
2593 }
2594
2595 /*
2596  * something quick and dirty to locate a file given a path
2597  * recursively walks down path in filename until it finds the
2598  * directory entry for the desired file
2599  */
2600 struct directory_entry *
2601 search_tree_file(struct directory *node, char *filename)
2602 {
2603         struct directory_entry *depnt;
2604         struct directory *dpnt;
2605         char            *p1;
2606         char            *rest;
2607         char            *subdir;
2608
2609         /* strip off next directory name from filename */
2610         subdir = strdup(filename);
2611
2612         if ((p1 = strchr(subdir, '/')) == subdir) {
2613                 fprintf(stderr,
2614                 "call to search_tree_file with an absolute path, stripping\n");
2615                 fprintf(stderr,
2616                 "initial path separator. Hope this was intended...\n");
2617                 memmove(subdir, subdir + 1, strlen(subdir) - 1);
2618                 p1 = strchr(subdir, '/');
2619         }
2620         /* do we need to find a subdirectory */
2621         if (p1) {
2622                 *p1 = '\0';
2623
2624 #ifdef DEBUG_TORITO
2625                 fprintf(stderr, "Looking for subdir called %s\n", p1);
2626 #endif
2627
2628                 rest = p1 + 1;
2629
2630 #ifdef DEBUG_TORITO
2631                 fprintf(stderr, "Remainder of path name is now %s\n", rest);
2632 #endif
2633
2634                 dpnt = node->subdir;
2635                 while (dpnt) {
2636 #ifdef DEBUG_TORITO
2637                         fprintf(stderr,
2638                                 "%4d %5d %s\n", dpnt->extent, dpnt->size,
2639                                 dpnt->de_name);
2640 #endif
2641                         if (strcmp(subdir, dpnt->de_name) == 0) {
2642 #ifdef DEBUG_TORITO
2643                                 fprintf(stderr,
2644                                 "Calling next level with filename = %s", rest);
2645 #endif
2646                                 return (search_tree_file(dpnt, rest));
2647                         }
2648                         dpnt = dpnt->next;
2649                 }
2650
2651                 /* if we got here means we couldnt find the subdir */
2652                 return (NULL);
2653         } else {
2654                 /* look for a normal file now */
2655                 depnt = node->contents;
2656                 while (depnt) {
2657 #ifdef DEBUG_TORITO
2658                         fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
2659                                 depnt->size, depnt->name);
2660 #endif
2661                         if (strcmp(filename, depnt->name) == 0) {
2662 #ifdef DEBUG_TORITO
2663                                 fprintf(stderr, "Found our file %s", filename);
2664 #endif
2665                                 return (depnt);
2666                         }
2667                         depnt = depnt->next;
2668                 }
2669                 /* if we got here means we couldnt find the subdir */
2670                 return (NULL);
2671         }
2672 #ifdef  ERIC_FUN
2673         fprintf(stderr, "We cant get here in search_tree_file :-/ \n");
2674 #endif
2675 }
2676
2677 void
2678 init_fstatbuf()
2679 {
2680         time_t  current_time;
2681
2682         if (fstatbuf.st_ctime == 0) {
2683                 time(&current_time);
2684                 if (rationalize_uid)
2685                         fstatbuf.st_uid = uid_to_use;
2686                 else
2687                         fstatbuf.st_uid = getuid();
2688                 if (rationalize_gid)
2689                         fstatbuf.st_gid = gid_to_use;
2690                 else
2691                         fstatbuf.st_gid = getgid();
2692                 fstatbuf.st_ctime = current_time;
2693                 fstatbuf.st_mtime = current_time;
2694                 fstatbuf.st_atime = current_time;
2695         }
2696 }