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