2 * This file has been modified for the cdrkit suite.
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).
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.
13 /* @(#)tree.c 1.82 04/06/12 joerg */
14 /* Parets from @(#)tree.c 1.112 08/08/14 joerg */
16 * File tree.c - scan directory tree and build memory structures for iso9660
19 * Written by Eric Youngdale (1993).
21 * Copyright 1993 Yggdrasil Computing, Incorporated
22 * Copyright (c) 1999,2000-2004 J. Schilling
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)
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.
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.
38 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
40 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
43 #include "genisoimage.h"
53 extern int allow_limited_size;
57 #include <vms/fabdef.h>
62 * Autoconf should be able to figure this one out for us and let us know
63 * whether the system has memmove or not.
66 #define memmove(d, s, n) bcopy((s), (d), (n))
69 static Uchar symlink_buff[PATH_MAX+1];
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);
87 int insert_file_entry(struct directory *this_dir,
92 int insert_file_entry(struct directory *this_dir,
96 void generate_iso9660_directories(struct directory *node,
98 struct directory *find_or_create_directory(struct directory *parent,
100 struct directory_entry *de,
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,
112 void init_fstatbuf(void);
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;
123 static char unkn[32];
125 if (S_ISFIFO(t)) /* 1 */
127 if (S_ISCHR(t)) /* 2 */
129 if (S_ISMPC(t)) /* 3 */
130 return ("multiplexed chr");
131 if (S_ISDIR(t)) /* 4 */
133 if (S_ISNAM(t)) /* 5 */
134 return ("named file");
135 if (S_ISBLK(t)) /* 6 */
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 */
145 if (S_ISSHAD(t)) /* 11 */
146 return ("Solaris shadow inode");
147 if (S_ISSOCK(t)) /* 12 */
149 if (S_ISDOOR(t)) /* 13 */
151 if (S_ISWHT(t)) /* 14 */
153 if (S_ISEVC(t)) /* 15 */
154 return ("event count");
157 * Needs to be last in case somebody makes this
158 * a supported file type.
160 if ((t & S_IFMT) == 0) /* 0 (unallocated) */
161 return ("unallocated");
163 sprintf(unkn, "octal '%o'", t & S_IFMT);
168 * Check if s1 ends in strings s2
171 rstr(char *s1, char *s2)
179 return ((char *) NULL);
181 if (strcmp(&s1[l1 - l2], s2) == 0)
182 return (&s1[l1 - l2]);
183 return ((char *) NULL);
187 stat_fix(struct stat *st)
189 int adjust_modes = 0;
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;
196 adjust_modes = (rationalize_filemode || rationalize_dirmode);
199 * If rationalizing, override the uid and gid, since the
200 * originals will only be useful on the author's system.
203 st->st_uid = uid_to_use;
205 st->st_gid = gid_to_use;
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;
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,
225 #if !defined(_WIN32) && !defined(__DJGPP__) /* make all file "executable" */
226 if (st->st_mode & 0111)
229 st->st_mode &= ~07222;
235 stat_filter(char *path, struct stat *st)
237 int result = stat(path, st);
239 if (result >= 0 && rationalize)
245 lstat_filter(char *path, struct stat *st)
247 int result = lstat(path, st);
249 if (result >= 0 && rationalize)
255 sort_n_finish(struct directory *this_dir)
257 struct directory_entry *s_entry;
258 struct directory_entry *s_entry1;
259 struct directory_entry *table;
264 register int new_reclen;
268 char newname[MAX_ISONAME+1];
269 char rootname[MAX_ISONAME+1];
270 char extname[MAX_ISONAME+1];
273 * Here we can take the opportunity to toss duplicate entries from the
276 /* ignore if it's hidden */
277 if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
285 * If we had artificially created this directory, then we might be
286 * missing the required '.' entries. Create these now if we need
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);
296 s_entry = this_dir->contents;
298 #ifdef USE_LARGEFILES
300 * Skip all but the last extent from a multi extent file,
301 * we like them all have the same name.
303 if ((s_entry->de_flags & MULTI_EXTENT) &&
304 (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)) {
305 s_entry = s_entry->next;
309 /* ignore if it's hidden */
310 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
311 s_entry = s_entry->next;
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;
322 * if the pair are associated, then skip (as they have the
325 if (apple_both && s_entry1->assoc &&
326 s_entry1->assoc == s_entry) {
327 s_entry = s_entry->next;
330 #endif /* APPLE_HYB */
332 if (s_entry1 == s_entry) {
335 "Fatal goof, file '%s' already in hash table.\n",
336 s_entry->isorec.name);
339 "Fatal goof, file '%s' already in hash table.\n",
340 s_entry->isorec.name);
345 * OK, handle the conflicts. Try substitute names until we
346 * come up with a winner
348 strcpy(rootname, s_entry->isorec.name);
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 ';'.
354 c = strchr(rootname, '.');
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
360 if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
361 c = strrchr(rootname, '.');
363 extname[0] = '\0'; /* In case we have no ext. */
366 *c = 0; /* Cut off complete ext. */
369 * Could not find any '.'.
371 c = strchr(rootname, ';');
373 *c = 0; /* Cut off version number */
376 c = strchr(extname, ';');
378 *c = 0; /* Cut off version number */
380 d1 = strlen(rootname);
381 if (full_iso9660_filenames || iso9660_level > 1) {
382 d2 = strlen(extname);
384 * 31/37 chars minus the 3 characters we are
385 * appending below to create unique filenames.
387 if ((d1 + d2) > (iso9660_namelen - 3))
388 rootname[iso9660_namelen - 3 - d2] = 0;
393 new_reclen = strlen(rootname);
394 sprintf(newname, "%s000%s%s",
397 ((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
398 omit_version_number ? "" : ";1"));
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);
410 fprintf(stderr, "NEW name '%s'\n", newname);
413 /* Sigh. VAXCRTL seems to be broken here */
417 while (newname[ijk]) {
418 if (newname[ijk] == ' ')
425 if (!find_file_hash(newname))
431 /* If we fell off the bottom here, we were in real trouble. */
434 "Unable to generate unique name for file %s\n",
438 "Unable to generate unique name for file %s\n",
445 * OK, now we have a good replacement name. Now decide which
446 * one of these two beasts should get the name changed
448 if (s_entry->priority < s_entry1->priority) {
450 fprintf(stderr, "Using %s for %s%s%s (%s)\n",
452 this_dir->whole_name, SPATH_SEPARATOR,
453 s_entry->name, s_entry1->name);
456 s_entry->isorec.name_len[0] = strlen(newname);
457 new_reclen = offsetof(struct iso_directory_record,
460 if (use_XA || use_RockRidge) {
462 new_reclen++; /* Pad to an even byte */
463 new_reclen += s_entry->rr_attr_size;
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;
474 * Copy over the new name to all other entries
476 for (s_e = s_entry->mxroot;
477 s_e && s_e->mxroot == s_entry->mxroot;
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);
486 /* has resource fork - needs new name */
487 if (apple_both && s_entry->assoc) {
488 struct directory_entry *s_entry2 =
492 * resource fork name *should* be the same as
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;
501 #endif /* APPLE_HYB */
503 delete_file_hash(s_entry1);
505 fprintf(stderr, "Using %s for %s%s%s (%s)\n",
507 this_dir->whole_name, SPATH_SEPARATOR,
508 s_entry1->name, s_entry->name);
510 s_entry1->isorec.name_len[0] = strlen(newname);
511 new_reclen = offsetof(struct iso_directory_record,
514 if (use_XA || use_RockRidge) {
516 new_reclen++; /* Pad to an even byte */
517 new_reclen += s_entry1->rr_attr_size;
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;
528 * Copy over the new name to all other entries
530 for (s_e = s_entry1->mxroot;
531 s_e && s_e->mxroot == s_entry1->mxroot;
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);
539 add_file_hash(s_entry1);
541 /* has resource fork - needs new name */
542 if (apple_both && s_entry1->assoc) {
543 struct directory_entry *s_entry2 =
547 * resource fork name *should* be the same as
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;
556 #endif /* APPLE_HYB */
558 add_file_hash(s_entry);
559 s_entry = s_entry->next;
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)
573 /* skip table entry for the resource fork */
575 (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
577 #endif /* APPLE_HYB */
578 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
580 if (s_entry->table) {
582 * Max namelen, a space before and a space
583 * after the iso filename.
585 tablesize += MAX_ISONAME + 2 +
586 strlen(s_entry->table);
591 table = (struct directory_entry *)
592 e_malloc(sizeof (struct directory_entry));
593 memset(table, 0, sizeof (struct directory_entry));
595 table->next = this_dir->contents;
596 this_dir->contents = table;
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;
611 table->de_flags |= INHIBIT_JOLIET_ENTRY;
613 * Always hide transtable from UDF tree.
615 table->de_flags |= INHIBIT_UDF_ENTRY;
616 /* table->name = strdup("<translation table>");*/
617 table->name = strdup(trans_tbl);
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.
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);
627 if (use_XA || use_RockRidge) {
628 fstatbuf.st_mode = 0444 | S_IFREG;
629 fstatbuf.st_nlink = 1;
630 generate_xa_rr_attributes("",
632 &fstatbuf, &fstatbuf, 0);
636 * We have now chosen the 8.3 names and we should now know the length
637 * of every entry in the directory.
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) {
644 new_reclen = strlen(s_entry->isorec.name);
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,
657 if (this_dir == root && strlen(s_entry->name)
659 path_table_size += new_reclen +
660 offsetof(struct iso_path_table,
665 if (path_table_size & 1)
666 path_table_size++; /* For odd lengths we pad */
667 s_entry->isorec.name_len[0] = new_reclen;
669 new_reclen += offsetof(struct iso_directory_record, name[0]);
674 new_reclen += s_entry->rr_attr_size;
679 if (new_reclen > 0xff) {
682 "Fatal error - RR overflow (reclen %d) for file %s\n",
687 "Fatal error - RR overflow (reclen %d) for file %s\n",
693 s_entry->isorec.length[0] = new_reclen;
696 status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
698 fprintf(stderr, "Unable to sort directory %s\n",
699 this_dir->whole_name);
701 fprintf(stderr, merge_warn_msg);
705 * If we are filling out a TRANS.TBL, generate the entries that will
710 for (s_entry = this_dir->contents; s_entry;
711 s_entry = s_entry->next) {
712 if (s_entry == table)
716 if (strcmp(s_entry->name, ".") == 0 ||
717 strcmp(s_entry->name, "..") == 0)
720 /* skip table entry for the resource fork */
722 (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
724 #endif /* APPLE_HYB */
725 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
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
732 * Old mkiofs introduced a space after the iso
733 * filename to make parsing TRANS.TBL easier.
735 sprintf(table->table + count, "%c %-*s%s",
738 s_entry->isorec.name, s_entry->table + 1);
739 count += strlen(table->table + count);
740 free(s_entry->table);
742 * for a memory file, set s_entry->table to the
743 * correct data - which is stored in
744 * s_entry->whole_name
746 if (s_entry->de_flags & MEMORY_FILE) {
747 s_entry->table = s_entry->whole_name;
748 s_entry->whole_name = NULL;
750 s_entry->table = NULL;
754 if (count != tablesize) {
757 "Translation table size mismatch %d %d\n",
761 "Translation table size mismatch %d %d\n",
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
771 s_entry = this_dir->contents;
772 this_dir->ce_bytes = 0;
774 /* skip if it's hidden */
775 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
776 s_entry = s_entry->next;
779 new_reclen = s_entry->isorec.length[0];
780 if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
783 this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
785 this_dir->size += new_reclen;
787 /* See if continuation entries were used on disc */
789 s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
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);*/
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.
806 if (pnt[0] == 'C' && pnt[1] == 'E') {
807 nbytes = get_733((char *) pnt + 20);
809 if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
812 ISO_ROUND_UP(this_dir->ce_bytes);
814 * Now store the block in the
817 this_dir->ce_bytes += nbytes;
818 if (this_dir->ce_bytes & 1)
819 this_dir->ce_bytes++;
825 s_entry = s_entry->next;
831 generate_reloc_directory()
834 struct directory_entry *s_entry;
836 /* Create an entry for our internal tree */
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;
846 reloc_dir->whole_name = strdup("./.rr_moved");
847 reloc_dir->de_name = strdup(".rr_moved");
849 reloc_dir->whole_name = strdup("./rr_moved");
850 reloc_dir->de_name = strdup("rr_moved");
852 reloc_dir->extent = 0;
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;
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;
866 reloc_dir->dir_flags |= INHIBIT_UDF_ENTRY;
867 s_entry->de_flags |= INHIBIT_UDF_ENTRY;
869 /* Hiding RR_MOVED seems not to be possible..... */
871 reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
872 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
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);
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);
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);
904 * Function: attach_dot_entries
906 * Purpose: Create . and .. entries for a new directory.
908 * Arguments: dir_stat contains the ownership/permission information
909 * for dirnode, and parent_stat contains
910 * ownership/permission information for its parent
913 * Notes: Only used for artificial directories that
917 attach_dot_entries(struct directory *dirnode, struct stat *dir_stat,
918 struct stat *parent_stat)
920 struct directory_entry *s_entry;
921 struct directory_entry *orig_contents;
926 orig_contents = dirnode->contents;
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));
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,
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;
954 dirnode->contents = s_entry;
955 dirnode->contents->next = orig_contents;
956 orig_contents = s_entry;
958 if (use_XA || use_RockRidge) {
959 generate_xa_rr_attributes("",
964 dirnode->dir_flags |= DIR_HAS_DOTDOT;
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));
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,
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;
992 dirnode->contents = s_entry;
993 dirnode->contents->next = orig_contents;
995 if (use_XA || use_RockRidge) {
997 if (dirnode == root) {
998 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
1000 generate_xa_rr_attributes("", ".", s_entry,
1001 dir_stat, dir_stat, deep_flag);
1003 dirnode->dir_flags |= DIR_HAS_DOT;
1008 update_nlink(struct directory_entry *s_entry, int value)
1013 pnt = s_entry->rr_attributes;
1014 len = s_entry->total_rr_attr_size;
1015 pnt = parse_xa(pnt, &len, 0);
1017 if (pnt[3] != 1 && pnt[3] != 2) {
1018 #ifdef USE_LIBSCHILY
1020 "**BAD RRVERSION (%d) for %c%c\n",
1021 pnt[3], pnt[0], pnt[1]);
1024 "**BAD RRVERSION (%d) for %c%c\n",
1025 pnt[3], pnt[0], pnt[1]);
1028 if (pnt[0] == 'P' && pnt[1] == 'X') {
1029 set_733((char *) pnt + 12, value);
1038 increment_nlink(struct directory_entry *s_entry)
1044 pnt = s_entry->rr_attributes;
1045 len = s_entry->total_rr_attr_size;
1046 pnt = parse_xa(pnt, &len, 0);
1048 if (pnt[3] != 1 && pnt[3] != 2) {
1049 #ifdef USE_LIBSCHILY
1051 "**BAD RRVERSION (%d) for %c%c\n",
1052 pnt[3], pnt[0], pnt[1]);
1055 "**BAD RRVERSION (%d) for %c%c\n",
1056 pnt[3], pnt[0], pnt[1]);
1059 if (pnt[0] == 'P' && pnt[1] == 'X') {
1060 nlink = get_733((char *) pnt + 12);
1061 set_733((char *) pnt + 12, nlink + 1);
1070 find_rr_attribute(unsigned char *pnt, int len, char *attr_type)
1072 pnt = parse_xa(pnt, &len, 0);
1074 if (pnt[3] != 1 && pnt[3] != 2) {
1075 #ifdef USE_LIBSCHILY
1077 "**BAD RRVERSION (%d) for %c%c\n",
1078 pnt[3], pnt[0], pnt[1]);
1081 "**BAD RRVERSION (%d) for %c%c\n",
1082 pnt[3], pnt[0], pnt[1]);
1085 if (strncmp((char *) pnt, attr_type, 2) == 0)
1086 return ((char *) pnt);
1087 else if (strncmp((char *) pnt, "ST", 2) == 0)
1096 finish_cl_pl_entries()
1098 struct directory_entry *s_entry;
1099 struct directory_entry *s_entry1;
1100 struct directory *d_entry;
1102 /* if the reloc_dir is hidden (empty), then return */
1103 if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
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) {
1113 d_entry = reloc_dir->subdir;
1115 if (d_entry->self == s_entry)
1117 d_entry = d_entry->next;
1120 #ifdef USE_LIBSCHILY
1122 "Unable to locate directory parent\n");
1124 fprintf(stderr, "Unable to locate directory parent\n");
1129 if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
1133 * First fix the PL pointer in the directory in the
1136 s_entry1 = d_entry->contents->next;
1138 /* set_733((char *) s_entry1->rr_attributes +*/
1139 /* s_entry1->total_rr_attr_size - 8,*/
1140 /* s_entry->filedir->extent); */
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.
1147 * So, just search for the attributes by name
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);
1155 /* Now fix the CL pointer */
1156 s_entry1 = s_entry->parent_rec;
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);
1165 s_entry->filedir = reloc_dir; /* Now we can fix this */
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
1172 increment_nlink(root->self);
1173 increment_nlink(root->self->next);
1174 d_entry = root->subdir;
1176 increment_nlink(d_entry->contents->next);
1177 d_entry = d_entry->next;
1180 finish_cl_pl_for_prev_session();
1184 * Function: scan_directory_tree
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.
1193 scan_directory_tree(struct directory *this_dir, char *path,
1194 struct directory_entry *de)
1197 char whole_path[PATH_MAX];
1198 struct dirent *d_entry;
1199 struct directory *parent;
1204 fprintf(stderr, "Scanning %s\n", path);
1206 /*#define check_needed*/
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.
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 */
1218 this_dir->dir_flags |= DIR_WAS_SCANNED;
1220 errno = 0; /* Paranoia */
1221 current_dir = opendir(path);
1225 * Apparently NFS sometimes allows you to open the directory, but then
1226 * refuses to allow you to read the contents. Allow for this
1232 d_entry = readdir(current_dir);
1235 if (!current_dir || !d_entry) {
1238 #ifdef USE_LIBSCHILY
1239 errmsg("Unable to open directory %s\n", path);
1241 fprintf(stderr, "Unable to open directory %s\n", path);
1243 if (errno == ENOTDIR) {
1244 /* Mark as not a directory */
1245 de->isorec.flags[0] &= ~ISO_DIRECTORY;
1249 closedir(current_dir);
1252 #ifdef ABORT_DEEP_ISO_ONLY
1253 if ((this_dir->depth > RR_relocation_depth) && !use_RockRidge) {
1254 static BOOL did_hint = FALSE;
1257 "Directories too deep for '%s' (%d) max is %d; ignored - continuing.\n",
1258 path, this_dir->depth, RR_relocation_depth);
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");
1265 closedir(current_dir);
1270 parent = de->filedir;
1272 * Set up the struct for the current directory, and insert it into
1276 vms_path_fixup(path);
1280 * if entry for this sub-directory is hidden, then hide this directory
1282 if (de->de_flags & INHIBIT_ISO9660_ENTRY)
1283 this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
1285 if (de->de_flags & INHIBIT_JOLIET_ENTRY)
1286 this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
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
1294 this_dir->sort = de->sort;
1295 #endif /* SORTING */
1298 * Now we scan the directory itself, and look at what is inside of it.
1304 * The first time through, skip this, since we already asked
1305 * for the first entry when we opened the directory.
1308 d_entry = readdir(current_dir);
1314 /* OK, got a valid entry */
1316 /* If we do not want all files, then pitch the backups. */
1318 if (strchr(d_entry->d_name, '~') ||
1319 strchr(d_entry->d_name, '#') ||
1320 rstr(d_entry->d_name, ".bak")) {
1323 "Ignoring file %s\n",
1332 * exclude certain HFS type files/directories for the
1335 if (hfs_exclude(d_entry->d_name))
1338 #endif /* APPLE_HYB */
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");
1347 fprintf(stderr, "Path name %s/%s too long.\n",
1348 path, d_entry->d_name);
1349 fprintf(stderr, "Overflow of stat buffer\n");
1354 /* Generate the complete ASCII path for this file */
1355 strcpy(whole_path, path);
1357 if (whole_path[strlen(whole_path) - 1] != '/')
1358 strcat(whole_path, "/");
1360 strcat(whole_path, d_entry->d_name);
1362 /** Should we exclude this file ? */
1363 if (matches(d_entry->d_name) || matches(whole_path)) {
1366 "Excluded by match: %s\n", whole_path);
1370 if (generate_tables &&
1371 strcmp(d_entry->d_name, trans_tbl) == 0) {
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.
1378 fprintf(stderr, "Excluded: %s\n", whole_path);
1383 * If we already have a '.' or a '..' entry, then don't insert
1386 if (strcmp(d_entry->d_name, ".") == 0 &&
1387 this_dir->dir_flags & DIR_HAS_DOT) {
1390 if (strcmp(d_entry->d_name, "..") == 0 &&
1391 this_dir->dir_flags & DIR_HAS_DOTDOT) {
1396 fprintf(stderr, "%s\n", whole_path);
1398 /* This actually adds the entry to the directory in question.*/
1400 insert_file_entry(this_dir, whole_path, d_entry->d_name, 0);
1402 insert_file_entry(this_dir, whole_path, d_entry->d_name);
1403 #endif /* APPLE_HYB */
1405 closedir(current_dir);
1409 * if we cached the HFS info stuff for this directory, then delete it
1411 if (this_dir->hfs_info) {
1412 del_hfs_info(this_dir->hfs_info);
1413 this_dir->hfs_info = 0;
1415 #endif /* APPLE_HYB */
1422 * Function: insert_file_entry
1424 * Purpose: Insert one entry into our directory node.
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.
1437 insert_file_entry(struct directory *this_dir, char *whole_path,
1438 char *short_name, int have_rsrc)
1441 insert_file_entry(struct directory *this_dir, char *whole_path,
1443 #endif /* APPLE_HYB */
1445 struct stat statbuf,
1447 struct directory_entry *s_entry,
1456 int htype = TYPE_NONE;
1458 #endif /* APPLE_HYB */
1460 status = stat_filter(whole_path, &statbuf);
1462 lstatus = lstat_filter(whole_path, &lstatbuf);
1464 if ((status == -1) && (lstatus == -1)) {
1466 * This means that the file doesn't exist, or isn't accessible.
1467 * Sometimes this is because of NFS permissions problems.
1469 #ifdef USE_LIBSCHILY
1470 errmsg("Non-existent or inaccessible: %s\n", whole_path);
1472 fprintf(stderr, "Non-existent or inaccessible: %s\n",
1477 if (this_dir == root && strcmp(short_name, ".") == 0)
1478 root_statbuf = statbuf; /* Save this for later on */
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;
1485 if (S_ISLNK(lstatbuf.st_mode)) {
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.
1494 if ((status || !follow_links)) {
1495 if (use_RockRidge) {
1497 statbuf.st_size = (off_t)0;
1498 STAT_INODE(statbuf) = UNCACHED_INODE;
1499 statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
1501 (statbuf.st_mode & ~S_IFMT) | S_IFREG;
1504 #ifdef USE_LIBSCHILY
1505 /* XXX errno may be wrong! */
1506 errmsg("Unable to stat file %s - ignoring and continuing.\n",
1510 "Unable to stat file %s - ignoring and continuing.\n",
1514 #ifdef USE_LIBSCHILY
1516 "Symlink %s ignored - continuing.\n",
1520 "Symlink %s ignored - continuing.\n",
1523 return (0); /* Non Rock Ridge discs */
1524 /* - ignore all symlinks */
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
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) {
1544 "Already cached directory seen (%s)\n",
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.
1559 /* no_scandir = 1;*/
1562 add_directory_hash(statbuf.st_dev,
1563 STAT_INODE(statbuf));
1568 * For non-directories, we just copy the stat information over
1569 * so we correctly include this file.
1572 !S_ISDIR(statbuf.st_mode)) {
1577 * Add directories to the cache so that we don't waste space even if
1578 * we are supposed to be following symlinks.
1581 strcmp(short_name, ".") &&
1582 strcmp(short_name, "..") &&
1583 S_ISDIR(statbuf.st_mode)) {
1584 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1587 if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
1588 statbuf.st_fab_rfm != FAB$C_STMLF)) {
1590 "Warning - file %s has an unsupported VMS record"
1592 whole_path, statbuf.st_fab_rfm);
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",
1602 "File %s is not readable (errno = %d) - ignoring\n",
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;
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)
1615 fprintf(stderr, "There is no way do represent this file size. Aborting. See -iso-level 3 or -allow-limited-size options\n");
1618 if(verbose>=1 && ! 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");
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.
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",*/
1638 "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1639 whole_path, (unsigned long) statbuf.st_dev,
1640 (unsigned long) STAT_INODE(statbuf));
1642 /* fprintf(stderr,*/
1643 /* "Directory loop - fatal goof (%s %lx %lu).\n",*/
1645 "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1646 whole_path, (unsigned long) statbuf.st_dev,
1647 (unsigned long) STAT_INODE(statbuf));
1650 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
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)) {
1658 "Unknown file type (%s) %s - ignoring and continuing.\n",
1659 filetype((int) lstatbuf.st_mode), whole_path);
1663 /* Who knows what trash this is - ignore and continue */
1666 #ifdef USE_LIBSCHILY
1667 errmsg("Unable to stat file %s - ignoring and continuing.\n",
1671 "Unable to stat file %s - ignoring and continuing.\n",
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.
1681 if (S_ISDIR(statbuf.st_mode)) {
1684 for (s_entry = this_dir->contents; s_entry;
1685 s_entry = s_entry->next) {
1686 if (strcmp(s_entry->name, short_name) == 0) {
1690 if (s_entry != NULL &&
1691 strcmp(short_name, ".") &&
1692 strcmp(short_name, "..")) {
1693 struct directory *child;
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)
1703 child = find_or_create_directory(reloc_dir,
1707 child = find_or_create_directory(this_dir,
1711 * If unable to scan directory, mark this as a
1715 /* if (no_scandir)*/
1719 dflag = scan_directory_tree(child,
1720 whole_path, s_entry);
1723 (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
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) {
1735 fprintf(stderr, "Hidden from HFS tree: %s\n",
1741 * check we are a file, using Apple extensions and have a .resource
1742 * part and not excluded
1744 if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
1745 char rsrc_path[PATH_MAX]; /* rsrc fork filename */
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 */
1751 struct stat rstatbuf,
1754 /* some further checks on the file */
1755 status = stat_filter(rsrc_path, &rstatbuf);
1757 lstatus = lstat_filter(rsrc_path, &rlstatbuf);
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) {
1765 * have a resource file - insert it into the
1766 * current directory but flag that we have a
1769 insert_file_entry(this_dir, rsrc_path,
1774 #endif /* APPLE_HYB */
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;
1784 s_entry->table = NULL;
1786 s_entry->name = strdup(short_name);
1787 s_entry->whole_name = strdup(whole_path);
1789 s_entry->de_flags = 0;
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
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, "..")
1799 if (i_matches(short_name) || i_matches(whole_path)) {
1802 "Hidden from ISO9660 tree: %s\n",
1805 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1807 if (h_matches(short_name) || h_matches(whole_path)) {
1810 "Hidden ISO9660 attribute: %s\n",
1813 s_entry->de_flags |= HIDDEN_FILE;
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, "..")
1821 if (j_matches(short_name) || j_matches(whole_path)) {
1824 "Hidden from Joliet tree: %s\n",
1827 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
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)) {
1838 "Hidden from UDF tree: %s\n",
1841 s_entry->de_flags |= INHIBIT_UDF_ENTRY;
1846 /* inherit any sort weight from parent directory */
1847 s_entry->sort = this_dir->sort;
1851 * No use at all to do a sort if we don't make a dvd video/audio
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.
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)
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);
1876 #endif /* SORTING */
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;
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;
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;
1899 * don't want the rsrc file to be included in any
1902 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1903 s_entry->de_flags |= INHIBIT_UDF_ENTRY;
1904 } else if (s_entry->next) {
1906 * if previous entry is an associated file,
1907 * then "link" it to this file i.e. we have a
1908 * data/resource pair
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;
1917 /* allocate HFS entry if required */
1918 if (apple_both && strcmp(short_name, ".") &&
1919 strcmp(short_name, "..")) {
1920 if (!s_entry->hfs_ent) {
1924 (hfsdirent *) e_malloc(sizeof (hfsdirent));
1926 /* fill in the defaults */
1927 memset(hfs_ent, 0, sizeof (hfsdirent));
1929 s_entry->hfs_ent = hfs_ent;
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
1939 s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
1941 * this will be overwritten - but might as
1942 * well set it here ...
1944 s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
1945 s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
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;
1954 #endif /* APPLE_HYB */
1956 if (strcmp(short_name, ".") == 0) {
1957 this_dir->dir_flags |= DIR_HAS_DOT;
1959 if (strcmp(short_name, "..") == 0) {
1960 this_dir->dir_flags |= DIR_HAS_DOTDOT;
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;
1971 /* don't want rsrc files to be cached */
1972 s_entry->inode = UNCACHED_INODE;
1973 s_entry->dev = (dev_t) UNCACHED_DEVICE;
1975 #endif /* APPLE_HYB */
1977 s_entry->inode = STAT_INODE(statbuf);
1978 s_entry->dev = statbuf.st_dev;
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;
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;
1996 s_entry->size = statbuf.st_size;
1999 set_733((char *) s_entry->isorec.size, statbuf.st_size);
2000 s_entry->realsize = statbuf.st_size;
2002 s_entry->isorec.flags[0] |= ISO_DIRECTORY;
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);
2011 /* if required, set ISO directory name from HFS name */
2013 iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
2015 #endif /* APPLE_HYB */
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;
2023 generate_reloc_directory();
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.
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);
2044 deep_flag = NEED_RE;
2046 if (use_XA || use_RockRidge) {
2047 generate_xa_rr_attributes(whole_path,
2048 short_name, s_entry1,
2049 &statbuf, &lstatbuf, deep_flag);
2054 * We need to set this temporarily so that the parent to this
2055 * is correctly determined.
2057 s_entry1->filedir = reloc_dir;
2058 child = find_or_create_directory(reloc_dir, whole_path,
2060 /* if (!no_scandir)*/
2062 scan_directory_tree(child, whole_path, s_entry1);
2063 s_entry1->filedir = this_dir;
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;
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;
2075 if (generate_tables &&
2076 strcmp(s_entry->name, ".") != 0 &&
2077 strcmp(s_entry->name, "..") != 0) {
2079 char buffer[SECTOR_SIZE];
2082 switch (lstatbuf.st_mode & S_IFMT) {
2084 sprintf(buffer, "D\t%s\n",
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
2095 * Use the device handling code from <device.h>
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))
2109 sprintf(buffer, "B\t%s\t%lu %lu\n",
2111 (unsigned long) major(statbuf.st_rdev),
2112 (unsigned long) minor(statbuf.st_rdev));
2117 sprintf(buffer, "P\t%s\n",
2123 sprintf(buffer, "C\t%s\t%lu %lu\n",
2125 (unsigned long) major(statbuf.st_rdev),
2126 (unsigned long) minor(statbuf.st_rdev));
2131 #ifdef HAVE_READLINK
2132 nchar = readlink(whole_path,
2133 (char *) symlink_buff,
2134 sizeof (symlink_buff)-1);
2138 symlink_buff[nchar < 0 ? 0 : nchar] = 0;
2139 sprintf(buffer, "L\t%s\t%s\n",
2140 s_entry->name, symlink_buff);
2145 sprintf(buffer, "S\t%s\n",
2151 sprintf(buffer, "F\t%s\n",
2155 s_entry->table = strdup(buffer);
2157 if (S_ISDIR(statbuf.st_mode)) {
2160 if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
2162 struct directory *child;
2164 child = find_or_create_directory(this_dir, whole_path,
2169 dflag = scan_directory_tree(child, whole_path,
2174 (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
2175 if (child->contents == NULL) {
2176 delete_directory(this_dir, child);
2180 /* If unable to scan directory, mark this as a non-directory */
2182 if (use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")
2184 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
2186 /* Now figure out how much room this file will take in the directory */
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 */
2193 /* fill in the rest of the HFS entry */
2194 get_hfs_info(whole_path, short_name, s_entry);
2196 /* if required, set ISO directory name from HFS name */
2198 iso9660_file_length(s_entry->hfs_ent->name,
2201 /* print details about the HFS file */
2203 print_hfs_info(s_entry);
2206 * copy the new ISO9660 name to the rsrc fork
2210 strcpy(s_entry->assoc->isorec.name,
2211 s_entry->isorec.name);
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
2221 s_entry->inode = UNCACHED_INODE;
2222 s_entry->dev = (dev_t) UNCACHED_DEVICE;
2224 } else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
2225 /* not a directory .. */
2228 * no mac equivalent, so ignore - have to be careful
2229 * here, the hfs_ent may be also be for a relocated
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);
2237 s_entry->hfs_ent = NULL;
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
2244 if (s_entry->assoc && s_entry->assoc->size == 0)
2245 delete_rsrc_ent(s_entry);
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);
2253 /* leave out resource fork for the time being */
2255 * XXX This is most likely wrong and should just be:
2256 * XXX if (use_XA || use_RockRidge) {
2258 /* if ((use_XA || use_RockRidge) && !have_rsrc) {*/
2259 if (use_XA || use_RockRidge) {
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);
2269 #ifdef USE_LARGEFILES
2270 #define LARGE_EXTENT 0xFFFFF800UL
2271 #define MAX_EXTENT 0xFFFFFFFEUL
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.
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.
2287 if (s_entry->size > MAX_EXTENT && do_largefiles) {
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;
2299 * full size UDF version
2301 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
2302 if (s_entry->size > (((off_t)190)*0x3FFFF800)) {
2304 #define EOVERFLOW EFBIG
2307 "File %s is too large - hiding from UDF tree.\n",
2309 s_entry->de_flags |= INHIBIT_UDF_ENTRY;
2313 * Prepare the first file multi-extent section of the file.
2316 s_entry->de_flags |= INHIBIT_UDF_ENTRY;
2317 size = s_entry->size;
2318 s_entry->size = LARGE_EXTENT;
2322 * Additional extents, as needed
2324 while (size > MAX_EXTENT) {
2325 s_entry1 = dup_directory_entry(s_entry);
2326 s_entry->next = s_entry1;
2330 size -= LARGE_EXTENT;
2333 * That was the last one.
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);
2339 #endif /* USE_LARGEFILES */
2344 EXPORT struct directory_entry *
2345 dup_directory_entry(s_entry)
2346 struct directory_entry *s_entry;
2348 struct directory_entry *s_entry1;
2350 s_entry1 = (struct directory_entry *)
2351 e_malloc(sizeof (struct directory_entry));
2352 memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
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);
2361 s_entry1->name = strdup(s_entry->name);
2362 if (s_entry->whole_name)
2363 s_entry1->whole_name = strdup(s_entry->whole_name);
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.
2374 generate_iso9660_directories(struct directory *node, FILE *outfile)
2376 struct directory *dpnt;
2381 if (dpnt->extent > session_start) {
2382 generate_one_directory(dpnt, outfile);
2385 generate_iso9660_directories(dpnt->subdir, outfile);
2391 * Function: find_or_create_directory
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.
2398 * Arguments: parent & de are never NULL at the same time.
2401 find_or_create_directory(struct directory *parent,
2403 struct directory_entry *de,
2405 struct stat *stat_template)
2407 struct directory *dpnt;
2408 struct directory_entry *orig_de;
2409 struct directory *next_brother;
2412 struct stat my_statbuf;
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
2424 fprintf(stderr, "Warning: missing whole name for: '%s'\n", de->name);
2427 pnt = strrchr(path, PATH_SEPARATOR);
2434 if (parent != NULL) {
2435 dpnt = parent->subdir;
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.
2444 if (flag && strcmp(dpnt->de_name, pnt) == 0) {
2451 * We don't know if we have a valid directory entry for this one yet.
2452 * If not, we need to create one.
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);
2472 * If we were given a stat template, use it for
2473 * ownership/permissions, otherwise use fallback defaults.
2476 if (stat_template) {
2477 my_statbuf = *stat_template;
2479 my_statbuf = fstatbuf; /* defaults */
2480 my_statbuf.st_mode = new_dir_mode;
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;
2487 * Apply attributes from my_statbuf to the new directory.
2489 if (use_XA || use_RockRidge) {
2490 generate_xa_rr_attributes("", (char *) pnt, de,
2491 &my_statbuf, &my_statbuf, 0);
2493 iso9660_date(de->isorec.date, fstatbuf.st_mtime);
2496 /* give the directory an HFS entry */
2499 hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
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;
2506 de->hfs_ent = hfs_ent;
2508 /* get the Mac directory name */
2509 get_hfs_dir((char *) path, (char *) pnt, de);
2511 #endif /* APPLE_HYB */
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.
2517 dpnt = (struct directory *) e_malloc(sizeof (struct directory));
2518 memset(dpnt, 0, sizeof (struct directory));
2520 dpnt->subdir = NULL;
2522 dpnt->contents = NULL;
2523 dpnt->whole_name = strdup(path);
2524 cpnt = strrchr(path, PATH_SEPARATOR);
2529 dpnt->de_name = strdup(cpnt);
2535 dpnt->hfs_ent = de->hfs_ent;
2536 #endif /* APPLE_HYB */
2538 if (orig_de == NULL) {
2539 struct stat xstatbuf;
2540 struct stat parent_statbuf;
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.
2549 if (parent == NULL || parent->whole_name[0] == '\0')
2552 sts = stat_filter(parent->whole_name, &parent_statbuf);
2555 parent_statbuf = fstatbuf;
2556 parent_statbuf.st_mode = new_dir_mode | S_IFDIR;
2557 parent_statbuf.st_nlink = 2;
2560 if (debug && parent) {
2561 fprintf(stderr, "stat parent->whole_name: '%s' -> %d.\n",
2562 parent->whole_name, sts);
2564 attach_dot_entries(dpnt, &my_statbuf, &parent_statbuf);
2566 if (!parent || parent == root) {
2568 root = dpnt; /* First time through for root */
2569 /* directory only */
2571 root->parent = root;
2574 if (!root->subdir) {
2575 root->subdir = dpnt;
2577 next_brother = root->subdir;
2578 while (next_brother->next)
2579 next_brother = next_brother->next;
2580 next_brother->next = dpnt;
2582 dpnt->parent = parent;
2585 /* Come through here for normal traversal of tree */
2587 fprintf(stderr, "%s(%d) ", path, dpnt->depth);
2589 if (parent->depth > RR_relocation_depth) {
2591 * XXX to prevent this, we would need to add
2592 * XXX support for RR directory relocation
2593 * XXX to find_or_create_directory()
2595 #ifdef USE_LIBSCHILY
2597 "Directories too deep for '%s' (%d) max is %d.\n",
2598 path, parent->depth, RR_relocation_depth);
2601 "Directories too deep for '%s' (%d) max is %d.\n",
2602 path, parent->depth, RR_relocation_depth);
2606 dpnt->parent = parent;
2607 dpnt->depth = parent->depth + 1;
2609 if (!parent->subdir) {
2610 parent->subdir = dpnt;
2612 next_brother = parent->subdir;
2613 while (next_brother->next)
2614 next_brother = next_brother->next;
2615 next_brother->next = dpnt;
2623 * Function: delete_directory
2625 * Purpose: Locate a directory entry in the tree, create if needed.
2630 delete_directory(parent, child)
2631 struct directory *parent;
2632 struct directory *child;
2634 struct directory *tdir;
2636 if (child->contents != NULL) {
2637 #ifdef USE_LIBSCHILY
2638 comerrno(EX_BAD, "Unable to delete non-empty directory\n");
2640 fprintf(stderr, "Unable to delete non-empty directory\n");
2644 free(child->whole_name);
2645 child->whole_name = NULL;
2647 free(child->de_name);
2648 child->de_name = NULL;
2651 if (apple_both && child->hfs_ent)
2652 free(child->hfs_ent);
2653 #endif /* APPLE_HYB */
2655 if (parent->subdir == child) {
2656 parent->subdir = child->next;
2658 for (tdir = parent->subdir; tdir->next != NULL;
2659 tdir = tdir->next) {
2660 if (tdir->next == child) {
2661 tdir->next = child->next;
2666 #ifdef USE_LIBSCHILY
2668 "Unable to locate child directory in parent list\n");
2671 "Unable to locate child directory in parent list\n");
2680 sort_tree(struct directory *node)
2682 struct directory *dpnt;
2688 ret = sort_n_finish(dpnt);
2693 sort_tree(dpnt->subdir);
2700 dump_tree(struct directory *node)
2702 struct directory *dpnt;
2707 fprintf(stderr, "%4d %5d %s\n",
2708 dpnt->extent, dpnt->size, dpnt->de_name);
2710 dump_tree(dpnt->subdir);
2716 update_nlink_field(struct directory *node)
2718 struct directory *dpnt;
2719 struct directory *xpnt;
2720 struct directory_entry *s_entry;
2726 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
2731 * First, count up the number of subdirectories this guy has.
2733 for (i = 0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
2734 if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
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.
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) ==
2751 /* Now update the field in the Rock Ridge entry. */
2752 update_nlink(dpnt->self, i + 2);
2754 /* Update the '.' entry for this directory. */
2755 update_nlink(dpnt->contents, i + 2);
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);
2762 update_nlink_field(dpnt->subdir);
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
2772 struct directory_entry *
2773 search_tree_file(struct directory *node, char *filename)
2775 struct directory_entry *depnt;
2776 struct directory *dpnt;
2781 /* strip off next directory name from filename */
2782 subdir = strdup(filename);
2784 if ((p1 = strchr(subdir, '/')) == subdir) {
2786 "call to search_tree_file with an absolute path, stripping\n");
2788 "initial path separator. Hope this was intended...\n");
2789 memmove(subdir, subdir + 1, strlen(subdir) - 1);
2790 p1 = strchr(subdir, '/');
2792 /* do we need to find a subdirectory */
2797 fprintf(stderr, "Looking for subdir called %s\n", p1);
2803 fprintf(stderr, "Remainder of path name is now %s\n", rest);
2806 dpnt = node->subdir;
2810 "%4d %5d %s\n", dpnt->extent, dpnt->size,
2813 if (strcmp(subdir, dpnt->de_name) == 0) {
2816 "Calling next level with filename = %s", rest);
2818 return (search_tree_file(dpnt, rest));
2823 /* if we got here means we couldnt find the subdir */
2826 /* look for a normal file now */
2827 depnt = node->contents;
2830 fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
2831 depnt->size, depnt->name);
2833 if (strcmp(filename, depnt->name) == 0) {
2835 fprintf(stderr, "Found our file %s", filename);
2839 depnt = depnt->next;
2841 /* if we got here means we couldnt find the subdir */
2845 fprintf(stderr, "We cant get here in search_tree_file :-/ \n");
2852 time_t current_time;
2854 if (fstatbuf.st_ctime == 0) {
2855 time(¤t_time);
2856 if (rationalize_uid)
2857 fstatbuf.st_uid = uid_to_use;
2859 fstatbuf.st_uid = getuid();
2860 if (rationalize_gid)
2861 fstatbuf.st_gid = gid_to_use;
2863 fstatbuf.st_gid = getgid();
2864 fstatbuf.st_ctime = current_time;
2865 fstatbuf.st_mtime = current_time;
2866 fstatbuf.st_atime = current_time;