diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
commit | 71dc8760ff4de5f365330d1bc571d934deb54af9 (patch) | |
tree | 7346d42a282562a3937d82307012b5857d642ce6 /genisoimage/tree.c | |
download | cdrkit-71dc8760ff4de5f365330d1bc571d934deb54af9.tar.gz |
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'genisoimage/tree.c')
-rw-r--r-- | genisoimage/tree.c | 2696 |
1 files changed, 2696 insertions, 0 deletions
diff --git a/genisoimage/tree.c b/genisoimage/tree.c new file mode 100644 index 0000000..7805888 --- /dev/null +++ b/genisoimage/tree.c @@ -0,0 +1,2696 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)tree.c 1.82 04/06/12 joerg */ +/* + * 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-2004 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 */ + +#include <mconfig.h> +#include "genisoimage.h" +#include "match.h" +#include "udf.h" +#include "exclude.h" +#include <timedefs.h> +#include <errno.h> +#include <fctldefs.h> +#include <device.h> +#include <schily.h> + +extern int allow_limited_size; + +#ifdef VMS +#include <sys/file.h> +#include <vms/fabdef.h> +#include "vms.h" +#endif + +/* + * Autoconf should be able to figure this one out for us and let us know + * whether the system has memmove or not. + */ +#ifndef HAVE_MEMMOVE +#define memmove(d, s, n) bcopy((s), (d), (n)) +#endif + +static Uchar symlink_buff[PATH_MAX+1]; + +static char *filetype(int t); +static char *rstr(char *s1, char *s2); +static void stat_fix(struct stat * st); +int stat_filter(char *path, struct stat *st); +int lstat_filter(char *path, struct stat *st); +static int sort_n_finish(struct directory *this_dir); +static void generate_reloc_directory(void); +static void attach_dot_entries(struct directory *dirnode, struct stat *dir_stat, + struct stat *parent_stat); +static void update_nlink(struct directory_entry *s_entry, int value); +static void increment_nlink(struct directory_entry *s_entry); +char *find_rr_attribute(unsigned char *pnt, int len, char *attr_type); +void finish_cl_pl_entries(void); +int scan_directory_tree(struct directory *this_dir, char *path, + struct directory_entry *de); +#ifdef APPLE_HYB +int insert_file_entry(struct directory *this_dir, + char *whole_path, + char *short_name, + int have_rsrc); +#else +int insert_file_entry(struct directory *this_dir, + char *whole_path, + char *short_name); +#endif +void generate_iso9660_directories(struct directory *node, + FILE *outfile); +struct directory *find_or_create_directory(struct directory *parent, + const char *path, + struct directory_entry *de, + int flag, + struct stat* stat_template); +static void delete_directory(struct directory *parent, + struct directory *child); +int sort_tree(struct directory *node); +void dump_tree(struct directory *node); +void update_nlink_field(struct directory *node); +struct directory_entry *search_tree_file(struct directory *node, + char *filename); +void init_fstatbuf(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; + +static char * +filetype(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_ISCNT(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 + */ +static char * +rstr(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); +} + +static void +stat_fix(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; + } + } +} + +int +stat_filter(char *path, struct stat *st) +{ + int result = stat(path, st); + + if (result >= 0 && rationalize) + stat_fix(st); + return (result); +} + +int +lstat_filter(char *path, struct stat *st) +{ + int result = lstat(path, st); + + if (result >= 0 && rationalize) + stat_fix(st); + return (result); +} + +static int +sort_n_finish(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)) { + fstatbuf.st_mode = new_dir_mode | S_IFDIR; + fstatbuf.st_nlink = 2; + attach_dot_entries(this_dir, &fstatbuf, &fstatbuf); + } + flush_file_hash(); + s_entry = this_dir->contents; + while (s_entry) { + /* 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) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Fatal goof, file '%s' already in hash table.\n", + s_entry->isorec.name); +#else + fprintf(stderr, + "Fatal goof, file '%s' already in hash table.\n", + s_entry->isorec.name); + exit(1); +#endif + } + /* + * OK, handle the conflicts. Try substitute names until we + * come up with a winner + */ + strcpy(rootname, s_entry->isorec.name); + /* + * 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) { + strcpy(extname, c); + *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) + fprintf(stderr, "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. */ +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Unable to generate unique name for file %s\n", + s_entry->name); +#else + fprintf(stderr, + "Unable to generate unique name for file %s\n", + s_entry->name); + exit(1); +#endif + +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 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); + 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 = (dev_t) UNCACHED_DEVICE; + set_723(table->isorec.volume_sequence_number, + volume_sequence_number); + set_733((char *) table->isorec.size, tablesize); + table->realsize = tablesize; + table->size = tablesize; + table->filedir = this_dir; + if (jhide_trans_tbl) + table->de_flags |= INHIBIT_JOLIET_ENTRY; +/* table->name = strdup("<translation table>");*/ + table->name = 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) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Fatal error - RR overflow (reclen %d) for file %s\n", + new_reclen, + s_entry->name); +#else + fprintf(stderr, + "Fatal error - RR overflow (reclen %d) for file %s\n", + new_reclen, + s_entry->name); + exit(1); +#endif + } + s_entry->isorec.length[0] = new_reclen; + } + + status = sort_directory(&this_dir->contents, (reloc_dir == this_dir)); + if (status > 0) { + fprintf(stderr, "Unable to sort directory %s\n", + this_dir->whole_name); + if(merge_warn_msg) + fprintf(stderr, merge_warn_msg); + exit(1); + } + /* + * 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) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Translation table size mismatch %d %d\n", + count, tablesize); +#else + fprintf(stderr, + "Translation table size mismatch %d %d\n", + count, tablesize); + exit(1); +#endif + } + } + /* + * 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); +} + +static 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 = strdup("./.rr_moved"); + reloc_dir->de_name = strdup(".rr_moved"); + } else { + reloc_dir->whole_name = strdup("./rr_moved"); + reloc_dir->de_name = strdup("rr_moved"); + } + 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 tree. */ + reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY; + s_entry->de_flags |= INHIBIT_JOLIET_ENTRY; + + /* Hiding RR_MOVED seems not to be possible..... */ +#ifdef HIDE_RR + reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; + s_entry->de_flags |= INHIBIT_ISO9660_ENTRY; +#endif + + root->contents = s_entry; + root->contents->name = 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 = (dev_t) 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, 0); + }; + + /* Now create the . and .. entries in rr_moved */ + /* Now create an actual directory entry */ + memset(&root_statbuf, 0x0, sizeof(struct stat)); /* be sure */ + attach_dot_entries(reloc_dir, &fstatbuf, &root_statbuf); +} + +/* + * Function: attach_dot_entries + * + * Purpose: Create . and .. entries for a new directory. + * + * Arguments: dir_stat contains the ownership/permission information + * for dirnode, and parent_stat contains + * ownership/permission information for its parent + * + * + * Notes: Only used for artificial directories that + * we are creating. + */ +static void +attach_dot_entries(struct directory *dirnode, struct stat *dir_stat, + struct stat *parent_stat) +{ + struct directory_entry *s_entry; + struct directory_entry *orig_contents; + int deep_flag = 0; + + init_fstatbuf(); + + orig_contents = dirnode->contents; + + if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 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 = 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, fstatbuf.st_mtime); + set_723(s_entry->isorec.volume_sequence_number, + volume_sequence_number); + set_733(s_entry->isorec.size, SECTOR_SIZE); + s_entry->realsize = 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, 0); + } + dirnode->dir_flags |= DIR_HAS_DOTDOT; + } + 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 = 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, fstatbuf.st_mtime); + set_723(s_entry->isorec.volume_sequence_number, + volume_sequence_number); + set_733(s_entry->isorec.size, SECTOR_SIZE); + s_entry->realsize=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, + dir_stat, dir_stat, deep_flag); + } + dirnode->dir_flags |= DIR_HAS_DOT; + } +} + +static void +update_nlink(struct directory_entry *s_entry, int value) +{ + unsigned char *pnt; + int len; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + pnt = parse_xa(pnt, &len, 0); + while (len >= 4) { + if (pnt[3] != 1 && pnt[3] != 2) { +#ifdef USE_LIBSCHILY + errmsgno(EX_BAD, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#else + fprintf(stderr, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#endif + } + if (pnt[0] == 'P' && pnt[1] == 'X') { + set_733((char *) pnt + 12, value); + break; + } + len -= pnt[2]; + pnt += pnt[2]; + } +} + +static void +increment_nlink(struct directory_entry *s_entry) +{ + unsigned char *pnt; + int len, + nlink; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + pnt = parse_xa(pnt, &len, 0); + while (len >= 4) { + if (pnt[3] != 1 && pnt[3] != 2) { +#ifdef USE_LIBSCHILY + errmsgno(EX_BAD, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#else + fprintf(stderr, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#endif + } + if (pnt[0] == 'P' && pnt[1] == 'X') { + nlink = get_733((char *) pnt + 12); + set_733((char *) pnt + 12, nlink + 1); + break; + } + len -= pnt[2]; + pnt += pnt[2]; + } +} + +char * +find_rr_attribute(unsigned char *pnt, int len, char *attr_type) +{ + pnt = parse_xa(pnt, &len, 0); + while (len >= 4) { + if (pnt[3] != 1 && pnt[3] != 2) { +#ifdef USE_LIBSCHILY + errmsgno(EX_BAD, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#else + fprintf(stderr, + "**BAD RRVERSION (%d) for %c%c\n", + pnt[3], pnt[0], pnt[1]); +#endif + } + 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); +} + +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) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Unable to locate directory parent\n"); +#else + fprintf(stderr, "Unable to locate directory parent\n"); + exit(1); +#endif + }; + + 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 */ + } + /* + * Next we need to modify the NLINK terms in the assorted root + * directory records to account for the presence of the RR_MOVED + * directory + */ + increment_nlink(root->self); + increment_nlink(root->self->next); + d_entry = root->subdir; + while (d_entry) { + increment_nlink(d_entry->contents->next); + d_entry = d_entry->next; + }; + + finish_cl_pl_for_prev_session(); +} + +/* + * 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: + */ +int +scan_directory_tree(struct directory *this_dir, char *path, + struct directory_entry *de) +{ + DIR *current_dir; + char whole_path[PATH_MAX]; + struct dirent *d_entry; + struct directory *parent; + int dflag; + char *old_path; + + 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 + */ + old_path = path; + + if (current_dir) { + errno = 0; + d_entry = readdir(current_dir); + } + + if (!current_dir || !d_entry) { + int ret = 1; + +#ifdef USE_LIBSCHILY + errmsg("Unable to open directory %s\n", path); +#else + fprintf(stderr, "Unable to open directory %s\n", path); +#endif + if (errno == ENOTDIR) { + /* Mark as not a directory */ + de->isorec.flags[0] &= ~ISO_DIRECTORY; + ret = 0; + } + if (current_dir) + closedir(current_dir); + return (ret); + } +#ifdef ABORT_DEEP_ISO_ONLY + if ((this_dir->depth > RR_relocation_depth) && !use_RockRidge) { + static BOOL did_hint = FALSE; + + errmsgno(EX_BAD, + "Directories too deep for '%s' (%d) max is %d; ignored - continuing.\n", + path, this_dir->depth, RR_relocation_depth); + 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"); + } + closedir(current_dir); + return (1); + } +#endif + + parent = de->filedir; + /* + * 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. + */ + dflag = 0; + while (1 == 1) { + + /* + * The first time through, skip this, since we already asked + * for the first entry when we opened the directory. + */ + if (dflag) + d_entry = readdir(current_dir); + dflag++; + + if (!d_entry) + break; + + /* OK, got a valid entry */ + + /* If we do not want all files, then pitch the backups. */ + if (!all_files) { + if (strchr(d_entry->d_name, '~') || + strchr(d_entry->d_name, '#') || + rstr(d_entry->d_name, ".bak")) { + if (verbose > 0) { + fprintf(stderr, + "Ignoring file %s\n", + d_entry->d_name); + } + continue; + } + } +#ifdef APPLE_HYB + if (apple_both) { + /* + * exclude certain HFS type files/directories for the + * time being + */ + if (hfs_exclude(d_entry->d_name)) + continue; + } +#endif /* APPLE_HYB */ + + if (strlen(path) + strlen(d_entry->d_name) + 2 > + sizeof (whole_path)) { +#ifdef USE_LIBSCHILY + errmsgno(EX_BAD, "Path name %s/%s too long.\n", + path, d_entry->d_name); + comerrno(EX_BAD, "Overflow of stat buffer\n"); +#else + fprintf(stderr, "Path name %s/%s too long.\n", + path, d_entry->d_name); + fprintf(stderr, "Overflow of stat buffer\n"); + exit(1); +#endif + }; + + /* Generate the complete ASCII path for this file */ + strcpy(whole_path, path); +#ifndef VMS + if (whole_path[strlen(whole_path) - 1] != '/') + strcat(whole_path, "/"); +#endif + strcat(whole_path, d_entry->d_name); + + /** Should we exclude this file ? */ + if (matches(d_entry->d_name) || matches(whole_path)) { + if (verbose > 1) { + fprintf(stderr, + "Excluded by match: %s\n", whole_path); + } + continue; + } + if (generate_tables && + strcmp(d_entry->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_entry->d_name, ".") == 0 && + this_dir->dir_flags & DIR_HAS_DOT) { + continue; + } + if (strcmp(d_entry->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.*/ +#ifdef APPLE_HYB + insert_file_entry(this_dir, whole_path, d_entry->d_name, 0); +#else + insert_file_entry(this_dir, whole_path, d_entry->d_name); +#endif /* APPLE_HYB */ + } + 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); +} + + +/* + * 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. + */ +#ifdef APPLE_HYB +int +insert_file_entry(struct directory *this_dir, char *whole_path, + char *short_name, int have_rsrc) +#else +int +insert_file_entry(struct directory *this_dir, char *whole_path, + char *short_name) +#endif /* APPLE_HYB */ +{ + struct stat statbuf, + lstatbuf; + struct directory_entry *s_entry, + *s_entry1; + int lstatus; + int status; + int deep_flag; + int no_scandir = 0; + +#ifdef APPLE_HYB + int x_hfs = 0; + int htype = TYPE_NONE; + +#endif /* APPLE_HYB */ + + 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. + */ +#ifdef USE_LIBSCHILY + errmsg("Non-existent or inaccessible: %s\n", whole_path); +#else + fprintf(stderr, "Non-existent or inaccessible: %s\n", + whole_path); +#endif + 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)) { + if (use_RockRidge) { + status = 0; + statbuf.st_size = (off_t)0; + STAT_INODE(statbuf) = UNCACHED_INODE; + statbuf.st_dev = (dev_t) UNCACHED_DEVICE; + statbuf.st_mode = + (statbuf.st_mode & ~S_IFMT) | S_IFREG; + } else { + if (follow_links) { +#ifdef USE_LIBSCHILY + /* XXX errno may be wrong! */ + errmsg("Unable to stat file %s - ignoring and continuing.\n", + whole_path); +#else + fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); +#endif + } else { +#ifdef USE_LIBSCHILY + errmsgno(EX_BAD, + "Symlink %s ignored - continuing.\n", + whole_path); +#else + fprintf(stderr, + "Symlink %s ignored - continuing.\n", + whole_path); +#endif + 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, ".") && + strcmp(short_name, "..")) { + 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 genisoimage 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, ".") && + strcmp(short_name, "..") && + 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) && (status = access(whole_path, R_OK))) { +#ifdef USE_LIBSCHILY + errmsg("File %s is not readable - ignoring\n", + whole_path); +#else + fprintf(stderr, + "File %s is not readable (errno = %d) - ignoring\n", + whole_path, errno); +#endif + return (0); + } + /* print a warning but don't spam too much */ + if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0xFFFFFFFF)) { + static int udf_warned; + + if( !allow_limited_size || verbose>1) + fprintf(stderr, "File %s is larger than 4GiB-1.\n", whole_path); + if( !allow_limited_size) + { + fprintf(stderr, "-allow-limited-size was not specified. There is no way do represent this file size. Aborting.\n"); + exit(1); + } + if(verbose>=1 && ! udf_warned ) { + udf_warned++; + fprintf(stderr, "This size can only be represented in the UDF filesystem.\n" + "Make sure that your clients support and use it.\n" + "ISO9660, Joliet, RockRidge, HFS will display incorrect size.\n"); + } + } + /* + * 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, ".") && + strcmp(short_name, "..")) { + if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) { +#ifdef USE_LIBSCHILY +/* 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)); +#else +/* fprintf(stderr,*/ +/* "Directory loop - fatal goof (%s %lx %lu).\n",*/ + fprintf(stderr, + "Warning: Directory loop (%s dev: %lx ino: %lu).\n", + whole_path, (unsigned long) statbuf.st_dev, + (unsigned long) STAT_INODE(statbuf)); +#endif + } + 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)) { + if ( ! (this_dir == root && strcmp(short_name, "..") == 0)) { + 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) { +#ifdef USE_LIBSCHILY + errmsg("Unable to stat file %s - ignoring and continuing.\n", + whole_path); +#else + fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); +#endif + return (0); + } + /* + * 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, ".") && + strcmp(short_name, "..")) { + struct directory *child; + + 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, NULL); + } else { + child = find_or_create_directory(this_dir, + whole_path, + s_entry, 1, NULL); + /* + * 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, ".") && + strcmp(short_name, "..")) { + 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, 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 = strdup(short_name); + s_entry->whole_name = strdup(whole_path); + + s_entry->de_flags = 0; + + /* + * 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; + } + } + +#ifdef SORTING + /* inherit any sort weight from parent directory */ + s_entry->sort = this_dir->sort; + +#ifdef DVD_VIDEO + /* + * 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_video) { + 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 tree + */ + s_entry->de_flags |= INHIBIT_JOLIET_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, ".") && + strcmp(short_name, "..")) { + if (!s_entry->hfs_ent) { + hfsdirent *hfs_ent; + + hfs_ent = + (hfsdirent *) e_malloc(sizeof (hfsdirent)); + + /* fill 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 = (dev_t) UNCACHED_DEVICE; + deep_flag = NEED_PL; + } else +#ifdef APPLE_HYB + if (have_rsrc) { + /* don't want rsrc files to be cached */ + s_entry->inode = UNCACHED_INODE; + s_entry->dev = (dev_t) 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) || + S_ISLNK(lstatbuf.st_mode)) { + 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); + s_entry->realsize = 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; + + if (!reloc_dir) + generate_reloc_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 = (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 = strdup(this_dir->contents->name); + s_entry1->whole_name = strdup(this_dir->contents->whole_name); + 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); + + deep_flag = NEED_RE; + + if (use_XA || use_RockRidge) { + generate_xa_rr_attributes(whole_path, + short_name, s_entry1, + &statbuf, &lstatbuf, deep_flag); + } + deep_flag = 0; + + /* + * 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, NULL); +/* if (!no_scandir)*/ + if (!0) + scan_directory_tree(child, whole_path, s_entry1); + s_entry1->filedir = this_dir; + + statbuf.st_size = (off_t)0; + statbuf.st_mode &= 0777; + set_733((char *) s_entry->isorec.size, 0); + s_entry->realsize=0; + s_entry->size = 0; + s_entry->isorec.flags[0] = ISO_FILE; + s_entry->inode = UNCACHED_INODE; + s_entry->de_flags |= RELOCATED_DIRECTORY; + 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 <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(whole_path, + (char *) symlink_buff, + sizeof (symlink_buff)-1); +#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 = 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, NULL); + if (no_scandir) + dflag = 1; + else + 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 + /* if 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) { + s_entry->inode = UNCACHED_INODE; + s_entry->dev = (dev_t) 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)) + 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); + } + /* 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); + + } + return (1); +} + + +void +generate_iso9660_directories(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; + } +} + +/* + * Function: find_or_create_directory + * + * Purpose: Locate a directory entry in the tree, create if needed. + * If a directory is created and stat_template is non-null, + * create the directory with ownership, permissions, etc., + * from stat_template, otherwise use fallback defaults. + * + * Arguments: parent & de are never NULL at the same time. + */ +struct directory * +find_or_create_directory(struct directory *parent, + const char *path, + struct directory_entry *de, + int flag, + struct stat *stat_template) +{ + struct directory *dpnt; + struct directory_entry *orig_de; + struct directory *next_brother; + const char *cpnt; + const char *pnt; + struct stat my_statbuf; + + 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) { + fprintf(stderr, "Warning: missing whole name for: '%s'\n", de->name); + path = de->name; + } + pnt = strrchr(path, PATH_SEPARATOR); + if (pnt == NULL) { + pnt = path; + } else { + pnt++; + } + + if (parent != NULL) { + dpnt = parent->subdir; + + 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) { + 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 = strdup(pnt); + de->whole_name = strdup(path); + de->filedir = parent; + de->isorec.flags[0] = ISO_DIRECTORY; + de->priority = 32768; + de->inode = UNCACHED_INODE; + de->dev = (dev_t) UNCACHED_DEVICE; + set_723(de->isorec.volume_sequence_number, + volume_sequence_number); + iso9660_file_length(pnt, de, 1); + + /* + * If we were given a stat template, use it for + * ownership/permissions, otherwise use fallback defaults. + */ + init_fstatbuf(); + if (stat_template) { + my_statbuf = *stat_template; + } else { + my_statbuf = fstatbuf; /* defaults */ + my_statbuf.st_mode = new_dir_mode; + } + my_statbuf.st_mode &= ~S_IFMT; /* zero out file type */ + my_statbuf.st_mode |= S_IFDIR; /* force to be a directory */ + my_statbuf.st_nlink = 2; + + /* + * Apply attributes from my_statbuf to the new directory. + */ + if (use_XA || use_RockRidge) { + generate_xa_rr_attributes("", (char *) pnt, de, + &my_statbuf, &my_statbuf, 0); + } + iso9660_date(de->isorec.date, fstatbuf.st_mtime); +#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 = my_statbuf.st_ctime; + hfs_ent->mddate = my_statbuf.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 = strdup(path); + cpnt = strrchr(path, PATH_SEPARATOR); + if (cpnt) + cpnt++; + else + cpnt = path; + dpnt->de_name = strdup(cpnt); + 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; + struct stat parent_statbuf; + 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 genisoimage was started. + */ + if (parent == NULL || parent->whole_name[0] == '\0') + sts = -1; + else + sts = stat_filter(parent->whole_name, &parent_statbuf); + + if (sts != 0) { + parent_statbuf = fstatbuf; + parent_statbuf.st_mode = new_dir_mode | S_IFDIR; + parent_statbuf.st_nlink = 2; + } + + if (debug && parent) { + fprintf(stderr, "stat parent->whole_name: '%s' -> %d.\n", + parent->whole_name, sts); + } + attach_dot_entries(dpnt, &my_statbuf, &parent_statbuf); + } + 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 { + /* Come through here for normal traversal of tree */ +#ifdef DEBUG + fprintf(stderr, "%s(%d) ", path, dpnt->depth); +#endif + if (parent->depth > RR_relocation_depth) { + /* + * XXX to prevent this, we would need to add + * XXX support for RR directory relocation + * XXX to find_or_create_directory() + */ +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Directories too deep for '%s' (%d) max is %d.\n", + path, parent->depth, RR_relocation_depth); +#else + fprintf(stderr, + "Directories too deep for '%s' (%d) max is %d.\n", + path, parent->depth, RR_relocation_depth); + exit(1); +#endif + } + dpnt->parent = parent; + dpnt->depth = parent->depth + 1; + + if (!parent->subdir) { + parent->subdir = dpnt; + } else { + next_brother = parent->subdir; + while (next_brother->next) + next_brother = next_brother->next; + next_brother->next = dpnt; + } + } + + return (dpnt); +} + +/* + * Function: delete_directory + * + * Purpose: Locate a directory entry in the tree, create if needed. + * + * Arguments: + */ +static void +delete_directory(parent, child) + struct directory *parent; + struct directory *child; +{ + struct directory *tdir; + + if (child->contents != NULL) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, "Unable to delete non-empty directory\n"); +#else + fprintf(stderr, "Unable to delete non-empty directory\n"); + exit(1); +#endif + } + 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->next != NULL; + tdir = tdir->next) { + if (tdir->next == child) { + tdir->next = child->next; + break; + } + } + if (tdir == NULL) { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, + "Unable to locate child directory in parent list\n"); +#else + fprintf(stderr, + "Unable to locate child directory in parent list\n"); + exit(1); +#endif + } + } + free(child); +} + +int +sort_tree(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); +} + +void +dump_tree(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; + } +} + +void +update_nlink_field(struct directory *node) +{ + struct directory *dpnt; + struct directory *xpnt; + struct directory_entry *s_entry; + int i; + + dpnt = node; + + while (dpnt) { + if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) { + dpnt = dpnt->next; + continue; + } + /* + * First, count up the number of subdirectories this guy has. + */ + for (i = 0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) + if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0) + i++; + /* + * Next check to see if we have any relocated directories in + * this directory. The nlink field will include these as + * real directories when they are properly relocated. + * In the non-rockridge disk, the relocated entries appear as + * zero length files. + */ + for (s_entry = dpnt->contents; s_entry; + s_entry = s_entry->next) { + if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0 && + (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == + 0) { + i++; + } + } + /* Now update the field in the Rock Ridge entry. */ + update_nlink(dpnt->self, i + 2); + + /* Update the '.' entry for this directory. */ + update_nlink(dpnt->contents, i + 2); + + /* Update all of the '..' entries that point to this guy. */ + for (xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) + update_nlink(xpnt->contents->next, i + 2); + + if (dpnt->subdir) + update_nlink_field(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 + */ +struct directory_entry * +search_tree_file(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 = 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", rest); +#endif + return (search_tree_file(dpnt, rest)); + } + dpnt = dpnt->next; + } + + /* if we got here means we couldnt 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 couldnt find the subdir */ + return (NULL); + } +#ifdef ERIC_FUN + fprintf(stderr, "We cant get here in search_tree_file :-/ \n"); +#endif +} + +void +init_fstatbuf() +{ + time_t current_time; + + if (fstatbuf.st_ctime == 0) { + time(¤t_time); + 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(); + fstatbuf.st_ctime = current_time; + fstatbuf.st_mtime = current_time; + fstatbuf.st_atime = current_time; + } +} |