--- /dev/null
+/* @(#)tree.c 1.137 16/12/13 joerg */
+#include <schily/mconfig.h>
+#ifndef lint
+static UConst char sccsid[] =
+ "@(#)tree.c 1.137 16/12/13 joerg";
+#endif
+/*
+ * File tree.c - scan directory tree and build memory structures for iso9660
+ * filesystem
+ *
+ * Written by Eric Youngdale (1993).
+ *
+ * Copyright 1993 Yggdrasil Computing, Incorporated
+ * Copyright (c) 1999,2000-2016 J. Schilling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+/* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
+
+/* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
+
+#include "mkisofs.h"
+#include "rock.h"
+#include "match.h"
+#include <schily/time.h>
+#include <schily/errno.h>
+#include <schily/fcntl.h>
+#include <schily/device.h>
+#include <schily/schily.h>
+
+#ifdef UDF
+#include "udf.h"
+#endif
+
+#ifdef VMS
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+#endif
+
+LOCAL Uchar symlink_buff[PATH_MAX+1];
+
+LOCAL char *filetype __PR((int t));
+LOCAL char *rstr __PR((char *s1, char *s2));
+LOCAL void stat_fix __PR((struct stat *st));
+EXPORT int stat_filter __PR((char *path, struct stat *st));
+EXPORT int lstat_filter __PR((char *path, struct stat *st));
+LOCAL int sort_n_finish __PR((struct directory *this_dir));
+LOCAL void generate_reloc_directory __PR((void));
+EXPORT void attach_dot_entries __PR((struct directory *dirnode,
+ struct stat *this_stat,
+ struct stat *parent_stat));
+EXPORT char *find_rr_attribute __PR((unsigned char *pnt, int len,
+ char *attr_type));
+EXPORT void finish_cl_pl_entries __PR((void));
+LOCAL void dir_nesting_warn __PR((struct directory *this_dir,
+ char *path, int contflag));
+EXPORT int scan_directory_tree __PR((struct directory *this_dir,
+ char *path,
+ struct directory_entry *de));
+LOCAL struct directory_entry *
+ dup_relocated_dir __PR((struct directory *this_dir,
+ struct directory_entry *s_entry,
+ char *whole_path,
+ char *short_name,
+ struct stat *statp));
+EXPORT int insert_file_entry __PR((struct directory *this_dir,
+ char *whole_path,
+ char *short_name,
+ struct stat *statp, int have_rsrc));
+EXPORT struct directory_entry *
+ dup_directory_entry __PR((struct directory_entry *s_entry));
+EXPORT void generate_iso9660_directories __PR((struct directory *node,
+ FILE *outfile));
+
+LOCAL void set_de_path __PR((struct directory *parent,
+ struct directory *this));
+
+EXPORT struct directory *
+ find_or_create_directory __PR((struct directory *parent,
+ char *path,
+ struct directory_entry *de,
+ int flag));
+LOCAL void delete_directory __PR((struct directory *parent,
+ struct directory *child));
+EXPORT int sort_tree __PR((struct directory *node));
+EXPORT void dump_tree __PR((struct directory *node));
+EXPORT struct directory_entry *
+ search_tree_file __PR((struct directory *node,
+ char *filename));
+EXPORT void init_fstatbuf __PR((void));
+
+extern int verbose;
+struct stat fstatbuf; /* We use this for the artificial */
+ /* entries we create */
+struct stat root_statbuf; /* Stat buffer for root directory */
+struct directory *reloc_dir;
+
+LOCAL char *
+filetype(t)
+ int t;
+{
+ static char unkn[32];
+
+ if (S_ISFIFO(t)) /* 1 */
+ return ("fifo");
+ if (S_ISCHR(t)) /* 2 */
+ return ("chr");
+ if (S_ISMPC(t)) /* 3 */
+ return ("multiplexed chr");
+ if (S_ISDIR(t)) /* 4 */
+ return ("dir");
+ if (S_ISNAM(t)) /* 5 */
+ return ("named file");
+ if (S_ISBLK(t)) /* 6 */
+ return ("blk");
+ if (S_ISMPB(t)) /* 7 */
+ return ("multiplexed blk");
+ if (S_ISREG(t)) /* 8 */
+ return ("regular file");
+ if (S_ISCTG(t)) /* 9 */
+ return ("contiguous file");
+ if (S_ISLNK(t)) /* 10 */
+ return ("symlink");
+ if (S_ISSHAD(t)) /* 11 */
+ return ("Solaris shadow inode");
+ if (S_ISSOCK(t)) /* 12 */
+ return ("socket");
+ if (S_ISDOOR(t)) /* 13 */
+ return ("door");
+ if (S_ISWHT(t)) /* 14 */
+ return ("whiteout");
+ if (S_ISEVC(t)) /* 15 */
+ return ("event count");
+
+ /*
+ * Needs to be last in case somebody makes this
+ * a supported file type.
+ */
+ if ((t & S_IFMT) == 0) /* 0 (unallocated) */
+ return ("unallocated");
+
+ sprintf(unkn, "octal '%o'", t & S_IFMT);
+ return (unkn);
+}
+
+/*
+ * Check if s1 ends in strings s2
+ */
+LOCAL char *
+rstr(s1, s2)
+ char *s1;
+ char *s2;
+{
+ int l1;
+ int l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+ if (l2 > l1)
+ return ((char *)NULL);
+
+ if (strcmp(&s1[l1 - l2], s2) == 0)
+ return (&s1[l1 - l2]);
+ return ((char *)NULL);
+}
+
+LOCAL void
+stat_fix(st)
+ struct stat *st;
+{
+ int adjust_modes = 0;
+
+ if (S_ISREG(st->st_mode))
+ adjust_modes = rationalize_filemode;
+ else if (S_ISDIR(st->st_mode))
+ adjust_modes = rationalize_dirmode;
+ else
+ adjust_modes = (rationalize_filemode || rationalize_dirmode);
+
+ /*
+ * If rationalizing, override the uid and gid, since the
+ * originals will only be useful on the author's system.
+ */
+ if (rationalize_uid)
+ st->st_uid = uid_to_use;
+ if (rationalize_gid)
+ st->st_gid = gid_to_use;
+
+ if (adjust_modes) {
+
+ if (S_ISREG(st->st_mode) && (filemode_to_use != 0)) {
+ st->st_mode = filemode_to_use | S_IFREG;
+ } else if (S_ISDIR(st->st_mode) && (dirmode_to_use != 0)) {
+ st->st_mode = dirmode_to_use | S_IFDIR;
+ } else {
+ /*
+ * Make sure the file modes make sense. Turn
+ * on all read bits. Turn on all exec/search
+ * bits if any exec/search bit is set. Turn
+ * off all write bits, and all special mode
+ * bits (on a r/o fs lock bits are useless,
+ * and with uid+gid 0 don't want set-id bits,
+ * either).
+ */
+
+ st->st_mode |= 0444;
+#if !defined(_WIN32) && !defined(__DJGPP__) /* make all file "executable" */
+ if (st->st_mode & 0111)
+#endif
+ st->st_mode |= 0111;
+ st->st_mode &= ~07222;
+ }
+ }
+}
+
+EXPORT int
+stat_filter(path, st)
+ char *path;
+ struct stat *st;
+{
+ int result = stat(path, st);
+
+ if (result >= 0 && rationalize)
+ stat_fix(st);
+ return (result);
+}
+
+EXPORT int
+lstat_filter(path, st)
+ char *path;
+ struct stat *st;
+{
+ int result = lstat(path, st);
+
+ if (result >= 0 && rationalize)
+ stat_fix(st);
+ return (result);
+}
+
+LOCAL int
+sort_n_finish(this_dir)
+ struct directory *this_dir;
+{
+ struct directory_entry *s_entry;
+ struct directory_entry *s_entry1;
+ struct directory_entry *table;
+ int count;
+ int d1;
+ int d2;
+ int d3;
+ register int new_reclen;
+ char *c;
+ int status = 0;
+ int tablesize = 0;
+ char newname[MAX_ISONAME+1];
+ char rootname[MAX_ISONAME+1];
+ char extname[MAX_ISONAME+1];
+
+ /*
+ * Here we can take the opportunity to toss duplicate entries from the
+ * directory.
+ */
+ /* ignore if it's hidden */
+ if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
+ return (0);
+ }
+ table = NULL;
+
+ init_fstatbuf();
+
+ /*
+ * If we had artificially created this directory, then we might be
+ * missing the required '.' entries. Create these now if we need
+ * them.
+ */
+ if ((this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
+ (DIR_HAS_DOT | DIR_HAS_DOTDOT)) {
+ attach_dot_entries(this_dir, NULL, NULL);
+ }
+ flush_file_hash();
+ s_entry = this_dir->contents;
+ while (s_entry) {
+#ifdef USE_LARGEFILES
+ /*
+ * Skip all but the last extent from a multi extent file,
+ * we like them all have the same name.
+ */
+ if ((s_entry->de_flags & MULTI_EXTENT) &&
+ (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)) {
+ s_entry = s_entry->next;
+ continue;
+ }
+#endif
+ /* ignore if it's hidden */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
+ s_entry = s_entry->next;
+ continue;
+ }
+ /*
+ * First assume no conflict, and handle this case
+ */
+ if (!(s_entry1 = find_file_hash(s_entry->isorec.name))) {
+ add_file_hash(s_entry);
+ s_entry = s_entry->next;
+ continue;
+ }
+#ifdef APPLE_HYB
+ /*
+ * if the pair are associated, then skip (as they have the
+ * same name!)
+ */
+ if (apple_both && s_entry1->assoc &&
+ s_entry1->assoc == s_entry) {
+ s_entry = s_entry->next;
+ continue;
+ }
+#endif /* APPLE_HYB */
+
+ if (s_entry1 == s_entry) {
+ comerrno(EX_BAD,
+ _("Fatal goof, file '%s' already in hash table.\n"),
+ s_entry->isorec.name);
+ }
+ /*
+ * OK, handle the conflicts. Try substitute names until we
+ * come up with a winner
+ */
+ strlcpy(rootname, s_entry->isorec.name, sizeof (rootname));
+ /*
+ * Strip off the non-significant part of the name so that we
+ * are left with a sensible root filename. If we don't find
+ * a '.', then try a ';'.
+ */
+ c = strchr(rootname, '.');
+ /*
+ * In case we ever allow more than on dot, only modify the
+ * section past the last dot if the file name starts with a
+ * dot.
+ */
+ if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
+ c = strrchr(rootname, '.');
+ }
+ extname[0] = '\0'; /* In case we have no ext. */
+ if (c) {
+ strlcpy(extname, c, sizeof (extname));
+ *c = 0; /* Cut off complete ext. */
+ } else {
+ /*
+ * Could not find any '.'.
+ */
+ c = strchr(rootname, ';');
+ if (c) {
+ *c = 0; /* Cut off version number */
+ }
+ }
+ c = strchr(extname, ';');
+ if (c) {
+ *c = 0; /* Cut off version number */
+ }
+ d1 = strlen(rootname);
+ if (full_iso9660_filenames || iso9660_level > 1) {
+ d2 = strlen(extname);
+ /*
+ * 31/37 chars minus the 3 characters we are
+ * appending below to create unique filenames.
+ */
+ if ((d1 + d2) > (iso9660_namelen - 3))
+ rootname[iso9660_namelen - 3 - d2] = 0;
+ } else {
+ if (d1 > 5)
+ rootname[5] = 0;
+ }
+ new_reclen = strlen(rootname);
+ sprintf(newname, "%s000%s%s",
+ rootname,
+ extname,
+ ((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
+ omit_version_number ? "" : ";1"));
+
+ for (d1 = 0; d1 < 36; d1++) {
+ for (d2 = 0; d2 < 36; d2++) {
+ for (d3 = 0; d3 < 36; d3++) {
+ newname[new_reclen + 0] =
+ (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10);
+ newname[new_reclen + 1] =
+ (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10);
+ newname[new_reclen + 2] =
+ (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10);
+ if (debug)
+ error(_("NEW name '%s'\n"), newname);
+
+#ifdef VMS
+ /* Sigh. VAXCRTL seems to be broken here */
+ {
+ int ijk = 0;
+
+ while (newname[ijk]) {
+ if (newname[ijk] == ' ')
+ newname[ijk] = '0';
+ ijk++;
+ }
+ }
+#endif
+
+ if (!find_file_hash(newname))
+ goto got_valid_name;
+ }
+ }
+ }
+
+ /*
+ * If we fell off the bottom here, we were in real trouble.
+ */
+ comerrno(EX_BAD,
+ _("Unable to generate unique name for file %s\n"),
+ s_entry->name);
+
+got_valid_name:
+ /*
+ * OK, now we have a good replacement name. Now decide which
+ * one of these two beasts should get the name changed
+ */
+ if (s_entry->priority < s_entry1->priority) {
+ if (verbose > 0) {
+ fprintf(stderr, _("Using %s for %s%s%s (%s)\n"),
+ newname,
+ this_dir->whole_name, SPATH_SEPARATOR,
+ s_entry->name, s_entry1->name);
+ }
+
+ s_entry->isorec.name_len[0] = strlen(newname);
+ new_reclen = offsetof(struct iso_directory_record,
+ name[0]) +
+ strlen(newname);
+ if (use_XA || use_RockRidge) {
+ if (new_reclen & 1)
+ new_reclen++; /* Pad to an even byte */
+ new_reclen += s_entry->rr_attr_size;
+ }
+ if (new_reclen & 1)
+ new_reclen++; /* Pad to an even byte */
+ s_entry->isorec.length[0] = new_reclen;
+ strcpy(s_entry->isorec.name, newname);
+#ifdef USE_LARGEFILES
+ if (s_entry->de_flags & MULTI_EXTENT) {
+ struct directory_entry *s_e;
+
+ /*
+ * Copy over the new name to all other entries
+ */
+ for (s_e = s_entry->mxroot;
+ s_e && s_e->mxroot == s_entry->mxroot;
+ s_e = s_e->next) {
+ s_e->isorec.length[0] = new_reclen;
+ s_e->isorec.name_len[0] = s_entry->isorec.name_len[0];
+ strcpy(s_e->isorec.name, newname);
+ }
+ }
+#endif
+#ifdef APPLE_HYB
+ /*
+ * Has resource fork - needs new name
+ */
+ if (apple_both && s_entry->assoc) {
+ struct directory_entry *s_entry2 =
+ s_entry->assoc;
+
+ /*
+ * resource fork name *should* be the same as
+ * the data fork
+ */
+ s_entry2->isorec.name_len[0] =
+ s_entry->isorec.name_len[0];
+ strcpy(s_entry2->isorec.name,
+ s_entry->isorec.name);
+ s_entry2->isorec.length[0] = new_reclen;
+ }
+#endif /* APPLE_HYB */
+ } else {
+ delete_file_hash(s_entry1);
+ if (verbose > 0) {
+ fprintf(stderr, _("Using %s for %s%s%s (%s)\n"),
+ newname,
+ this_dir->whole_name, SPATH_SEPARATOR,
+ s_entry1->name, s_entry->name);
+ }
+ s_entry1->isorec.name_len[0] = strlen(newname);
+ new_reclen = offsetof(struct iso_directory_record,
+ name[0]) +
+ strlen(newname);
+ if (use_XA || use_RockRidge) {
+ if (new_reclen & 1)
+ new_reclen++; /* Pad to an even byte */
+ new_reclen += s_entry1->rr_attr_size;
+ }
+ if (new_reclen & 1)
+ new_reclen++; /* Pad to an even byte */
+ s_entry1->isorec.length[0] = new_reclen;
+ strcpy(s_entry1->isorec.name, newname);
+#ifdef USE_LARGEFILES
+ if (s_entry1->de_flags & MULTI_EXTENT) {
+ struct directory_entry *s_e;
+
+ /*
+ * Copy over the new name to all other entries
+ */
+ for (s_e = s_entry1->mxroot;
+ s_e && s_e->mxroot == s_entry1->mxroot;
+ s_e = s_e->next) {
+ s_e->isorec.length[0] = new_reclen;
+ s_e->isorec.name_len[0] = s_entry1->isorec.name_len[0];
+ strcpy(s_e->isorec.name, newname);
+ }
+ }
+#endif
+ add_file_hash(s_entry1);
+#ifdef APPLE_HYB
+ /*
+ * Has resource fork - needs new name
+ */
+ if (apple_both && s_entry1->assoc) {
+ struct directory_entry *s_entry2 =
+ s_entry1->assoc;
+
+ /*
+ * resource fork name *should* be the same as
+ * the data fork
+ */
+ s_entry2->isorec.name_len[0] =
+ s_entry1->isorec.name_len[0];
+ strcpy(s_entry2->isorec.name,
+ s_entry1->isorec.name);
+ s_entry2->isorec.length[0] = new_reclen;
+ }
+#endif /* APPLE_HYB */
+ }
+ add_file_hash(s_entry);
+ s_entry = s_entry->next;
+ }
+
+ if (generate_tables &&
+ !find_file_hash(trans_tbl) &&
+ (reloc_dir != this_dir) &&
+ (this_dir->extent == 0)) {
+ /*
+ * First we need to figure out how big this table is
+ */
+ for (s_entry = this_dir->contents; s_entry;
+ s_entry = s_entry->next) {
+ if (strcmp(s_entry->name, ".") == 0 ||
+ strcmp(s_entry->name, "..") == 0)
+ continue;
+#ifdef APPLE_HYB
+ /*
+ * Skip table entry for the resource fork
+ */
+ if (apple_both &&
+ (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
+ continue;
+#endif /* APPLE_HYB */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
+ continue;
+ if (s_entry->table) {
+ /*
+ * Max namelen, a space before and a space
+ * after the iso filename.
+ */
+ tablesize += MAX_ISONAME + 2 +
+ strlen(s_entry->table);
+ }
+ }
+ }
+ if (tablesize > 0) {
+ table = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(table, 0, sizeof (struct directory_entry));
+ table->table = NULL;
+ table->next = this_dir->contents;
+ this_dir->contents = table;
+
+ table->filedir = root;
+ table->isorec.flags[0] = ISO_FILE;
+ table->priority = 32768;
+ iso9660_date(table->isorec.date, fstatbuf.st_mtime);
+ table->inode = TABLE_INODE;
+ table->dev = UNCACHED_DEVICE;
+ set_723(table->isorec.volume_sequence_number,
+ volume_sequence_number);
+ set_733((char *)table->isorec.size, tablesize);
+ table->size = tablesize;
+ table->filedir = this_dir;
+ if (jhide_trans_tbl)
+ table->de_flags |= INHIBIT_JOLIET_ENTRY;
+ /*
+ * Always hide transtable from UDF tree.
+ */
+ table->de_flags |= INHIBIT_UDF_ENTRY;
+/* table->name = e_strdup("<translation table>");*/
+ table->name = e_strdup(trans_tbl);
+ /*
+ * We use sprintf() to create the strings, for this reason
+ * we need to add one byte for the null character at the
+ * end of the string even though we don't use it.
+ */
+ table->table = (char *)e_malloc(ISO_ROUND_UP(tablesize)+1);
+ memset(table->table, 0, ISO_ROUND_UP(tablesize)+1);
+ iso9660_file_length(trans_tbl, table, 0);
+
+ if (use_XA || use_RockRidge) {
+ fstatbuf.st_mode = 0444 | S_IFREG;
+ fstatbuf.st_nlink = 1;
+ generate_xa_rr_attributes("",
+ trans_tbl, table,
+ &fstatbuf, &fstatbuf, 0);
+ }
+ }
+ /*
+ * We have now chosen the 8.3 names and we should now know the length
+ * of every entry in the directory.
+ */
+ for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
+ /* skip if it's hidden */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
+ continue;
+ }
+ new_reclen = strlen(s_entry->isorec.name);
+
+ /*
+ * First update the path table sizes for directories.
+ */
+ if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
+ if (strcmp(s_entry->name, ".") != 0 &&
+ strcmp(s_entry->name, "..") != 0) {
+ path_table_size += new_reclen +
+ offsetof(struct iso_path_table,
+ name[0]);
+ if (new_reclen & 1)
+ path_table_size++;
+ } else {
+ new_reclen = 1;
+ if (this_dir == root && strlen(s_entry->name)
+ == 1) {
+ path_table_size += new_reclen +
+ offsetof(struct iso_path_table,
+ name[0]);
+ }
+ }
+ }
+ if (path_table_size & 1)
+ path_table_size++; /* For odd lengths we pad */
+ s_entry->isorec.name_len[0] = new_reclen;
+
+ new_reclen += offsetof(struct iso_directory_record, name[0]);
+
+ if (new_reclen & 1)
+ new_reclen++;
+
+ new_reclen += s_entry->rr_attr_size;
+
+ if (new_reclen & 1)
+ new_reclen++;
+
+ if (new_reclen > 0xff) {
+ comerrno(EX_BAD,
+ _("Fatal error - RR overflow (reclen %d) for file %s\n"),
+ new_reclen,
+ s_entry->name);
+ }
+ s_entry->isorec.length[0] = new_reclen;
+ }
+
+ status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
+ if (status > 0) {
+ errmsgno(EX_BAD, _("Unable to sort directory %s\n"),
+ this_dir->whole_name);
+ errmsgno(EX_BAD,
+ _("If there was more than one directory type argument to mkisofs\n"));
+ comerrno(EX_BAD,
+ _("use -graft-points to create different target directory names.\n"));
+ }
+ /*
+ * If we are filling out a TRANS.TBL, generate the entries that will
+ * go in the thing.
+ */
+ if (table) {
+ count = 0;
+ for (s_entry = this_dir->contents; s_entry;
+ s_entry = s_entry->next) {
+ if (s_entry == table)
+ continue;
+ if (!s_entry->table)
+ continue;
+ if (strcmp(s_entry->name, ".") == 0 ||
+ strcmp(s_entry->name, "..") == 0)
+ continue;
+#ifdef APPLE_HYB
+ /*
+ * Skip table entry for the resource fork
+ */
+ if (apple_both &&
+ (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
+ continue;
+#endif /* APPLE_HYB */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
+ continue;
+ /*
+ * Warning: we cannot use the return value of sprintf
+ * because old BSD based sprintf() implementations
+ * will return a pointer to the result instead of a
+ * count.
+ * Old mkiofs introduced a space after the iso
+ * filename to make parsing TRANS.TBL easier.
+ */
+ sprintf(table->table + count, "%c %-*s%s",
+ s_entry->table[0],
+ MAX_ISONAME + 1,
+ s_entry->isorec.name, s_entry->table + 1);
+ count += strlen(table->table + count);
+ free(s_entry->table);
+ /*
+ * for a memory file, set s_entry->table to the
+ * correct data - which is stored in
+ * s_entry->whole_name
+ */
+ if (s_entry->de_flags & MEMORY_FILE) {
+ s_entry->table = s_entry->whole_name;
+ s_entry->whole_name = NULL;
+ } else {
+ s_entry->table = NULL;
+ }
+ }
+
+ if (count != tablesize) {
+ comerrno(EX_BAD,
+ _("Translation table size mismatch %d %d\n"),
+ count, tablesize);
+ }
+ }
+ /*
+ * Now go through the directory and figure out how large this one will
+ * be. Do not split a directory entry across a sector boundary
+ */
+ s_entry = this_dir->contents;
+ this_dir->ce_bytes = 0;
+ while (s_entry) {
+ /* skip if it's hidden */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
+ s_entry = s_entry->next;
+ continue;
+ }
+ new_reclen = s_entry->isorec.length[0];
+ if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
+ >= SECTOR_SIZE)
+
+ this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
+ ~(SECTOR_SIZE - 1);
+ this_dir->size += new_reclen;
+
+ /*
+ * See if continuation entries were used on disc
+ */
+ if (use_RockRidge &&
+ s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
+ unsigned char *pnt;
+ int len;
+ int nbytes;
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+ pnt = parse_xa(pnt, &len, 0);
+/* pnt = parse_xa(pnt, &len, s_entry);*/
+
+ /*
+ * We make sure that each continuation entry record is
+ * not split across sectors, but each file could in
+ * theory have more than one CE, so we scan through
+ * and figure out what we need.
+ */
+ while (len > 3) {
+ if (pnt[0] == 'C' && pnt[1] == 'E') {
+ nbytes = get_733((char *)pnt + 20);
+
+ if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
+ SECTOR_SIZE)
+ this_dir->ce_bytes =
+ ISO_ROUND_UP(this_dir->ce_bytes);
+ /*
+ * Now store the block in the
+ * ce buffer
+ */
+ this_dir->ce_bytes += nbytes;
+ if (this_dir->ce_bytes & 1)
+ this_dir->ce_bytes++;
+ }
+ len -= pnt[2];
+ pnt += pnt[2];
+ }
+ }
+ s_entry = s_entry->next;
+ }
+ return (status);
+}
+
+LOCAL void
+generate_reloc_directory()
+{
+ time_t current_time;
+ struct directory_entry *s_entry;
+
+ /*
+ * Create an entry for our internal tree
+ */
+ time(¤t_time);
+ reloc_dir = (struct directory *)
+ e_malloc(sizeof (struct directory));
+ memset(reloc_dir, 0, sizeof (struct directory));
+ reloc_dir->parent = root;
+ reloc_dir->next = root->subdir;
+ root->subdir = reloc_dir;
+ reloc_dir->depth = 1;
+ if (hide_rr_moved) {
+ reloc_dir->whole_name = e_strdup("./.rr_moved");
+ reloc_dir->de_name = e_strdup(".rr_moved");
+ } else {
+ reloc_dir->whole_name = e_strdup("./rr_moved");
+ reloc_dir->de_name = e_strdup("rr_moved");
+ }
+ reloc_dir->de_path = reloc_dir->de_name;
+ reloc_dir->extent = 0;
+
+
+ /*
+ * Now create an actual directory entry
+ */
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(s_entry, 0, sizeof (struct directory_entry));
+ s_entry->next = root->contents;
+ reloc_dir->self = s_entry;
+
+ /*
+ * The rr_moved entry will not appear in the Joliet nor the UDF tree.
+ */
+ reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
+ s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+
+ reloc_dir->dir_flags |= INHIBIT_UDF_ENTRY;
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+
+ root->contents = s_entry;
+ root->contents->name = e_strdup(reloc_dir->de_name);
+ root->contents->filedir = root;
+ root->contents->isorec.flags[0] = ISO_DIRECTORY;
+ root->contents->priority = 32768;
+ iso9660_date(root->contents->isorec.date, current_time);
+ root->contents->inode = UNCACHED_INODE;
+ root->contents->dev = UNCACHED_DEVICE;
+ set_723(root->contents->isorec.volume_sequence_number,
+ volume_sequence_number);
+ iso9660_file_length(reloc_dir->de_name, root->contents, 1);
+
+ init_fstatbuf();
+
+ if (use_XA || use_RockRidge) {
+ fstatbuf.st_mode = 0555 | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ generate_xa_rr_attributes("",
+ hide_rr_moved ? ".rr_moved" : "rr_moved",
+ s_entry, &fstatbuf, &fstatbuf, NEED_RE);
+ };
+
+ /*
+ * Now create the . and .. entries in rr_moved
+ * Now create an actual directory entry
+ */
+ if (root_statbuf.st_nlink == 0)
+ root_statbuf = fstatbuf;
+ attach_dot_entries(reloc_dir, NULL, &root_statbuf);
+}
+
+/*
+ * Function: attach_dot_entries
+ *
+ * Purpose: Create . and .. entries for a new directory.
+ *
+ * Notes: Only used for artificial directories that
+ * we are creating.
+ */
+EXPORT void
+attach_dot_entries(dirnode, this_stat, parent_stat)
+ struct directory *dirnode;
+ struct stat *this_stat;
+ struct stat *parent_stat;
+{
+ struct directory_entry *s_entry;
+ struct directory_entry *orig_contents;
+ int deep_flag = 0;
+
+ init_fstatbuf();
+ fstatbuf.st_mode = new_dir_mode | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ if (parent_stat == NULL)
+ parent_stat = &fstatbuf;
+ if (this_stat == NULL)
+ this_stat = &fstatbuf;
+
+ orig_contents = dirnode->contents;
+
+ if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 0) {
+ if (dirnode->parent &&
+ dirnode->parent == reloc_dir) {
+ deep_flag = NEED_PL;
+ }
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry, dirnode->self,
+ sizeof (struct directory_entry));
+#ifdef APPLE_HYB
+ if (dirnode->self->hfs_ent) {
+ s_entry->hfs_ent = (hfsdirent *)
+ e_malloc(sizeof (hfsdirent));
+ memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
+ sizeof (hfsdirent));
+ }
+#endif
+ s_entry->name = e_strdup("..");
+ s_entry->whole_name = NULL;
+ s_entry->isorec.name_len[0] = 1;
+ s_entry->isorec.flags[0] = ISO_DIRECTORY;
+ iso9660_file_length("..", s_entry, 1);
+ iso9660_date(s_entry->isorec.date, parent_stat->st_mtime);
+ set_723(s_entry->isorec.volume_sequence_number,
+ volume_sequence_number);
+ set_733(s_entry->isorec.size, SECTOR_SIZE);
+ memset(s_entry->isorec.extent, 0, 8);
+ s_entry->filedir = dirnode->parent;
+
+ dirnode->contents = s_entry;
+ dirnode->contents->next = orig_contents;
+ orig_contents = s_entry;
+
+ if (use_XA || use_RockRidge) {
+ generate_xa_rr_attributes("",
+ "..", s_entry,
+ parent_stat,
+ parent_stat, deep_flag);
+ }
+ dirnode->dir_flags |= DIR_HAS_DOTDOT;
+ }
+ deep_flag = 0;
+ if ((dirnode->dir_flags & DIR_HAS_DOT) == 0) {
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry, dirnode->self,
+ sizeof (struct directory_entry));
+#ifdef APPLE_HYB
+ if (dirnode->self->hfs_ent) {
+ s_entry->hfs_ent = (hfsdirent *)
+ e_malloc(sizeof (hfsdirent));
+ memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
+ sizeof (hfsdirent));
+ }
+#endif
+ s_entry->name = e_strdup(".");
+ s_entry->whole_name = NULL;
+ s_entry->isorec.name_len[0] = 1;
+ s_entry->isorec.flags[0] = ISO_DIRECTORY;
+ iso9660_file_length(".", s_entry, 1);
+ iso9660_date(s_entry->isorec.date, this_stat->st_mtime);
+ set_723(s_entry->isorec.volume_sequence_number,
+ volume_sequence_number);
+ set_733(s_entry->isorec.size, SECTOR_SIZE);
+ memset(s_entry->isorec.extent, 0, 8);
+ s_entry->filedir = dirnode;
+
+ dirnode->contents = s_entry;
+ dirnode->contents->next = orig_contents;
+
+ if (use_XA || use_RockRidge) {
+ if (dirnode == root) {
+ deep_flag |= NEED_CE | NEED_SP; /* For extension record */
+ }
+ generate_xa_rr_attributes("",
+ ".", s_entry,
+ this_stat, this_stat, deep_flag);
+ }
+ dirnode->dir_flags |= DIR_HAS_DOT;
+ }
+}
+
+EXPORT char *
+find_rr_attribute(pnt, len, attr_type)
+ unsigned char *pnt;
+ int len;
+ char *attr_type;
+{
+ pnt = parse_xa(pnt, &len, 0);
+ while (len >= 4) {
+ if (pnt[3] != 1 && pnt[3] != 2) {
+ errmsgno(EX_BAD,
+ _("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
+ pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
+ }
+ if (pnt[2] < 4) {
+ errmsgno(EX_BAD,
+ _("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
+ pnt[2], pnt, pnt[0], pnt[1]);
+ return (NULL);
+ }
+ if (strncmp((char *)pnt, attr_type, 2) == 0)
+ return ((char *)pnt);
+ else if (strncmp((char *)pnt, "ST", 2) == 0)
+ return (NULL);
+ len -= pnt[2];
+ pnt += pnt[2];
+ }
+ return (NULL);
+}
+
+EXPORT void
+finish_cl_pl_entries()
+{
+ struct directory_entry *s_entry;
+ struct directory_entry *s_entry1;
+ struct directory *d_entry;
+
+ /*
+ * If the reloc_dir is hidden (empty), then return
+ */
+ if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
+ return;
+
+ s_entry = reloc_dir->contents;
+ s_entry = s_entry->next->next; /* Skip past . and .. */
+ for (; s_entry; s_entry = s_entry->next) {
+ /* skip if it's hidden */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
+ continue;
+ }
+ d_entry = reloc_dir->subdir;
+ while (d_entry) {
+ if (d_entry->self == s_entry)
+ break;
+ d_entry = d_entry->next;
+ };
+ if (!d_entry) {
+ comerrno(EX_BAD,
+ _("Unable to locate directory parent\n"));
+ };
+
+ if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
+ char *rr_attr;
+
+ /*
+ * First fix the PL pointer in the directory in the
+ * rr_reloc dir
+ */
+ s_entry1 = d_entry->contents->next;
+
+/* set_733((char *) s_entry1->rr_attributes +*/
+/* s_entry1->total_rr_attr_size - 8,*/
+/* s_entry->filedir->extent); */
+ /*
+ * The line above won't work when entry was read from
+ * the previous session, because if total_rr_attr_size
+ * was odd when recording previous session, now we have
+ * total_rr_attr_size off by 1 due to padding.
+ *
+ * So, just search for the attributes by name
+ */
+ rr_attr = find_rr_attribute(s_entry1->rr_attributes,
+ s_entry1->total_rr_attr_size, "PL");
+ if (rr_attr != NULL)
+ set_733(rr_attr + 4, s_entry->filedir->extent);
+
+
+ /*
+ * Now fix the CL pointer
+ */
+ s_entry1 = s_entry->parent_rec;
+
+/* set_733((char *) s_entry1->rr_attributes +*/
+/* s_entry1->total_rr_attr_size - 8, d_entry->extent); */
+ rr_attr = find_rr_attribute(s_entry1->rr_attributes,
+ s_entry1->total_rr_attr_size, "CL");
+ if (rr_attr != NULL)
+ set_733(rr_attr + 4, d_entry->extent);
+ }
+ s_entry->filedir = reloc_dir; /* Now we can fix this */
+ }
+ /*
+ * We would need to modify the NLINK terms in the assorted root
+ * directory records to account for the presence of the RR_MOVED
+ * directory. We do not do this here because we do it later when
+ * we correct the link count for all direstories in the tree.
+ */
+
+
+ finish_cl_pl_for_prev_session();
+}
+
+LOCAL void
+dir_nesting_warn(this_dir, path, contflag)
+ struct directory *this_dir;
+ char *path;
+ int contflag;
+{
+ static BOOL did_hint = FALSE;
+
+ errmsgno(EX_BAD,
+ _("Directories too deep for '%s' (%d) max is %d%s.\n"),
+ path, this_dir->depth, RR_relocation_depth,
+ contflag?_("; ignored - continuing"):"");
+ if (!did_hint) {
+ did_hint = TRUE;
+ errmsgno(EX_BAD, _("To include the complete directory tree,\n"));
+ errmsgno(EX_BAD, _("use Rock Ridge extensions via -R or -r,\n"));
+ errmsgno(EX_BAD, _("or allow deep ISO9660 directory nesting via -D.\n"));
+ }
+}
+
+/*
+ * Function: scan_directory_tree
+ *
+ * Purpose: Walk through a directory on the local machine
+ * filter those things we don't want to include
+ * and build our representation of a dir.
+ *
+ * Notes:
+ */
+EXPORT int
+scan_directory_tree(this_dir, path, de)
+ struct directory *this_dir;
+ char *path;
+ struct directory_entry *de;
+{
+ DIR *current_dir;
+ char whole_path[2*PATH_MAX]; /* Avoid stat buffer overflow */
+ struct dirent *d_entry;
+ int dflag;
+extern BOOL nodesc;
+
+ if (nodesc)
+ return (1);
+
+ if (verbose > 1) {
+ fprintf(stderr, _("Scanning %s\n"), path);
+ }
+/*#define check_needed*/
+#ifdef check_needed
+ /*
+ * Trying to use this to avoid directory loops from hard links
+ * or followed symlinks does not work. It would prevent us from
+ * implementing merge directories.
+ */
+ if (this_dir->dir_flags & DIR_WAS_SCANNED) {
+ fprintf(stderr, _("Already scanned directory %s\n"), path);
+ return (1); /* It's a directory */
+ }
+#endif
+ this_dir->dir_flags |= DIR_WAS_SCANNED;
+
+ errno = 0; /* Paranoia */
+ current_dir = opendir(path);
+ d_entry = NULL;
+
+ /*
+ * Apparently NFS sometimes allows you to open the directory, but then
+ * refuses to allow you to read the contents. Allow for this
+ */
+ if (current_dir) {
+ errno = 0;
+ d_entry = readdir(current_dir);
+ }
+
+ if (!current_dir || (!d_entry && errno != 0)) {
+ int ret = 1;
+
+ errmsg(_("Unable to open directory %s\n"), path);
+
+ if (errno == ENOTDIR) {
+ /*
+ * Mark as not a directory
+ */
+ de->isorec.flags[0] &= ~ISO_DIRECTORY;
+ ret = 0;
+ }
+ if (current_dir)
+ closedir(current_dir);
+ return (ret);
+ }
+
+ /*
+ * Set up the struct for the current directory, and insert it into
+ * the tree
+ */
+#ifdef VMS
+ vms_path_fixup(path);
+#endif
+
+ /*
+ * if entry for this sub-directory is hidden, then hide this directory
+ */
+ if (de->de_flags & INHIBIT_ISO9660_ENTRY)
+ this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
+
+ if (de->de_flags & INHIBIT_JOLIET_ENTRY)
+ this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
+
+#ifdef SORTING
+ /*
+ * set any sort weighting from it's own directory entry - if a
+ * directory is given a weighting, then all the contents will use
+ * this as the default weighting
+ */
+ this_dir->sort = de->sort;
+#endif /* SORTING */
+
+ /*
+ * Now we scan the directory itself, and look at what is inside of it.
+ */
+ whole_path[0] = '\0';
+ dflag = -2;
+ while (1 == 1) {
+ char *d_name;
+
+ if (dflag < 0) {
+ /*
+ * Some filesystems do not deliver "." and ".." at all,
+ * others (on Linux) deliver them in the wrong order.
+ * Make sure we add "." and ".." before all other
+ * entries.
+ */
+ if (dflag < -1)
+ d_name = ".";
+ else
+ d_name = "..";
+ dflag++;
+ } else {
+ /*
+ * The first time through, skip this, since we already
+ * asked for the first entry when we opened the
+ * directory.
+ */
+ if (dflag > 0) {
+ d_entry = readdir(current_dir);
+ } else {
+ dflag++;
+ }
+ if (!d_entry)
+ break;
+ d_name = d_entry->d_name;
+ }
+
+ /*
+ * OK, got a valid entry
+ *
+ * If we do not want all files, then pitch the backups.
+ */
+ if (!all_files) {
+ if (strchr(d_name, '~') ||
+ strchr(d_name, '#') ||
+ rstr(d_name, ".bak")) {
+ if (verbose > 0) {
+ fprintf(stderr,
+ _("Ignoring file %s\n"),
+ d_name);
+ }
+ continue;
+ }
+ }
+#ifdef APPLE_HYB
+ if (apple_both) {
+ /*
+ * exclude certain HFS type files/directories for the
+ * time being
+ */
+ if (hfs_exclude(d_name))
+ continue;
+ }
+#endif /* APPLE_HYB */
+
+ if (strlen(path) + strlen(d_name) + 2 > sizeof (whole_path)) {
+ errmsgno(EX_BAD, _("Path name %s/%s too long.\n"),
+ path, d_name);
+ comerrno(EX_BAD, _("Overflow of stat buffer\n"));
+ };
+
+ /*
+ * Generate the complete ASCII path for this file
+ */
+ strlcpy(whole_path, path, sizeof (whole_path));
+#ifndef VMS
+ if (whole_path[strlen(whole_path) - 1] != '/')
+ strcat(whole_path, "/");
+#endif
+ strcat(whole_path, d_name);
+
+ /*
+ * Should we exclude this file ?
+ * Do no check "." and ".."
+ */
+ if (!(d_name[0] == '.' && (d_name[1] == '\0' ||
+ (d_name[1] == '.' && d_name[2] == '\0'))) &&
+ (matches(d_name) || matches(whole_path))) {
+ if (verbose > 1) {
+ fprintf(stderr,
+ _("Excluded by match: %s\n"), whole_path);
+ }
+ continue;
+ }
+ if (generate_tables &&
+ strcmp(d_name, trans_tbl) == 0) {
+ /*
+ * Ignore this entry. We are going to be generating
+ * new versions of these files, and we need to ignore
+ * any originals that we might have found.
+ */
+ if (verbose > 1) {
+ fprintf(stderr, _("Excluded: %s\n"), whole_path);
+ }
+ continue;
+ }
+ /*
+ * If we already have a '.' or a '..' entry, then don't insert
+ * new ones.
+ */
+ if (strcmp(d_name, ".") == 0 &&
+ this_dir->dir_flags & DIR_HAS_DOT) {
+ continue;
+ }
+ if (strcmp(d_name, "..") == 0 &&
+ this_dir->dir_flags & DIR_HAS_DOTDOT) {
+ continue;
+ }
+#if 0
+ if (verbose > 1)
+ fprintf(stderr, "%s\n", whole_path);
+#endif
+ /*
+ * This actually adds the entry to the directory in question.
+ */
+ insert_file_entry(this_dir, whole_path, d_name, NULL, 0);
+ }
+ closedir(current_dir);
+
+#ifdef APPLE_HYB
+ /*
+ * if we cached the HFS info stuff for this directory, then delete it
+ */
+ if (this_dir->hfs_info) {
+ del_hfs_info(this_dir->hfs_info);
+ this_dir->hfs_info = 0;
+ }
+#endif /* APPLE_HYB */
+
+ return (1);
+}
+
+LOCAL struct directory_entry *
+dup_relocated_dir(this_dir, s_entry, whole_path, short_name, statp)
+ struct directory *this_dir;
+ struct directory_entry *s_entry;
+ char *whole_path;
+ char *short_name;
+ struct stat *statp;
+{
+ struct directory_entry *s_entry1;
+
+ if (!reloc_dir)
+ generate_reloc_directory();
+ init_fstatbuf();
+
+ /*
+ * Replicate the entry for this directory. The old one will
+ * stay where it is, and it will be neutered so that it no
+ * longer looks like a directory. The new one will look like
+ * a directory, and it will be put in the reloc_dir.
+ */
+ s_entry1 = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
+ s_entry1->table = NULL;
+ s_entry1->name = e_strdup(short_name);
+ s_entry1->whole_name = e_strdup(whole_path);
+ s_entry1->next = reloc_dir->contents;
+ reloc_dir->contents = s_entry1;
+ s_entry1->priority = 32768;
+ s_entry1->parent_rec = this_dir->contents;
+ set_723(s_entry1->isorec.volume_sequence_number,
+ volume_sequence_number);
+ s_entry1->filedir = this_dir;
+ iso9660_date(s_entry1->isorec.date, fstatbuf.st_mtime);
+
+ if (use_XA || use_RockRidge) {
+ generate_xa_rr_attributes(whole_path,
+ short_name, s_entry1,
+ statp, statp, NEED_RE);
+ }
+
+ statp->st_size = (off_t)0;
+ statp->st_mode &= 0777;
+ set_733((char *)s_entry->isorec.size, 0);
+ s_entry->size = 0;
+ s_entry->isorec.flags[0] = ISO_FILE;
+ s_entry->inode = UNCACHED_INODE;
+ s_entry->dev = UNCACHED_DEVICE;
+ s_entry->de_flags |= RELOCATED_DIRECTORY;
+
+ return (s_entry1);
+}
+
+
+/*
+ * Function: insert_file_entry
+ *
+ * Purpose: Insert one entry into our directory node.
+ *
+ * Note:
+ * This function inserts a single entry into the directory. It
+ * is assumed that all filtering and decision making regarding what
+ * we want to include has already been made, so the purpose of this
+ * is to insert one entry (file, link, dir, etc), into this directory.
+ * Note that if the entry is a dir (or if we are following links,
+ * and the thing it points to is a dir), then we will scan those
+ * trees before we return.
+ */
+EXPORT int
+insert_file_entry(this_dir, whole_path, short_name, statp, have_rsrc)
+ struct directory *this_dir;
+ char *whole_path;
+ char *short_name;
+ struct stat *statp;
+ int have_rsrc;
+{
+ struct stat statbuf,
+ lstatbuf;
+ struct directory_entry *s_entry,
+ *s_entry1;
+ int lstatus;
+ int status;
+ int deep_flag;
+#ifdef USE_NO_SCANDIR
+ int no_scandir = 0;
+#endif
+
+#ifdef APPLE_HYB
+ int x_hfs = 0;
+ int htype = TYPE_NONE;
+
+#endif /* APPLE_HYB */
+
+ if (statp) {
+ status = lstatus = 0;
+ lstatbuf = *statp;
+ if (S_ISLNK(lstatbuf.st_mode)) {
+ status = stat_filter(short_name, &statbuf);
+ } else {
+ statbuf = *statp;
+ }
+ } else {
+ status = stat_filter(whole_path, &statbuf);
+
+ lstatus = lstat_filter(whole_path, &lstatbuf);
+ }
+
+ if ((status == -1) && (lstatus == -1)) {
+ /*
+ * This means that the file doesn't exist, or isn't accessible.
+ * Sometimes this is because of NFS permissions problems.
+ */
+ errmsg(_("Non-existent or inaccessible: %s\n"), whole_path);
+ return (0);
+ }
+ if (S_ISDIR(statbuf.st_mode) &&
+ (this_dir->depth > RR_relocation_depth) && !use_RockRidge &&
+ strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0) {
+ dir_nesting_warn(this_dir, whole_path, TRUE);
+ return (0);
+ }
+ if (this_dir == root && strcmp(short_name, ".") == 0)
+ root_statbuf = statbuf; /* Save this for later on */
+
+ /*
+ * We do this to make sure that the root entries are consistent
+ */
+ if (this_dir == root && strcmp(short_name, "..") == 0) {
+ statbuf = root_statbuf;
+ lstatbuf = root_statbuf;
+ }
+ if (S_ISLNK(lstatbuf.st_mode)) {
+ /*
+ * Here we decide how to handle the symbolic links. Here we
+ * handle the general case - if we are not following links or
+ * there is an error, then we must change something. If RR
+ * is in use, it is easy, we let RR describe the file. If
+ * not, then we punt the file.
+ */
+ if ((status || !follow_links)) {
+#ifdef UDF
+ if (use_RockRidge || use_udf) {
+#else
+ if (use_RockRidge) {
+#endif
+ status = 0;
+ STAT_INODE(statbuf) = UNCACHED_INODE;
+ statbuf.st_dev = UNCACHED_DEVICE;
+#ifdef UDF
+ if (create_udfsymlinks) {
+ char symlinkcontents[2048];
+ off_t size = sizeof (symlinkcontents);
+
+ if (udf_get_symlinkcontents(whole_path,
+ symlinkcontents, &size) == -1) {
+ statbuf.st_size = (off_t)0;
+ statbuf.st_mode =
+ (statbuf.st_mode & ~S_IFMT) | S_IFREG;
+ } else {
+ statbuf.st_size = size;
+ statbuf.st_mode = lstatbuf.st_mode;
+ }
+ } else {
+#endif
+ statbuf.st_size = (off_t)0;
+ statbuf.st_mode =
+ (statbuf.st_mode & ~S_IFMT) | S_IFREG;
+#ifdef UDF
+ }
+#endif
+ } else {
+ if (follow_links) {
+ /* XXX errno may be wrong! */
+ errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
+ whole_path);
+ } else {
+ errmsgno(EX_BAD,
+ _("Symlink %s ignored - continuing.\n"),
+ whole_path);
+ return (0); /* Non Rock Ridge discs */
+ /* - ignore all symlinks */
+ }
+ }
+ }
+ /*
+ * Here we handle a different kind of case. Here we have a
+ * symlink, but we want to follow symlinks. If we run across
+ * a directory loop, then we need to pretend that we are not
+ * following symlinks for this file. If this is the first
+ * time we have seen this, then make this seem as if there was
+ * no symlink there in the first place
+ */
+ if (follow_links &&
+ S_ISDIR(statbuf.st_mode)) {
+ if (strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (find_directory_hash(statbuf.st_dev,
+ STAT_INODE(statbuf))) {
+ if (!use_RockRidge) {
+ fprintf(stderr,
+ _("Already cached directory seen (%s)\n"),
+ whole_path);
+ return (0);
+ }
+ lstatbuf = statbuf;
+ /*
+ * XXX when this line was active,
+ * XXX mkisofs did not include all
+ * XXX files if it was called with '-f'
+ * XXX (follow symlinks).
+ * XXX Now scan_directory_tree()
+ * XXX checks if the directory has
+ * XXX already been scanned via the
+ * XXX DIR_WAS_SCANNED flag.
+ */
+/* no_scandir = 1;*/
+ } else {
+ lstatbuf = statbuf;
+ add_directory_hash(statbuf.st_dev,
+ STAT_INODE(statbuf));
+ }
+ }
+ }
+ /*
+ * For non-directories, we just copy the stat information over
+ * so we correctly include this file.
+ */
+ if (follow_links &&
+ !S_ISDIR(statbuf.st_mode)) {
+ lstatbuf = statbuf;
+ }
+ }
+ /*
+ * Add directories to the cache so that we don't waste space even if
+ * we are supposed to be following symlinks.
+ */
+ if (follow_links &&
+ strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0 &&
+ S_ISDIR(statbuf.st_mode)) {
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+ }
+#ifdef VMS
+ if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
+ statbuf.st_fab_rfm != FAB$C_STMLF)) {
+ fprintf(stderr,
+ _("Warning - file %s has an unsupported VMS record format (%d)\n"),
+ whole_path, statbuf.st_fab_rfm);
+ }
+#endif
+
+ if (S_ISREG(lstatbuf.st_mode) &&
+ ((statp != NULL && (status = access(short_name, R_OK))) ||
+ (statp == NULL && (status = access(whole_path, R_OK))))) {
+ errmsg(_("File %s is not readable - ignoring\n"),
+ whole_path);
+ return (0);
+ }
+#ifdef USE_LARGEFILES
+ if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= maxnonlarge) &&
+ !do_largefiles) {
+#else
+ /*
+ * >= is required by the large file summit standard.
+ */
+ if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0x7FFFFFFF)) {
+#endif
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#else
+ errno = EFBIG;
+#endif
+ errmsg(_("File %s is too large for current mkisofs settings (-iso-level 3 or more required) - ignoring\n"),
+ whole_path);
+ return (0);
+ }
+ /*
+ * Add this so that we can detect directory loops with hard links.
+ * If we are set up to follow symlinks, then we skip this checking.
+ */
+ if (!follow_links &&
+ S_ISDIR(lstatbuf.st_mode) &&
+ strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
+/* comerrno(EX_BAD,*/
+/* _("Directory loop - fatal goof (%s %lx %lu).\n"),*/
+ errmsgno(EX_BAD,
+ _("Warning: Directory loop (%s dev: %lx ino: %lu).\n"),
+ whole_path, (unsigned long) statbuf.st_dev,
+ (unsigned long) STAT_INODE(statbuf));
+ }
+ add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+ }
+ if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
+ !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) &&
+ !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
+ !S_ISDIR(lstatbuf.st_mode)) {
+ fprintf(stderr,
+ _("Unknown file type (%s) %s - ignoring and continuing.\n"),
+ filetype((int)lstatbuf.st_mode), whole_path);
+ return (0);
+ }
+ /*
+ * Who knows what trash this is - ignore and continue
+ */
+ if (status) {
+ errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
+ whole_path);
+ return (0);
+ }
+
+#if !defined(__MINGW32__) && !defined(_MSC_VER)
+#define is_archive(st) ((st).st_dev == archive_dev && (st).st_ino == archive_ino)
+ if (archive_isreg && is_archive(statbuf)) {
+ errmsgno(EX_BAD,
+ _("'%s' is the archive. Not dumped.\n"), whole_path);
+ return (0);
+ }
+#endif
+
+ /*
+ * Check to see if we have already seen this directory node. If so,
+ * then we don't create a new entry for it, but we do want to recurse
+ * beneath it and add any new files we do find.
+ */
+ if (S_ISDIR(statbuf.st_mode)) {
+ int dflag;
+
+ for (s_entry = this_dir->contents; s_entry;
+ s_entry = s_entry->next) {
+ if (strcmp(s_entry->name, short_name) == 0) {
+ break;
+ }
+ }
+ if (s_entry != NULL &&
+ strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ struct directory *child;
+
+ /*
+ * This should not create a new directory
+ */
+ if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
+ for (s_entry = reloc_dir->contents; s_entry;
+ s_entry = s_entry->next) {
+ if (strcmp(s_entry->name, short_name)
+ == 0) {
+ break;
+ }
+ }
+ child = find_or_create_directory(reloc_dir,
+ whole_path,
+ s_entry, 1);
+ } else {
+ child = find_or_create_directory(this_dir,
+ whole_path,
+ s_entry, 1);
+ /*
+ * If unable to scan directory, mark this as a
+ * non-directory
+ */
+ }
+/* if (no_scandir)*/
+ if (0)
+ dflag = 1;
+ else
+ dflag = scan_directory_tree(child,
+ whole_path, s_entry);
+ if (!dflag) {
+ lstatbuf.st_mode =
+ (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+ }
+ return (0);
+ }
+ }
+#ifdef APPLE_HYB
+ /*
+ * Should we exclude this HFS file ? - only works with -hfs
+ */
+ if (!have_rsrc && apple_hyb && strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if ((x_hfs = (hfs_matches(short_name) ||
+ hfs_matches(whole_path))) == 1) {
+ if (verbose > 1) {
+ fprintf(stderr, _("Hidden from HFS tree: %s\n"),
+ whole_path);
+ }
+ }
+ }
+ /*
+ * check we are a file, using Apple extensions and have a .resource
+ * part and not excluded
+ */
+ if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
+ char rsrc_path[PATH_MAX]; /* rsrc fork filename */
+
+ /*
+ * Construct the resource full path
+ */
+ htype = get_hfs_rname(whole_path, short_name, rsrc_path);
+ /*
+ * Check we can read the resouce fork
+ */
+ if (htype) {
+ struct stat rstatbuf,
+ rlstatbuf;
+
+ /*
+ * Some further checks on the file
+ */
+ status = stat_filter(rsrc_path, &rstatbuf);
+
+ lstatus = lstat_filter(rsrc_path, &rlstatbuf);
+
+/* if (!status && !lstatus && S_ISREG(rlstatbuf.st_mode)*/
+/* && rlstatbuf.st_size > (off_t)0) { */
+ if (!status && !lstatus && S_ISREG(rstatbuf.st_mode) &&
+ rstatbuf.st_size > (off_t)0) {
+
+ /*
+ * have a resource file - insert it into the
+ * current directory but flag that we have a
+ * resource fork
+ */
+ insert_file_entry(this_dir, rsrc_path,
+ short_name, NULL, htype);
+ }
+ }
+ }
+#endif /* APPLE_HYB */
+
+ s_entry = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ /* memset the whole struct, not just the isorec.extent part JCP */
+ memset(s_entry, 0, sizeof (struct directory_entry));
+ s_entry->next = this_dir->contents;
+/* memset(s_entry->isorec.extent, 0, 8); */
+ this_dir->contents = s_entry;
+ deep_flag = 0;
+ s_entry->table = NULL;
+
+ s_entry->name = e_strdup(short_name);
+ s_entry->whole_name = e_strdup(whole_path);
+
+ s_entry->de_flags = 0;
+ if (S_ISLNK(lstatbuf.st_mode))
+ s_entry->de_flags |= IS_SYMLINK;
+#ifdef DUPLICATES_ONCE
+ s_entry->digest_fast = NULL;
+ s_entry->digest_full = NULL;
+#endif
+
+ /*
+ * If the current directory is hidden, then hide all it's members
+ * otherwise check if this entry needs to be hidden as well
+ */
+ if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
+ s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
+ } else if (strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (i_matches(short_name) || i_matches(whole_path)) {
+ if (verbose > 1) {
+ fprintf(stderr,
+ _("Hidden from ISO9660 tree: %s\n"),
+ whole_path);
+ }
+ s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
+ }
+ if (h_matches(short_name) || h_matches(whole_path)) {
+ if (verbose > 1) {
+ fprintf(stderr,
+ _("Hidden ISO9660 attribute: %s\n"),
+ whole_path);
+ }
+ s_entry->de_flags |= HIDDEN_FILE;
+ }
+ }
+ if (this_dir != reloc_dir &&
+ this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
+ s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+ } else if (strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (j_matches(short_name) || j_matches(whole_path)) {
+ if (verbose > 1) {
+ fprintf(stderr,
+ _("Hidden from Joliet tree: %s\n"),
+ whole_path);
+ }
+ s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+ }
+ }
+ if (this_dir != reloc_dir &&
+ this_dir->dir_flags & INHIBIT_UDF_ENTRY) {
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+ } else if (strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (u_matches(short_name) || u_matches(whole_path)) {
+ if (verbose > 1) {
+ fprintf(stderr,
+ _("Hidden from UDF tree: %s\n"),
+ whole_path);
+ }
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+ }
+ }
+
+#ifdef SORTING
+ /*
+ * Inherit any sort weight from parent directory
+ */
+ s_entry->sort = this_dir->sort;
+
+#ifdef DVD_AUD_VID
+ /*
+ * No use at all to do a sort if we don't make a dvd video/audio
+ */
+ /*
+ * Assign special weights to VIDEO_TS and AUDIO_TS files.
+ * This can't be done with sort_matches for two reasons:
+ * first, we need to match against the destination (DVD)
+ * path rather than the source path, and second, there are
+ * about 2400 different file names to check, each needing
+ * a different priority, and adding that many patterns to
+ * sort_matches would slow things to a crawl.
+ */
+
+ if (dvd_aud_vid_flag) {
+ s_entry->sort = assign_dvd_weights(s_entry->name, this_dir, s_entry->sort);
+ /*
+ * Turn on sorting if necessary, regardless of cmd-line options
+ */
+ if ((s_entry->sort != this_dir->sort) && do_sort == 0)
+ do_sort++;
+ }
+#endif
+
+ /*
+ * See if this entry should have a new weighting
+ */
+ if (do_sort && strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ s_entry->sort = sort_matches(whole_path, s_entry->sort);
+ }
+#endif /* SORTING */
+
+ s_entry->filedir = this_dir;
+ s_entry->isorec.flags[0] = ISO_FILE;
+ if (s_entry->de_flags & HIDDEN_FILE)
+ s_entry->isorec.flags[0] |= ISO_EXISTENCE;
+ s_entry->isorec.ext_attr_length[0] = 0;
+ iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
+ s_entry->isorec.file_unit_size[0] = 0;
+ s_entry->isorec.interleave[0] = 0;
+
+#ifdef APPLE_HYB
+ if (apple_both && !x_hfs) {
+ s_entry->hfs_ent = NULL;
+ s_entry->assoc = NULL;
+ s_entry->hfs_off = (off_t)0;
+ s_entry->hfs_type = htype;
+ if (have_rsrc) {
+ /* associated (rsrc) file */
+ s_entry->isorec.flags[0] |= ISO_ASSOCIATED;
+ /* set the type of HFS file */
+ s_entry->hfs_type = have_rsrc;
+ /*
+ * don't want the rsrc file to be included in any
+ * Joliet/UDF tree
+ */
+ s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+ } else if (s_entry->next) {
+ /*
+ * if previous entry is an associated file,
+ * then "link" it to this file i.e. we have a
+ * data/resource pair
+ */
+ if (s_entry->next->isorec.flags[0] & ISO_ASSOCIATED) {
+ s_entry->assoc = s_entry->next;
+ /*
+ * share the same HFS parameters
+ */
+ s_entry->hfs_ent = s_entry->next->hfs_ent;
+ s_entry->hfs_type = s_entry->next->hfs_type;
+ }
+ }
+ /*
+ * Allocate HFS entry if required
+ */
+ if (apple_both && strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ if (!s_entry->hfs_ent) {
+ hfsdirent *hfs_ent;
+
+ hfs_ent =
+ (hfsdirent *) e_malloc(sizeof (hfsdirent));
+
+ /*
+ * Sill in the defaults
+ */
+ memset(hfs_ent, 0, sizeof (hfsdirent));
+
+ s_entry->hfs_ent = hfs_ent;
+ }
+ /*
+ * the resource fork is processed first, but the
+ * data fork's time info is used in preference
+ * i.e. time info is set from the resource fork
+ * initially, then it is set from the data fork
+ */
+ if (have_rsrc) {
+ /*
+ * Set rsrc size
+ */
+ s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
+ /*
+ * This will be overwritten - but might as
+ * well set it here ...
+ */
+ s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
+ s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
+ } else {
+ /*
+ * Set data size
+ */
+ s_entry->hfs_ent->u.file.dsize = lstatbuf.st_size;
+ s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
+ s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
+ }
+ }
+ }
+#endif /* APPLE_HYB */
+
+ if (strcmp(short_name, ".") == 0) {
+ this_dir->dir_flags |= DIR_HAS_DOT;
+ }
+ if (strcmp(short_name, "..") == 0) {
+ this_dir->dir_flags |= DIR_HAS_DOTDOT;
+ }
+ if (this_dir->parent &&
+ this_dir->parent == reloc_dir &&
+ strcmp(short_name, "..") == 0) {
+ s_entry->inode = UNCACHED_INODE;
+ s_entry->dev = UNCACHED_DEVICE;
+ deep_flag = NEED_PL;
+ } else
+#ifdef APPLE_HYB
+ if (have_rsrc) {
+ /*
+ * don't want rsrc files to be cached
+ */
+ s_entry->de_flags |= RESOURCE_FORK;
+ s_entry->inode = UNCACHED_INODE;
+ s_entry->dev = UNCACHED_DEVICE;
+ } else
+#endif /* APPLE_HYB */
+ {
+ s_entry->inode = STAT_INODE(statbuf);
+ s_entry->dev = statbuf.st_dev;
+ }
+ set_723(s_entry->isorec.volume_sequence_number,
+ volume_sequence_number);
+ iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
+ s_entry->rr_attr_size = 0;
+ s_entry->total_rr_attr_size = 0;
+ s_entry->rr_attributes = NULL;
+
+ /*
+ * Directories are assigned sizes later on
+ */
+ if (!S_ISDIR(statbuf.st_mode)) {
+ if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
+ S_ISFIFO(lstatbuf.st_mode) ||
+ S_ISSOCK(lstatbuf.st_mode) ||
+#ifdef UDF
+ (S_ISLNK(lstatbuf.st_mode) && !create_udfsymlinks)) {
+#else
+ FALSE) {
+#endif
+ s_entry->size = (off_t)0;
+ statbuf.st_size = (off_t)0;
+ } else {
+ s_entry->size = statbuf.st_size;
+ }
+
+ set_733((char *)s_entry->isorec.size, statbuf.st_size);
+ } else {
+ s_entry->isorec.flags[0] |= ISO_DIRECTORY;
+ }
+#ifdef APPLE_HYB
+ /*
+ * If the directory is HFS excluded, then we don't have an hfs_ent
+ */
+ if (apple_both && s_entry->hfs_ent &&
+ (s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
+ /*
+ * Get the Mac directory name
+ */
+ get_hfs_dir(whole_path, short_name, s_entry);
+
+ /*
+ * If required, set ISO directory name from HFS name
+ */
+ if (use_mac_name)
+ iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
+ }
+#endif /* APPLE_HYB */
+
+ if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0 &&
+ S_ISDIR(statbuf.st_mode) &&
+ this_dir->depth > RR_relocation_depth) {
+ struct directory *child;
+
+ /*
+ * Replicate the entry for this directory. The old one will
+ * stay where it is, and it will be neutered so that it no
+ * longer looks like a directory. The new one will look like
+ * a directory, and it will be put in the reloc_dir.
+ */
+ s_entry1 = dup_relocated_dir(this_dir, s_entry,
+ whole_path, short_name, &statbuf);
+
+ /*
+ * We need to set this temporarily so that the parent to this
+ * is correctly determined.
+ */
+ s_entry1->filedir = reloc_dir;
+ child = find_or_create_directory(reloc_dir, whole_path,
+ s_entry1, 0);
+ free(child->de_path); /* allocated in this case */
+ set_de_path(this_dir, child);
+
+
+/* if (!no_scandir)*/
+ if (!0)
+ scan_directory_tree(child, whole_path, s_entry1);
+ s_entry1->filedir = this_dir;
+ deep_flag = NEED_CL;
+ }
+ if (generate_tables &&
+ strcmp(s_entry->name, ".") != 0 &&
+ strcmp(s_entry->name, "..") != 0) {
+
+ char buffer[SECTOR_SIZE];
+ int nchar;
+
+ switch (lstatbuf.st_mode & S_IFMT) {
+ case S_IFDIR:
+ sprintf(buffer, "D\t%s\n",
+ s_entry->name);
+ break;
+
+/*
+ * extra for WIN32 - if it doesn't have the major/minor defined, then
+ * S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
+ * code similar to that in rock.c
+ */
+#if 0
+/*
+ * Use the device handling code from <schily/device.h>
+ */
+#ifndef major
+#define major(dev) (sizeof (dev_t) <= 2 ? ((dev) >> 8) : \
+ (sizeof (dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
+ (((dev) >> 16) >> 16)))
+#define minor(dev) (sizeof (dev_t) <= 2 ? (dev) & 0xff : \
+ (sizeof (dev_t) <= 4 ? (dev) & 0xffff : \
+ (dev) & 0xffffffff))
+#endif
+#endif
+
+#ifdef S_IFBLK
+ case S_IFBLK:
+ sprintf(buffer, "B\t%s\t%lu %lu\n",
+ s_entry->name,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ break;
+#endif
+#ifdef S_IFIFO
+ case S_IFIFO:
+ sprintf(buffer, "P\t%s\n",
+ s_entry->name);
+ break;
+#endif
+#ifdef S_IFCHR
+ case S_IFCHR:
+ sprintf(buffer, "C\t%s\t%lu %lu\n",
+ s_entry->name,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ break;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+#ifdef HAVE_READLINK
+ nchar = readlink(statp?short_name:whole_path,
+ (char *)symlink_buff,
+ sizeof (symlink_buff)-1);
+ if (nchar < 0) {
+ errmsg(_("Cannot read link '%s'.\n"),
+ statp?short_name:whole_path);
+ }
+#else
+ nchar = -1;
+#endif
+ symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+ sprintf(buffer, "L\t%s\t%s\n",
+ s_entry->name, symlink_buff);
+ break;
+#endif
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ sprintf(buffer, "S\t%s\n",
+ s_entry->name);
+ break;
+#endif
+ case S_IFREG:
+ default:
+ sprintf(buffer, "F\t%s\n",
+ s_entry->name);
+ break;
+ };
+ s_entry->table = e_strdup(buffer);
+ }
+ if (S_ISDIR(statbuf.st_mode)) {
+ int dflag;
+
+ if (strcmp(short_name, ".") != 0 &&
+ strcmp(short_name, "..") != 0) {
+ struct directory *child;
+
+ child = find_or_create_directory(this_dir, whole_path,
+ s_entry, 1);
+#ifdef USE_NO_SCANDIR
+ if (no_scandir)
+ dflag = 1;
+ else
+#endif
+ dflag = scan_directory_tree(child, whole_path,
+ s_entry);
+
+ if (!dflag) {
+ lstatbuf.st_mode =
+ (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+ if (child->contents == NULL) {
+ delete_directory(this_dir, child);
+ }
+ }
+ }
+ /* If unable to scan directory, mark this as a non-directory */
+ }
+ if (use_RockRidge && this_dir == root &&
+ strcmp(s_entry->name, ".") == 0) {
+ deep_flag |= NEED_CE | NEED_SP; /* For extension record */
+ }
+ /*
+ * Now figure out how much room this file will take in the directory
+ */
+
+#ifdef APPLE_HYB
+ /*
+ * Ff the file is HFS excluded, then we don't have an hfs_ent
+ */
+ if (apple_both && !have_rsrc && s_entry->hfs_ent) {
+ if (S_ISREG(lstatbuf.st_mode)) { /* it's a regular file */
+
+ /*
+ * Fill in the rest of the HFS entry
+ */
+ get_hfs_info(whole_path, short_name, s_entry);
+
+ /*
+ * If required, set ISO directory name from HFS name
+ */
+ if (use_mac_name)
+ iso9660_file_length(s_entry->hfs_ent->name,
+ s_entry, 0);
+
+ /*
+ * Print details about the HFS file
+ */
+ if (verbose > 2)
+ print_hfs_info(s_entry);
+
+ /*
+ * copy the new ISO9660 name to the rsrc fork
+ * - if it exists
+ */
+ if (s_entry->assoc)
+ strcpy(s_entry->assoc->isorec.name,
+ s_entry->isorec.name);
+
+ /*
+ * we can't handle hard links in the hybrid case, so we
+ * "uncache" the file. The downside to this is that
+ * hard linked files are added to the output image
+ * more than once (we've already done this for rsrc
+ * files)
+ */
+ if (apple_hyb && have_rsrc) {
+ s_entry->de_flags |= RESOURCE_FORK;
+ s_entry->inode = UNCACHED_INODE;
+ s_entry->dev = UNCACHED_DEVICE;
+ }
+ } else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
+ /* not a directory .. */
+
+ /*
+ * no mac equivalent, so ignore - have to be careful
+ * here, the hfs_ent may be also be for a relocated
+ * directory
+ */
+ if (s_entry->hfs_ent &&
+ !(s_entry->de_flags & RELOCATED_DIRECTORY) &&
+ (s_entry->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
+ free(s_entry->hfs_ent);
+ }
+ s_entry->hfs_ent = NULL;
+ }
+ /*
+ * if the rsrc size is zero, then we don't need the entry, so
+ * we might as well delete it - this will only happen if we
+ * didn't know the rsrc size from the rsrc file size
+ */
+ if (s_entry->assoc && s_entry->assoc->size == 0)
+ delete_rsrc_ent(s_entry);
+ }
+ if (apple_ext && s_entry->assoc) {
+ /*
+ * Need Apple extensions for the resource fork as well
+ */
+ generate_xa_rr_attributes(whole_path,
+ short_name, s_entry->assoc,
+ &statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
+ }
+ /* leave out resource fork for the time being */
+ /*
+ * XXX This is most likely wrong and should just be:
+ * XXX if (use_XA || use_RockRidge) {
+ */
+/* if ((use_XA || use_RockRidge) && !have_rsrc) {*/
+ if (use_XA || use_RockRidge) {
+#else
+ if (use_XA || use_RockRidge) {
+#endif /* APPLE_HYB */
+ generate_xa_rr_attributes(whole_path,
+ short_name, s_entry,
+ &statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
+
+ }
+#ifdef UDF
+ /* set some info used for udf */
+ s_entry->mode = lstatbuf.st_mode;
+ s_entry->rdev = lstatbuf.st_rdev;
+ s_entry->uid = lstatbuf.st_uid;
+ s_entry->gid = lstatbuf.st_gid;
+ s_entry->atime.tv_sec = lstatbuf.st_atime;
+ s_entry->atime.tv_nsec = stat_ansecs(&lstatbuf);
+ s_entry->mtime.tv_sec = lstatbuf.st_mtime;
+ s_entry->mtime.tv_nsec = stat_mnsecs(&lstatbuf);
+ s_entry->ctime.tv_sec = lstatbuf.st_ctime;
+ s_entry->ctime.tv_nsec = stat_cnsecs(&lstatbuf);
+#endif
+
+#ifdef USE_LARGEFILES
+#ifndef MAX_EXTENT
+ /*
+ * Allow to #define MAX_EXTENT from outside for debug purposes.
+ */
+#ifdef PROTOTYPES
+#define LARGE_EXTENT ((off_t)0xFFFFF800UL)
+#define MAX_EXTENT ((off_t)0xFFFFFFFEUL)
+#else
+#define LARGE_EXTENT ((off_t)0xFFFFF800L)
+#define MAX_EXTENT ((off_t)0xFFFFFFFEL)
+#endif
+#else /* MAX_EXTENT */
+#define LARGE_EXTENT MAX_EXTENT & ~(off_t)2047L
+#endif /* !MAX_EXTENT */
+ /*
+ * Break up files greater than (4GB -2) into multiple extents.
+ * The original entry, with ->size untouched, remains for UDF.
+ * Each of the new file sections will get its own entry.
+ * The file sections are the only entries actually written out to the
+ * disk. The UDF entry will use "mxroot" to get the same start
+ * block as the first file section, and all the sections will end up
+ * in the ISO9660 directory in the correct order by "mxpart",
+ * which the directory sorting routine knows about.
+ *
+ * If we ever need to be able to find mxpart == 1 after sorting,
+ * we need to add another pointer to s_entry or to be very careful
+ * with the loops above where the ISO-9660 name is copied back to
+ * all multi-extent parts.
+ */
+ if (s_entry->size > MAX_EXTENT) {
+ off_t size;
+
+ s_entry->de_flags |= MULTI_EXTENT;
+ s_entry->isorec.flags[0] |= ISO_MULTIEXTENT;
+ s_entry->mxroot = s_entry;
+ s_entry->mxpart = 0;
+ set_733((char *)s_entry->isorec.size, LARGE_EXTENT);
+ s_entry1 = dup_directory_entry(s_entry);
+ s_entry->next = s_entry1;
+
+ /*
+ * full size UDF version
+ */
+ s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
+ if (s_entry->size > (((off_t)190)*0x3FFFF800)) {
+#ifndef EOVERFLOW
+#define EOVERFLOW EFBIG
+#endif
+ errmsgno(EOVERFLOW,
+ _("File %s is too large - hiding from UDF tree.\n"),
+ whole_path);
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+ }
+
+ /*
+ * Prepare the first file multi-extent section of the file.
+ */
+ s_entry = s_entry1;
+ s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+ size = s_entry->size;
+ s_entry->size = LARGE_EXTENT;
+ s_entry->mxpart++;
+
+ /*
+ * Additional extents, as needed
+ */
+ while (size > MAX_EXTENT) {
+ s_entry1 = dup_directory_entry(s_entry);
+ s_entry->next = s_entry1;
+
+ s_entry = s_entry1;
+ s_entry->mxpart++;
+ size -= LARGE_EXTENT;
+ }
+ /*
+ * That was the last one.
+ */
+ s_entry->isorec.flags[0] &= ~ISO_MULTIEXTENT;
+ s_entry->size = size;
+ set_733((char *)s_entry->isorec.size, (UInt32_t)s_entry->size);
+ }
+#endif /* USE_LARGEFILES */
+
+ return (1);
+}
+
+EXPORT struct directory_entry *
+dup_directory_entry(s_entry)
+ struct directory_entry *s_entry;
+{
+ struct directory_entry *s_entry1;
+
+ s_entry1 = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
+
+ if (s_entry->rr_attributes) {
+ s_entry1->rr_attributes =
+ e_malloc(s_entry->total_rr_attr_size);
+ memcpy(s_entry1->rr_attributes, s_entry->rr_attributes,
+ s_entry->total_rr_attr_size);
+ }
+ if (s_entry->name)
+ s_entry1->name = e_strdup(s_entry->name);
+ if (s_entry->whole_name)
+ s_entry1->whole_name = e_strdup(s_entry->whole_name);
+#ifdef APPLE_HYB
+ /*
+ * If we also duplicate s_entry->hfs_ent, we would need to change
+ * free_one_directory() and other calls to free(s_entry->hfs_ent) too.
+ */
+#endif
+ return (s_entry1);
+}
+
+EXPORT void
+generate_iso9660_directories(node, outfile)
+ struct directory *node;
+ FILE *outfile;
+{
+ struct directory *dpnt;
+
+ dpnt = node;
+
+ while (dpnt) {
+ if (dpnt->extent > session_start) {
+ generate_one_directory(dpnt, outfile);
+ }
+ if (dpnt->subdir)
+ generate_iso9660_directories(dpnt->subdir, outfile);
+ dpnt = dpnt->next;
+ }
+}
+
+/*
+ * XXX This may need some work for the MVS port.
+ */
+LOCAL void
+set_de_path(parent, this)
+ struct directory *parent;
+ struct directory *this;
+{
+ char *p;
+ size_t len;
+
+ if (parent == NULL) { /* We are just creating root */
+ this->de_path = this->whole_name;
+ return;
+ } else if (parent == root) { /* full path == component */
+ this->de_path = this->de_name;
+ return;
+ }
+ len = strlen(parent->de_path)+1+strlen(this->de_name)+1;
+ p = e_malloc(len);
+ js_snprintf(p, len, "%s/%s", parent->de_path, this->de_name);
+ this->de_path = p;
+}
+
+/*
+ * Function: find_or_create_directory
+ *
+ * Purpose: Locate a directory entry in the tree, create if needed.
+ *
+ * Arguments: parent & de are never NULL at the same time.
+ */
+EXPORT struct directory *
+find_or_create_directory(parent, path, de, flag)
+ struct directory *parent;
+ char *path;
+ struct directory_entry *de;
+ int flag;
+{
+ struct directory *child = 0;
+ struct directory *dpnt;
+ struct directory_entry *orig_de;
+ struct directory *next_brother;
+ const char *cpnt;
+ const char *pnt;
+ int deep_flag = 0;
+
+ orig_de = de;
+
+ /*
+ * XXX It seems that the tree that has been read from the
+ * XXX previous session does not carry whole_name entries.
+ * XXX We provide a hack in multi.c:find_or_create_directory()
+ * XXX that should be removed when a reasonable method could
+ * XXX be found.
+ */
+ if (path == NULL) {
+ error(_("Warning: missing whole name for: '%s'\n"), de->name);
+ path = de->name;
+ if (path == NULL)
+ comerrno(EX_BAD, _("Panic no node name.\n"));
+ }
+ pnt = strrchr(path, PATH_SEPARATOR);
+ if (pnt == NULL) {
+ pnt = path;
+ } else {
+ pnt++;
+ }
+
+ if (parent != NULL) {
+
+ dpnt = parent->subdir;
+ if (dpnt == NULL) {
+ struct directory_entry *s_entry;
+
+ for (s_entry = parent->contents; s_entry;
+ s_entry = s_entry->next) {
+ if ((strcmp(s_entry->name, pnt) == 0) &&
+ (s_entry->de_flags & RELOCATED_DIRECTORY)) {
+ return (find_or_create_directory(
+ reloc_dir, path, de,
+ flag));
+ }
+ }
+ }
+
+ while (dpnt) {
+ /*
+ * Weird hack time - if there are two directories by
+ * the same name in the reloc_dir, they are not
+ * treated as the same thing unless the entire path
+ * matches completely.
+ */
+ if (flag && strcmp(dpnt->de_name, pnt) == 0) {
+
+ /*
+ * XXX Remove test?
+ * XXX dpnt->de_path should always be != NULL
+ */
+ if (dpnt->de_path != NULL &&
+ strcmp(dpnt->de_path, path) == 0)
+ return (dpnt);
+
+ if (parent != reloc_dir &&
+ strcmp(dpnt->de_name, pnt) == 0)
+ return (dpnt);
+ }
+ dpnt = dpnt->next;
+ }
+ }
+ /*
+ * We don't know if we have a valid directory entry for this one yet.
+ * If not, we need to create one.
+ */
+ if (de == NULL) {
+ de = (struct directory_entry *)
+ e_malloc(sizeof (struct directory_entry));
+ memset(de, 0, sizeof (struct directory_entry));
+ de->next = parent->contents;
+ parent->contents = de;
+ de->name = e_strdup(pnt);
+ de->whole_name = e_strdup(path);
+ de->filedir = parent;
+ de->isorec.flags[0] = ISO_DIRECTORY;
+ de->priority = 32768;
+ de->inode = UNCACHED_INODE;
+ de->dev = UNCACHED_DEVICE;
+ set_723(de->isorec.volume_sequence_number,
+ volume_sequence_number);
+ iso9660_file_length(pnt, de, 1);
+
+ init_fstatbuf();
+#ifdef APPLE_HYB
+ if (apple_both) {
+ /*
+ * Give the directory an HFS entry
+ */
+ hfsdirent *hfs_ent;
+
+ hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
+
+ /*
+ * Fill in the defaults
+ */
+ memset(hfs_ent, 0, sizeof (hfsdirent));
+ hfs_ent->crdate = fstatbuf.st_ctime;
+ hfs_ent->mddate = fstatbuf.st_mtime;
+
+ de->hfs_ent = hfs_ent;
+
+ /*
+ * Get the Mac directory name
+ */
+ get_hfs_dir((char *)path, (char *)pnt, de);
+ }
+#endif /* APPLE_HYB */
+ }
+ /*
+ * If we don't have a directory for this one yet, then allocate it now,
+ * and patch it into the tree in the appropriate place.
+ */
+ dpnt = (struct directory *)e_malloc(sizeof (struct directory));
+ memset(dpnt, 0, sizeof (struct directory));
+ dpnt->next = NULL;
+ dpnt->subdir = NULL;
+ dpnt->self = de;
+ dpnt->contents = NULL;
+ dpnt->whole_name = e_strdup(path);
+ cpnt = strrchr(path, PATH_SEPARATOR);
+ if (cpnt)
+ cpnt++;
+ else
+ cpnt = path;
+ dpnt->de_name = e_strdup(cpnt);
+ dpnt->de_path = NULL;
+ set_de_path(parent, dpnt);
+ dpnt->size = 0;
+ dpnt->extent = 0;
+ dpnt->jextent = 0;
+ dpnt->jsize = 0;
+#ifdef APPLE_HYB
+ dpnt->hfs_ent = de->hfs_ent;
+#endif /* APPLE_HYB */
+
+ if (orig_de == NULL) {
+ struct stat xstatbuf;
+ int sts;
+
+ /*
+ * Now add a . and .. entry in the directory itself. This is a
+ * little tricky - if the real directory exists, we need to
+ * stat it first. Otherwise, we use the fictitious fstatbuf
+ * which points to the time at which mkisofs was started.
+ */
+ if (parent == NULL || parent->whole_name[0] == '\0')
+ sts = -1;
+ else
+ sts = stat_filter(parent->whole_name, &xstatbuf);
+ if (debug && parent) {
+ error(_("stat parent->whole_name: '%s' -> %d.\n"),
+ parent->whole_name, sts);
+ }
+ if (sts == 0) {
+ attach_dot_entries(dpnt, NULL, &xstatbuf);
+ } else {
+ attach_dot_entries(dpnt, NULL, NULL);
+ }
+ }
+ if (!parent || parent == root) {
+ if (!root) {
+ root = dpnt; /* First time through for root */
+ /* directory only */
+ root->depth = 0;
+ root->parent = root;
+ } else {
+ dpnt->depth = 1;
+ if (!root->subdir) {
+ root->subdir = dpnt;
+ } else {
+ next_brother = root->subdir;
+ while (next_brother->next)
+ next_brother = next_brother->next;
+ next_brother->next = dpnt;
+ }
+ dpnt->parent = parent;
+ }
+ } else {
+ struct directory_entry *s_entry1;
+
+ /*
+ * Come through here for normal traversal of tree
+ */
+#ifdef DEBUG
+ fprintf(stderr, "%s(%d) ", path, dpnt->depth);
+#endif
+
+ if (parent->depth > RR_relocation_depth && use_RockRidge) {
+ /*
+ * We come here in case that a graft-point needs to
+ * create a new relocated (deep) directory.
+ *
+ * Replicate the entry for this directory. The old one
+ * will stay where it is, and it will be neutered so
+ * that it no longer looks like a directory. The new
+ * one will look like a directory, and it will be put
+ * in the reloc_dir.
+ */
+ s_entry1 = dup_relocated_dir(parent, de, path,
+ dpnt->de_name, &fstatbuf);
+ child = find_or_create_directory(reloc_dir, path,
+ s_entry1, 0);
+ free(child->de_path); /* allocated in this case */
+ set_de_path(parent, child);
+
+ deep_flag |= NEED_CL;
+ }
+ if (parent->depth > RR_relocation_depth && !use_RockRidge) {
+ dir_nesting_warn(parent, path, FALSE);
+ exit(EX_BAD);
+ }
+ dpnt->parent = parent;
+ dpnt->depth = parent->depth + 1;
+
+ if ((deep_flag & NEED_CL) == 0) {
+ /*
+ * Do not add this directory to the list of subdirs if
+ * this is a relocated directory.
+ */
+ if (!parent->subdir) {
+ parent->subdir = dpnt;
+ } else {
+ next_brother = parent->subdir;
+ while (next_brother->next)
+ next_brother = next_brother->next;
+ next_brother->next = dpnt;
+ }
+ }
+ }
+ /*
+ * It doesn't exist for real, so we cannot add any
+ * XA or Rock Ridge attributes.
+ */
+ if (orig_de == NULL || (parent == NULL && path[0] == '\0')) {
+ init_fstatbuf();
+ fstatbuf.st_mode = new_dir_mode | S_IFDIR;
+ fstatbuf.st_nlink = 2;
+ if ((use_XA || use_RockRidge) &&
+ !(parent == NULL && path[0] == '\0')) {
+ /*
+ * We cannot set up RR attrubutes for the real
+ * ISO-9660 root directory. This is why we
+ * check for parent == NULL && path[0] == '\0'.
+ */
+ generate_xa_rr_attributes("",
+ (char *)pnt, de,
+ &fstatbuf,
+ &fstatbuf, deep_flag);
+ }
+#ifdef UDF
+ /* set some info used for udf */
+ de->mode = fstatbuf.st_mode;
+ de->uid = fstatbuf.st_uid;
+ de->gid = fstatbuf.st_gid;
+ de->atime.tv_sec = fstatbuf.st_atime;
+ de->atime.tv_nsec = stat_ansecs(&fstatbuf);
+ de->mtime.tv_sec = fstatbuf.st_mtime;
+ de->mtime.tv_nsec = stat_mnsecs(&fstatbuf);
+ de->ctime.tv_sec = fstatbuf.st_ctime;
+ de->ctime.tv_nsec = stat_cnsecs(&fstatbuf);
+#endif
+ iso9660_date(de->isorec.date, fstatbuf.st_mtime);
+ }
+ if (child)
+ return (child); /* Return reloaction target */
+
+ return (dpnt);
+}
+
+/*
+ * Function: delete_directory
+ *
+ * Purpose: Locate a directory entry in the tree, create if needed.
+ *
+ * Arguments:
+ */
+LOCAL void
+delete_directory(parent, child)
+ struct directory *parent;
+ struct directory *child;
+{
+ struct directory *tdir;
+
+ if (child == NULL)
+ return;
+ if (child->contents != NULL) {
+ comerrno(EX_BAD, _("Unable to delete non-empty directory\n"));
+ }
+ free(child->whole_name);
+ child->whole_name = NULL;
+
+ free(child->de_name);
+ child->de_name = NULL;
+
+#ifdef APPLE_HYB
+ if (apple_both && child->hfs_ent)
+ free(child->hfs_ent);
+#endif /* APPLE_HYB */
+
+ if (parent->subdir == child) {
+ parent->subdir = child->next;
+ } else {
+ for (tdir = parent->subdir; tdir != NULL && tdir->next != NULL;
+ tdir = tdir->next) {
+ if (tdir->next == child) {
+ tdir->next = child->next;
+ break;
+ }
+ }
+ if (tdir == NULL || tdir->next != child->next) {
+ comerrno(EX_BAD,
+ _("Unable to locate child directory in parent list\n"));
+ }
+ }
+ free(child);
+}
+
+EXPORT int
+sort_tree(node)
+ struct directory *node;
+{
+ struct directory *dpnt;
+ int ret = 0;
+
+ dpnt = node;
+
+ while (dpnt) {
+ ret = sort_n_finish(dpnt);
+ if (ret) {
+ break;
+ }
+ if (dpnt->subdir)
+ sort_tree(dpnt->subdir);
+ dpnt = dpnt->next;
+ }
+ return (ret);
+}
+
+EXPORT void
+dump_tree(node)
+ struct directory *node;
+{
+ struct directory *dpnt;
+
+ dpnt = node;
+
+ while (dpnt) {
+ fprintf(stderr, "%4d %5d %s\n",
+ dpnt->extent, dpnt->size, dpnt->de_name);
+ if (dpnt->subdir)
+ dump_tree(dpnt->subdir);
+ dpnt = dpnt->next;
+ }
+}
+
+/*
+ * something quick and dirty to locate a file given a path
+ * recursively walks down path in filename until it finds the
+ * directory entry for the desired file
+ */
+EXPORT struct directory_entry *
+search_tree_file(node, filename)
+ struct directory *node;
+ char *filename;
+{
+ struct directory_entry *depnt;
+ struct directory *dpnt;
+ char *p1;
+ char *rest;
+ char *subdir;
+
+ /*
+ * Strip off next directory name from filename:
+ */
+ subdir = e_strdup(filename);
+
+ if ((p1 = strchr(subdir, '/')) == subdir) {
+ fprintf(stderr,
+ _("call to search_tree_file with an absolute path, stripping\n"));
+ fprintf(stderr,
+ _("initial path separator. Hope this was intended...\n"));
+ memmove(subdir, subdir + 1, strlen(subdir) - 1);
+ p1 = strchr(subdir, '/');
+ }
+ /*
+ * Do we need to find a subdirectory?
+ */
+ if (p1) {
+ *p1 = '\0';
+
+#ifdef DEBUG_TORITO
+ fprintf(stderr, _("Looking for subdir called %s\n"), p1);
+#endif
+
+ rest = p1 + 1;
+
+#ifdef DEBUG_TORITO
+ fprintf(stderr, _("Remainder of path name is now %s\n"), rest);
+#endif
+
+ dpnt = node->subdir;
+ while (dpnt) {
+#ifdef DEBUG_TORITO
+ fprintf(stderr,
+ "%4d %5d %s\n", dpnt->extent, dpnt->size,
+ dpnt->de_name);
+#endif
+ if (strcmp(subdir, dpnt->de_name) == 0) {
+#ifdef DEBUG_TORITO
+ fprintf(stderr,
+ _("Calling next level with filename = %s\n"), rest);
+#endif
+ return (search_tree_file(dpnt, rest));
+ }
+ dpnt = dpnt->next;
+ }
+
+ /*
+ * If we got here means we couldn't find the subdir.
+ */
+ return (NULL);
+ } else {
+ /*
+ * Look for a normal file now
+ */
+ depnt = node->contents;
+ while (depnt) {
+#ifdef DEBUG_TORITO
+ fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
+ depnt->size, depnt->name);
+#endif
+ if (strcmp(filename, depnt->name) == 0) {
+#ifdef DEBUG_TORITO
+ fprintf(stderr, _("Found our file %s"), filename);
+#endif
+ return (depnt);
+ }
+ depnt = depnt->next;
+ }
+ /*
+ * If we got here means we couldn't find the subdir.
+ */
+ return (NULL);
+ }
+#ifdef ERIC_FUN
+ fprintf(stderr, _("We cant get here in search_tree_file :-/ \n"));
+#endif
+}
+
+EXPORT void
+init_fstatbuf()
+{
+ struct timeval current_time;
+
+ if (fstatbuf.st_ctime == 0) {
+ gettimeofday(¤t_time, NULL);
+ if (rationalize_uid)
+ fstatbuf.st_uid = uid_to_use;
+ else
+ fstatbuf.st_uid = getuid();
+ if (rationalize_gid)
+ fstatbuf.st_gid = gid_to_use;
+ else
+ fstatbuf.st_gid = getgid();
+
+ current_time.tv_usec *= 1000;
+ fstatbuf.st_ctime = current_time.tv_sec;
+ stat_set_ansecs(&fstatbuf, current_time.tv_usec);
+ fstatbuf.st_mtime = current_time.tv_sec;
+ stat_set_mnsecs(&fstatbuf, current_time.tv_usec);
+ fstatbuf.st_atime = current_time.tv_sec;
+ stat_set_cnsecs(&fstatbuf, current_time.tv_usec);
+ }
+}