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 */
15 * File tree.c - scan directory tree and build memory structures for iso9660
18 * Written by Eric Youngdale (1993).
20 * Copyright 1993 Yggdrasil Computing, Incorporated
21 * Copyright (c) 1999,2000-2004 J. Schilling
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2, or (at your option)
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
39 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
42 #include "genisoimage.h"
52 extern int allow_limited_size;
56 #include <vms/fabdef.h>
61 * Autoconf should be able to figure this one out for us and let us know
62 * whether the system has memmove or not.
65 #define memmove(d, s, n) bcopy((s), (d), (n))
68 static Uchar symlink_buff[PATH_MAX+1];
70 static char *filetype(int t);
71 static char *rstr(char *s1, char *s2);
72 static void stat_fix(struct stat * st);
73 int stat_filter(char *path, struct stat *st);
74 int lstat_filter(char *path, struct stat *st);
75 static int sort_n_finish(struct directory *this_dir);
76 static void generate_reloc_directory(void);
77 static void attach_dot_entries(struct directory *dirnode, struct stat *dir_stat,
78 struct stat *parent_stat);
79 static void update_nlink(struct directory_entry *s_entry, int value);
80 static void increment_nlink(struct directory_entry *s_entry);
81 char *find_rr_attribute(unsigned char *pnt, int len, char *attr_type);
82 void finish_cl_pl_entries(void);
83 int scan_directory_tree(struct directory *this_dir, char *path,
84 struct directory_entry *de);
86 int insert_file_entry(struct directory *this_dir,
91 int insert_file_entry(struct directory *this_dir,
95 void generate_iso9660_directories(struct directory *node,
97 struct directory *find_or_create_directory(struct directory *parent,
99 struct directory_entry *de,
101 struct stat* stat_template);
102 static void delete_directory(struct directory *parent,
103 struct directory *child);
104 int sort_tree(struct directory *node);
105 void dump_tree(struct directory *node);
106 void update_nlink_field(struct directory *node);
107 struct directory_entry *search_tree_file(struct directory *node,
109 void init_fstatbuf(void);
112 struct stat fstatbuf; /* We use this for the artificial */
113 /* entries we create */
114 struct stat root_statbuf; /* Stat buffer for root directory */
115 struct directory *reloc_dir;
120 static char unkn[32];
122 if (S_ISFIFO(t)) /* 1 */
124 if (S_ISCHR(t)) /* 2 */
126 if (S_ISMPC(t)) /* 3 */
127 return ("multiplexed chr");
128 if (S_ISDIR(t)) /* 4 */
130 if (S_ISNAM(t)) /* 5 */
131 return ("named file");
132 if (S_ISBLK(t)) /* 6 */
134 if (S_ISMPB(t)) /* 7 */
135 return ("multiplexed blk");
136 if (S_ISREG(t)) /* 8 */
137 return ("regular file");
138 if (S_ISCNT(t)) /* 9 */
139 return ("contiguous file");
140 if (S_ISLNK(t)) /* 10 */
142 if (S_ISSHAD(t)) /* 11 */
143 return ("Solaris shadow inode");
144 if (S_ISSOCK(t)) /* 12 */
146 if (S_ISDOOR(t)) /* 13 */
148 if (S_ISWHT(t)) /* 14 */
150 if (S_ISEVC(t)) /* 15 */
151 return ("event count");
154 * Needs to be last in case somebody makes this
155 * a supported file type.
157 if ((t & S_IFMT) == 0) /* 0 (unallocated) */
158 return ("unallocated");
160 sprintf(unkn, "octal '%o'", t & S_IFMT);
165 * Check if s1 ends in strings s2
168 rstr(char *s1, char *s2)
176 return ((char *) NULL);
178 if (strcmp(&s1[l1 - l2], s2) == 0)
179 return (&s1[l1 - l2]);
180 return ((char *) NULL);
184 stat_fix(struct stat *st)
186 int adjust_modes = 0;
188 if (S_ISREG(st->st_mode))
189 adjust_modes = rationalize_filemode;
190 else if (S_ISDIR(st->st_mode))
191 adjust_modes = rationalize_dirmode;
193 adjust_modes = (rationalize_filemode || rationalize_dirmode);
196 * If rationalizing, override the uid and gid, since the
197 * originals will only be useful on the author's system.
200 st->st_uid = uid_to_use;
202 st->st_gid = gid_to_use;
206 if (S_ISREG(st->st_mode) && (filemode_to_use != 0)) {
207 st->st_mode = filemode_to_use | S_IFREG;
208 } else if (S_ISDIR(st->st_mode) && (dirmode_to_use != 0)) {
209 st->st_mode = dirmode_to_use | S_IFDIR;
212 * Make sure the file modes make sense. Turn
213 * on all read bits. Turn on all exec/search
214 * bits if any exec/search bit is set. Turn
215 * off all write bits, and all special mode
216 * bits (on a r/o fs lock bits are useless,
217 * and with uid+gid 0 don't want set-id bits,
222 #if !defined(_WIN32) && !defined(__DJGPP__) /* make all file "executable" */
223 if (st->st_mode & 0111)
226 st->st_mode &= ~07222;
232 stat_filter(char *path, struct stat *st)
234 int result = stat(path, st);
236 if (result >= 0 && rationalize)
242 lstat_filter(char *path, struct stat *st)
244 int result = lstat(path, st);
246 if (result >= 0 && rationalize)
252 sort_n_finish(struct directory *this_dir)
254 struct directory_entry *s_entry;
255 struct directory_entry *s_entry1;
256 struct directory_entry *table;
261 register int new_reclen;
265 char newname[MAX_ISONAME+1];
266 char rootname[MAX_ISONAME+1];
267 char extname[MAX_ISONAME+1];
270 * Here we can take the opportunity to toss duplicate entries from the
273 /* ignore if it's hidden */
274 if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
282 * If we had artificially created this directory, then we might be
283 * missing the required '.' entries. Create these now if we need
286 if ((this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
287 (DIR_HAS_DOT | DIR_HAS_DOTDOT)) {
288 fstatbuf.st_mode = new_dir_mode | S_IFDIR;
289 fstatbuf.st_nlink = 2;
290 attach_dot_entries(this_dir, &fstatbuf, &fstatbuf);
293 s_entry = this_dir->contents;
295 /* ignore if it's hidden */
296 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
297 s_entry = s_entry->next;
300 /* First assume no conflict, and handle this case */
301 if (!(s_entry1 = find_file_hash(s_entry->isorec.name))) {
302 add_file_hash(s_entry);
303 s_entry = s_entry->next;
308 * if the pair are associated, then skip (as they have the
311 if (apple_both && s_entry1->assoc &&
312 s_entry1->assoc == s_entry) {
313 s_entry = s_entry->next;
316 #endif /* APPLE_HYB */
318 if (s_entry1 == s_entry) {
321 "Fatal goof, file '%s' already in hash table.\n",
322 s_entry->isorec.name);
325 "Fatal goof, file '%s' already in hash table.\n",
326 s_entry->isorec.name);
331 * OK, handle the conflicts. Try substitute names until we
332 * come up with a winner
334 strcpy(rootname, s_entry->isorec.name);
336 * Strip off the non-significant part of the name so that we
337 * are left with a sensible root filename. If we don't find
338 * a '.', then try a ';'.
340 c = strchr(rootname, '.');
342 * In case we ever allow more than on dot, only modify the
343 * section past the last dot if the file name starts with a
346 if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
347 c = strrchr(rootname, '.');
349 extname[0] = '\0'; /* In case we have no ext. */
352 *c = 0; /* Cut off complete ext. */
355 * Could not find any '.'.
357 c = strchr(rootname, ';');
359 *c = 0; /* Cut off version number */
362 c = strchr(extname, ';');
364 *c = 0; /* Cut off version number */
366 d1 = strlen(rootname);
367 if (full_iso9660_filenames || iso9660_level > 1) {
368 d2 = strlen(extname);
370 * 31/37 chars minus the 3 characters we are
371 * appending below to create unique filenames.
373 if ((d1 + d2) > (iso9660_namelen - 3))
374 rootname[iso9660_namelen - 3 - d2] = 0;
379 new_reclen = strlen(rootname);
380 sprintf(newname, "%s000%s%s",
383 ((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
384 omit_version_number ? "" : ";1"));
386 for (d1 = 0; d1 < 36; d1++) {
387 for (d2 = 0; d2 < 36; d2++) {
388 for (d3 = 0; d3 < 36; d3++) {
389 newname[new_reclen + 0] =
390 (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10);
391 newname[new_reclen + 1] =
392 (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10);
393 newname[new_reclen + 2] =
394 (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10);
396 fprintf(stderr, "NEW name '%s'\n", newname);
399 /* Sigh. VAXCRTL seems to be broken here */
403 while (newname[ijk]) {
404 if (newname[ijk] == ' ')
411 if (!find_file_hash(newname))
417 /* If we fell off the bottom here, we were in real trouble. */
420 "Unable to generate unique name for file %s\n",
424 "Unable to generate unique name for file %s\n",
431 * OK, now we have a good replacement name. Now decide which
432 * one of these two beasts should get the name changed
434 if (s_entry->priority < s_entry1->priority) {
436 fprintf(stderr, "Using %s for %s%s%s (%s)\n",
438 this_dir->whole_name, SPATH_SEPARATOR,
439 s_entry->name, s_entry1->name);
441 s_entry->isorec.name_len[0] = strlen(newname);
442 new_reclen = offsetof(struct iso_directory_record,
445 if (use_XA || use_RockRidge) {
447 new_reclen++; /* Pad to an even byte */
448 new_reclen += s_entry->rr_attr_size;
451 new_reclen++; /* Pad to an even byte */
452 s_entry->isorec.length[0] = new_reclen;
453 strcpy(s_entry->isorec.name, newname);
455 /* has resource fork - needs new name */
456 if (apple_both && s_entry->assoc) {
457 struct directory_entry *s_entry2 =
461 * resource fork name *should* be the same as
464 s_entry2->isorec.name_len[0] =
465 s_entry->isorec.name_len[0];
466 strcpy(s_entry2->isorec.name,
467 s_entry->isorec.name);
468 s_entry2->isorec.length[0] = new_reclen;
470 #endif /* APPLE_HYB */
472 delete_file_hash(s_entry1);
474 fprintf(stderr, "Using %s for %s%s%s (%s)\n",
476 this_dir->whole_name, SPATH_SEPARATOR,
477 s_entry1->name, s_entry->name);
479 s_entry1->isorec.name_len[0] = strlen(newname);
480 new_reclen = offsetof(struct iso_directory_record,
483 if (use_XA || use_RockRidge) {
485 new_reclen++; /* Pad to an even byte */
486 new_reclen += s_entry1->rr_attr_size;
489 new_reclen++; /* Pad to an even byte */
490 s_entry1->isorec.length[0] = new_reclen;
491 strcpy(s_entry1->isorec.name, newname);
492 add_file_hash(s_entry1);
494 /* has resource fork - needs new name */
495 if (apple_both && s_entry1->assoc) {
496 struct directory_entry *s_entry2 =
500 * resource fork name *should* be the same as
503 s_entry2->isorec.name_len[0] =
504 s_entry1->isorec.name_len[0];
505 strcpy(s_entry2->isorec.name,
506 s_entry1->isorec.name);
507 s_entry2->isorec.length[0] = new_reclen;
509 #endif /* APPLE_HYB */
511 add_file_hash(s_entry);
512 s_entry = s_entry->next;
515 if (generate_tables &&
516 !find_file_hash(trans_tbl) &&
517 (reloc_dir != this_dir) &&
518 (this_dir->extent == 0)) {
519 /* First we need to figure out how big this table is */
520 for (s_entry = this_dir->contents; s_entry;
521 s_entry = s_entry->next) {
522 if (strcmp(s_entry->name, ".") == 0 ||
523 strcmp(s_entry->name, "..") == 0)
526 /* skip table entry for the resource fork */
528 (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
530 #endif /* APPLE_HYB */
531 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
533 if (s_entry->table) {
535 * Max namelen, a space before and a space
536 * after the iso filename.
538 tablesize += MAX_ISONAME + 2 +
539 strlen(s_entry->table);
544 table = (struct directory_entry *)
545 e_malloc(sizeof (struct directory_entry));
546 memset(table, 0, sizeof (struct directory_entry));
548 table->next = this_dir->contents;
549 this_dir->contents = table;
551 table->filedir = root;
552 table->isorec.flags[0] = ISO_FILE;
553 table->priority = 32768;
554 iso9660_date(table->isorec.date, fstatbuf.st_mtime);
555 table->inode = TABLE_INODE;
556 table->dev = (dev_t) UNCACHED_DEVICE;
557 set_723(table->isorec.volume_sequence_number,
558 volume_sequence_number);
559 set_733((char *) table->isorec.size, tablesize);
560 table->realsize = tablesize;
561 table->size = tablesize;
562 table->filedir = this_dir;
564 table->de_flags |= INHIBIT_JOLIET_ENTRY;
565 /* table->name = strdup("<translation table>");*/
566 table->name = strdup(trans_tbl);
568 * We use sprintf() to create the strings, for this reason
569 * we need to add one byte for the null character at the
570 * end of the string even though we don't use it.
572 table->table = (char *) e_malloc(ISO_ROUND_UP(tablesize)+1);
573 memset(table->table, 0, ISO_ROUND_UP(tablesize)+1);
574 iso9660_file_length(trans_tbl, table, 0);
576 if (use_XA || use_RockRidge) {
577 fstatbuf.st_mode = 0444 | S_IFREG;
578 fstatbuf.st_nlink = 1;
579 generate_xa_rr_attributes("",
581 &fstatbuf, &fstatbuf, 0);
585 * We have now chosen the 8.3 names and we should now know the length
586 * of every entry in the directory.
588 for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
589 /* skip if it's hidden */
590 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
593 new_reclen = strlen(s_entry->isorec.name);
595 /* First update the path table sizes for directories. */
596 if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
597 if (strcmp(s_entry->name, ".") != 0 &&
598 strcmp(s_entry->name, "..") != 0) {
599 path_table_size += new_reclen +
600 offsetof(struct iso_path_table,
606 if (this_dir == root && strlen(s_entry->name)
608 path_table_size += new_reclen +
609 offsetof(struct iso_path_table,
614 if (path_table_size & 1)
615 path_table_size++; /* For odd lengths we pad */
616 s_entry->isorec.name_len[0] = new_reclen;
618 new_reclen += offsetof(struct iso_directory_record, name[0]);
623 new_reclen += s_entry->rr_attr_size;
628 if (new_reclen > 0xff) {
631 "Fatal error - RR overflow (reclen %d) for file %s\n",
636 "Fatal error - RR overflow (reclen %d) for file %s\n",
642 s_entry->isorec.length[0] = new_reclen;
645 status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
647 fprintf(stderr, "Unable to sort directory %s\n",
648 this_dir->whole_name);
650 fprintf(stderr, merge_warn_msg);
654 * If we are filling out a TRANS.TBL, generate the entries that will
659 for (s_entry = this_dir->contents; s_entry;
660 s_entry = s_entry->next) {
661 if (s_entry == table)
665 if (strcmp(s_entry->name, ".") == 0 ||
666 strcmp(s_entry->name, "..") == 0)
669 /* skip table entry for the resource fork */
671 (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
673 #endif /* APPLE_HYB */
674 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
677 * Warning: we cannot use the return value of sprintf
678 * because old BSD based sprintf() implementations
679 * will return a pointer to the result instead of a
681 * Old mkiofs introduced a space after the iso
682 * filename to make parsing TRANS.TBL easier.
684 sprintf(table->table + count, "%c %-*s%s",
687 s_entry->isorec.name, s_entry->table + 1);
688 count += strlen(table->table + count);
689 free(s_entry->table);
691 * for a memory file, set s_entry->table to the
692 * correct data - which is stored in
693 * s_entry->whole_name
695 if (s_entry->de_flags & MEMORY_FILE) {
696 s_entry->table = s_entry->whole_name;
697 s_entry->whole_name = NULL;
699 s_entry->table = NULL;
703 if (count != tablesize) {
706 "Translation table size mismatch %d %d\n",
710 "Translation table size mismatch %d %d\n",
717 * Now go through the directory and figure out how large this one will
718 * be. Do not split a directory entry across a sector boundary
720 s_entry = this_dir->contents;
721 this_dir->ce_bytes = 0;
723 /* skip if it's hidden */
724 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
725 s_entry = s_entry->next;
728 new_reclen = s_entry->isorec.length[0];
729 if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
732 this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
734 this_dir->size += new_reclen;
736 /* See if continuation entries were used on disc */
738 s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
743 pnt = s_entry->rr_attributes;
744 len = s_entry->total_rr_attr_size;
745 pnt = parse_xa(pnt, &len, 0);
746 /* pnt = parse_xa(pnt, &len, s_entry);*/
749 * We make sure that each continuation entry record is
750 * not split across sectors, but each file could in
751 * theory have more than one CE, so we scan through
752 * and figure out what we need.
755 if (pnt[0] == 'C' && pnt[1] == 'E') {
756 nbytes = get_733((char *) pnt + 20);
758 if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
761 ISO_ROUND_UP(this_dir->ce_bytes);
763 * Now store the block in the
766 this_dir->ce_bytes += nbytes;
767 if (this_dir->ce_bytes & 1)
768 this_dir->ce_bytes++;
774 s_entry = s_entry->next;
780 generate_reloc_directory()
783 struct directory_entry *s_entry;
785 /* Create an entry for our internal tree */
787 reloc_dir = (struct directory *)
788 e_malloc(sizeof (struct directory));
789 memset(reloc_dir, 0, sizeof (struct directory));
790 reloc_dir->parent = root;
791 reloc_dir->next = root->subdir;
792 root->subdir = reloc_dir;
793 reloc_dir->depth = 1;
795 reloc_dir->whole_name = strdup("./.rr_moved");
796 reloc_dir->de_name = strdup(".rr_moved");
798 reloc_dir->whole_name = strdup("./rr_moved");
799 reloc_dir->de_name = strdup("rr_moved");
801 reloc_dir->extent = 0;
804 /* Now create an actual directory entry */
805 s_entry = (struct directory_entry *)
806 e_malloc(sizeof (struct directory_entry));
807 memset(s_entry, 0, sizeof (struct directory_entry));
808 s_entry->next = root->contents;
809 reloc_dir->self = s_entry;
811 /* The rr_moved entry will not appear in the Joliet tree. */
812 reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
813 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
815 /* Hiding RR_MOVED seems not to be possible..... */
817 reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
818 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
821 root->contents = s_entry;
822 root->contents->name = strdup(reloc_dir->de_name);
823 root->contents->filedir = root;
824 root->contents->isorec.flags[0] = ISO_DIRECTORY;
825 root->contents->priority = 32768;
826 iso9660_date(root->contents->isorec.date, current_time);
827 root->contents->inode = UNCACHED_INODE;
828 root->contents->dev = (dev_t) UNCACHED_DEVICE;
829 set_723(root->contents->isorec.volume_sequence_number,
830 volume_sequence_number);
831 iso9660_file_length(reloc_dir->de_name, root->contents, 1);
835 if (use_XA || use_RockRidge) {
836 fstatbuf.st_mode = 0555 | S_IFDIR;
837 fstatbuf.st_nlink = 2;
838 generate_xa_rr_attributes("",
839 hide_rr_moved ? ".rr_moved" : "rr_moved",
840 s_entry, &fstatbuf, &fstatbuf, 0);
843 /* Now create the . and .. entries in rr_moved */
844 /* Now create an actual directory entry */
845 memset(&root_statbuf, 0x0, sizeof(struct stat)); /* be sure */
846 attach_dot_entries(reloc_dir, &fstatbuf, &root_statbuf);
850 * Function: attach_dot_entries
852 * Purpose: Create . and .. entries for a new directory.
854 * Arguments: dir_stat contains the ownership/permission information
855 * for dirnode, and parent_stat contains
856 * ownership/permission information for its parent
859 * Notes: Only used for artificial directories that
863 attach_dot_entries(struct directory *dirnode, struct stat *dir_stat,
864 struct stat *parent_stat)
866 struct directory_entry *s_entry;
867 struct directory_entry *orig_contents;
872 orig_contents = dirnode->contents;
874 if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 0) {
875 s_entry = (struct directory_entry *)
876 e_malloc(sizeof (struct directory_entry));
877 memcpy(s_entry, dirnode->self,
878 sizeof (struct directory_entry));
880 if (dirnode->self->hfs_ent) {
881 s_entry->hfs_ent = (hfsdirent *)
882 e_malloc(sizeof (hfsdirent));
883 memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
887 s_entry->name = strdup("..");
888 s_entry->whole_name = NULL;
889 s_entry->isorec.name_len[0] = 1;
890 s_entry->isorec.flags[0] = ISO_DIRECTORY;
891 iso9660_file_length("..", s_entry, 1);
892 iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
893 set_723(s_entry->isorec.volume_sequence_number,
894 volume_sequence_number);
895 set_733(s_entry->isorec.size, SECTOR_SIZE);
896 s_entry->realsize = SECTOR_SIZE;
897 memset(s_entry->isorec.extent, 0, 8);
898 s_entry->filedir = dirnode->parent;
900 dirnode->contents = s_entry;
901 dirnode->contents->next = orig_contents;
902 orig_contents = s_entry;
904 if (use_XA || use_RockRidge) {
905 generate_xa_rr_attributes("",
910 dirnode->dir_flags |= DIR_HAS_DOTDOT;
912 if ((dirnode->dir_flags & DIR_HAS_DOT) == 0) {
913 s_entry = (struct directory_entry *)
914 e_malloc(sizeof (struct directory_entry));
915 memcpy(s_entry, dirnode->self,
916 sizeof (struct directory_entry));
918 if (dirnode->self->hfs_ent) {
919 s_entry->hfs_ent = (hfsdirent *)
920 e_malloc(sizeof (hfsdirent));
921 memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
925 s_entry->name = strdup(".");
926 s_entry->whole_name = NULL;
927 s_entry->isorec.name_len[0] = 1;
928 s_entry->isorec.flags[0] = ISO_DIRECTORY;
929 iso9660_file_length(".", s_entry, 1);
930 iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
931 set_723(s_entry->isorec.volume_sequence_number,
932 volume_sequence_number);
933 set_733(s_entry->isorec.size, SECTOR_SIZE);
934 s_entry->realsize=SECTOR_SIZE;
935 memset(s_entry->isorec.extent, 0, 8);
936 s_entry->filedir = dirnode;
938 dirnode->contents = s_entry;
939 dirnode->contents->next = orig_contents;
941 if (use_XA || use_RockRidge) {
943 if (dirnode == root) {
944 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
946 generate_xa_rr_attributes("", ".", s_entry,
947 dir_stat, dir_stat, deep_flag);
949 dirnode->dir_flags |= DIR_HAS_DOT;
954 update_nlink(struct directory_entry *s_entry, int value)
959 pnt = s_entry->rr_attributes;
960 len = s_entry->total_rr_attr_size;
961 pnt = parse_xa(pnt, &len, 0);
963 if (pnt[3] != 1 && pnt[3] != 2) {
966 "**BAD RRVERSION (%d) for %c%c\n",
967 pnt[3], pnt[0], pnt[1]);
970 "**BAD RRVERSION (%d) for %c%c\n",
971 pnt[3], pnt[0], pnt[1]);
974 if (pnt[0] == 'P' && pnt[1] == 'X') {
975 set_733((char *) pnt + 12, value);
984 increment_nlink(struct directory_entry *s_entry)
990 pnt = s_entry->rr_attributes;
991 len = s_entry->total_rr_attr_size;
992 pnt = parse_xa(pnt, &len, 0);
994 if (pnt[3] != 1 && pnt[3] != 2) {
997 "**BAD RRVERSION (%d) for %c%c\n",
998 pnt[3], pnt[0], pnt[1]);
1001 "**BAD RRVERSION (%d) for %c%c\n",
1002 pnt[3], pnt[0], pnt[1]);
1005 if (pnt[0] == 'P' && pnt[1] == 'X') {
1006 nlink = get_733((char *) pnt + 12);
1007 set_733((char *) pnt + 12, nlink + 1);
1016 find_rr_attribute(unsigned char *pnt, int len, char *attr_type)
1018 pnt = parse_xa(pnt, &len, 0);
1020 if (pnt[3] != 1 && pnt[3] != 2) {
1021 #ifdef USE_LIBSCHILY
1023 "**BAD RRVERSION (%d) for %c%c\n",
1024 pnt[3], pnt[0], pnt[1]);
1027 "**BAD RRVERSION (%d) for %c%c\n",
1028 pnt[3], pnt[0], pnt[1]);
1031 if (strncmp((char *) pnt, attr_type, 2) == 0)
1032 return ((char *) pnt);
1033 else if (strncmp((char *) pnt, "ST", 2) == 0)
1042 finish_cl_pl_entries()
1044 struct directory_entry *s_entry;
1045 struct directory_entry *s_entry1;
1046 struct directory *d_entry;
1048 /* if the reloc_dir is hidden (empty), then return */
1049 if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
1052 s_entry = reloc_dir->contents;
1053 s_entry = s_entry->next->next; /* Skip past . and .. */
1054 for (; s_entry; s_entry = s_entry->next) {
1055 /* skip if it's hidden */
1056 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1059 d_entry = reloc_dir->subdir;
1061 if (d_entry->self == s_entry)
1063 d_entry = d_entry->next;
1066 #ifdef USE_LIBSCHILY
1068 "Unable to locate directory parent\n");
1070 fprintf(stderr, "Unable to locate directory parent\n");
1075 if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
1079 * First fix the PL pointer in the directory in the
1082 s_entry1 = d_entry->contents->next;
1084 /* set_733((char *) s_entry1->rr_attributes +*/
1085 /* s_entry1->total_rr_attr_size - 8,*/
1086 /* s_entry->filedir->extent); */
1088 * The line above won't work when entry was read from
1089 * the previous session, because if total_rr_attr_size
1090 * was odd when recording previous session, now we have
1091 * total_rr_attr_size off by 1 due to padding.
1093 * So, just search for the attributes by name
1095 rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1096 s_entry1->total_rr_attr_size, "PL");
1097 if (rr_attr != NULL)
1098 set_733(rr_attr + 4, s_entry->filedir->extent);
1101 /* Now fix the CL pointer */
1102 s_entry1 = s_entry->parent_rec;
1104 /* set_733((char *) s_entry1->rr_attributes +*/
1105 /* s_entry1->total_rr_attr_size - 8, d_entry->extent); */
1106 rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1107 s_entry1->total_rr_attr_size, "CL");
1108 if (rr_attr != NULL)
1109 set_733(rr_attr + 4, d_entry->extent);
1111 s_entry->filedir = reloc_dir; /* Now we can fix this */
1114 * Next we need to modify the NLINK terms in the assorted root
1115 * directory records to account for the presence of the RR_MOVED
1118 increment_nlink(root->self);
1119 increment_nlink(root->self->next);
1120 d_entry = root->subdir;
1122 increment_nlink(d_entry->contents->next);
1123 d_entry = d_entry->next;
1126 finish_cl_pl_for_prev_session();
1130 * Function: scan_directory_tree
1132 * Purpose: Walk through a directory on the local machine
1133 * filter those things we don't want to include
1134 * and build our representation of a dir.
1139 scan_directory_tree(struct directory *this_dir, char *path,
1140 struct directory_entry *de)
1143 char whole_path[PATH_MAX];
1144 struct dirent *d_entry;
1145 struct directory *parent;
1150 fprintf(stderr, "Scanning %s\n", path);
1152 /*#define check_needed*/
1155 * Trying to use this to avoid directory loops from hard links
1156 * or followed symlinks does not work. It would prevent us from
1157 * implementing merge directories.
1159 if (this_dir->dir_flags & DIR_WAS_SCANNED) {
1160 fprintf(stderr, "Already scanned directory %s\n", path);
1161 return (1); /* It's a directory */
1164 this_dir->dir_flags |= DIR_WAS_SCANNED;
1166 errno = 0; /* Paranoia */
1167 current_dir = opendir(path);
1171 * Apparently NFS sometimes allows you to open the directory, but then
1172 * refuses to allow you to read the contents. Allow for this
1178 d_entry = readdir(current_dir);
1181 if (!current_dir || !d_entry) {
1184 #ifdef USE_LIBSCHILY
1185 errmsg("Unable to open directory %s\n", path);
1187 fprintf(stderr, "Unable to open directory %s\n", path);
1189 if (errno == ENOTDIR) {
1190 /* Mark as not a directory */
1191 de->isorec.flags[0] &= ~ISO_DIRECTORY;
1195 closedir(current_dir);
1198 #ifdef ABORT_DEEP_ISO_ONLY
1199 if ((this_dir->depth > RR_relocation_depth) && !use_RockRidge) {
1200 static BOOL did_hint = FALSE;
1203 "Directories too deep for '%s' (%d) max is %d; ignored - continuing.\n",
1204 path, this_dir->depth, RR_relocation_depth);
1207 errmsgno(EX_BAD, "To include the complete directory tree,\n");
1208 errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n");
1209 errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n");
1211 closedir(current_dir);
1216 parent = de->filedir;
1218 * Set up the struct for the current directory, and insert it into
1222 vms_path_fixup(path);
1226 * if entry for this sub-directory is hidden, then hide this directory
1228 if (de->de_flags & INHIBIT_ISO9660_ENTRY)
1229 this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
1231 if (de->de_flags & INHIBIT_JOLIET_ENTRY)
1232 this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
1236 * set any sort weighting from it's own directory entry - if a
1237 * directory is given a weighting, then all the contents will use
1238 * this as the default weighting
1240 this_dir->sort = de->sort;
1241 #endif /* SORTING */
1244 * Now we scan the directory itself, and look at what is inside of it.
1250 * The first time through, skip this, since we already asked
1251 * for the first entry when we opened the directory.
1254 d_entry = readdir(current_dir);
1260 /* OK, got a valid entry */
1262 /* If we do not want all files, then pitch the backups. */
1264 if (strchr(d_entry->d_name, '~') ||
1265 strchr(d_entry->d_name, '#') ||
1266 rstr(d_entry->d_name, ".bak")) {
1269 "Ignoring file %s\n",
1278 * exclude certain HFS type files/directories for the
1281 if (hfs_exclude(d_entry->d_name))
1284 #endif /* APPLE_HYB */
1286 if (strlen(path) + strlen(d_entry->d_name) + 2 >
1287 sizeof (whole_path)) {
1288 #ifdef USE_LIBSCHILY
1289 errmsgno(EX_BAD, "Path name %s/%s too long.\n",
1290 path, d_entry->d_name);
1291 comerrno(EX_BAD, "Overflow of stat buffer\n");
1293 fprintf(stderr, "Path name %s/%s too long.\n",
1294 path, d_entry->d_name);
1295 fprintf(stderr, "Overflow of stat buffer\n");
1300 /* Generate the complete ASCII path for this file */
1301 strcpy(whole_path, path);
1303 if (whole_path[strlen(whole_path) - 1] != '/')
1304 strcat(whole_path, "/");
1306 strcat(whole_path, d_entry->d_name);
1308 /** Should we exclude this file ? */
1309 if (matches(d_entry->d_name) || matches(whole_path)) {
1312 "Excluded by match: %s\n", whole_path);
1316 if (generate_tables &&
1317 strcmp(d_entry->d_name, trans_tbl) == 0) {
1319 * Ignore this entry. We are going to be generating
1320 * new versions of these files, and we need to ignore
1321 * any originals that we might have found.
1324 fprintf(stderr, "Excluded: %s\n", whole_path);
1329 * If we already have a '.' or a '..' entry, then don't insert
1332 if (strcmp(d_entry->d_name, ".") == 0 &&
1333 this_dir->dir_flags & DIR_HAS_DOT) {
1336 if (strcmp(d_entry->d_name, "..") == 0 &&
1337 this_dir->dir_flags & DIR_HAS_DOTDOT) {
1342 fprintf(stderr, "%s\n", whole_path);
1344 /* This actually adds the entry to the directory in question.*/
1346 insert_file_entry(this_dir, whole_path, d_entry->d_name, 0);
1348 insert_file_entry(this_dir, whole_path, d_entry->d_name);
1349 #endif /* APPLE_HYB */
1351 closedir(current_dir);
1355 * if we cached the HFS info stuff for this directory, then delete it
1357 if (this_dir->hfs_info) {
1358 del_hfs_info(this_dir->hfs_info);
1359 this_dir->hfs_info = 0;
1361 #endif /* APPLE_HYB */
1368 * Function: insert_file_entry
1370 * Purpose: Insert one entry into our directory node.
1373 * This function inserts a single entry into the directory. It
1374 * is assumed that all filtering and decision making regarding what
1375 * we want to include has already been made, so the purpose of this
1376 * is to insert one entry (file, link, dir, etc), into this directory.
1377 * Note that if the entry is a dir (or if we are following links,
1378 * and the thing it points to is a dir), then we will scan those
1379 * trees before we return.
1383 insert_file_entry(struct directory *this_dir, char *whole_path,
1384 char *short_name, int have_rsrc)
1387 insert_file_entry(struct directory *this_dir, char *whole_path,
1389 #endif /* APPLE_HYB */
1391 struct stat statbuf,
1393 struct directory_entry *s_entry,
1402 int htype = TYPE_NONE;
1404 #endif /* APPLE_HYB */
1406 status = stat_filter(whole_path, &statbuf);
1408 lstatus = lstat_filter(whole_path, &lstatbuf);
1410 if ((status == -1) && (lstatus == -1)) {
1412 * This means that the file doesn't exist, or isn't accessible.
1413 * Sometimes this is because of NFS permissions problems.
1415 #ifdef USE_LIBSCHILY
1416 errmsg("Non-existent or inaccessible: %s\n", whole_path);
1418 fprintf(stderr, "Non-existent or inaccessible: %s\n",
1423 if (this_dir == root && strcmp(short_name, ".") == 0)
1424 root_statbuf = statbuf; /* Save this for later on */
1426 /* We do this to make sure that the root entries are consistent */
1427 if (this_dir == root && strcmp(short_name, "..") == 0) {
1428 statbuf = root_statbuf;
1429 lstatbuf = root_statbuf;
1431 if (S_ISLNK(lstatbuf.st_mode)) {
1434 * Here we decide how to handle the symbolic links. Here we
1435 * handle the general case - if we are not following links or
1436 * there is an error, then we must change something. If RR
1437 * is in use, it is easy, we let RR describe the file. If
1438 * not, then we punt the file.
1440 if ((status || !follow_links)) {
1441 if (use_RockRidge) {
1443 statbuf.st_size = (off_t)0;
1444 STAT_INODE(statbuf) = UNCACHED_INODE;
1445 statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
1447 (statbuf.st_mode & ~S_IFMT) | S_IFREG;
1450 #ifdef USE_LIBSCHILY
1451 /* XXX errno may be wrong! */
1452 errmsg("Unable to stat file %s - ignoring and continuing.\n",
1456 "Unable to stat file %s - ignoring and continuing.\n",
1460 #ifdef USE_LIBSCHILY
1462 "Symlink %s ignored - continuing.\n",
1466 "Symlink %s ignored - continuing.\n",
1469 return (0); /* Non Rock Ridge discs */
1470 /* - ignore all symlinks */
1475 * Here we handle a different kind of case. Here we have a
1476 * symlink, but we want to follow symlinks. If we run across
1477 * a directory loop, then we need to pretend that we are not
1478 * following symlinks for this file. If this is the first
1479 * time we have seen this, then make this seem as if there was
1480 * no symlink there in the first place
1483 S_ISDIR(statbuf.st_mode)) {
1484 if (strcmp(short_name, ".") &&
1485 strcmp(short_name, "..")) {
1486 if (find_directory_hash(statbuf.st_dev,
1487 STAT_INODE(statbuf))) {
1488 if (!use_RockRidge) {
1490 "Already cached directory seen (%s)\n",
1496 * XXX when this line was active,
1497 * XXX genisoimage did not include all
1498 * XXX files if it was called with '-f'
1499 * XXX (follow symlinks).
1500 * XXX Now scan_directory_tree()
1501 * XXX checks if the directory has
1502 * XXX already been scanned via the
1503 * XXX DIR_WAS_SCANNED flag.
1505 /* no_scandir = 1;*/
1508 add_directory_hash(statbuf.st_dev,
1509 STAT_INODE(statbuf));
1514 * For non-directories, we just copy the stat information over
1515 * so we correctly include this file.
1518 !S_ISDIR(statbuf.st_mode)) {
1523 * Add directories to the cache so that we don't waste space even if
1524 * we are supposed to be following symlinks.
1527 strcmp(short_name, ".") &&
1528 strcmp(short_name, "..") &&
1529 S_ISDIR(statbuf.st_mode)) {
1530 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1533 if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
1534 statbuf.st_fab_rfm != FAB$C_STMLF)) {
1536 "Warning - file %s has an unsupported VMS record"
1538 whole_path, statbuf.st_fab_rfm);
1542 if (S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))) {
1543 #ifdef USE_LIBSCHILY
1544 errmsg("File %s is not readable - ignoring\n",
1548 "File %s is not readable (errno = %d) - ignoring\n",
1553 /* print a warning but don't spam too much */
1554 if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0xFFFFFFFF)) {
1555 static int udf_warned;
1557 if( !allow_limited_size || verbose>1)
1558 fprintf(stderr, "File %s is larger than 4GiB-1.\n", whole_path);
1559 if( !allow_limited_size)
1561 fprintf(stderr, "-allow-limited-size was not specified. There is no way do represent this file size. Aborting.\n");
1564 if(verbose>=1 && ! udf_warned ) {
1566 fprintf(stderr, "This size can only be represented in the UDF filesystem.\n"
1567 "Make sure that your clients support and use it.\n"
1568 "ISO9660, Joliet, RockRidge, HFS will display incorrect size.\n");
1572 * Add this so that we can detect directory loops with hard links.
1573 * If we are set up to follow symlinks, then we skip this checking.
1575 if (!follow_links &&
1576 S_ISDIR(lstatbuf.st_mode) &&
1577 strcmp(short_name, ".") &&
1578 strcmp(short_name, "..")) {
1579 if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
1580 #ifdef USE_LIBSCHILY
1581 /* comerrno(EX_BAD,*/
1582 /* "Directory loop - fatal goof (%s %lx %lu).\n",*/
1584 "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1585 whole_path, (unsigned long) statbuf.st_dev,
1586 (unsigned long) STAT_INODE(statbuf));
1588 /* fprintf(stderr,*/
1589 /* "Directory loop - fatal goof (%s %lx %lu).\n",*/
1591 "Warning: Directory loop (%s dev: %lx ino: %lu).\n",
1592 whole_path, (unsigned long) statbuf.st_dev,
1593 (unsigned long) STAT_INODE(statbuf));
1596 add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1598 if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
1599 !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) &&
1600 !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
1601 !S_ISDIR(lstatbuf.st_mode)) {
1602 if ( ! (this_dir == root && strcmp(short_name, "..") == 0)) {
1604 "Unknown file type (%s) %s - ignoring and continuing.\n",
1605 filetype((int) lstatbuf.st_mode), whole_path);
1609 /* Who knows what trash this is - ignore and continue */
1612 #ifdef USE_LIBSCHILY
1613 errmsg("Unable to stat file %s - ignoring and continuing.\n",
1617 "Unable to stat file %s - ignoring and continuing.\n",
1623 * Check to see if we have already seen this directory node. If so,
1624 * then we don't create a new entry for it, but we do want to recurse
1625 * beneath it and add any new files we do find.
1627 if (S_ISDIR(statbuf.st_mode)) {
1630 for (s_entry = this_dir->contents; s_entry;
1631 s_entry = s_entry->next) {
1632 if (strcmp(s_entry->name, short_name) == 0) {
1636 if (s_entry != NULL &&
1637 strcmp(short_name, ".") &&
1638 strcmp(short_name, "..")) {
1639 struct directory *child;
1641 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
1642 for (s_entry = reloc_dir->contents; s_entry;
1643 s_entry = s_entry->next) {
1644 if (strcmp(s_entry->name, short_name)
1649 child = find_or_create_directory(reloc_dir,
1653 child = find_or_create_directory(this_dir,
1657 * If unable to scan directory, mark this as a
1661 /* if (no_scandir)*/
1665 dflag = scan_directory_tree(child,
1666 whole_path, s_entry);
1669 (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
1675 /* Should we exclude this HFS file ? - only works with -hfs */
1676 if (!have_rsrc && apple_hyb && strcmp(short_name, ".") &&
1677 strcmp(short_name, "..")) {
1678 if ((x_hfs = (hfs_matches(short_name) ||
1679 hfs_matches(whole_path))) == 1) {
1681 fprintf(stderr, "Hidden from HFS tree: %s\n",
1687 * check we are a file, using Apple extensions and have a .resource
1688 * part and not excluded
1690 if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
1691 char rsrc_path[PATH_MAX]; /* rsrc fork filename */
1693 /* construct the resource full path */
1694 htype = get_hfs_rname(whole_path, short_name, rsrc_path);
1695 /* check we can read the resouce fork */
1697 struct stat rstatbuf,
1700 /* some further checks on the file */
1701 status = stat_filter(rsrc_path, &rstatbuf);
1703 lstatus = lstat_filter(rsrc_path, &rlstatbuf);
1705 /* if (!status && !lstatus && S_ISREG(rlstatbuf.st_mode)*/
1706 /* && rlstatbuf.st_size > (off_t)0) { */
1707 if (!status && !lstatus && S_ISREG(rstatbuf.st_mode) &&
1708 rstatbuf.st_size > (off_t)0) {
1711 * have a resource file - insert it into the
1712 * current directory but flag that we have a
1715 insert_file_entry(this_dir, rsrc_path,
1720 #endif /* APPLE_HYB */
1722 s_entry = (struct directory_entry *)
1723 e_malloc(sizeof (struct directory_entry));
1724 /* memset the whole struct, not just the isorec.extent part JCP */
1725 memset(s_entry, 0, sizeof (struct directory_entry));
1726 s_entry->next = this_dir->contents;
1727 /* memset(s_entry->isorec.extent, 0, 8); */
1728 this_dir->contents = s_entry;
1730 s_entry->table = NULL;
1732 s_entry->name = strdup(short_name);
1733 s_entry->whole_name = strdup(whole_path);
1735 s_entry->de_flags = 0;
1738 * If the current directory is hidden, then hide all it's members
1739 * otherwise check if this entry needs to be hidden as well
1741 if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
1742 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1743 } else if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
1745 if (i_matches(short_name) || i_matches(whole_path)) {
1748 "Hidden from ISO9660 tree: %s\n",
1751 s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1753 if (h_matches(short_name) || h_matches(whole_path)) {
1756 "Hidden ISO9660 attribute: %s\n",
1759 s_entry->de_flags |= HIDDEN_FILE;
1762 if (this_dir != reloc_dir &&
1763 this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1764 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1765 } else if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
1767 if (j_matches(short_name) || j_matches(whole_path)) {
1770 "Hidden from Joliet tree: %s\n",
1773 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1778 /* inherit any sort weight from parent directory */
1779 s_entry->sort = this_dir->sort;
1783 * No use at all to do a sort if we don't make a dvd video/audio
1786 * Assign special weights to VIDEO_TS and AUDIO_TS files.
1787 * This can't be done with sort_matches for two reasons:
1788 * first, we need to match against the destination (DVD)
1789 * path rather than the source path, and second, there are
1790 * about 2400 different file names to check, each needing
1791 * a different priority, and adding that many patterns to
1792 * sort_matches would slow things to a crawl.
1796 s_entry->sort = assign_dvd_weights(s_entry->name, this_dir, s_entry->sort);
1797 /* turn on sorting if necessary, regardless of cmd-line options */
1798 if ((s_entry->sort != this_dir->sort) && do_sort == 0)
1803 /* see if this entry should have a new weighting */
1804 if (do_sort && strcmp(short_name, ".") != 0 &&
1805 strcmp(short_name, "..") != 0) {
1806 s_entry->sort = sort_matches(whole_path, s_entry->sort);
1808 #endif /* SORTING */
1810 s_entry->filedir = this_dir;
1811 s_entry->isorec.flags[0] = ISO_FILE;
1812 if (s_entry->de_flags & HIDDEN_FILE)
1813 s_entry->isorec.flags[0] |= ISO_EXISTENCE;
1814 s_entry->isorec.ext_attr_length[0] = 0;
1815 iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
1816 s_entry->isorec.file_unit_size[0] = 0;
1817 s_entry->isorec.interleave[0] = 0;
1820 if (apple_both && !x_hfs) {
1821 s_entry->hfs_ent = NULL;
1822 s_entry->assoc = NULL;
1823 s_entry->hfs_off = (off_t)0;
1824 s_entry->hfs_type = htype;
1826 /* associated (rsrc) file */
1827 s_entry->isorec.flags[0] |= ISO_ASSOCIATED;
1828 /* set the type of HFS file */
1829 s_entry->hfs_type = have_rsrc;
1831 * don't want the rsrc file to be included in any
1834 s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1835 } else if (s_entry->next) {
1837 * if previous entry is an associated file,
1838 * then "link" it to this file i.e. we have a
1839 * data/resource pair
1841 if (s_entry->next->isorec.flags[0] & ISO_ASSOCIATED) {
1842 s_entry->assoc = s_entry->next;
1843 /* share the same HFS parameters */
1844 s_entry->hfs_ent = s_entry->next->hfs_ent;
1845 s_entry->hfs_type = s_entry->next->hfs_type;
1848 /* allocate HFS entry if required */
1849 if (apple_both && strcmp(short_name, ".") &&
1850 strcmp(short_name, "..")) {
1851 if (!s_entry->hfs_ent) {
1855 (hfsdirent *) e_malloc(sizeof (hfsdirent));
1857 /* fill in the defaults */
1858 memset(hfs_ent, 0, sizeof (hfsdirent));
1860 s_entry->hfs_ent = hfs_ent;
1863 * the resource fork is processed first, but the
1864 * data fork's time info is used in preference
1865 * i.e. time info is set from the resource fork
1866 * initially, then it is set from the data fork
1870 s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
1872 * this will be overwritten - but might as
1873 * well set it here ...
1875 s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
1876 s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
1879 s_entry->hfs_ent->u.file.dsize = lstatbuf.st_size;
1880 s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
1881 s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
1885 #endif /* APPLE_HYB */
1887 if (strcmp(short_name, ".") == 0) {
1888 this_dir->dir_flags |= DIR_HAS_DOT;
1890 if (strcmp(short_name, "..") == 0) {
1891 this_dir->dir_flags |= DIR_HAS_DOTDOT;
1893 if (this_dir->parent &&
1894 this_dir->parent == reloc_dir &&
1895 strcmp(short_name, "..") == 0) {
1896 s_entry->inode = UNCACHED_INODE;
1897 s_entry->dev = (dev_t) UNCACHED_DEVICE;
1898 deep_flag = NEED_PL;
1902 /* don't want rsrc files to be cached */
1903 s_entry->inode = UNCACHED_INODE;
1904 s_entry->dev = (dev_t) UNCACHED_DEVICE;
1906 #endif /* APPLE_HYB */
1908 s_entry->inode = STAT_INODE(statbuf);
1909 s_entry->dev = statbuf.st_dev;
1911 set_723(s_entry->isorec.volume_sequence_number,
1912 volume_sequence_number);
1913 iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
1914 s_entry->rr_attr_size = 0;
1915 s_entry->total_rr_attr_size = 0;
1916 s_entry->rr_attributes = NULL;
1918 /* Directories are assigned sizes later on */
1919 if (!S_ISDIR(statbuf.st_mode)) {
1920 if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
1921 S_ISFIFO(lstatbuf.st_mode) ||
1922 S_ISSOCK(lstatbuf.st_mode) ||
1923 S_ISLNK(lstatbuf.st_mode)) {
1924 s_entry->size = (off_t)0;
1925 statbuf.st_size = (off_t)0;
1927 s_entry->size = statbuf.st_size;
1930 set_733((char *) s_entry->isorec.size, statbuf.st_size);
1931 s_entry->realsize = statbuf.st_size;
1933 s_entry->isorec.flags[0] |= ISO_DIRECTORY;
1936 /* if the directory is HFS excluded, then we don't have an hfs_ent */
1937 if (apple_both && s_entry->hfs_ent &&
1938 (s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
1939 /* get the Mac directory name */
1940 get_hfs_dir(whole_path, short_name, s_entry);
1942 /* if required, set ISO directory name from HFS name */
1944 iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
1946 #endif /* APPLE_HYB */
1948 if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0 &&
1949 S_ISDIR(statbuf.st_mode) &&
1950 this_dir->depth > RR_relocation_depth) {
1951 struct directory *child;
1954 generate_reloc_directory();
1957 * Replicate the entry for this directory. The old one will
1958 * stay where it is, and it will be neutered so that it no
1959 * longer looks like a directory. The new one will look like
1960 * a directory, and it will be put in the reloc_dir.
1962 s_entry1 = (struct directory_entry *)
1963 e_malloc(sizeof (struct directory_entry));
1964 memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
1965 s_entry1->table = NULL;
1966 s_entry1->name = strdup(this_dir->contents->name);
1967 s_entry1->whole_name = strdup(this_dir->contents->whole_name);
1968 s_entry1->next = reloc_dir->contents;
1969 reloc_dir->contents = s_entry1;
1970 s_entry1->priority = 32768;
1971 s_entry1->parent_rec = this_dir->contents;
1972 set_723(s_entry1->isorec.volume_sequence_number,
1973 volume_sequence_number);
1975 deep_flag = NEED_RE;
1977 if (use_XA || use_RockRidge) {
1978 generate_xa_rr_attributes(whole_path,
1979 short_name, s_entry1,
1980 &statbuf, &lstatbuf, deep_flag);
1985 * We need to set this temporarily so that the parent to this
1986 * is correctly determined.
1988 s_entry1->filedir = reloc_dir;
1989 child = find_or_create_directory(reloc_dir, whole_path,
1991 /* if (!no_scandir)*/
1993 scan_directory_tree(child, whole_path, s_entry1);
1994 s_entry1->filedir = this_dir;
1996 statbuf.st_size = (off_t)0;
1997 statbuf.st_mode &= 0777;
1998 set_733((char *) s_entry->isorec.size, 0);
1999 s_entry->realsize=0;
2001 s_entry->isorec.flags[0] = ISO_FILE;
2002 s_entry->inode = UNCACHED_INODE;
2003 s_entry->de_flags |= RELOCATED_DIRECTORY;
2004 deep_flag = NEED_CL;
2006 if (generate_tables &&
2007 strcmp(s_entry->name, ".") != 0 &&
2008 strcmp(s_entry->name, "..") != 0) {
2010 char buffer[SECTOR_SIZE];
2013 switch (lstatbuf.st_mode & S_IFMT) {
2015 sprintf(buffer, "D\t%s\n",
2020 * extra for WIN32 - if it doesn't have the major/minor defined, then
2021 * S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
2022 * code similar to that in rock.c
2026 * Use the device handling code from <device.h>
2029 #define major(dev) (sizeof (dev_t) <= 2 ? ((dev) >> 8) : \
2030 (sizeof (dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
2031 (((dev) >> 16) >> 16)))
2032 #define minor(dev) (sizeof (dev_t) <= 2 ? (dev) & 0xff : \
2033 (sizeof (dev_t) <= 4 ? (dev) & 0xffff : \
2034 (dev) & 0xffffffff))
2040 sprintf(buffer, "B\t%s\t%lu %lu\n",
2042 (unsigned long) major(statbuf.st_rdev),
2043 (unsigned long) minor(statbuf.st_rdev));
2048 sprintf(buffer, "P\t%s\n",
2054 sprintf(buffer, "C\t%s\t%lu %lu\n",
2056 (unsigned long) major(statbuf.st_rdev),
2057 (unsigned long) minor(statbuf.st_rdev));
2062 #ifdef HAVE_READLINK
2063 nchar = readlink(whole_path,
2064 (char *) symlink_buff,
2065 sizeof (symlink_buff)-1);
2069 symlink_buff[nchar < 0 ? 0 : nchar] = 0;
2070 sprintf(buffer, "L\t%s\t%s\n",
2071 s_entry->name, symlink_buff);
2076 sprintf(buffer, "S\t%s\n",
2082 sprintf(buffer, "F\t%s\n",
2086 s_entry->table = strdup(buffer);
2088 if (S_ISDIR(statbuf.st_mode)) {
2091 if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..")
2093 struct directory *child;
2095 child = find_or_create_directory(this_dir, whole_path,
2100 dflag = scan_directory_tree(child, whole_path,
2105 (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
2106 if (child->contents == NULL) {
2107 delete_directory(this_dir, child);
2111 /* If unable to scan directory, mark this as a non-directory */
2113 if (use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")
2115 deep_flag |= NEED_CE | NEED_SP; /* For extension record */
2117 /* Now figure out how much room this file will take in the directory */
2120 /* if the file is HFS excluded, then we don't have an hfs_ent */
2121 if (apple_both && !have_rsrc && s_entry->hfs_ent) {
2122 if (S_ISREG(lstatbuf.st_mode)) { /* it's a regular file */
2124 /* fill in the rest of the HFS entry */
2125 get_hfs_info(whole_path, short_name, s_entry);
2127 /* if required, set ISO directory name from HFS name */
2129 iso9660_file_length(s_entry->hfs_ent->name,
2132 /* print details about the HFS file */
2134 print_hfs_info(s_entry);
2137 * copy the new ISO9660 name to the rsrc fork
2141 strcpy(s_entry->assoc->isorec.name,
2142 s_entry->isorec.name);
2145 * we can't handle hard links in the hybrid case, so we
2146 * "uncache" the file. The downside to this is that
2147 * hard linked files are added to the output image
2148 * more than once (we've already done this for rsrc
2152 s_entry->inode = UNCACHED_INODE;
2153 s_entry->dev = (dev_t) UNCACHED_DEVICE;
2155 } else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
2156 /* not a directory .. */
2159 * no mac equivalent, so ignore - have to be careful
2160 * here, the hfs_ent may be also be for a relocated
2163 if (s_entry->hfs_ent &&
2164 !(s_entry->de_flags & RELOCATED_DIRECTORY))
2165 free(s_entry->hfs_ent);
2166 s_entry->hfs_ent = NULL;
2169 * if the rsrc size is zero, then we don't need the entry, so
2170 * we might as well delete it - this will only happen if we
2171 * didn't know the rsrc size from the rsrc file size
2173 if (s_entry->assoc && s_entry->assoc->size == 0)
2174 delete_rsrc_ent(s_entry);
2176 if (apple_ext && s_entry->assoc) {
2177 /* need Apple extensions for the resource fork as well */
2178 generate_xa_rr_attributes(whole_path,
2179 short_name, s_entry->assoc,
2180 &statbuf, &lstatbuf, deep_flag);
2182 /* leave out resource fork for the time being */
2184 * XXX This is most likely wrong and should just be:
2185 * XXX if (use_XA || use_RockRidge) {
2187 /* if ((use_XA || use_RockRidge) && !have_rsrc) {*/
2188 if (use_XA || use_RockRidge) {
2190 if (use_XA || use_RockRidge) {
2191 #endif /* APPLE_HYB */
2192 generate_xa_rr_attributes(whole_path,
2193 short_name, s_entry,
2194 &statbuf, &lstatbuf, deep_flag);
2202 generate_iso9660_directories(struct directory *node, FILE *outfile)
2204 struct directory *dpnt;
2209 if (dpnt->extent > session_start) {
2210 generate_one_directory(dpnt, outfile);
2213 generate_iso9660_directories(dpnt->subdir, outfile);
2219 * Function: find_or_create_directory
2221 * Purpose: Locate a directory entry in the tree, create if needed.
2222 * If a directory is created and stat_template is non-null,
2223 * create the directory with ownership, permissions, etc.,
2224 * from stat_template, otherwise use fallback defaults.
2226 * Arguments: parent & de are never NULL at the same time.
2229 find_or_create_directory(struct directory *parent,
2231 struct directory_entry *de,
2233 struct stat *stat_template)
2235 struct directory *dpnt;
2236 struct directory_entry *orig_de;
2237 struct directory *next_brother;
2240 struct stat my_statbuf;
2245 * XXX It seems that the tree that has been read from the
2246 * XXX previous session does not carry whole_name entries.
2247 * XXX We provide a hack in multi.c:find_or_create_directory()
2248 * XXX that should be removed when a reasonable method could
2252 fprintf(stderr, "Warning: missing whole name for: '%s'\n", de->name);
2255 pnt = strrchr(path, PATH_SEPARATOR);
2262 if (parent != NULL) {
2263 dpnt = parent->subdir;
2267 * Weird hack time - if there are two directories by
2268 * the same name in the reloc_dir, they are not
2269 * treated as the same thing unless the entire path
2270 * matches completely.
2272 if (flag && strcmp(dpnt->de_name, pnt) == 0) {
2279 * We don't know if we have a valid directory entry for this one yet.
2280 * If not, we need to create one.
2283 de = (struct directory_entry *)
2284 e_malloc(sizeof (struct directory_entry));
2285 memset(de, 0, sizeof (struct directory_entry));
2286 de->next = parent->contents;
2287 parent->contents = de;
2288 de->name = strdup(pnt);
2289 de->whole_name = strdup(path);
2290 de->filedir = parent;
2291 de->isorec.flags[0] = ISO_DIRECTORY;
2292 de->priority = 32768;
2293 de->inode = UNCACHED_INODE;
2294 de->dev = (dev_t) UNCACHED_DEVICE;
2295 set_723(de->isorec.volume_sequence_number,
2296 volume_sequence_number);
2297 iso9660_file_length(pnt, de, 1);
2300 * If we were given a stat template, use it for
2301 * ownership/permissions, otherwise use fallback defaults.
2304 if (stat_template) {
2305 my_statbuf = *stat_template;
2307 my_statbuf = fstatbuf; /* defaults */
2308 my_statbuf.st_mode = new_dir_mode;
2310 my_statbuf.st_mode &= ~S_IFMT; /* zero out file type */
2311 my_statbuf.st_mode |= S_IFDIR; /* force to be a directory */
2312 my_statbuf.st_nlink = 2;
2315 * Apply attributes from my_statbuf to the new directory.
2317 if (use_XA || use_RockRidge) {
2318 generate_xa_rr_attributes("", (char *) pnt, de,
2319 &my_statbuf, &my_statbuf, 0);
2321 iso9660_date(de->isorec.date, fstatbuf.st_mtime);
2324 /* give the directory an HFS entry */
2327 hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
2329 /* fill in the defaults */
2330 memset(hfs_ent, 0, sizeof (hfsdirent));
2331 hfs_ent->crdate = my_statbuf.st_ctime;
2332 hfs_ent->mddate = my_statbuf.st_mtime;
2334 de->hfs_ent = hfs_ent;
2336 /* get the Mac directory name */
2337 get_hfs_dir((char *) path, (char *) pnt, de);
2339 #endif /* APPLE_HYB */
2342 * If we don't have a directory for this one yet, then allocate it now,
2343 * and patch it into the tree in the appropriate place.
2345 dpnt = (struct directory *) e_malloc(sizeof (struct directory));
2346 memset(dpnt, 0, sizeof (struct directory));
2348 dpnt->subdir = NULL;
2350 dpnt->contents = NULL;
2351 dpnt->whole_name = strdup(path);
2352 cpnt = strrchr(path, PATH_SEPARATOR);
2357 dpnt->de_name = strdup(cpnt);
2363 dpnt->hfs_ent = de->hfs_ent;
2364 #endif /* APPLE_HYB */
2366 if (orig_de == NULL) {
2367 struct stat xstatbuf;
2368 struct stat parent_statbuf;
2372 * Now add a . and .. entry in the directory itself. This is a
2373 * little tricky - if the real directory exists, we need to
2374 * stat it first. Otherwise, we use the fictitious fstatbuf
2375 * which points to the time at which genisoimage was started.
2377 if (parent == NULL || parent->whole_name[0] == '\0')
2380 sts = stat_filter(parent->whole_name, &parent_statbuf);
2383 parent_statbuf = fstatbuf;
2384 parent_statbuf.st_mode = new_dir_mode | S_IFDIR;
2385 parent_statbuf.st_nlink = 2;
2388 if (debug && parent) {
2389 fprintf(stderr, "stat parent->whole_name: '%s' -> %d.\n",
2390 parent->whole_name, sts);
2392 attach_dot_entries(dpnt, &my_statbuf, &parent_statbuf);
2394 if (!parent || parent == root) {
2396 root = dpnt; /* First time through for root */
2397 /* directory only */
2399 root->parent = root;
2402 if (!root->subdir) {
2403 root->subdir = dpnt;
2405 next_brother = root->subdir;
2406 while (next_brother->next)
2407 next_brother = next_brother->next;
2408 next_brother->next = dpnt;
2410 dpnt->parent = parent;
2413 /* Come through here for normal traversal of tree */
2415 fprintf(stderr, "%s(%d) ", path, dpnt->depth);
2417 if (parent->depth > RR_relocation_depth) {
2419 * XXX to prevent this, we would need to add
2420 * XXX support for RR directory relocation
2421 * XXX to find_or_create_directory()
2423 #ifdef USE_LIBSCHILY
2425 "Directories too deep for '%s' (%d) max is %d.\n",
2426 path, parent->depth, RR_relocation_depth);
2429 "Directories too deep for '%s' (%d) max is %d.\n",
2430 path, parent->depth, RR_relocation_depth);
2434 dpnt->parent = parent;
2435 dpnt->depth = parent->depth + 1;
2437 if (!parent->subdir) {
2438 parent->subdir = dpnt;
2440 next_brother = parent->subdir;
2441 while (next_brother->next)
2442 next_brother = next_brother->next;
2443 next_brother->next = dpnt;
2451 * Function: delete_directory
2453 * Purpose: Locate a directory entry in the tree, create if needed.
2458 delete_directory(parent, child)
2459 struct directory *parent;
2460 struct directory *child;
2462 struct directory *tdir;
2464 if (child->contents != NULL) {
2465 #ifdef USE_LIBSCHILY
2466 comerrno(EX_BAD, "Unable to delete non-empty directory\n");
2468 fprintf(stderr, "Unable to delete non-empty directory\n");
2472 free(child->whole_name);
2473 child->whole_name = NULL;
2475 free(child->de_name);
2476 child->de_name = NULL;
2479 if (apple_both && child->hfs_ent)
2480 free(child->hfs_ent);
2481 #endif /* APPLE_HYB */
2483 if (parent->subdir == child) {
2484 parent->subdir = child->next;
2486 for (tdir = parent->subdir; tdir->next != NULL;
2487 tdir = tdir->next) {
2488 if (tdir->next == child) {
2489 tdir->next = child->next;
2494 #ifdef USE_LIBSCHILY
2496 "Unable to locate child directory in parent list\n");
2499 "Unable to locate child directory in parent list\n");
2508 sort_tree(struct directory *node)
2510 struct directory *dpnt;
2516 ret = sort_n_finish(dpnt);
2521 sort_tree(dpnt->subdir);
2528 dump_tree(struct directory *node)
2530 struct directory *dpnt;
2535 fprintf(stderr, "%4d %5d %s\n",
2536 dpnt->extent, dpnt->size, dpnt->de_name);
2538 dump_tree(dpnt->subdir);
2544 update_nlink_field(struct directory *node)
2546 struct directory *dpnt;
2547 struct directory *xpnt;
2548 struct directory_entry *s_entry;
2554 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
2559 * First, count up the number of subdirectories this guy has.
2561 for (i = 0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
2562 if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
2565 * Next check to see if we have any relocated directories in
2566 * this directory. The nlink field will include these as
2567 * real directories when they are properly relocated.
2568 * In the non-rockridge disk, the relocated entries appear as
2569 * zero length files.
2571 for (s_entry = dpnt->contents; s_entry;
2572 s_entry = s_entry->next) {
2573 if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0 &&
2574 (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) ==
2579 /* Now update the field in the Rock Ridge entry. */
2580 update_nlink(dpnt->self, i + 2);
2582 /* Update the '.' entry for this directory. */
2583 update_nlink(dpnt->contents, i + 2);
2585 /* Update all of the '..' entries that point to this guy. */
2586 for (xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
2587 update_nlink(xpnt->contents->next, i + 2);
2590 update_nlink_field(dpnt->subdir);
2596 * something quick and dirty to locate a file given a path
2597 * recursively walks down path in filename until it finds the
2598 * directory entry for the desired file
2600 struct directory_entry *
2601 search_tree_file(struct directory *node, char *filename)
2603 struct directory_entry *depnt;
2604 struct directory *dpnt;
2609 /* strip off next directory name from filename */
2610 subdir = strdup(filename);
2612 if ((p1 = strchr(subdir, '/')) == subdir) {
2614 "call to search_tree_file with an absolute path, stripping\n");
2616 "initial path separator. Hope this was intended...\n");
2617 memmove(subdir, subdir + 1, strlen(subdir) - 1);
2618 p1 = strchr(subdir, '/');
2620 /* do we need to find a subdirectory */
2625 fprintf(stderr, "Looking for subdir called %s\n", p1);
2631 fprintf(stderr, "Remainder of path name is now %s\n", rest);
2634 dpnt = node->subdir;
2638 "%4d %5d %s\n", dpnt->extent, dpnt->size,
2641 if (strcmp(subdir, dpnt->de_name) == 0) {
2644 "Calling next level with filename = %s", rest);
2646 return (search_tree_file(dpnt, rest));
2651 /* if we got here means we couldnt find the subdir */
2654 /* look for a normal file now */
2655 depnt = node->contents;
2658 fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
2659 depnt->size, depnt->name);
2661 if (strcmp(filename, depnt->name) == 0) {
2663 fprintf(stderr, "Found our file %s", filename);
2667 depnt = depnt->next;
2669 /* if we got here means we couldnt find the subdir */
2673 fprintf(stderr, "We cant get here in search_tree_file :-/ \n");
2680 time_t current_time;
2682 if (fstatbuf.st_ctime == 0) {
2683 time(¤t_time);
2684 if (rationalize_uid)
2685 fstatbuf.st_uid = uid_to_use;
2687 fstatbuf.st_uid = getuid();
2688 if (rationalize_gid)
2689 fstatbuf.st_gid = gid_to_use;
2691 fstatbuf.st_gid = getgid();
2692 fstatbuf.st_ctime = current_time;
2693 fstatbuf.st_mtime = current_time;
2694 fstatbuf.st_atime = current_time;