]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Import http://www.tux.org/pub/people/eric-youngdale/mkisofs/mkisofs-1.11.3.tar.gz
authorRobert Millan <rmh@aybabtu.com>
Sun, 8 Nov 2009 22:51:08 +0000 (22:51 +0000)
committerRobert Millan <rmh@aybabtu.com>
Sun, 8 Nov 2009 22:51:08 +0000 (22:51 +0000)
15 files changed:
util/mkisofs/defaults.h [new file with mode: 0644]
util/mkisofs/eltorito.c [new file with mode: 0644]
util/mkisofs/exclude.h [new file with mode: 0644]
util/mkisofs/fnmatch.c [new file with mode: 0644]
util/mkisofs/hash.c [new file with mode: 0644]
util/mkisofs/iso9660.h [new file with mode: 0644]
util/mkisofs/match.c [new file with mode: 0644]
util/mkisofs/match.h [new file with mode: 0644]
util/mkisofs/mkisofs.c [new file with mode: 0644]
util/mkisofs/mkisofs.h [new file with mode: 0644]
util/mkisofs/multi.c [new file with mode: 0644]
util/mkisofs/name.c [new file with mode: 0644]
util/mkisofs/rock.c [new file with mode: 0644]
util/mkisofs/tree.c [new file with mode: 0644]
util/mkisofs/write.c [new file with mode: 0644]

diff --git a/util/mkisofs/defaults.h b/util/mkisofs/defaults.h
new file mode 100644 (file)
index 0000000..91e6789
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Header file defaults.h - assorted default values for character strings in
+ * the volume descriptor.
+ *
+ *     $Id: defaults.h,v 1.4 1997/04/10 03:31:53 eric Rel $
+ */
+
+#define  PREPARER_DEFAULT      NULL
+#define  PUBLISHER_DEFAULT     NULL
+#define  APPID_DEFAULT                 NULL
+#define  COPYRIGHT_DEFAULT     NULL
+#define  BIBLIO_DEFAULT        NULL
+#define  ABSTRACT_DEFAULT      NULL
+#define  VOLSET_ID_DEFAULT     NULL
+#define  VOLUME_ID_DEFAULT     "CDROM"
+#define  BOOT_CATALOG_DEFAULT   "boot.catalog"
+#define  BOOT_IMAGE_DEFAULT     NULL
+#ifdef __QNX__
+#define  SYSTEM_ID_DEFAULT     "QNX"
+#endif
+
+#ifdef __osf__
+#define  SYSTEM_ID_DEFAULT     "OSF"
+#endif
+
+#ifdef __sun
+#define  SYSTEM_ID_DEFAULT     "Solaris"
+#endif
+
+#ifdef __hpux
+#define  SYSTEM_ID_DEFAULT     "HP-UX"
+#endif
+
+#ifdef __sgi
+#define  SYSTEM_ID_DEFAULT     "SGI"
+#endif
+
+#ifdef _AIX
+#define  SYSTEM_ID_DEFAULT     "AIX"
+#endif
+
+#ifndef SYSTEM_ID_DEFAULT
+#define  SYSTEM_ID_DEFAULT     "LINUX"
+#endif
diff --git a/util/mkisofs/eltorito.c b/util/mkisofs/eltorito.c
new file mode 100644 (file)
index 0000000..0ac5a12
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Program eltorito.c - Handle El Torito specific extensions to iso9660.
+ * 
+
+   Written by Michael Fulbright <msf@redhat.com> (1996).
+
+   Copyright 1996 RedHat Software, Incorporated
+
+   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.   */
+
+
+static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $";
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#undef MIN
+#define MIN(a, b) (((a) < (b))? (a): (b))
+
+static struct eltorito_validation_entry valid_desc;
+static struct eltorito_defaultboot_entry default_desc;
+
+/*
+ * Check for presence of boot catalog. If it does not exist then make it 
+ */
+void FDECL1(init_boot_catalog, const char *, path)
+{
+
+    int                  bcat;
+    char               * bootpath;                /* filename of boot catalog */
+    char               * buf;
+    struct stat          statbuf;
+    
+    bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2);
+    strcpy(bootpath, path);
+    if (bootpath[strlen(bootpath)-1] != '/') 
+    {
+       strcat(bootpath,"/");
+    }
+    
+    strcat(bootpath, boot_catalog);
+    
+    /*
+     * check for the file existing 
+     */
+#ifdef DEBUG_TORITO
+    printf("Looking for boot catalog file %s\n",bootpath);
+#endif
+    
+    if (!stat_filter(bootpath, &statbuf)) 
+    {
+       /*
+        * make sure its big enough to hold what we want 
+        */
+       if (statbuf.st_size == 2048) 
+       {
+           /*
+            * printf("Boot catalog exists, so we do nothing\n"); 
+            */
+           free(bootpath);
+           return;
+       }
+       else 
+       {
+           fprintf(stderr, "A boot catalog exists and appears corrupted.\n");
+           fprintf(stderr, "Please check the following file: %s.\n",bootpath);
+           fprintf(stderr, "This file must be removed before a bootable CD can be done.\n");
+           free(bootpath);
+           exit(1);
+       }
+    }
+    
+    /*
+     * file does not exist, so we create it 
+     * make it one CD sector long
+     */
+    bcat = open(bootpath, O_WRONLY | O_CREAT, S_IROTH | S_IRGRP | S_IRWXU );
+    if (bcat == -1) 
+    {
+       fprintf(stderr, "Error creating boot catalog, exiting...\n");
+       perror("");
+       exit(1);
+    }
+    
+    buf = (char *) e_malloc( 2048 );
+    write(bcat, buf, 2048);
+    close(bcat);
+    free(bootpath);
+} /* init_boot_catalog(... */
+
+void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
+{
+    int                                bootcat;
+    int                                checksum;
+    unsigned char                    * checksum_ptr;
+    struct directory_entry      * de;
+    struct directory_entry      * de2;
+    int                                i;
+    int                                nsectors;
+    
+    memset(boot_desc, 0, sizeof(*boot_desc));
+    boot_desc->id[0] = 0;
+    memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+    boot_desc->version[0] = 1;
+    
+    memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID));
+    
+    /*
+     * search from root of iso fs to find boot catalog 
+     */
+    de2 = search_tree_file(root, boot_catalog);
+    if (!de2) 
+    {
+       fprintf(stderr,"Uh oh, I cant find the boot catalog!\n");
+       exit(1);
+    }
+    
+    set_731(boot_desc->bootcat_ptr,
+           (unsigned int) get_733(de2->isorec.extent));
+    
+    /* 
+     * now adjust boot catalog
+     * lets find boot image first 
+     */
+    de=search_tree_file(root, boot_image);
+    if (!de) 
+    {
+       fprintf(stderr,"Uh oh, I cant find the boot image!\n");
+       exit(1);
+    } 
+    
+    /* 
+     * we have the boot image, so write boot catalog information
+     * Next we write out the primary descriptor for the disc 
+     */
+    memset(&valid_desc, 0, sizeof(valid_desc));
+    valid_desc.headerid[0] = 1;
+    valid_desc.arch[0] = EL_TORITO_ARCH_x86;
+    
+    /*
+     * we'll shove start of publisher id into id field, may get truncated
+     * but who really reads this stuff!
+     */
+    if (publisher)
+        memcpy_max(valid_desc.id,  publisher, MIN(23, strlen(publisher)));
+    
+    valid_desc.key1[0] = 0x55;
+    valid_desc.key2[0] = 0xAA;
+    
+    /*
+     * compute the checksum 
+     */
+    checksum=0;
+    checksum_ptr = (unsigned char *) &valid_desc;
+    for (i=0; i<sizeof(valid_desc); i+=2) 
+    {
+       /*
+        * skip adding in ckecksum word, since we dont have it yet! 
+        */
+       if (i == 28)
+       {
+           continue;
+       }
+       checksum += (unsigned int)checksum_ptr[i];
+       checksum += ((unsigned int)checksum_ptr[i+1])*256;
+    }
+    
+    /* 
+     * now find out the real checksum 
+     */
+    checksum = -checksum;
+    set_721(valid_desc.cksum, (unsigned int) checksum);
+    
+    /*
+     * now make the initial/default entry for boot catalog 
+     */
+    memset(&default_desc, 0, sizeof(default_desc));
+    default_desc.boot_id[0] = EL_TORITO_BOOTABLE;
+    
+    /*
+     * use default BIOS loadpnt
+     */ 
+    set_721(default_desc.loadseg, 0);
+    default_desc.arch[0] = EL_TORITO_ARCH_x86;
+    
+    /*
+     * figure out size of boot image in sectors, for now hard code to
+     * assume 512 bytes/sector on a bootable floppy
+     */
+    nsectors = ((de->size + 511) & ~(511))/512;
+    printf("\nSize of boot image is %d sectors -> ", nsectors); 
+    
+    /*
+     * choose size of emulated floppy based on boot image size 
+     */
+    if (nsectors == 2880 ) 
+    {
+       default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP;
+       printf("Emulating a 1.44 meg floppy\n");
+    }
+    else if (nsectors == 5760 ) 
+    {
+       default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP;
+       printf("Emulating a 2.88 meg floppy\n");
+    }
+    else if (nsectors == 2400 ) 
+    {
+       default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP;
+       printf("Emulating a 1.2 meg floppy\n");
+    }
+    else 
+    {
+       fprintf(stderr,"\nError - boot image is not the an allowable size.\n");
+       exit(1);
+    }
+    
+    
+    /* 
+     * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!! 
+     */
+    nsectors = 1;
+    set_721(default_desc.nsect, (unsigned int) nsectors );
+#ifdef DEBUG_TORITO
+    printf("Extent of boot images is %d\n",get_733(de->isorec.extent));
+#endif
+    set_731(default_desc.bootoff, 
+           (unsigned int) get_733(de->isorec.extent));
+    
+    /*
+     * now write it to disk 
+     */
+    bootcat = open(de2->whole_name, O_RDWR);
+    if (bootcat == -1) 
+    {
+       fprintf(stderr,"Error opening boot catalog for update.\n");
+       perror("");
+       exit(1);
+    }
+    
+    /* 
+     * write out 
+     */
+    write(bootcat, &valid_desc, 32);
+    write(bootcat, &default_desc, 32);
+    close(bootcat);
+} /* get_torito_desc(... */
diff --git a/util/mkisofs/exclude.h b/util/mkisofs/exclude.h
new file mode 100644 (file)
index 0000000..b9581a9
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de:
+ * added 'exclude' option (-x) to specify pathnames NOT to be included in 
+ * CD image.
+ *
+ *     $Id: exclude.h,v 1.1 1997/02/23 15:53:19 eric Rel $
+ */
+
+void exclude();
+int is_excluded();
diff --git a/util/mkisofs/fnmatch.c b/util/mkisofs/fnmatch.c
new file mode 100644 (file)
index 0000000..cd5c0b2
--- /dev/null
@@ -0,0 +1,226 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+static char rcsid[] ="$Id: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $";
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+
+#ifndef FNM_FILE_NAME
+#define        FNM_FILE_NAME   FNM_PATHNAME /* Preferred GNU name.  */
+#endif
+
+#ifndef FNM_LEADING_DIR
+#define        FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match.  */
+#endif
+
+#ifndef FNM_CASEFOLD
+#define        FNM_CASEFOLD    (1 << 4) /* Compare without regard to case.  */
+#endif
+
+
+#include <ctype.h>
+
+#if defined (STDC_HEADERS) || !defined (isascii)
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not.  */
+int
+fnmatch (pattern, string, flags)
+     const char *pattern;
+     const char *string;
+     int flags;
+{
+  register const char *p = pattern, *n = string;
+  register char c;
+
+/* Note that this evalutes C many times.  */
+#define FOLD(c)        ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+
+  while ((c = *p++) != '\0')
+    {
+      c = FOLD (c);
+
+      switch (c)
+       {
+       case '?':
+         if (*n == '\0')
+           return FNM_NOMATCH;
+         else if ((flags & FNM_FILE_NAME) && *n == '/')
+           return FNM_NOMATCH;
+         else if ((flags & FNM_PERIOD) && *n == '.' &&
+                  (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+         break;
+
+       case '\\':
+         if (!(flags & FNM_NOESCAPE))
+           {
+             c = *p++;
+             c = FOLD (c);
+           }
+         if (FOLD (*n) != c)
+           return FNM_NOMATCH;
+         break;
+
+       case '*':
+         if ((flags & FNM_PERIOD) && *n == '.' &&
+             (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+
+         for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+           if (((flags & FNM_FILE_NAME) && *n == '/') ||
+               (c == '?' && *n == '\0'))
+             return FNM_NOMATCH;
+
+         if (c == '\0')
+           return 0;
+
+         {
+           char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+           c1 = FOLD (c1);
+           for (--p; *n != '\0'; ++n)
+             if ((c == '[' || FOLD (*n) == c1) &&
+                 fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+               return 0;
+           return FNM_NOMATCH;
+         }
+
+       case '[':
+         {
+           /* Nonzero if the sense of the character class is inverted.  */
+           register int not;
+
+           if (*n == '\0')
+             return FNM_NOMATCH;
+
+           if ((flags & FNM_PERIOD) && *n == '.' &&
+               (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+             return FNM_NOMATCH;
+
+           not = (*p == '!' || *p == '^');
+           if (not)
+             ++p;
+
+           c = *p++;
+           for (;;)
+             {
+               register char cstart = c, cend = c;
+
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 cstart = cend = *p++;
+
+               cstart = cend = FOLD (cstart);
+
+               if (c == '\0')
+                 /* [ (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               c = FOLD (c);
+
+               if ((flags & FNM_FILE_NAME) && c == '/')
+                 /* [/] can never match.  */
+                 return FNM_NOMATCH;
+
+               if (c == '-' && *p != ']')
+                 {
+                   cend = *p++;
+                   if (!(flags & FNM_NOESCAPE) && cend == '\\')
+                     cend = *p++;
+                   if (cend == '\0')
+                     return FNM_NOMATCH;
+                   cend = FOLD (cend);
+
+                   c = *p++;
+                 }
+
+               if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+                 goto matched;
+
+               if (c == ']')
+                 break;
+             }
+           if (!not)
+             return FNM_NOMATCH;
+           break;
+
+         matched:;
+           /* Skip the rest of the [...] that already matched.  */
+           while (c != ']')
+             {
+               if (c == '\0')
+                 /* [... (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 /* XXX 1003.2d11 is unclear if this is right.  */
+                 ++p;
+             }
+           if (not)
+             return FNM_NOMATCH;
+         }
+         break;
+
+       default:
+         if (c != FOLD (*n))
+           return FNM_NOMATCH;
+       }
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return 0;
+
+  if ((flags & FNM_LEADING_DIR) && *n == '/')
+    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
+    return 0;
+
+  return FNM_NOMATCH;
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/util/mkisofs/hash.c b/util/mkisofs/hash.c
new file mode 100644 (file)
index 0000000..67098d5
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * File hash.c - generate hash tables for iso9660 filesystem.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: hash.c,v 1.2 1997/02/23 16:11:15 eric Rel $";
+
+#include <stdlib.h>
+#include "mkisofs.h"
+
+#define NR_HASH 1024
+
+#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH)
+
+static struct file_hash * hash_table[NR_HASH] = {0,};
+
+void FDECL1(add_hash, struct directory_entry *, spnt){
+  struct file_hash * s_hash;
+  unsigned int hash_number;
+
+  if(spnt->size == 0 || spnt->starting_block == 0) 
+    if(spnt->size != 0 || spnt->starting_block != 0) {
+      fprintf(stderr,"Non zero-length file assigned zero extent.\n");
+      exit(1);
+    };
+
+  if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return;
+  hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
+
+#if 0
+  if (verbose) fprintf(stderr,"%s ",spnt->name);
+#endif
+  s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+  s_hash->next = hash_table[hash_number];
+  s_hash->inode = spnt->inode;
+  s_hash->dev = spnt->dev;
+  s_hash->starting_block = spnt->starting_block;
+  s_hash->size = spnt->size;
+  hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){
+  unsigned int hash_number;
+  struct file_hash * spnt;
+  hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+  if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+  spnt = hash_table[hash_number];
+  while(spnt){
+    if(spnt->inode == inode && spnt->dev == dev) return spnt;
+    spnt = spnt->next;
+  };
+  return NULL;
+}
+
+
+static struct file_hash * directory_hash_table[NR_HASH] = {0,};
+
+void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){
+  struct file_hash * s_hash;
+  unsigned int hash_number;
+
+  if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return;
+  hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+
+  s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+  s_hash->next = directory_hash_table[hash_number];
+  s_hash->inode = inode;
+  s_hash->dev = dev;
+  directory_hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){
+  unsigned int hash_number;
+  struct file_hash * spnt;
+  hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+  if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+  spnt = directory_hash_table[hash_number];
+  while(spnt){
+    if(spnt->inode == inode && spnt->dev == dev) return spnt;
+    spnt = spnt->next;
+  };
+  return NULL;
+}
+
+struct  name_hash
+{
+  struct name_hash * next;
+  struct directory_entry * de;
+};
+
+#define NR_NAME_HASH 128
+
+static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
+
+/*
+ * Find the hash bucket for this name.
+ */
+static  unsigned int FDECL1(name_hash, const char *, name)
+{
+  unsigned int hash = 0;
+  const char * p;
+  
+  p = name;
+  
+  while (*p) 
+    {
+      /*
+       * Don't hash the  iso9660 version number.  This way
+       * we can detect duplicates in cases where we have
+       * directories (i.e. foo) and non-directories
+       * (i.e. foo;1).
+       */
+      if( *p == ';' )
+       {
+         break;
+       }
+      hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
+    }
+  return hash % NR_NAME_HASH;
+}
+
+void FDECL1(add_file_hash, struct directory_entry *, de){
+       struct name_hash  * new;
+       int hash;
+
+       new = (struct  name_hash *) e_malloc(sizeof(struct name_hash));
+       new->de = de;
+       new->next = NULL;
+       hash = name_hash(de->isorec.name);
+
+       /* Now insert into the hash table */
+       new->next = name_hash_table[hash];
+       name_hash_table[hash] = new;
+}
+
+struct directory_entry * FDECL1(find_file_hash, char *, name)
+{
+  struct name_hash  * nh;
+  char             * p1;
+  char             * p2;
+  
+  for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
+    {
+      p1 = name;
+      p2 = nh->de->isorec.name;
+
+      /*
+       * Look for end of string, or a mismatch.
+       */
+      while(1==1)
+       {
+         if(    (*p1 == '\0' || *p1 == ';')
+             || (*p2 == '\0' || *p2 == ';')
+             || (*p1 != *p2) )
+           {
+             break;
+           }
+         p1++;
+         p2++;
+       }
+
+      /*
+       * If we are at the end of both strings, then
+       * we have a match.
+       */
+      if(    (*p1 == '\0' || *p1 == ';')
+         && (*p2 == '\0' || *p2 == ';') )
+       {
+         return nh->de;
+       }
+    }
+  return NULL;
+}
+
+int FDECL1(delete_file_hash, struct directory_entry *, de){
+       struct name_hash  * nh, *prev;
+       int hash;
+
+       prev = NULL;
+       hash = name_hash(de->isorec.name);
+       for(nh = name_hash_table[hash]; nh; nh = nh->next) {
+               if(nh->de == de) break;
+               prev = nh;
+       }
+       if(!nh) return 1;
+       if(!prev)
+               name_hash_table[hash] = nh->next;
+       else
+               prev->next = nh->next;
+       free(nh);
+       return 0;
+}
+
+void flush_file_hash(){
+       struct name_hash  * nh, *nh1;
+       int i;
+
+       for(i=0; i<NR_NAME_HASH; i++) {
+               nh = name_hash_table[i];
+               while(nh) {
+                       nh1 =  nh->next;
+                       free(nh);
+                       nh = nh1;
+               }
+               name_hash_table[i] =  NULL;
+               
+       }
+}
diff --git a/util/mkisofs/iso9660.h b/util/mkisofs/iso9660.h
new file mode 100644 (file)
index 0000000..a58f96f
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Header file iso9660.h - assorted structure definitions and typecasts.
+ * specific to iso9660 filesystem.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+/*
+ *     $Id: iso9660.h,v 1.1 1997/02/23 15:55:25 eric Rel $
+ */
+
+#ifndef _ISOFS_FS_H
+#define _ISOFS_FS_H
+
+/*
+ * The isofs filesystem constants/structures
+ */
+
+/* This part borrowed from the bsd386 isofs */
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_volume_descriptor {
+       char type[ISODCL(1,1)]; /* 711 */
+       char id[ISODCL(2,6)];
+       char version[ISODCL(7,7)];
+       char data[ISODCL(8,2048)];
+};
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+#define EL_TORITO_ID "EL TORITO SPECIFICATION"
+#define EL_TORITO_ARCH_x86 0
+#define EL_TORITO_ARCH_PPC 1
+#define EL_TORITO_ARCH_MAC 2
+#define EL_TORITO_BOOTABLE 0x88
+#define EL_TORITO_MEDIA_NOEMUL 0
+#define EL_TORITO_MEDIA_12FLOP  1
+#define EL_TORITO_MEDIA_144FLOP 2
+#define EL_TORITO_MEDIA_288FLOP 3
+#define EL_TORITO_MEDIA_HD      4
+
+struct iso_primary_descriptor {
+       char type                       [ISODCL (  1,   1)]; /* 711 */
+       char id                         [ISODCL (  2,   6)];
+       char version                    [ISODCL (  7,   7)]; /* 711 */
+       char unused1                    [ISODCL (  8,   8)];
+       char system_id                  [ISODCL (  9,  40)]; /* achars */
+       char volume_id                  [ISODCL ( 41,  72)]; /* dchars */
+       char unused2                    [ISODCL ( 73,  80)];
+       char volume_space_size          [ISODCL ( 81,  88)]; /* 733 */
+       char unused3                    [ISODCL ( 89, 120)];
+       char volume_set_size            [ISODCL (121, 124)]; /* 723 */
+       char volume_sequence_number     [ISODCL (125, 128)]; /* 723 */
+       char logical_block_size         [ISODCL (129, 132)]; /* 723 */
+       char path_table_size            [ISODCL (133, 140)]; /* 733 */
+       char type_l_path_table          [ISODCL (141, 144)]; /* 731 */
+       char opt_type_l_path_table      [ISODCL (145, 148)]; /* 731 */
+       char type_m_path_table          [ISODCL (149, 152)]; /* 732 */
+       char opt_type_m_path_table      [ISODCL (153, 156)]; /* 732 */
+       char root_directory_record      [ISODCL (157, 190)]; /* 9.1 */
+       char volume_set_id              [ISODCL (191, 318)]; /* dchars */
+       char publisher_id               [ISODCL (319, 446)]; /* achars */
+       char preparer_id                [ISODCL (447, 574)]; /* achars */
+       char application_id             [ISODCL (575, 702)]; /* achars */
+       char copyright_file_id          [ISODCL (703, 739)]; /* 7.5 dchars */
+       char abstract_file_id           [ISODCL (740, 776)]; /* 7.5 dchars */
+       char bibliographic_file_id      [ISODCL (777, 813)]; /* 7.5 dchars */
+       char creation_date              [ISODCL (814, 830)]; /* 8.4.26.1 */
+       char modification_date          [ISODCL (831, 847)]; /* 8.4.26.1 */
+       char expiration_date            [ISODCL (848, 864)]; /* 8.4.26.1 */
+       char effective_date             [ISODCL (865, 881)]; /* 8.4.26.1 */
+       char file_structure_version     [ISODCL (882, 882)]; /* 711 */
+       char unused4                    [ISODCL (883, 883)];
+       char application_data           [ISODCL (884, 1395)];
+       char unused5                    [ISODCL (1396, 2048)];
+};
+
+/* El Torito Boot Record Volume Descriptor */
+struct eltorito_boot_descriptor {
+        char id                                [ISODCL (  1,    1)]; /* 711 */
+       char id2                        [ISODCL (  2,    6)];
+       char version                    [ISODCL (  7,    7)]; /* 711 */
+       char system_id                  [ISODCL (  8,   39)];
+       char unused2                    [ISODCL ( 40,   71)];
+        char bootcat_ptr                [ISODCL ( 72 ,  75)];
+       char unused5                    [ISODCL ( 76, 2048)];
+};
+
+/* Validation entry for El Torito */
+struct eltorito_validation_entry {
+        char headerid                          [ISODCL (  1,    1)]; /* 711 */
+       char arch                       [ISODCL (  2,    2)];
+       char pad1                       [ISODCL (  3,    4)]; /* 711 */
+       char id                         [ISODCL (  5,   28)];
+       char cksum                      [ISODCL ( 29,   30)];
+        char key1                       [ISODCL ( 31,   31)];
+       char key2                       [ISODCL ( 32,   32)];
+};
+
+/* El Torito initial/default entry in boot catalog */
+struct eltorito_defaultboot_entry {
+        char boot_id                           [ISODCL (  1,    1)]; /* 711 */
+       char boot_media                 [ISODCL (  2,    2)];
+       char loadseg                    [ISODCL (  3,    4)]; /* 711 */
+       char arch                       [ISODCL (  5,    5)];
+       char pad1                       [ISODCL (  6,    6)];
+        char nsect                      [ISODCL (  7,    8)];
+       char bootoff                    [ISODCL (  9,   12)];
+        char pad2                       [ISODCL ( 13,   32)];
+};
+
+
+/* We use this to help us look up the parent inode numbers. */
+
+struct iso_path_table{
+       unsigned char  name_len[2];     /* 721 */
+       char extent[4];         /* 731 */
+       char  parent[2];        /* 721 */
+       char name[1];
+};
+
+struct iso_directory_record {
+       unsigned char length                    [ISODCL (1, 1)]; /* 711 */
+       char ext_attr_length            [ISODCL (2, 2)]; /* 711 */
+       char extent                     [ISODCL (3, 10)]; /* 733 */
+       char size                       [ISODCL (11, 18)]; /* 733 */
+       char date                       [ISODCL (19, 25)]; /* 7 by 711 */
+       char flags                      [ISODCL (26, 26)];
+       char file_unit_size             [ISODCL (27, 27)]; /* 711 */
+       char interleave                 [ISODCL (28, 28)]; /* 711 */
+       char volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
+       unsigned char name_len          [ISODCL (33, 33)]; /* 711 */
+       char name                       [34]; /* Not really, but we need something here */
+};
+#endif
+
+
+
diff --git a/util/mkisofs/match.c b/util/mkisofs/match.c
new file mode 100644 (file)
index 0000000..0f5c7d8
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 27-Mar-96: Jan-Piet Mens <jpm@mens.de>
+ * added 'match' option (-m) to specify regular expressions NOT to be included
+ * in the CD image.
+ */
+
+static char rcsid[] ="$Id: match.c,v 1.2 1997/02/23 16:10:42 eric Rel $";
+
+#include <stdio.h>
+#ifndef VMS
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+#include <string.h>
+#include "match.h"
+
+#define MAXMATCH 1000
+static char *mat[MAXMATCH];
+
+void add_match(fn)
+char * fn;
+{
+  register int i;
+
+  for (i=0; mat[i] && i<MAXMATCH; i++);
+  if (i == MAXMATCH) {
+    fprintf(stderr,"Can't exclude RE '%s' - too many entries in table\n",fn);
+    return;
+  }
+
+  mat[i] = (char *) malloc(strlen(fn)+1);
+  if (! mat[i]) {
+    fprintf(stderr,"Can't allocate memory for excluded filename\n");
+    return;
+  }
+
+  strcpy(mat[i],fn);
+}
+
+int matches(fn)
+char * fn;
+{
+  /* very dumb search method ... */
+  register int i;
+
+  for (i=0; mat[i] && i<MAXMATCH; i++) {
+    if (fnmatch(mat[i], fn, FNM_FILE_NAME) != FNM_NOMATCH) {
+      return 1; /* found -> excluded filenmae */
+    }
+  }
+  return 0; /* not found -> not excluded */
+}
diff --git a/util/mkisofs/match.h b/util/mkisofs/match.h
new file mode 100644 (file)
index 0000000..90def7c
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 27th March 1996. Added by Jan-Piet Mens for matching regular expressions
+ *                 in paths.
+ * 
+ */
+
+/*
+ *     $Id: match.h,v 1.1 1997/02/23 15:56:12 eric Rel $
+ */
+
+#include "fnmatch.h"
+
+void add_match();
+int matches();
diff --git a/util/mkisofs/mkisofs.c b/util/mkisofs/mkisofs.c
new file mode 100644 (file)
index 0000000..a2e2d18
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * Program mkisofs.c - generate iso9660 filesystem  based upon directory
+ * tree on hard disk.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: mkisofs.c,v 1.10.1.3 1998/06/02 03:36:16 eric Exp $";
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <errno.h>
+#include "mkisofs.h"
+#include "config.h"
+
+#ifdef linux
+#include <getopt.h>
+#endif
+
+#include "iso9660.h"
+#include <ctype.h>
+
+#ifndef VMS
+#include <time.h>
+#else
+#include <sys/time.h>
+#include "vms.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifndef VMS
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#include "exclude.h"
+
+#ifdef __NetBSD__
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+struct directory * root = NULL;
+
+static char version_string[] = "mkisofs v1.11.3";
+
+FILE * discimage;
+unsigned int next_extent = 0;
+unsigned int last_extent = 0;
+unsigned int session_start = 0;
+unsigned int path_table_size = 0;
+unsigned int path_table[4] = {0,};
+unsigned int path_blocks = 0;
+struct iso_directory_record root_record;
+char * extension_record = NULL;
+int extension_record_extent = 0;
+static  int extension_record_size = 0;
+
+/* These variables are associated with command line options */
+int use_eltorito = 0;
+int use_RockRidge = 0;
+int verbose = 0;
+int all_files  = 0;
+int follow_links = 0;
+int rationalize = 0;
+int generate_tables = 0;
+char * preparer = PREPARER_DEFAULT;
+char * publisher = PUBLISHER_DEFAULT;
+char * appid = APPID_DEFAULT;
+char * copyright = COPYRIGHT_DEFAULT;
+char * biblio = BIBLIO_DEFAULT;
+char * abstract = ABSTRACT_DEFAULT;
+char * volset_id = VOLSET_ID_DEFAULT;
+char * volume_id = VOLUME_ID_DEFAULT;
+char * system_id = SYSTEM_ID_DEFAULT;
+char * boot_catalog = BOOT_CATALOG_DEFAULT;
+char * boot_image = BOOT_IMAGE_DEFAULT;
+
+int omit_period = 0;             /* Violates iso9660, but these are a pain */
+int transparent_compression = 0; /* So far only works with linux */
+int omit_version_number = 0;     /* May violate iso9660, but noone uses vers*/
+int RR_relocation_depth = 6;     /* Violates iso9660, but most systems work */
+int full_iso9660_filenames = 0;  /* Used with Amiga.  Disc will not work with
+                                 DOS */
+int allow_leading_dots = 0;     /* DOS cannot read names with leading dots */
+
+struct rcopts{
+  char * tag;
+  char ** variable;
+};
+
+struct rcopts rcopt[] = {
+  {"PREP", &preparer},
+  {"PUBL", &publisher},
+  {"APPI", &appid},
+  {"COPY", &copyright},
+  {"BIBL", &biblio},
+  {"ABST", &abstract},
+  {"VOLS", &volset_id},
+  {"VOLI", &volume_id},
+  {"SYSI", &system_id},
+  {NULL, NULL}
+};
+
+#if defined(ultrix) || defined(_AUX_SOURCE)
+char *strdup(s)
+char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
+#endif
+
+void FDECL1(read_rcfile, char *, appname)
+{
+  FILE * rcfile;
+  struct rcopts * rco;
+  char * pnt, *pnt1;
+  char linebuffer[256];
+  static char rcfn[] = ".mkisofsrc";
+  char filename[1000];
+  int linum;
+
+  strcpy(filename, rcfn);
+  rcfile = fopen(filename, "r");
+  if (!rcfile && errno != ENOENT)
+    perror(filename);
+
+  if (!rcfile)
+    {
+      pnt = getenv("MKISOFSRC");
+      if (pnt && strlen(pnt) <= sizeof(filename))
+       {
+         strcpy(filename, pnt);
+         rcfile = fopen(filename, "r");
+         if (!rcfile && errno != ENOENT)
+           perror(filename);
+       }
+    }
+
+  if (!rcfile)
+    {
+      pnt = getenv("HOME");
+      if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename))
+       {
+         strcpy(filename, pnt);
+         strcat(filename, "/");
+         strcat(filename, rcfn);
+         rcfile = fopen(filename, "r");
+         if (!rcfile && errno != ENOENT)
+           perror(filename);
+       }
+    }
+  if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename))
+    {
+      strcpy(filename, appname);
+      pnt = strrchr(filename, '/');
+      if (pnt)
+       {
+         strcpy(pnt + 1, rcfn);
+         rcfile = fopen(filename, "r");
+         if (!rcfile && errno != ENOENT)
+           perror(filename);
+       }
+    }
+  if (!rcfile)
+    return;
+  fprintf(stderr, "Using \"%s\"\n", filename);
+  /* OK, we got it.  Now read in the lines and parse them */
+  linum = 0;
+  while (fgets(linebuffer, sizeof(linebuffer), rcfile))
+    {
+      char *name;
+      char *name_end;
+      ++linum;
+      /* skip any leading white space */
+       pnt = linebuffer;
+      while (*pnt == ' ' || *pnt == '\t')
+       ++pnt;
+      /* If we are looking at a # character, this line is a comment. */
+       if (*pnt == '#')
+         continue;
+      /* The name should begin in the left margin.  Make sure it is in
+        upper case.  Stop when we see white space or a comment. */
+       name = pnt;
+      while (*pnt && isalpha(*pnt))
+       {
+         if(islower(*pnt))
+           *pnt = toupper(*pnt);
+         pnt++;
+       }
+      if (name == pnt)
+       {
+         fprintf(stderr, "%s:%d: name required\n", filename, linum);
+         continue;
+       }
+      name_end = pnt;
+      /* Skip past white space after the name */
+      while (*pnt == ' ' || *pnt == '\t')
+       pnt++;
+      /* silently ignore errors in the rc file. */
+      if (*pnt != '=')
+       {
+         fprintf(stderr, "%s:%d: equals sign required\n", filename, linum);
+         continue;
+       }
+      /* Skip pas the = sign, and any white space following it */
+      pnt++; /* Skip past '=' sign */
+      while (*pnt == ' ' || *pnt == '\t')
+       pnt++;
+
+      /* now it is safe to NUL terminate the name */
+
+       *name_end = 0;
+
+      /* Now get rid of trailing newline */
+
+      pnt1 = pnt;
+      while (*pnt1)
+       {
+         if (*pnt1 == '\n')
+           {
+             *pnt1 = 0;
+             break;
+           }
+         pnt1++;
+       };
+      /* OK, now figure out which option we have */
+      for(rco = rcopt; rco->tag; rco++) {
+       if(strcmp(rco->tag, name) == 0)
+         {
+           *rco->variable = strdup(pnt);
+           break;
+         };
+      }
+      if (rco->tag == NULL)
+       {
+         fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum,
+                 name);
+       }
+     }
+  if (ferror(rcfile))
+    perror(filename);
+  fclose(rcfile);
+}
+
+char * path_table_l = NULL;
+char * path_table_m = NULL;
+int goof = 0;
+
+void usage(){
+       fprintf(stderr,"Usage:\n");
+       fprintf(stderr,
+"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
+[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]"
+#ifdef ADD_FILES
+"[-i file] \n"
+#endif
+"[-P publisher] [ -A app_id ] [-z] \n \
+[-b boot_image_name] [-c boot_catalog-name] \
+[-x path -x path ...] path\n");
+       exit(1);
+}
+
+
+/* 
+ * Fill in date in the iso9660 format 
+ *
+ * The standards  state that the timezone offset is in multiples of 15
+ * minutes, and is what you add to GMT to get the localtime.  The U.S.
+ * is always at a negative offset, from -5h to -8h (can vary a little
+ * with DST,  I guess).  The Linux iso9660 filesystem has had the sign
+ * of this wrong for ages (mkisofs had it wrong too for the longest time).
+ */
+int FDECL2(iso9660_date,char *, result, time_t, ctime){
+  struct tm *local;
+  local = localtime(&ctime);
+  result[0] = local->tm_year;
+  result[1] = local->tm_mon + 1;
+  result[2] = local->tm_mday;
+  result[3] = local->tm_hour;
+  result[4] = local->tm_min;
+  result[5] = local->tm_sec;
+
+  /* 
+   * Must recalculate proper timezone offset each time,
+   * as some files use daylight savings time and some don't... 
+   */
+  result[6] = local->tm_yday;  /* save yday 'cause gmtime zaps it */
+  local = gmtime(&ctime);
+  local->tm_year -= result[0];
+  local->tm_yday -= result[6];
+  local->tm_hour -= result[3];
+  local->tm_min -= result[4];
+  if (local->tm_year < 0) 
+    {
+      local->tm_yday = -1;
+    }
+  else 
+    {
+      if (local->tm_year > 0) local->tm_yday = 1;
+    }
+
+  result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15;
+
+  return 0;
+}
+
+
+extern char * cdwrite_data;
+
+int FDECL2(main, int, argc, char **, argv){
+  char * outfile;
+  struct directory_entry de;
+  unsigned long mem_start;
+  struct stat statbuf;
+  char * scan_tree;
+  char * merge_image = NULL;
+  struct iso_directory_record * mrootp = NULL;
+  int c;
+#ifdef ADD_FILES
+  char *add_file_file = NULL;
+#endif
+
+  if (argc < 2)
+    usage();
+
+  /* Get the defaults from the .mkisofsrc file */
+  read_rcfile(argv[0]);
+
+  outfile = NULL;
+  while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF)
+    switch (c)
+      {
+      case 'C':
+       /*
+        * This is a temporary hack until cdwrite gets the proper hooks in
+        * it.
+        */
+       cdwrite_data = optarg;
+       break;
+      case 'a':
+       all_files++;
+       break;
+      case 'b':
+       use_eltorito++;
+       boot_image = optarg;  /* pathname of the boot image on cd */
+       if (boot_image == NULL) {
+               fprintf(stderr,"Required boot image pathname missing\n");
+               exit(1);
+       }
+       break;
+      case 'c':
+       use_eltorito++;
+       boot_catalog = optarg;  /* pathname of the boot image on cd */
+       if (boot_catalog == NULL) {
+               fprintf(stderr,"Required boot catalog pathname missing\n");
+               exit(1);
+       }
+       break;
+      case 'A':
+       appid = optarg;
+       if(strlen(appid) > 128) {
+               fprintf(stderr,"Application-id string too long\n");
+               exit(1);
+       };
+       break;
+      case 'd':
+       omit_period++;
+       break;
+      case 'D':
+       RR_relocation_depth = 32767;
+       break;
+      case 'f':
+       follow_links++;
+       break;
+      case 'i':
+#ifdef ADD_FILES
+       add_file_file = optarg;
+       break;
+#else
+       usage();
+       exit(1);
+#endif
+      case 'l':
+       full_iso9660_filenames++;
+       break;
+      case 'L':
+        allow_leading_dots++;
+        break;
+      case 'M':
+       merge_image = optarg;
+       break;
+      case 'N':
+       omit_version_number++;
+       break;
+      case 'o':
+       outfile = optarg;
+       break;
+      case 'p':
+       preparer = optarg;
+       if(strlen(preparer) > 128) {
+               fprintf(stderr,"Preparer string too long\n");
+               exit(1);
+       };
+       break;
+      case 'P':
+       publisher = optarg;
+       if(strlen(publisher) > 128) {
+               fprintf(stderr,"Publisher string too long\n");
+               exit(1);
+       };
+       break;
+      case 'R':
+       use_RockRidge++;
+       break;
+      case 'r':
+       rationalize++;
+       use_RockRidge++;
+       break;
+      case 'T':
+       generate_tables++;
+       break;
+      case 'V':
+       volume_id = optarg;
+       break;
+      case 'v':
+       verbose++;
+       break;
+      case 'z':
+#ifdef VMS
+       fprintf(stderr,"Transparent compression not supported with VMS\n");
+       exit(1);
+#else
+       transparent_compression++;
+#endif
+       break;
+      case 'm':
+        add_match(optarg);
+       break;
+      case 'x':
+        exclude(optarg);
+       break;
+      default:
+       usage();
+       exit(1);
+      }
+#ifdef __NetBSD__
+    {
+       int resource;
+    struct rlimit rlp;
+       if (getrlimit(RLIMIT_DATA,&rlp) == -1) 
+               perror("Warning: getrlimit");
+       else {
+               rlp.rlim_cur=33554432;
+               if (setrlimit(RLIMIT_DATA,&rlp) == -1)
+                       perror("Warning: setrlimit");
+               }
+       }
+#endif
+#ifdef HAVE_SBRK
+  mem_start = (unsigned long) sbrk(0);
+#endif
+
+  if(verbose) fprintf(stderr,"%s\n", version_string);
+
+  if(     (cdwrite_data != NULL && merge_image == NULL)
+       || (cdwrite_data == NULL && merge_image != NULL) )
+    {
+      fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n");
+      exit(0);
+    }
+
+  /*  The first step is to scan the directory tree, and take some notes */
+
+  scan_tree = argv[optind];
+
+#ifdef ADD_FILES
+  if (add_file_file) {
+    add_file(add_file_file);
+  }
+  add_file_list (argc, argv, optind+1);
+#endif
+
+  if(!scan_tree){
+         usage();
+         exit(1);
+  };
+
+#ifndef VMS
+  if(scan_tree[strlen(scan_tree)-1] != '/') {
+    scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
+    strcpy(scan_tree, argv[optind]);
+    strcat(scan_tree, "/");
+  };
+#endif
+
+  if(use_RockRidge){
+#if 1
+       extension_record = generate_rr_extension_record("RRIP_1991A",
+                                      "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
+                                      "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
+#else
+       extension_record = generate_rr_extension_record("IEEE_P1282",
+                                      "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
+                                      "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
+#endif
+  }
+
+  /*
+   * See if boot catalog file exists in root directory, if not
+   * we will create it.
+   */
+  if (use_eltorito)
+    init_boot_catalog(argv[optind]);
+
+  /*
+   * Find the device and inode number of the root directory.
+   * Record this in the hash table so we don't scan it more than
+   * once.
+   */
+  stat_filter(argv[optind], &statbuf);
+  add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
+
+  memset(&de, 0, sizeof(de));
+
+  de.filedir = root;  /* We need this to bootstrap */
+
+  if( merge_image != NULL )
+    {
+      mrootp = merge_isofs(merge_image);
+      if( mrootp == NULL )
+       {
+         /*
+          * Complain and die.
+          */
+         fprintf(stderr,"Unable to open previous session image %s\n",
+                 merge_image);
+         exit(1);
+       }
+
+      memcpy(&de.isorec.extent, mrootp->extent, 8);      
+    }
+
+  /*
+   * Scan the actual directory (and any we find below it)
+   * for files to write out to the output image.
+   */
+  if (!scan_directory_tree(argv[optind], &de, mrootp))
+    {
+      exit(1);
+    }
+
+  /*
+   * Fix a couple of things in the root directory so that everything
+   * is self consistent.
+   */
+  root->self = root->contents;  /* Fix this up so that the path tables get done right */
+
+  if(reloc_dir) sort_n_finish(reloc_dir);
+
+  if (goof) exit(1);
+  
+  /*
+   * OK, ready to write the file.  Open it up, and generate the thing.
+   */
+  if (outfile){
+         discimage = fopen(outfile, "w");
+         if (!discimage){
+                 fprintf(stderr,"Unable to open disc image file\n");
+                 exit(1);
+
+         };
+  } else
+         discimage =  stdout;
+
+  /* Now assign addresses on the disc for the path table. */
+
+  path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
+  if (path_blocks & 1) path_blocks++;
+
+  path_table[0] = session_start + 0x10 + 2 + (use_eltorito ? 1 : 0);
+  path_table[1] = 0;
+  path_table[2] = path_table[0] + path_blocks;
+  path_table[3] = 0;
+
+  last_extent += path_table[2] - session_start + path_blocks;  
+               /* The next free block */
+
+  /* The next step is to go through the directory tree and assign extent
+     numbers for all of the directories */
+
+  assign_directory_addresses(root);
+
+  if(extension_record) {
+         struct directory_entry * s_entry;
+         extension_record_extent = last_extent++;
+         s_entry = root->contents;
+         set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
+                 extension_record_extent);
+         set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
+                 extension_record_size);
+  };
+
+  if (use_RockRidge && reloc_dir)
+         finish_cl_pl_entries();
+
+  /* Now we generate the path tables that are used by DOS to improve directory
+     access times. */
+  generate_path_tables();
+
+  /* Generate root record for volume descriptor. */
+  generate_root_record();
+
+  if (verbose)
+    dump_tree(root);
+
+  if( in_image != NULL )
+    {
+      fclose(in_image);
+    }
+
+  iso_write(discimage);
+
+#ifdef HAVE_SBRK
+  fprintf(stderr,"Max brk space used %x\n", 
+         (unsigned int)(((unsigned long)sbrk(0)) - mem_start));
+#endif
+  fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
+#ifdef VMS
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+void *
+FDECL1(e_malloc, size_t, size)
+{
+void* pt = 0;
+       if( (size > 0) && ((pt=malloc(size))==NULL) ) {
+               fprintf(stderr, "Not enough memory\n");
+               exit (1);
+               }
+return pt;
+}
diff --git a/util/mkisofs/mkisofs.h b/util/mkisofs/mkisofs.h
new file mode 100644 (file)
index 0000000..bc264d9
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Header file mkisofs.h - assorted structure definitions and typecasts.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+/*
+ *     $Id: mkisofs.h,v 1.5 1997/05/17 15:50:28 eric Exp $
+ */
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdio.h>
+
+/* This symbol is used to indicate that we do not have things like
+   symlinks, devices, and so forth available.  Just files and dirs */
+
+#ifdef VMS
+#define NON_UNIXFS
+#endif
+
+#ifdef DJGPP
+#define NON_UNIXFS
+#endif
+
+#ifdef VMS
+#include <sys/dir.h>
+#define dirent direct
+#else
+#include <dirent.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef linux
+#include <sys/dir.h>
+#endif
+
+#ifdef ultrix
+extern char *strdup();
+#endif
+
+#ifdef __STDC__
+#define DECL(NAME,ARGS) NAME ARGS
+#define FDECL1(NAME,TYPE0, ARG0) \
+       NAME(TYPE0 ARG0)
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \
+       NAME(TYPE0 ARG0, TYPE1 ARG1)
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+       NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2)
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+       NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3)
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+       NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4)
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+       NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5)
+#else
+#define DECL(NAME,ARGS) NAME()
+#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0;
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1;
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+       NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2;
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+       NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3;
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+       NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4;
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+       NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5;
+#define const
+#endif
+
+
+#ifdef __svr4__
+#include <stdlib.h>
+#else
+extern int optind;
+extern char *optarg;
+/* extern int getopt (int __argc, char **__argv, char *__optstring); */
+#endif
+
+#include "iso9660.h"
+#include "defaults.h"
+
+struct directory_entry{
+  struct directory_entry * next;
+  struct iso_directory_record isorec;
+  unsigned int starting_block;
+  unsigned int size;
+  unsigned int priority;
+  char * name;
+  char * table;
+  char * whole_name;
+  struct directory * filedir;
+  struct directory_entry * parent_rec;
+  unsigned int de_flags;
+  ino_t inode;  /* Used in the hash table */
+  dev_t dev;  /* Used in the hash table */
+  unsigned char * rr_attributes;
+  unsigned int rr_attr_size;
+  unsigned int total_rr_attr_size;
+};
+
+struct file_hash{
+  struct file_hash * next;
+  ino_t inode;  /* Used in the hash table */
+  dev_t dev;  /* Used in the hash table */
+  unsigned int starting_block;
+  unsigned int size;
+};
+  
+/* 
+ * This structure describes one complete directory.  It has pointers
+ * to other directories in the overall tree so that it is clear where
+ * this directory lives in the tree, and it also must contain pointers
+ * to the contents of the directory.  Note that subdirectories of this
+ * directory exist twice in this stucture.  Once in the subdir chain,
+ * and again in the contents chain.
+ */
+struct directory{
+  struct directory * next;  /* Next directory at same level as this one */
+  struct directory * subdir; /* First subdirectory in this directory */
+  struct directory * parent;
+  struct directory_entry * contents;
+  struct directory_entry * self;
+  char * whole_name;  /* Entire path */
+  char * de_name;  /* Entire path */
+  unsigned int ce_bytes;  /* Number of bytes of CE entries reqd for this dir */
+  unsigned int depth;
+  unsigned int size;
+  unsigned int extent;
+  unsigned short path_index;
+};
+
+struct deferred{
+  struct deferred * next;
+  unsigned int starting_block;
+  char * name;
+  struct directory * filedir;
+  unsigned int flags;
+};
+
+extern int goof;
+extern struct directory * root;
+extern struct directory * reloc_dir;
+extern unsigned int next_extent;
+extern unsigned int last_extent;
+extern unsigned int last_extent_written;
+extern unsigned int session_start;
+extern unsigned int path_table_size;
+extern unsigned int path_table[4];
+extern unsigned int path_blocks;
+extern char * path_table_l;
+extern char * path_table_m;
+extern struct iso_directory_record root_record;
+
+extern int use_eltorito;
+extern int use_RockRidge;
+extern int rationalize;
+extern int follow_links;
+extern int verbose;
+extern int all_files;
+extern int generate_tables;
+extern int omit_period;
+extern int omit_version_number;
+extern int transparent_compression;
+extern int RR_relocation_depth;
+extern int full_iso9660_filenames;
+
+/* tree.c */
+extern int DECL(stat_filter, (char *, struct stat *));
+extern void DECL(sort_n_finish,(struct directory *));
+extern void finish_cl_pl_entries();
+extern int DECL(scan_directory_tree,(char * path, 
+                                    struct directory_entry * self,
+                                    struct iso_directory_record *));
+extern void DECL(generate_iso9660_directories,(struct directory *, FILE*));
+extern void DECL(dump_tree,(struct directory * node));
+extern struct directory_entry * DECL(search_tree_file, (struct 
+                               directory * node,char * filename));
+
+/* eltorito.c */
+extern void DECL(init_boot_catalog, (const char * path ));
+extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path ));
+
+/* write.c */
+extern void DECL(assign_directory_addresses,(struct directory * root));
+extern int DECL(get_733,(char *));
+extern int DECL(isonum_733,(unsigned char *));
+extern void DECL(set_723,(char *, unsigned int));
+extern void DECL(set_731,(char *, unsigned int));
+extern void DECL(set_721,(char *, unsigned int));
+extern void DECL(set_733,(char *, unsigned int));
+extern void DECL(sort_directory,(struct directory_entry **));
+extern void generate_root_record();
+extern void DECL(generate_one_directory,(struct directory *, FILE*));
+extern void generate_path_tables();
+extern int DECL(iso_write,(FILE * outfile));
+extern void DECL(memcpy_max, (char *, char *, int));
+
+
+/* multi.c */
+
+extern FILE * in_image;
+extern struct iso_directory_record *
+       DECL(merge_isofs,(char * path)); 
+
+extern int DECL(free_mdinfo, (struct directory_entry **, int len));
+
+extern struct directory_entry ** 
+       DECL(read_merging_directory,(struct iso_directory_record *, int*));
+extern void 
+       DECL(merge_remaining_entries, (struct directory *, 
+                                      struct directory_entry **, int));
+
+/* match.c */
+extern int DECL(matches, (char *));
+extern void DECL(add_match, (char *));
+
+/* files.c */
+struct dirent * DECL(readdir_add_files, (char **, char *, DIR *));
+
+/* */
+
+extern int DECL(iso9660_file_length,(const char* name, 
+                              struct directory_entry * sresult, int flag));
+extern int DECL(iso9660_date,(char *, time_t));
+extern void DECL(add_hash,(struct directory_entry *));
+extern struct file_hash * DECL(find_hash,(dev_t, ino_t));
+extern void DECL(add_directory_hash,(dev_t, ino_t));
+extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t));
+extern void flush_file_hash();
+extern int DECL(delete_file_hash,(struct directory_entry *));
+extern struct directory_entry * DECL(find_file_hash,(char *));
+extern void DECL(add_file_hash,(struct directory_entry *));
+extern int DECL(generate_rock_ridge_attributes,(char *, char *,
+                                         struct directory_entry *, 
+                                         struct stat *, struct stat *,
+                                         int  deep_flag));
+extern char * DECL(generate_rr_extension_record,(char * id,  char  * descriptor,
+                                   char * source, int  * size));
+
+extern int    DECL(check_prev_session, (struct directory_entry **, int len,
+                                    struct directory_entry *,
+                                    struct stat *,
+                                    struct stat *,
+                                    struct directory_entry **));
+
+#ifdef USE_SCG
+/* scsi.c */
+extern int     readsecs(int startsecno, void *buffer, int sectorcount);
+extern int     scsidev_open(char *path);
+#endif
+
+extern char * extension_record;
+extern int extension_record_extent;
+extern int n_data_extents;
+
+/* These are a few goodies that can be specified on the command line, and  are
+   filled into the root record */
+
+extern char * preparer;
+extern char * publisher;
+extern char * copyright;
+extern char * biblio;
+extern char * abstract;
+extern char * appid;
+extern char * volset_id;
+extern char * system_id;
+extern char * volume_id;
+extern char * boot_catalog;
+extern char * boot_image;
+
+extern void * DECL(e_malloc,(size_t));
+
+
+#define SECTOR_SIZE (2048)
+#define ROUND_UP(X)    ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
+
+#define NEED_RE 1
+#define NEED_PL  2
+#define NEED_CL 4
+#define NEED_CE 8
+#define NEED_SP 16
+
+#define PREV_SESS_DEV (sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd)
+#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe)
+#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff)
+#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff)
+
+#ifdef VMS
+#define STAT_INODE(X) (X.st_ino[0])
+#define PATH_SEPARATOR ']'
+#define SPATH_SEPARATOR ""
+#else
+#define STAT_INODE(X) (X.st_ino)
+#define PATH_SEPARATOR '/'
+#define SPATH_SEPARATOR "/"
+#endif
+
+/*
+ * When using multi-session, indicates that we can reuse the
+ * TRANS.TBL information for this directory entry.  If this flag
+ * is set for all entries in a directory, it means we can just
+ * reuse the TRANS.TBL and not generate a new one.
+ */
+#define SAFE_TO_REUSE_TABLE_ENTRY  1
+/*
+ * Volume sequence number to use in all of the iso directory records.
+ */
+#define DEF_VSN                1
+
+/*
+ * Make sure we have a definition for this.  If not, take a very conservative
+ * guess.  From what I can tell SunOS is the only one with this trouble.
+ */
+#ifndef NAME_MAX
+#ifdef FILENAME_MAX
+#define NAME_MAX       FILENAME_MAX
+#else
+#define NAME_MAX       128
+#endif
+#endif
diff --git a/util/mkisofs/multi.c b/util/mkisofs/multi.c
new file mode 100644 (file)
index 0000000..13ba6f6
--- /dev/null
@@ -0,0 +1,1018 @@
+/*
+ * File multi.c - scan existing iso9660 image and merge into 
+ * iso9660 filesystem.  Used for multisession support.
+ *
+ * Written by Eric Youngdale (1996).
+ *
+ * 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.  
+ */
+
+static char rcsid[] ="$Id: multi.c,v 1.6.1.3 1998/06/02 03:00:25 eric Exp $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifndef VMS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#define TF_CREATE 1
+#define TF_MODIFY 2
+#define TF_ACCESS 4
+#define TF_ATTRIBUTES 8
+
+static int  DECL(get_session_start, (int *));
+static int  DECL(merge_old_directory_into_tree, (struct directory_entry *,
+                                                struct directory *));
+
+static int
+isonum_711 (unsigned char * p)
+{
+       return (*p & 0xff);
+}
+
+int
+isonum_721 (unsigned char * p)
+{
+       return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
+}
+
+static int
+isonum_723 (unsigned char * p)
+{
+#if 0
+       if (p[0] != p[3] || p[1] != p[2]) {
+               fprintf (stderr, "invalid format 7.2.3 number\n");
+               exit (1);
+       }
+#endif
+       return (isonum_721 (p));
+}
+
+int
+isonum_731 (unsigned char * p)
+{
+       return ((p[0] & 0xff)
+               | ((p[1] & 0xff) << 8)
+               | ((p[2] & 0xff) << 16)
+               | ((p[3] & 0xff) << 24));
+}
+
+int
+isonum_733 (unsigned char * p)
+{
+       return (isonum_731 (p));
+}
+
+FILE * in_image = NULL;
+
+#ifndef        USE_SCG
+/*
+ * Don't define readsecs if mkisofs is linked with
+ * the SCSI library.
+ * readsecs() will be implemented as SCSI command in this case.
+ *
+ * Use global var in_image directly in readsecs()
+ * the SCSI equivalent will not use a FILE* for I/O.
+ *
+ * The main point of this pointless abstraction is that Solaris won't let
+ * you read 2K sectors from the cdrom driver.  The fact that 99.9% of the
+ * discs out there have a 2K sectorsize doesn't seem to matter that much.
+ * Anyways, this allows the use of a scsi-generics type of interface on
+ * Solaris.
+ */
+static int
+readsecs(int startsecno, void *buffer, int sectorcount)
+{
+       int     f = fileno(in_image);
+
+       if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) {
+               fprintf(stderr," Seek error on old image\n");
+               exit(10);
+       }
+       return (read(f, buffer, sectorcount * SECTOR_SIZE));
+}
+#endif
+
+/*
+ * Parse the RR attributes so we can find the file name.
+ */
+static int 
+FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
+{
+       int cont_extent, cont_offset, cont_size;
+       char name_buf[256];
+
+       cont_extent = cont_offset = cont_size = 0;
+
+       while(len >= 4){
+               if(pnt[3] != 1) {
+                 printf("**BAD RRVERSION");
+                 return -1;
+               };
+               if(strncmp((char *) pnt, "NM", 2) == 0) {
+                 strncpy(name_buf, (char *) pnt+5, pnt[2] - 5);
+                 name_buf[pnt[2] - 5] = 0;
+                 dpnt->name = strdup(name_buf);
+                 return 0;
+               }
+
+               if(strncmp((char *) pnt, "CE", 2) == 0) {
+                       cont_extent = isonum_733(pnt+4);
+                       cont_offset = isonum_733(pnt+12);
+                       cont_size = isonum_733(pnt+20);
+               };
+
+               len -= pnt[2];
+               pnt += pnt[2];
+               if(len <= 3 && cont_extent) {
+                 unsigned char sector[SECTOR_SIZE];
+                 readsecs(cont_extent, sector, 1);
+                 parse_rr(&sector[cont_offset], cont_size, dpnt);
+               };
+       };
+       return 0;
+}
+
+
+static int 
+FDECL4(check_rr_dates, struct directory_entry *, dpnt, 
+       struct directory_entry *, current, 
+       struct stat *, statbuf, 
+       struct stat *,lstatbuf)
+{
+       int cont_extent, cont_offset, cont_size;
+       int offset;
+       unsigned char * pnt;
+       int len;
+       int same_file;
+       int same_file_type;
+       mode_t mode;
+       char time_buf[7];
+       
+       
+       cont_extent = cont_offset = cont_size = 0;
+       same_file = 1;
+       same_file_type = 1;
+
+       pnt = dpnt->rr_attributes;
+       len = dpnt->rr_attr_size;
+       /*
+        * We basically need to parse the rr attributes again, and
+        * dig out the dates and file types.
+        */
+       while(len >= 4){
+               if(pnt[3] != 1) {
+                 printf("**BAD RRVERSION");
+                 return -1;
+               };
+
+               /*
+                * If we have POSIX file modes, make sure that the file type
+                * is the same.  If it isn't, then we must always
+                * write the new file.
+                */
+               if(strncmp((char *) pnt, "PX", 2) == 0) {
+                 mode = isonum_733(pnt + 4);
+                 if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) )
+                   {
+                     same_file_type = 0;
+                     same_file = 0;
+                   }
+               }
+
+               if(strncmp((char *) pnt, "TF", 2) == 0) {
+                 offset = 5;
+                 if( pnt[4] & TF_CREATE )
+                   {
+                     iso9660_date((char *) time_buf, lstatbuf->st_ctime);
+                     if(memcmp(time_buf, pnt+offset, 7) == 0) 
+                       same_file = 0;
+                     offset += 7;
+                   }
+                 if( pnt[4] & TF_MODIFY )
+                   {
+                     iso9660_date((char *) time_buf, lstatbuf->st_mtime);
+                     if(memcmp(time_buf, pnt+offset, 7) == 0) 
+                       same_file = 0;
+                     offset += 7;
+                   }
+               }
+
+               if(strncmp((char *) pnt, "CE", 2) == 0) {
+                       cont_extent = isonum_733(pnt+4);
+                       cont_offset = isonum_733(pnt+12);
+                       cont_size = isonum_733(pnt+20);
+               };
+
+               len -= pnt[2];
+               pnt += pnt[2];
+               if(len <= 3 && cont_extent) {
+                 unsigned char sector[SECTOR_SIZE];
+
+                 readsecs(cont_extent, sector, 1);
+                 parse_rr(&sector[cont_offset], cont_size, dpnt);
+               };
+       };
+
+       /*
+        * If we have the same fundamental file type, then it is clearly
+        * safe to reuse the TRANS.TBL entry.
+        */
+       if( same_file_type )
+         {
+           current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+         }
+
+       return same_file;
+}
+
+struct directory_entry **
+FDECL2(read_merging_directory, struct iso_directory_record *, mrootp,
+       int *, nent)
+{
+  unsigned char                        * cpnt;
+  unsigned char                        * cpnt1;
+  char                         * dirbuff;
+  int                            i;
+  struct iso_directory_record  * idr;
+  int                            len;
+  struct directory_entry       **pnt;
+  int                            rlen;
+  struct directory_entry       **rtn;
+  int                            seen_rockridge;
+  unsigned char                        * tt_buf;
+  int                            tt_extent;
+  int                            tt_size;
+
+  /*
+   * First, allocate a buffer large enough to read in the entire
+   * directory.
+   */
+  dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size));
+
+  readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff,
+          isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE);
+
+  /*
+   * Next look over the directory, and count up how many entries we
+   * have.
+   */
+  len = isonum_733((unsigned char *)mrootp->size);
+  i = 0;
+  *nent = 0;
+  while(i < len )
+    {
+      idr = (struct iso_directory_record *) &dirbuff[i];
+      if(idr->length[0] == 0) 
+       {
+         i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
+         continue;
+       }
+      (*nent)++;
+      i += idr->length[0];
+    }
+
+  /*
+   * Now allocate the buffer which will hold the array we are
+   * about to return.
+   */
+  rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn));
+
+  /*
+   * Finally, scan the directory one last time, and pick out the
+   * relevant bits of information, and store it in the relevant
+   * bits of the structure.
+   */
+  i = 0;
+  pnt = rtn;
+  tt_extent = 0;
+  seen_rockridge = 0;
+  tt_size = 0;
+  while(i < len )
+    {
+      idr = (struct iso_directory_record *) &dirbuff[i];
+      if(idr->length[0] == 0) 
+       {
+         i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1);
+         continue;
+       }
+      *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn));
+      (*pnt)->next = NULL;
+      (*pnt)->isorec = *idr;
+      (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent);
+      (*pnt)->size = isonum_733((unsigned char *)idr->size);
+      (*pnt)->priority = 0;
+      (*pnt)->name = NULL;
+      (*pnt)->table = NULL;
+      (*pnt)->whole_name = NULL;
+      (*pnt)->filedir = NULL;
+      (*pnt)->parent_rec = NULL;
+      /*
+       * Set this information so that we correctly cache previous
+       * session bits of information.
+       */
+      (*pnt)->inode = (*pnt)->starting_block;
+      (*pnt)->dev = PREV_SESS_DEV;
+      (*pnt)->rr_attributes = NULL;
+      (*pnt)->rr_attr_size = 0;
+      (*pnt)->total_rr_attr_size = 0;
+      (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY;
+
+      /*
+       * Check for and parse any RR attributes for the file.
+       * All we are really looking for here is the original name
+       * of the file.
+       */
+      rlen = idr->length[0] & 0xff;
+      cpnt = (unsigned char *) idr;
+      
+      rlen -= sizeof(struct iso_directory_record);
+      cpnt += sizeof(struct iso_directory_record);
+      
+      rlen += sizeof(idr->name);
+      cpnt -= sizeof(idr->name);
+      
+      rlen -= idr->name_len[0];
+      cpnt += idr->name_len[0];
+      
+      if((idr->name_len[0] & 1) == 0){
+       cpnt++;
+       rlen--;
+      };
+
+      if( rlen != 0 )
+       {
+         (*pnt)->total_rr_attr_size =  (*pnt)->rr_attr_size = rlen;
+         (*pnt)->rr_attributes = e_malloc(rlen);
+         memcpy((*pnt)->rr_attributes,  cpnt, rlen);
+         seen_rockridge = 1;
+       }
+
+      /*
+       * Now zero out the remainder of the name field.
+       */
+      cpnt = (unsigned char *) &(*pnt)->isorec.name;
+      cpnt += idr->name_len[0];
+      memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]);
+
+      parse_rr((*pnt)->rr_attributes, rlen, *pnt);
+      
+      if(    ((*pnt)->isorec.name_len[0] == 1)
+         && (    ((*pnt)->isorec.name[0] == 0)
+              || ((*pnt)->isorec.name[0] == 1)) )
+       {
+         if( (*pnt)->name != NULL )
+           {
+             free((*pnt)->name);
+           }
+         if( (*pnt)->whole_name != NULL )
+           {
+             free((*pnt)->whole_name);
+           }
+         if( (*pnt)->isorec.name[0] == 0 )
+           {
+             (*pnt)->name = strdup(".");
+           }
+         else
+           {
+             (*pnt)->name = strdup("..");
+           }
+       }
+
+      if( strncmp(idr->name, "TRANS.TBL", 9) == 0)
+       {
+         if( (*pnt)->name != NULL )
+           {
+             free((*pnt)->name);
+           }
+         if( (*pnt)->whole_name != NULL )
+           {
+             free((*pnt)->whole_name);
+           }
+         (*pnt)->name = strdup("<translation table>");
+         tt_extent = isonum_733((unsigned char *)idr->extent);
+         tt_size = isonum_733((unsigned char *)idr->size);
+       }
+      
+      pnt++;
+      i += idr->length[0];
+    }
+
+  /*
+   * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
+   * to get the filenames of the files.  Also, save the table info, just
+   * in case we need to use it.
+   */
+  if( tt_extent != 0 && tt_size != 0 )
+    {
+      tt_buf = (unsigned char *) e_malloc(tt_size);
+      readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE);
+
+      /*
+       * Loop through the file, examine each entry, and attempt to
+       * attach it to the correct entry.
+       */
+      cpnt = tt_buf;
+      cpnt1 = tt_buf;
+      while( cpnt - tt_buf < tt_size )
+       {
+         while(*cpnt1 != '\n' && *cpnt1 != '\0')  cpnt1++;
+         *cpnt1 = '\0';
+
+         for(pnt = rtn, i = 0; i <*nent; i++, pnt++)
+           {
+             rlen = isonum_711((*pnt)->isorec.name_len);
+             if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name,
+                         rlen) == 0 
+                 && cpnt[2+rlen] == ' ')
+               {
+                 (*pnt)->table = e_malloc(strlen((char*)cpnt) - 34);
+                 sprintf((*pnt)->table, "%c\t%s\n",
+                         *cpnt, cpnt+37);
+                 if( (*pnt)->name == NULL )
+                   {
+                     (*pnt)->name = strdup((char *) cpnt+37);
+                   }
+                 break;
+               }
+           }
+         cpnt = cpnt1 + 1;
+         cpnt1 = cpnt;
+       }
+      
+      free(tt_buf);
+    }
+  else if( !seen_rockridge )
+    {
+      /*
+       * This is a fatal error right now because we must have some mechanism
+       * for taking the 8.3 names back to the original unix names.
+       * In principle we could do this the hard way, and try and translate
+       * the unix names that we have seen forwards, but this would be
+       * a real pain in the butt.
+       */
+      fprintf(stderr,"Previous session must have either Rock Ridge (-R) or\n");
+      fprintf(stderr,"TRANS.TBL (-T) for mkisofs to be able to correctly\n");
+      fprintf(stderr,"generate additional sessions.\n");
+      exit(3);
+    }
+
+  if( dirbuff != NULL )
+    {
+      free(dirbuff);
+    }
+  
+  return rtn;
+}
+
+/*
+ * Free any associated data related to the structures.
+ */
+int 
+FDECL2(free_mdinfo, struct directory_entry **  , ptr, int, len )
+{
+  int          i;
+  struct directory_entry **p;
+
+  p = ptr;
+  for(i=0; i<len; i++, p++)
+    {
+      /*
+       * If the tree-handling code decided that it needed an entry,
+       * it will have removed it from the list.  Thus we must allow
+       * for null pointers here.
+       */
+      if( *p == NULL )
+       {
+         continue;
+       }
+
+      if( (*p)->name != NULL )
+       {
+         free((*p)->name);
+       }
+
+      if( (*p)->whole_name != NULL )
+       {
+         free((*p)->whole_name);
+       }
+
+      if( (*p)->rr_attributes != NULL )
+       {
+         free((*p)->rr_attributes);
+       }
+
+      if( (*p)->table != NULL )
+       {
+         free((*p)->table);
+       }
+
+      free(*p);
+
+    }
+
+  free(ptr);
+  return 0;
+}
+
+/*
+ * Search the list to see if we have any entries from the previous
+ * session that match this entry.  If so, copy the extent number
+ * over so we don't bother to write it out to the new session.
+ */
+
+int
+FDECL6(check_prev_session, struct directory_entry **  , ptr, int, len,
+       struct directory_entry *, curr_entry,
+       struct stat *, statbuf, struct stat *, lstatbuf,
+       struct directory_entry **, odpnt)
+{
+  int          i;
+
+  for( i=0; i < len; i++ )
+    {
+      if( ptr[i] == NULL )
+       {
+         continue;
+       }
+
+#if 0
+      if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+         && ptr[i]->name[0] == '\0' )
+       {
+         continue;
+       }
+      if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+         && ptr[i]->name[0] == 1)
+       {
+         continue;
+       }
+#else
+      if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 )
+       {
+         continue;
+       }
+      if( ptr[i]->name != NULL  && strcmp(ptr[i]->name, "..") == 0 )
+       {
+         continue;
+       }
+#endif
+
+      if(    ptr[i]->name != NULL
+         && strcmp(ptr[i]->name, curr_entry->name) != 0 )
+       {
+         continue;
+       }
+
+      /*
+       * We know that the files have the same name.  If they also have
+       * the same file type (i.e. file, dir, block, etc), then we
+       * can safely reuse the TRANS.TBL entry for this file.
+       * The check_rr_dates function will do this for us.
+       *
+       * Verify that the file type and dates are consistent.
+       * If not, we probably have a different file, and we need
+       * to write it out again.
+       */
+      if(    (ptr[i]->rr_attributes != NULL)
+         && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) )
+       {
+         goto found_it;
+       }
+
+
+      /*
+       * Verify size and timestamp.  If rock ridge is in use, we need
+       * to compare dates from RR too.  Directories are special, we
+       * calculate their size later.
+       */
+      if(     (curr_entry->isorec.flags[0] & 2) == 0
+         &&  ptr[i]->size != curr_entry->size )
+       {
+         goto found_it;
+       }
+
+      if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 )
+       {
+         goto found_it;
+       }
+
+      /*
+       * Never ever reuse directory extents.  See comments in
+       * tree.c for an explaination of why this must be the case.
+       */
+      if( (curr_entry->isorec.flags[0] & 2) != 0 )
+       {
+         goto found_it;
+       }
+
+      memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
+      curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+      goto found_it;
+    }
+  return 0;
+
+found_it:
+  if( odpnt != NULL )
+    {
+      *odpnt = ptr[i];
+    }
+  else
+    {
+      free(ptr[i]);
+    }
+  ptr[i] = NULL;
+  return 0;
+}
+
+/*
+ * merge_isofs:  Scan an existing image, and return a pointer
+ * to the root directory for this image.
+ */
+struct iso_directory_record * FDECL1(merge_isofs, char *, path)
+{
+  char                           buffer[SECTOR_SIZE];
+  int                            file_addr;
+  int                            i;
+  struct iso_primary_descriptor * pri = NULL;
+  struct iso_directory_record   * rootp;
+  struct iso_volume_descriptor  * vdp;
+
+  /*
+   * Start by opening up the image and searching for the volume header.
+   * Ultimately, we need to search for volume headers in multiple places
+   * because we might be starting with a multisession image.
+   * FIXME(eric).
+   */
+
+#ifndef        USE_SCG
+  in_image = fopen(path, "rb");
+  if( in_image == NULL )
+    {
+      return NULL;
+    }
+#else
+  if (strchr(path, '/')) {
+       in_image = fopen(path, "rb");
+       if( in_image == NULL ) {
+               return NULL;
+       }
+  } else {
+       if (scsidev_open(path) < 0)
+               return NULL;
+  }
+#endif
+
+  get_session_start(&file_addr);
+
+  for(i = 0; i< 100; i++)
+    {
+      if (readsecs(file_addr/SECTOR_SIZE, &buffer,
+                  sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer))
+       {
+         fprintf(stderr," Read error on old image %s\n", path);
+         exit(10);
+       }
+
+      vdp = (struct iso_volume_descriptor *)buffer;
+
+      if(    (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0)
+         && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) )
+       {
+         break;
+       }
+      file_addr += SECTOR_SIZE;
+    }
+
+  if( i == 100 )
+    {
+      return NULL;
+    }
+
+  pri = (struct iso_primary_descriptor *)vdp;
+
+  /*
+   * Check the blocksize of the image to make sure it is compatible.
+   */
+  if(    (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE)
+      || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) )
+    {
+      return NULL;
+    }
+
+  /*
+   * Get the location and size of the root directory.
+   */
+  rootp = (struct iso_directory_record *) 
+    malloc(sizeof(struct iso_directory_record));
+
+  memcpy(rootp, pri->root_directory_record, sizeof(*rootp));
+
+  return rootp;
+}
+
+void FDECL3(merge_remaining_entries, struct directory *, this_dir,
+           struct directory_entry **, pnt,
+           int, n_orig)
+{
+  int i;
+  struct directory_entry * s_entry;
+  unsigned int ttbl_extent = 0;
+  unsigned int ttbl_index  = 0;
+
+  /*
+   * Whatever is leftover in the list needs to get merged back
+   * into the directory.
+   */
+  for( i=0; i < n_orig; i++ )
+    {
+      if( pnt[i] == NULL )
+       {
+         continue;
+       }
+      
+      if( pnt[i]->name != NULL
+         && strcmp(pnt[i]->name, "<translation table>") == 0 )
+       {
+         ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent);
+         ttbl_index = i;
+         continue;
+       }
+      /*
+       * Skip directories for now - these need to be treated
+       * differently.
+       */
+      if( (pnt[i]->isorec.flags[0] & 2) != 0 )
+       {
+         /*
+          * FIXME - we need to insert this directory into the
+          * tree, so that the path tables we generate will
+          * be correct.
+          */
+         if(    (strcmp(pnt[i]->name, ".") == 0)
+             || (strcmp(pnt[i]->name, "..") == 0) )
+           {
+             free(pnt[i]);
+             pnt[i] = NULL;
+             continue;
+           }
+         else
+           {
+             merge_old_directory_into_tree(pnt[i], this_dir);
+           }
+       }
+      pnt[i]->next = this_dir->contents;
+      pnt[i]->filedir = this_dir;
+      this_dir->contents = pnt[i];
+      pnt[i] = NULL;
+    }
+  
+
+  /*
+   * If we don't have an entry for the translation table, then
+   * don't bother trying to copy the starting extent over.
+   * Note that it is possible that if we are copying the entire
+   * directory, the entry for the translation table will have already
+   * been inserted into the linked list and removed from the old
+   * entries list, in which case we want to leave the extent number
+   * as it was before.
+   */
+  if( ttbl_extent == 0 )
+    {
+      return;
+    }
+
+  /*
+   * Finally, check the directory we are creating to see whether
+   * there are any new entries in it.  If there are not, we can
+   * reuse the same translation table.
+   */
+  for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+    {
+      /*
+       * Don't care about '.' or '..'.  They are never in the table
+       * anyways.
+       */
+      if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 )
+       {
+         continue;
+       }
+      if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 )
+       {
+         continue;
+       }
+      if( strcmp(s_entry->name, "<translation table>") == 0)
+       {
+         continue;
+       }
+      if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 )
+       {
+         return;
+       }
+    }
+
+  /*
+   * Locate the translation table, and re-use the same extent.
+   * It isn't clear that there should ever be one in there already
+   * so for now we try and muddle through the best we can.
+   */
+  for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+    {
+      if( strcmp(s_entry->name, "<translation table>") == 0)
+       {
+         fprintf(stderr,"Should never get here\n");
+         set_733(s_entry->isorec.extent, ttbl_extent);
+         return;
+       }
+    }
+
+  pnt[ttbl_index]->next = this_dir->contents;
+  pnt[ttbl_index]->filedir = this_dir;
+  this_dir->contents = pnt[ttbl_index];
+  pnt[ttbl_index] = NULL;
+}
+
+
+/*
+ * Here we have a case of a directory that has completely disappeared from
+ * the face of the earth on the tree we are mastering from.  Go through and
+ * merge it into the tree, as well as everything beneath it.
+ *
+ * Note that if a directory has been moved for some reason, this will
+ * incorrectly pick it up and attempt to merge it back into the old
+ * location.  FIXME(eric).
+ */
+static int
+FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, 
+       struct directory *, parent)
+{
+  struct directory_entry       **contents = NULL;
+  int                            i;
+  int                            n_orig;
+  struct directory             * this_dir, *next_brother;
+  char                           whole_path[1024];
+
+  this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+  this_dir->next = NULL;
+  this_dir->subdir = NULL;
+  this_dir->self = dpnt;
+  this_dir->contents = NULL;
+  this_dir->size = 0;
+  this_dir->extent = 0;
+  this_dir->depth = parent->depth + 1;
+  this_dir->parent = parent;
+  if(!parent->subdir)
+    parent->subdir = this_dir;
+  else {
+    next_brother = parent->subdir;
+    while(next_brother->next) next_brother = next_brother->next;
+    next_brother->next = this_dir;
+  }
+
+  /*
+   * Set the name for this directory.
+   */
+  strcpy(whole_path, parent->de_name);
+  strcat(whole_path, SPATH_SEPARATOR);
+  strcat(whole_path, dpnt->name);
+  this_dir->de_name = strdup(whole_path);
+  this_dir->whole_name = strdup(whole_path);
+
+  /*
+   * Now fill this directory using information from the previous
+   * session.
+   */
+  contents = read_merging_directory(&dpnt->isorec, &n_orig);
+  /*
+   * Start by simply copying the '.', '..' and non-directory
+   * entries to this directory.  Technically we could let
+   * merge_remaining_entries handle this, but it gets rather confused
+   * by the '.' and '..' entries.
+   */
+  for(i=0; i < n_orig; i ++ )
+    {
+      /*
+       * We can always reuse the TRANS.TBL in this particular case.
+       */
+      contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;      
+
+      if(    ((contents[i]->isorec.flags[0] & 2) != 0)
+         && (i >= 2) )
+       {
+         continue;
+       }
+
+      /*
+       * If we have a directory, don't reuse the extent number.
+       */
+      if( (contents[i]->isorec.flags[0] & 2) != 0 )
+       {
+         memset(contents[i]->isorec.extent, 0, 8);
+       }
+
+      contents[i]->next = this_dir->contents;
+      contents[i]->filedir = this_dir;
+      this_dir->contents = contents[i];
+      contents[i] = NULL;
+    }
+
+  /*
+   * Zero the extent number for ourselves.
+   */
+  memset(dpnt->isorec.extent, 0, 8);
+
+  /*
+   * Anything that is left are other subdirectories that need to be merged.
+   */
+  merge_remaining_entries(this_dir, contents, n_orig);
+  free_mdinfo(contents, n_orig);
+  sort_n_finish(this_dir);
+
+  return 0;
+}
+
+
+char * cdwrite_data = NULL;
+
+static int
+FDECL1(get_session_start, int *, file_addr) 
+{
+  char * pnt;
+
+#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS
+  /*
+   * FIXME(eric).  We need to coordinate with cdwrite to obtain
+   * the parameters.  For now, we assume we are writing the 2nd session,
+   * so we start from the session that starts at 0.
+   */
+
+  *file_addr = (16 << 11);
+
+  /*
+   * We need to coordinate with cdwrite to get the next writable address
+   * from the device.  Here is where we use it.
+   */
+  session_start = last_extent = last_extent_written = cdwrite_result();
+
+#else
+
+  if( cdwrite_data == NULL )
+    {
+      fprintf(stderr,"Special parameters for cdwrite not specified with -C\n");
+      exit(1);
+    }
+
+  /*
+   * Next try and find the ',' in there which delimits the two numbers.
+   */
+  pnt = strchr(cdwrite_data, ',');
+  if( pnt == NULL )
+    {
+      fprintf(stderr, "Malformed cdwrite parameters\n");
+      exit(1);
+    }
+
+  *pnt = '\0';
+  *file_addr = atol(cdwrite_data) * SECTOR_SIZE;
+  pnt++;
+
+  session_start = last_extent = last_extent_written = atol(pnt);
+
+  pnt--;
+  *pnt = ',';
+
+#endif
+  return 0;
+}
+
diff --git a/util/mkisofs/name.c b/util/mkisofs/name.c
new file mode 100644 (file)
index 0000000..10475d4
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * File name.c - map full Unix file names to unique 8.3 names that
+ * would be valid on DOS.
+ *
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: name.c,v 1.7 1997/11/09 16:42:51 eric Exp $";
+
+#include "mkisofs.h"
+
+#include <ctype.h>
+
+extern int allow_leading_dots;
+   
+/*
+ * Function:   iso9660_file_length
+ *
+ * Purpose:    Map file name to 8.3 format, return length
+ *             of result.
+ *
+ * Arguments:  name    file name we need to map.
+ *             sresult directory entry structure to contain mapped name.
+ *             dirflag flag indicating whether this is a directory or not.
+ *
+ * Notes:      This procedure probably needs to be rationalized somehow.
+ *             New options to affect the behavior of this function
+ *             would also be nice to have.
+ */
+int FDECL3(iso9660_file_length,
+          const char*, name, 
+          struct directory_entry *, sresult, 
+          int, dirflag)
+{
+  char         * c;
+  int            chars_after_dot  = 0;
+  int            chars_before_dot = 0;
+  int            current_length   = 0;
+  int            extra            = 0;
+  int            ignore           = 0;
+  char         * last_dot;
+  const char   * pnt;
+  int            priority         = 32767;
+  char         * result;
+  int            seen_dot         = 0;
+  int            seen_semic       = 0;
+  int            tildes           = 0;
+
+  result = sresult->isorec.name;
+
+  /*
+   * For the '.' entry, generate the correct record, and return
+   * 1 for the length.
+   */
+  if(strcmp(name,".") == 0)
+    {
+      if(result) 
+       {
+         *result = 0;
+       }
+      return 1;
+    }
+
+  /*
+   * For the '..' entry, generate the correct record, and return
+   * 1 for the length.
+   */
+  if(strcmp(name,"..") == 0)
+    {
+      if(result) 
+       {
+         *result++ = 1;
+         *result++ = 0;
+       }
+      return 1;
+    }
+
+  /*
+   * Now scan the directory one character at a time, and figure out
+   * what to do.
+   */
+  pnt = name;
+
+  /*
+   * Find the '.' that we intend to use for the extension.  Usually this
+   * is the last dot, but if we have . followed by nothing or a ~, we
+   * would consider this to be unsatisfactory, and we keep searching.
+   */
+  last_dot = strrchr (pnt,'.');
+  if(    (last_dot != NULL)
+      && (    (last_dot[1] == '~')
+          || (last_dot[1] == '\0')
+          || (last_dot[1] == '\0')) )
+    {
+      c = last_dot;
+      *c = '\0';
+      last_dot = strrchr (pnt,'.');
+      *c = '.';
+    }
+
+  while(*pnt)
+    {
+#ifdef VMS
+      if( strcmp(pnt,".DIR;1") == 0 ) 
+       {
+         break;
+       }
+#endif
+
+      /*
+       * This character indicates a Unix style of backup file
+       * generated by some editors.  Lower the priority of
+       * the file.
+       */
+      if(*pnt == '#') 
+       {
+         priority = 1; 
+         pnt++; 
+         continue; 
+       }
+
+      /*
+       * This character indicates a Unix style of backup file
+       * generated by some editors.  Lower the priority of
+       * the file.
+       */
+      if(*pnt == '~') 
+       {
+         priority = 1; 
+         tildes++; 
+         pnt++; 
+         continue;
+       }
+
+      /*
+       * This might come up if we had some joker already try and put
+       * iso9660 version numbers into the file names.  This would be
+       * a silly thing to do on a Unix box, but we check for it
+       * anyways.  If we see this, then we don't have to add our
+       * own version number at the end.
+       */
+      if(*pnt == ';') 
+       {
+         seen_semic = 1; 
+         *result++ = *pnt++; 
+         continue; 
+       }
+
+      /*
+       * If we have a name with multiple '.' characters, we ignore everything
+       * after we have gotten the extension.
+       */
+      if(ignore) 
+       {
+         pnt++; 
+         continue;
+       }
+
+      /*
+       * Spin past any iso9660 version number we might have.
+       */
+      if(seen_semic)
+       {
+         if(*pnt >= '0' && *pnt <= '9') 
+           {
+             *result++ = *pnt;
+           }
+         extra++;
+         pnt++;
+         continue;
+       }
+
+       /*
+        * If we have full names, the names we generate will not
+        * work on a DOS machine, since they are not guaranteed
+        * to be 8.3.  Nonetheless, in many cases this is a useful
+        * option.  We still only allow one '.' character in the
+        * name, however.
+        */
+      if(full_iso9660_filenames) 
+       {
+         /* Here we allow a more relaxed syntax. */
+         if(*pnt == '.') 
+           {
+             if (seen_dot) 
+               {
+                 ignore++; 
+                 continue;
+               }
+             seen_dot++;
+           }
+         if(current_length < 30) 
+           {
+             if( *pnt < 0 )
+               {
+                 *result++ = '_';
+               }
+             else
+               {
+                 *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
+               }
+           }
+       }
+      else
+       { 
+         /* 
+          * Dos style filenames.  We really restrict the
+          * names here.
+          */
+         /* It would be nice to have .tar.gz transform to .tgz,
+          * .ps.gz to .psz, ...
+          */
+         if(*pnt == '.') 
+           {
+             if (!chars_before_dot && !allow_leading_dots) 
+               {
+                 /* DOS can't read files with dot first */
+                 chars_before_dot++;
+                 if (result) 
+                   {
+                     *result++ = '_'; /* Substitute underscore */
+                   }
+               }
+             else if( pnt != last_dot )
+               {
+                 /*
+                  * If this isn't the dot that we use for the extension,
+                  * then change the character into a '_' instead.
+                  */
+                 if(chars_before_dot < 8) 
+                   {
+                     chars_before_dot++;
+                     if(result) 
+                       {
+                         *result++ = '_';
+                       }
+                   }
+               }
+             else 
+               {
+                 if (seen_dot) 
+                   {
+                     ignore++; continue;
+                   }
+                 if(result) 
+                   {
+                     *result++ = '.';
+                   }
+                 seen_dot++;
+               }
+           }
+         else 
+           {
+             if(    (seen_dot && (chars_after_dot < 3) && ++chars_after_dot)
+                    || (!seen_dot && (chars_before_dot < 8) && ++chars_before_dot) )
+               {
+                 if(result) 
+                   {
+                     switch (*pnt) 
+                       {
+                       default:
+                         if( *pnt < 0 )
+                           {
+                             *result++ = '_';
+                           }
+                         else
+                           {
+                             *result++ = islower(*pnt) ? toupper(*pnt) : *pnt;
+                           }
+                         break;
+
+                       /* 
+                        * Descriptions of DOS's 'Parse Filename'
+                        * (function 29H) describes V1 and V2.0+
+                        * separator and terminator characters.
+                        * These characters in a DOS name make
+                        * the file visible but un-manipulable
+                        * (all useful operations error off.
+                        */
+                       /* separators */
+                       case '+':
+                       case '=':
+                       case '%': /* not legal DOS filename */
+                       case ':':
+                       case ';': /* already handled */
+                       case '.': /* already handled */
+                       case ',': /* already handled */
+                       case '\t':
+                       case ' ':
+                         /* V1 only separators */
+                       case '/':
+                       case '"':
+                       case '[':
+                       case ']':
+                         /* terminators */
+                       case '>':
+                       case '<':
+                       case '|':
+                         /* Hmm - what to do here?  Skip?
+                          * Win95 looks like it substitutes '_'
+                          */
+                         *result++ = '_';
+                         break;
+                       } /* switch (*pnt) */
+                   } /* if (result) */
+               } /* if (chars_{after,before}_dot) ... */
+           } /* else *pnt == '.' */
+       } /* else DOS file names */
+      current_length++;
+      pnt++;
+    } /* while (*pnt) */
+  
+  /*
+   * OK, that wraps up the scan of the name.  Now tidy up a few other
+   * things.
+   */
+
+  /*
+   * Look for emacs style of numbered backups, like foo.c.~3~.  If
+   * we see this, convert the version number into the priority
+   * number.  In case of name conflicts, this is what would end
+   * up being used as the 'extension'.
+   */
+  if(tildes == 2)
+    {
+      int prio1 = 0;
+      pnt = name;
+      while (*pnt && *pnt != '~') 
+       {
+         pnt++;
+       }
+      if (*pnt) 
+       {
+         pnt++;
+       }
+      while(*pnt && *pnt != '~')
+       {
+         prio1 = 10*prio1 + *pnt - '0';
+         pnt++;
+       }
+      priority = prio1;
+    }
+  
+  /*
+   * If this is not a directory, force a '.' in case we haven't
+   * seen one, and add a version number if we haven't seen one
+   * of those either.
+   */
+  if (!dirflag)
+    {
+      if (!seen_dot && !omit_period) 
+       {
+         if (result) *result++ = '.'; 
+         extra++;
+       }
+      if(!omit_version_number && !seen_semic) 
+       {
+         if(result)
+           {
+             *result++ = ';';
+             *result++ = '1';
+           };
+         extra += 2;
+       }
+    }
+                   
+  if(result) 
+    {
+      *result++ = 0;
+    }
+  sresult->priority = priority;
+
+  return (chars_before_dot + chars_after_dot + seen_dot + extra);
+}
diff --git a/util/mkisofs/rock.c b/util/mkisofs/rock.c
new file mode 100644 (file)
index 0000000..47cba55
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * File rock.c - generate RRIP  records for iso9660 filesystems.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: rock.c,v 1.3 1997/05/17 15:45:26 eric Exp $";
+
+#include <stdlib.h>
+
+#include "config.h"
+
+#ifndef VMS
+#if defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <string.h>
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m)     (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#define SU_VERSION 1
+
+#define SL_ROOT    8
+#define SL_PARENT  4
+#define SL_CURRENT 2
+#define SL_CONTINUE 1
+
+#define CE_SIZE 28
+#define CL_SIZE 12
+#define ER_SIZE 8
+#define NM_SIZE 5
+#define PL_SIZE 12
+#define PN_SIZE 20
+#define PX_SIZE 36
+#define RE_SIZE 4
+#define SL_SIZE 20
+#define ZZ_SIZE 15
+#ifdef __QNX__
+#define TF_SIZE (5 + 4 * 7)
+#else
+#define TF_SIZE (5 + 3 * 7)
+#endif
+
+/* If we need to store this number of bytes, make sure we
+   do not box ourselves in so that we do not have room for
+   a CE entry for the continuation record */
+
+#define MAYBE_ADD_CE_ENTRY(BYTES) \
+    (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0) 
+
+/*
+ * Buffer to build RR attributes
+ */
+
+static unsigned char Rock[16384];
+static unsigned char symlink_buff[256];
+static int ipnt = 0;
+static int recstart = 0;
+static int currlen = 0;
+static int mainrec = 0;
+static int reclimit;
+
+static void add_CE_entry(){
+          if(recstart)
+           set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
+         Rock[ipnt++] ='C';
+         Rock[ipnt++] ='E';
+         Rock[ipnt++] = CE_SIZE;
+         Rock[ipnt++] = SU_VERSION;
+         set_733((char*)Rock + ipnt, 0);
+         ipnt += 8;
+         set_733((char*)Rock + ipnt, 0);
+         ipnt += 8;
+         set_733((char*)Rock + ipnt, 0);
+         ipnt += 8;
+         recstart = ipnt;
+         currlen = 0;
+         if(!mainrec) mainrec = ipnt;
+         reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
+}
+
+#ifdef __STDC__
+int generate_rock_ridge_attributes (char * whole_name, char * name,
+                                   struct directory_entry * s_entry,
+                                   struct stat * statbuf,
+                                   struct stat * lstatbuf,
+                                   int deep_opt)
+#else
+int generate_rock_ridge_attributes (whole_name, name,
+                                   s_entry,
+                                   statbuf,
+                                   lstatbuf,
+                                   deep_opt)
+char * whole_name; char * name; struct directory_entry * s_entry;
+struct stat * statbuf, *lstatbuf;
+int deep_opt;
+#endif
+{
+  int flagpos, flagval;
+  int need_ce;
+
+  statbuf = statbuf;        /* this shuts up unreferenced compiler warnings */
+  mainrec = recstart = ipnt = 0;
+  reclimit = 0xf8;
+
+  /* Obtain the amount of space that is currently used for the directory
+     record.  Assume max for name, since name conflicts may cause us
+     to rename the file later on */
+  currlen = sizeof(s_entry->isorec);
+
+  /* Identify that we are using the SUSP protocol */
+  if(deep_opt & NEED_SP){
+         Rock[ipnt++] ='S';
+         Rock[ipnt++] ='P';
+         Rock[ipnt++] = 7;
+         Rock[ipnt++] = SU_VERSION;
+         Rock[ipnt++] = 0xbe;
+         Rock[ipnt++] = 0xef;
+         Rock[ipnt++] = 0;
+  };
+
+  /* First build the posix name field */
+  Rock[ipnt++] ='R';
+  Rock[ipnt++] ='R';
+  Rock[ipnt++] = 5;
+  Rock[ipnt++] = SU_VERSION;
+  flagpos = ipnt;
+  flagval = 0;
+  Rock[ipnt++] = 0;   /* We go back and fix this later */
+
+  if(strcmp(name,".")  && strcmp(name,"..")){
+    char * npnt;
+    int remain, use;
+
+    remain = strlen(name);
+    npnt = name;
+
+    while(remain){
+          use = remain;
+         need_ce = 0;
+         /* Can we fit this SUSP and a CE entry? */
+         if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+           use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+           need_ce++;
+         }
+
+         /* Only room for 256 per SUSP field */
+         if(use > 0xf8) use = 0xf8;
+
+         /* First build the posix name field */
+         Rock[ipnt++] ='N';
+         Rock[ipnt++] ='M';
+         Rock[ipnt++] = NM_SIZE + use;
+         Rock[ipnt++] = SU_VERSION;
+         Rock[ipnt++] = (remain != use ? 1 : 0);
+         flagval |= (1<<3);
+         strncpy((char *)&Rock[ipnt], npnt, use);
+         npnt += use;
+         ipnt += use;
+         remain -= use;
+         if(remain && need_ce) add_CE_entry();
+       };
+  };
+
+  /*
+   * Add the posix modes 
+   */
+  if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
+  Rock[ipnt++] ='P';
+  Rock[ipnt++] ='X';
+  Rock[ipnt++] = PX_SIZE;
+  Rock[ipnt++] = SU_VERSION;  
+  flagval |= (1<<0);
+  set_733((char*)Rock + ipnt, lstatbuf->st_mode);
+  ipnt += 8;
+  set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
+  ipnt += 8;
+  set_733((char*)Rock + ipnt, lstatbuf->st_uid);
+  ipnt += 8;
+  set_733((char*)Rock + ipnt, lstatbuf->st_gid);
+  ipnt += 8;
+
+  /*
+   * Check for special devices
+   */
+#ifndef NON_UNIXFS
+  if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
+    if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
+    Rock[ipnt++] ='P';
+    Rock[ipnt++] ='N';
+    Rock[ipnt++] = PN_SIZE;
+    Rock[ipnt++] = SU_VERSION;  
+    flagval |= (1<<1);
+#if !defined(MAJOR_IN_SYSMACROS) && !defined(MAJOR_IN_MKDEV)
+    set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
+    ipnt += 8;
+    set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
+    ipnt += 8;
+#else
+    /*
+     * If we don't have sysmacros.h, then we have to guess as to how
+     * best to pick apart the device number for major/minor.
+     * Note: this may very well be wrong for many systems, so
+     * it is always best to use the major/minor macros if the
+     * system supports it.
+     */
+    if(sizeof(dev_t) <= 2) {
+        set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
+        ipnt += 8;
+        set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
+        ipnt += 8;
+    }
+    else if(sizeof(dev_t) <= 4) {
+        set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
+        ipnt += 8;
+        set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
+        ipnt += 8;
+    }
+    else {
+        set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
+        ipnt += 8;
+        set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
+        ipnt += 8;
+    }
+#endif
+  };
+#endif
+  /*
+   * Check for and symbolic links.  VMS does not have these.
+   */
+  if (S_ISLNK(lstatbuf->st_mode)){
+    int lenpos, lenval, j0, j1;
+    int nchar;
+    unsigned char * cpnt, *cpnt1;
+    nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff));
+    symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+    set_733(s_entry->isorec.size, 0);
+    cpnt = &symlink_buff[0];
+    flagval |= (1<<2);
+
+    while(nchar){
+      if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
+      Rock[ipnt++] ='S';
+      Rock[ipnt++] ='L';
+      lenpos = ipnt;
+      Rock[ipnt++] = SL_SIZE;
+      Rock[ipnt++] = SU_VERSION;  
+      Rock[ipnt++] = 0; /* Flags */
+      lenval = 5;
+      while(*cpnt){
+       cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
+       if(cpnt1) {
+         nchar--;
+         *cpnt1 = 0;
+       };
+       
+       /* We treat certain components in a special way.  */
+       if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
+         if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+         Rock[ipnt++] = SL_PARENT;
+         Rock[ipnt++] = 0;  /* length is zero */
+         lenval += 2;
+         nchar -= 2;
+       } else if(cpnt[0] == '.' && cpnt[1] == 0){
+         if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+         Rock[ipnt++] = SL_CURRENT;
+         Rock[ipnt++] = 0;  /* length is zero */
+         lenval += 2;
+         nchar -= 1;
+       } else if(cpnt[0] == 0){
+         if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+         Rock[ipnt++] = SL_ROOT;
+         Rock[ipnt++] = 0;  /* length is zero */
+         lenval += 2;
+       } else {
+         /* If we do not have enough room for a component, start
+            a new continuations segment now */
+         if(MAYBE_ADD_CE_ENTRY(6)) {
+           add_CE_entry();
+           if(cpnt1){
+             *cpnt1 = '/';
+              nchar++;
+             cpnt1 = NULL; /* A kluge so that we can restart properly */
+           }
+           break;
+         }
+         j0 = strlen((char *) cpnt);
+         while(j0) {
+           j1 = j0;
+           if(j1 > 0xf8) j1 = 0xf8;
+           need_ce = 0;
+           if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+             j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+             need_ce++;
+           }
+           Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
+           Rock[ipnt++] = j1;
+           strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
+           ipnt += j1;
+           lenval += j1 + 2;
+           cpnt += j1;
+           nchar -= j1;  /* Number we processed this time */
+           j0 -= j1;
+           if(need_ce) {
+             add_CE_entry();
+             if(cpnt1) {
+               *cpnt1 = '/';
+                nchar++;
+               cpnt1 = NULL; /* A kluge so that we can restart properly */
+             }
+             break;
+           }
+         }
+       };
+       if(cpnt1) {
+         cpnt = cpnt1 + 1;
+       } else
+         break;
+      }
+      Rock[lenpos] = lenval;
+      if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
+    } /* while nchar */
+  } /* Is a symbolic link */
+  /* 
+   * Add in the Rock Ridge TF time field
+   */
+  if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
+  Rock[ipnt++] ='T';
+  Rock[ipnt++] ='F';
+  Rock[ipnt++] = TF_SIZE;
+  Rock[ipnt++] = SU_VERSION;
+#ifdef __QNX__
+  Rock[ipnt++] = 0x0f;
+#else
+  Rock[ipnt++] = 0x0e;
+#endif
+  flagval |= (1<<7);
+#ifdef __QNX__
+  iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
+  ipnt += 7;
+#endif
+  iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
+  ipnt += 7;
+  iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
+  ipnt += 7;
+  iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
+  ipnt += 7;
+
+  /* 
+   * Add in the Rock Ridge RE time field
+   */
+  if(deep_opt & NEED_RE){
+          if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
+         Rock[ipnt++] ='R';
+         Rock[ipnt++] ='E';
+         Rock[ipnt++] = RE_SIZE;
+         Rock[ipnt++] = SU_VERSION;
+         flagval |= (1<<6);
+  };
+  /* 
+   * Add in the Rock Ridge PL record, if required.
+   */
+  if(deep_opt & NEED_PL){
+          if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
+         Rock[ipnt++] ='P';
+         Rock[ipnt++] ='L';
+         Rock[ipnt++] = PL_SIZE;
+         Rock[ipnt++] = SU_VERSION;
+         set_733((char*)Rock + ipnt, 0);
+         ipnt += 8;
+         flagval |= (1<<5);
+  };
+
+  /* 
+   * Add in the Rock Ridge CL field, if required.
+   */
+  if(deep_opt & NEED_CL){
+          if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
+         Rock[ipnt++] ='C';
+         Rock[ipnt++] ='L';
+         Rock[ipnt++] = CL_SIZE;
+         Rock[ipnt++] = SU_VERSION;
+         set_733((char*)Rock + ipnt, 0);
+         ipnt += 8;
+         flagval |= (1<<4);
+  };
+
+#ifndef VMS
+  /* If transparent compression was requested, fill in the correct
+     field for this file */
+  if(transparent_compression && 
+     S_ISREG(lstatbuf->st_mode) &&
+     strlen(name) > 3 &&
+     strcmp(name + strlen(name) - 3,".gZ") == 0){
+    FILE * zipfile;
+    char * checkname;
+    unsigned int file_size;
+    unsigned char header[8];
+    int OK_flag;
+
+    /* First open file and verify that the correct algorithm was used */
+    file_size = 0;
+    OK_flag = 1;
+
+    zipfile = fopen(whole_name, "r");
+    fread(header, 1, sizeof(header), zipfile);
+
+    /* Check some magic numbers from gzip. */
+    if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
+    /* Make sure file was blocksized. */
+    if(((header[3] & 0x40) == 0)) OK_flag = 0;
+    /* OK, now go to the end of the file and get some more info */
+    if(OK_flag){
+      int status;
+      status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
+      if(status == -1) OK_flag = 0;
+    }
+    if(OK_flag){
+      if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
+       OK_flag = 0;
+      else {
+       int blocksize;
+       blocksize = (header[3] << 8) | header[2];
+       file_size = ((unsigned int)header[7] << 24) | 
+                   ((unsigned int)header[6] << 16) | 
+                   ((unsigned int)header[5] << 8)  | header[4];
+#if 0
+       fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
+#endif
+       if(blocksize != SECTOR_SIZE) OK_flag = 0;
+      }
+    }
+    fclose(zipfile);
+
+    checkname = strdup(whole_name);
+    checkname[strlen(whole_name)-3] = 0;
+    zipfile = fopen(checkname, "r");
+    if(zipfile) {
+      OK_flag = 0;
+      fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n");
+      fclose(zipfile);
+    }
+
+    free(checkname);
+
+    if(OK_flag){
+      if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
+      Rock[ipnt++] ='Z';
+      Rock[ipnt++] ='Z';
+      Rock[ipnt++] = ZZ_SIZE;
+      Rock[ipnt++] = SU_VERSION;
+      Rock[ipnt++] = 'g'; /* Identify compression technique used */
+      Rock[ipnt++] = 'z';
+      Rock[ipnt++] = 3;
+      set_733((char*)Rock + ipnt, file_size); /* Real file size */
+      ipnt += 8;
+    };
+  }
+#endif
+  /* 
+   * Add in the Rock Ridge CE field, if required.  We use  this for the
+   * extension record that is stored in the root directory.
+   */
+  if(deep_opt & NEED_CE) add_CE_entry();
+  /*
+   * Done filling in all of the fields.  Now copy it back to a buffer for the
+   * file in question.
+   */
+
+  /* Now copy this back to the buffer for the file */
+  Rock[flagpos] = flagval;
+
+  /* If there was a CE, fill in the size field */
+  if(recstart)
+    set_733((char*)Rock + recstart - 8, ipnt - recstart);
+
+  s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
+  s_entry->total_rr_attr_size = ipnt;
+  s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
+  memcpy(s_entry->rr_attributes, Rock, ipnt);
+  return ipnt;
+}
+
+/* Guaranteed to  return a single sector with the relevant info */
+
+char * FDECL4(generate_rr_extension_record, char *, id,  char  *, descriptor,
+                                   char *, source, int  *, size){
+  int ipnt = 0;
+  char * pnt;
+  int len_id, len_des, len_src;
+
+  len_id = strlen(id);
+  len_des =  strlen(descriptor);
+  len_src = strlen(source);
+  Rock[ipnt++] ='E';
+  Rock[ipnt++] ='R';
+  Rock[ipnt++] = ER_SIZE + len_id + len_des + len_src;
+  Rock[ipnt++] = 1;
+  Rock[ipnt++] = len_id;
+  Rock[ipnt++] = len_des;
+  Rock[ipnt++] = len_src;
+  Rock[ipnt++] = 1;
+
+  memcpy(Rock  + ipnt, id, len_id);
+  ipnt += len_id;
+
+  memcpy(Rock  + ipnt, descriptor, len_des);
+  ipnt += len_des;
+
+  memcpy(Rock  + ipnt, source, len_src);
+  ipnt += len_src;
+
+  if(ipnt  > SECTOR_SIZE) {
+         fprintf(stderr,"Extension record too  long\n");
+         exit(1);
+  };
+  pnt = (char *) e_malloc(SECTOR_SIZE);
+  memset(pnt, 0,  SECTOR_SIZE);
+  memcpy(pnt, Rock, ipnt);
+  *size = ipnt;
+  return pnt;
+}
diff --git a/util/mkisofs/tree.c b/util/mkisofs/tree.c
new file mode 100644 (file)
index 0000000..7180905
--- /dev/null
@@ -0,0 +1,1292 @@
+/*
+ * File tree.c - scan directory  tree and build memory structures for iso9660
+ * filesystem
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: tree.c,v 1.9.1.2 1998/06/02 03:17:31 eric Exp $";
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "config.h"
+
+#ifndef VMS
+#if defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#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
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#include <sys/stat.h>
+
+#include "exclude.h"
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m)     (0)
+#define S_ISSOCK(m)    (0)
+#define S_ISFIFO(m)    (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#endif
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+#   define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+#   define S_ISSOCK(m) (0)
+# endif
+#endif
+#endif
+
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+static unsigned char symlink_buff[256];
+
+extern int verbose;
+
+struct stat fstatbuf = {0,};  /* We use this for the artificial entries we create */
+
+struct stat root_statbuf = {0, };  /* Stat buffer for root directory */
+
+struct directory * reloc_dir = NULL;
+
+void
+FDECL1(stat_fix, struct stat *, st)
+{
+  /* Remove the uid and gid, they will only be useful on the author's
+     system.  */
+  st->st_uid = 0;
+  st->st_gid = 0;
+
+ /*
+  * 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 (st->st_mode & 0111)
+    st->st_mode |= 0111;
+  st->st_mode &= ~07222;
+}
+
+int
+FDECL2(stat_filter, char *, path, struct stat *, st)
+{
+  int result = stat(path, st);
+  if (result >= 0 && rationalize)
+    stat_fix(st);
+  return result;
+}
+
+int
+FDECL2(lstat_filter, char *, path, struct stat *, st)
+{
+  int result = lstat(path, st);
+  if (result >= 0 && rationalize)
+    stat_fix(st);
+  return result;
+}
+
+void FDECL1(sort_n_finish, struct directory *, this_dir)
+{
+  struct directory_entry  * s_entry;
+  struct directory_entry  * s_entry1;
+  time_t                   current_time;
+  struct directory_entry  * table;
+  int                      count;
+  int                      d1;
+  int                      d2;
+  int                      d3;
+  int                      new_reclen;
+  char                  *  c;
+  int                      tablesize = 0;
+  char                     newname[34];
+  char                     rootname[34];
+
+  /* Here we can take the opportunity to toss duplicate entries from the
+     directory.  */
+
+  table = NULL;
+
+  if(fstatbuf.st_ctime == 0)
+    {
+      time (&current_time);
+      fstatbuf.st_uid = 0;
+      fstatbuf.st_gid = 0;
+      fstatbuf.st_ctime = current_time;
+      fstatbuf.st_mtime = current_time;
+      fstatbuf.st_atime = current_time;
+    }
+
+  flush_file_hash();
+  s_entry = this_dir->contents;
+  while(s_entry)
+    {
+         
+      /*
+       * 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;
+       }
+         
+      if(s_entry1 == s_entry)
+       {
+         fprintf(stderr,"Fatal goof\n");
+         exit(1);
+       }
+      
+      /* 
+       * OK, handle the conflicts.  Try substitute names until we come
+       * up with a winner 
+       */
+      strcpy(rootname, s_entry->isorec.name);
+      if(full_iso9660_filenames) 
+       {
+         if(strlen(rootname) > 27) rootname[27] = 0;
+       }
+
+      /*
+       * 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, '.');
+      if (c) 
+       *c = 0;
+      else
+       {
+         c  = strchr(rootname, ';');
+         if (c) *c = 0;
+       }
+      for(d1 = 0; d1 < 36; d1++)
+       {
+         for(d2 = 0; d2 < 36; d2++)
+           {
+             for(d3 = 0; d3 < 36; d3++)
+               {
+                 sprintf(newname,"%s.%c%c%c%s", rootname,  
+                         (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10),
+                         (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10),
+                         (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10),
+                         (s_entry->isorec.flags[0] == 2 || 
+                          omit_version_number ? "" : ";1"));
+                 
+#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.
+       */
+      fprintf(stderr,"Unable to  generate unique  name for file %s\n", s_entry->name);
+      exit(1);
+
+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) 
+       {
+         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 =  sizeof(struct iso_directory_record) -
+           sizeof(s_entry->isorec.name) +
+           strlen(newname);
+         if(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);
+       }
+      else 
+       {
+         delete_file_hash(s_entry1);
+         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 =  sizeof(struct iso_directory_record) -
+           sizeof(s_entry1->isorec.name) +
+           strlen(newname);
+         if(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);
+       }
+      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; 
+         if(s_entry->table) tablesize += 35 + 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] = 0;
+      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, DEF_VSN);
+      set_733((char *) table->isorec.size, tablesize);
+      table->size = tablesize;
+      table->filedir = this_dir;
+      table->name = strdup("<translation table>");
+      table->table = (char *) e_malloc(ROUND_UP(tablesize));
+      memset(table->table, 0, ROUND_UP(tablesize));
+      iso9660_file_length  ("TRANS.TBL", table, 0);
+      
+      if(use_RockRidge)
+       {
+         fstatbuf.st_mode = 0444 | S_IFREG;
+         fstatbuf.st_nlink = 1;
+         generate_rock_ridge_attributes("",
+                                        "TRANS.TBL", table,
+                                        &fstatbuf, &fstatbuf, 0);
+       }
+    }
+  
+  for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+    {
+      new_reclen = strlen(s_entry->isorec.name);
+         
+      if(s_entry->isorec.flags[0] ==  2)
+       {
+         if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 
+           {
+             path_table_size += new_reclen + sizeof(struct iso_path_table) - 1;
+             if (new_reclen & 1) path_table_size++;
+           }
+         else 
+           {
+             new_reclen = 1;
+             if (this_dir == root && strlen(s_entry->name) == 1)
+               path_table_size += sizeof(struct iso_path_table);
+           }
+       }
+      if(path_table_size & 1) path_table_size++;  /* For odd lengths we pad */
+      s_entry->isorec.name_len[0] = new_reclen;
+      
+      new_reclen += 
+       sizeof(struct iso_directory_record) -
+       sizeof(s_entry->isorec.name);
+      
+      if (new_reclen & 1)      
+       new_reclen++;
+      
+      new_reclen += s_entry->rr_attr_size;
+      
+      if (new_reclen & 1) new_reclen++;
+      
+      if(new_reclen > 0xff) 
+       {
+         fprintf(stderr,"Fatal error - RR overflow for file %s\n",
+                 s_entry->name);
+         exit(1);
+       }
+      s_entry->isorec.length[0] = new_reclen;
+    }
+
+  sort_directory(&this_dir->contents);
+
+  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;
+       
+       count += sprintf(table->table + count, "%c %-34s%s",
+                        s_entry->table[0],
+                        s_entry->isorec.name, s_entry->table+1);
+       free(s_entry->table);
+       s_entry->table = NULL;
+      }
+
+      if(count !=  tablesize) 
+       {
+         fprintf(stderr,"Translation table size mismatch %d %d\n",
+                 count, tablesize);
+         exit(1);
+       }
+    }
+
+  /* 
+   * 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)
+    {
+      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;
+         
+         /*
+          * 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 = 
+                                   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;
+    }
+}
+
+static void generate_reloc_directory()
+{
+       int new_reclen;
+       time_t current_time;
+       struct directory_entry  *s_entry;
+
+       /* Create an  entry for our internal tree */
+       time (&current_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;
+       reloc_dir->whole_name = strdup("./rr_moved");
+       reloc_dir->de_name =  strdup("rr_moved");
+       reloc_dir->extent = 0;
+       
+       new_reclen  = strlen(reloc_dir->de_name);
+       
+       /* 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;
+
+       root->contents = s_entry;
+       root->contents->name = strdup(reloc_dir->de_name);
+       root->contents->filedir = root;
+       root->contents->isorec.flags[0] = 2;
+       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, DEF_VSN);
+       iso9660_file_length (reloc_dir->de_name, root->contents, 1);
+
+       if(use_RockRidge){
+               fstatbuf.st_mode = 0555 | S_IFDIR;
+               fstatbuf.st_nlink = 2;
+               generate_rock_ridge_attributes("",
+                                              "rr_moved", s_entry,
+                                              &fstatbuf, &fstatbuf, 0);
+       };
+       
+       /* Now create the . and .. entries in rr_moved */
+       /* Now create an actual directory  entry */
+       s_entry = (struct directory_entry *) 
+               e_malloc(sizeof (struct directory_entry));
+       memcpy(s_entry, root->contents, 
+              sizeof(struct directory_entry));
+       s_entry->name = strdup(".");
+       iso9660_file_length (".", s_entry, 1);
+
+       s_entry->filedir = reloc_dir;
+       reloc_dir->contents = s_entry;
+
+       if(use_RockRidge){
+               fstatbuf.st_mode = 0555 | S_IFDIR;
+               fstatbuf.st_nlink = 2;
+               generate_rock_ridge_attributes("",
+                                              ".", s_entry,
+                                              &fstatbuf, &fstatbuf, 0);
+       };
+       
+       s_entry = (struct directory_entry *) 
+               e_malloc(sizeof (struct directory_entry));
+       memcpy(s_entry, root->contents, 
+              sizeof(struct directory_entry));
+       s_entry->name = strdup("..");
+       iso9660_file_length ("..", s_entry, 1);
+       s_entry->filedir = root;
+       reloc_dir->contents->next = s_entry;
+       reloc_dir->contents->next->next = NULL;
+       if(use_RockRidge){
+               fstatbuf.st_mode = 0555 | S_IFDIR;
+               fstatbuf.st_nlink = 2;
+               generate_rock_ridge_attributes("",
+                                              "..", s_entry,
+                                              &root_statbuf, &root_statbuf, 0);
+       };
+}
+
+static void FDECL1(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;
+  while(len){
+    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];
+  };
+}
+
+void finish_cl_pl_entries(){
+  struct directory_entry  *s_entry, *s_entry1;
+  struct directory *  d_entry;
+
+  s_entry = reloc_dir->contents;
+   s_entry  = s_entry->next->next;  /* Skip past . and .. */
+  for(; s_entry; s_entry = s_entry->next){
+         d_entry = reloc_dir->subdir;
+         while(d_entry){
+                 if(d_entry->self == s_entry) break;
+                 d_entry = d_entry->next;
+         };
+         if(!d_entry){
+                 fprintf(stderr,"Unable to locate directory parent\n");
+                 exit(1);
+         };
+
+         /* 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);
+
+         /* 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);
+
+         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;
+  };
+}
+
+/*
+ * This function scans the directory tree, looking for files, and it makes
+ * note of everything that is found.  We also begin to construct the ISO9660
+ * directory entries, so that we can determine how large each directory is.
+ */
+
+int
+FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
+       struct iso_directory_record *, mrootp){
+  DIR                          * current_dir;
+  char                           whole_path[1024];
+  struct dirent                        * d_entry;
+  struct directory_entry       * s_entry, *s_entry1;
+  struct directory             * this_dir, *next_brother, *parent;
+  struct stat                    statbuf, lstatbuf;
+  int                            status, dflag;
+  int                            lstatus;
+  int                            n_orig;
+  struct directory_entry       **orig_contents = NULL;
+  struct directory_entry        * odpnt = NULL;
+  char                         * cpnt;
+  int                            new_reclen;
+  int                            deep_flag;
+  char                         * old_path;
+
+  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) d_entry = readdir_add_files(&path, old_path, current_dir);
+
+  if(!current_dir || !d_entry) {
+         fprintf(stderr,"Unable to open directory %s\n", path);
+         de->isorec.flags[0] &= ~2; /* Mark as not a directory */
+         if(current_dir) closedir(current_dir);
+         return 0;
+  };
+
+  parent = de->filedir;
+  /* Set up the struct for the current directory, and insert it into the
+     tree */
+
+#ifdef VMS
+  vms_path_fixup(path);
+#endif
+
+  this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+  this_dir->next = NULL;
+  new_reclen = 0;
+  this_dir->subdir = NULL;
+  this_dir->self = de;
+  this_dir->contents = NULL;
+  this_dir->whole_name = strdup(path);
+  cpnt = strrchr(path, PATH_SEPARATOR);
+  if(cpnt)
+    cpnt++;
+  else
+    cpnt = path;
+  this_dir->de_name = strdup(cpnt);
+  this_dir->size = 0;
+  this_dir->extent = 0;
+
+  if(!parent || parent == root){
+    if (!root) {
+      root = this_dir;  /* First time through for root directory only */
+      root->depth = 0;
+      root->parent = root;
+    } else {
+      this_dir->depth = 1;
+      if(!root->subdir)
+       root->subdir = this_dir;
+      else {
+       next_brother = root->subdir;
+       while(next_brother->next) next_brother = next_brother->next;
+       next_brother->next = this_dir;
+      };
+      this_dir->parent = parent;
+    };
+  } else {
+         /* Come through here for  normal traversal of  tree */
+#ifdef DEBUG
+         fprintf(stderr,"%s(%d) ", path, this_dir->depth);
+#endif
+         if(parent->depth >  RR_relocation_depth) {
+                 fprintf(stderr,"Directories too deep  %s\n", path);
+                 exit(1);
+         };
+
+         this_dir->parent = parent; 
+         this_dir->depth = parent->depth + 1;
+
+         if(!parent->subdir)
+                 parent->subdir = this_dir;
+         else {
+                 next_brother = parent->subdir;
+                 while(next_brother->next) next_brother = next_brother->next;
+                 next_brother->next = this_dir;
+         }
+  }
+
+  /*
+   * Parse the same directory in the image that we are merging
+   * for multisession stuff.
+   */
+  if( mrootp != NULL )
+    {
+      orig_contents = read_merging_directory(mrootp, &n_orig);
+    }
+
+/* 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_add_files(&path, old_path, 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,'~')) continue;
+           if(strchr(d_entry->d_name,'#')) continue;
+    };
+
+    if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
+      fprintf(stderr, "Overflow of stat buffer\n");
+      exit(1);
+    };
+
+    /* 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 (is_excluded(whole_path)) {
+      if (verbose) {
+        fprintf(stderr, "Excluded: %s\n",whole_path);
+      }
+      continue;
+    }
+    /** Should we exclude this file ? */
+    if (matches(d_entry->d_name)) {
+      if (verbose) {
+       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) 
+         {
+           fprintf(stderr, "Excluded: %s\n",whole_path);
+         }
+       continue;
+      }
+
+#if 0
+    if (verbose)  fprintf(stderr, "%s\n",whole_path);
+#endif
+    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
+        * or it could mean that the user has attempted to 'add' something
+        * with the -i option and the directory being added doesn't exist.
+        */
+       fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path);
+       continue;
+      }
+
+    if(this_dir == root && strcmp(d_entry->d_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(d_entry->d_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 = 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) fprintf(stderr,
+                                   "Unable to stat file %s - ignoring and continuing.\n",
+                                   whole_path);
+                           else fprintf(stderr,
+                                   "Symlink %s ignored - continuing.\n",
+                                   whole_path);
+                           continue;  /* 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(d_entry->d_name, ".")
+                  && strcmp(d_entry->d_name, "..") )
+                 {
+                   if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
+                     {
+                       if(!use_RockRidge) 
+                         {
+                           fprintf(stderr, "Already cached directory seen (%s)\n", 
+                                   whole_path);
+                           continue;
+                         }
+                       statbuf.st_size = 0;
+                       STAT_INODE(statbuf) = UNCACHED_INODE;
+                       statbuf.st_dev = (dev_t) UNCACHED_DEVICE;
+                       statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG;
+                   } 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(d_entry->d_name, ".")
+       && strcmp(d_entry->d_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))){
+      fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", 
+             whole_path, errno);
+      continue;
+    }
+
+    /* 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(d_entry->d_name, ".") 
+       && strcmp(d_entry->d_name, "..") ) 
+      {
+           if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
+                   fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).\n",
+                           whole_path, (unsigned long) statbuf.st_dev,
+                           (unsigned long) STAT_INODE(statbuf));
+                   exit(1);
+           };
+           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 - ignoring and continuing.\n",
+             whole_path);
+      continue;
+    };
+
+    /* Who knows what trash this is - ignore and continue */
+
+    if(status) {
+           fprintf(stderr,
+                   "Unable to stat file %s - ignoring and continuing.\n",
+                   whole_path);
+           continue; 
+    };
+
+    s_entry = (struct directory_entry *) 
+      e_malloc(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(d_entry->d_name);
+    s_entry->whole_name = strdup (whole_path);
+
+    s_entry->de_flags = 0;
+    s_entry->filedir = this_dir;
+    s_entry->isorec.flags[0] = 0;
+    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;
+    if(parent && parent ==  reloc_dir && strcmp(d_entry->d_name,  "..") == 0){
+           s_entry->inode = UNCACHED_INODE;
+           s_entry->dev = (dev_t) UNCACHED_DEVICE;
+           deep_flag  = NEED_PL;
+    } else  {
+           s_entry->inode = STAT_INODE(statbuf);
+           s_entry->dev = statbuf.st_dev;
+    };
+    set_723(s_entry->isorec.volume_sequence_number, DEF_VSN);
+    iso9660_file_length(d_entry->d_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)) {
+       set_733((char *) s_entry->isorec.size, statbuf.st_size); 
+
+       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 = 0; 
+       else
+         s_entry->size = statbuf.st_size; 
+    } else
+      s_entry->isorec.flags[0] = 2;
+
+    /*
+     * We always should create an entirely new directory tree whenever
+     * we generate a new session, unless there were *no* changes whatsoever
+     * to any of the directories, in which case it would be kind of pointless
+     * to generate a new session.
+     *
+     * I believe it is possible to rigorously prove that any change anywhere
+     * in the filesystem will force the entire tree to be regenerated
+     * because the modified directory will get a new extent number.  Since
+     * each subdirectory of the changed directory has a '..' entry, all of
+     * them will need to be rewritten too, and since the parent directory
+     * of the modified directory will have an extent pointer to the directory
+     * it too will need to be rewritten.  Thus we will never be able to reuse
+     * any directory information when writing new sessions.
+     *
+     * We still check the previous session so we can mark off the equivalent
+     * entry in the list we got from the original disc, however.
+     */
+    if(S_ISDIR(statbuf.st_mode) && orig_contents != NULL){
+      check_prev_session(orig_contents, n_orig, s_entry,
+                        &statbuf, &lstatbuf, &odpnt);
+    }
+
+    if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") && 
+       S_ISDIR(statbuf.st_mode) && this_dir->depth >  RR_relocation_depth){
+                 if(!reloc_dir) generate_reloc_directory();
+
+                 s_entry1 = (struct directory_entry *) 
+                         e_malloc(sizeof (struct directory_entry));
+                 memcpy(s_entry1, this_dir->contents, 
+                        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;
+
+                 deep_flag = NEED_RE;
+
+                 if(use_RockRidge) {
+                         generate_rock_ridge_attributes(whole_path,
+                                                        d_entry->d_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;
+                 if( odpnt != NULL )
+                   {
+                     scan_directory_tree(whole_path, s_entry1, &odpnt->isorec);
+                   }
+                 else
+                   {
+                     scan_directory_tree(whole_path, s_entry1, NULL);
+                   }
+                 if( odpnt != NULL )
+                   {
+                     free(odpnt);
+                     odpnt = NULL;
+                   }
+                 s_entry1->filedir = this_dir;
+
+                 statbuf.st_size = 0;
+                 statbuf.st_mode &= 0777;
+                 set_733((char *) s_entry->isorec.size, 0);
+                 s_entry->size = 0;
+                 s_entry->isorec.flags[0] = 0;
+                 s_entry->inode = UNCACHED_INODE;
+                 deep_flag = NEED_CL;
+         };
+    if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) {
+           char  buffer[2048];
+           int nchar;
+           switch(lstatbuf.st_mode & S_IFMT){
+           case S_IFDIR:
+                   sprintf(buffer,"D\t%s\n",
+                           s_entry->name);
+                   break;
+#ifndef NON_UNIXFS
+           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;
+           case S_IFIFO:
+                   sprintf(buffer,"P\t%s\n",
+                           s_entry->name);
+                   break;
+           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;
+           case S_IFLNK:
+                   nchar = readlink(whole_path, 
+                                    symlink_buff, 
+                                    sizeof(symlink_buff));
+                   symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+                   sprintf(buffer,"L\t%s\t%s\n",
+                           s_entry->name, symlink_buff);
+                   break;
+#ifdef S_IFSOCK
+           case S_IFSOCK:
+                   sprintf(buffer,"S\t%s\n",
+                           s_entry->name);
+                   break;
+#endif
+#endif /* NON_UNIXFS */
+           case S_IFREG:
+           default:
+                   sprintf(buffer,"F\t%s\n",
+                           s_entry->name);
+                   break;
+           };
+           s_entry->table = strdup(buffer);
+    };
+    
+    /*
+     * See if we have an entry for this guy in the previous session.
+     */
+    if( orig_contents != NULL && !S_ISDIR(statbuf.st_mode))
+      {
+       check_prev_session(orig_contents, n_orig, s_entry, 
+                          &statbuf, &lstatbuf, NULL);
+      }
+
+    if(S_ISDIR(statbuf.st_mode)){
+            int dflag;
+           if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) {
+             if( odpnt != NULL )
+               {
+                 dflag = scan_directory_tree(whole_path, s_entry, 
+                                             &odpnt->isorec);
+               }
+             else
+               {
+                 dflag = scan_directory_tree(whole_path, s_entry, NULL);
+               }
+           /* If unable to scan directory, mark this as a non-directory */
+               if(!dflag)
+                 lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+               if( odpnt != NULL )
+                 {
+                   free(odpnt);
+                   odpnt = NULL;
+                 }
+             }
+         }
+
+  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 */
+
+    if(use_RockRidge) {
+           generate_rock_ridge_attributes(whole_path,
+                                          d_entry->d_name, s_entry,
+                                          &statbuf, &lstatbuf, deep_flag);
+           
+    }
+  }
+  closedir(current_dir);
+
+  if( orig_contents != NULL )
+    {
+      merge_remaining_entries(this_dir, orig_contents, n_orig);
+      free_mdinfo(orig_contents, n_orig);
+    }
+
+  if( this_dir->contents == NULL )
+    {
+      /*
+       * This directory must have been inaccessible.
+       */
+      return 0;
+    }
+  sort_n_finish(this_dir);
+
+  return 1;
+}
+
+
+void FDECL2(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;
+  }
+}
+
+void FDECL1(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;
+  }
+}
+
+/*
+ * 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 * FDECL2(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
+      printf("Looking for subdir called %s\n",p1); 
+#endif
+
+      rest = p1+1;
+
+#ifdef DEBUG_TORITO
+      printf("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)) 
+          {
+#ifdef DEBUG_TORITO
+            printf("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)) 
+           {
+#ifdef DEBUG_TORITO
+             printf("Found our file %s", filename); 
+#endif
+             return(depnt);
+           }
+         depnt = depnt->next;
+       }
+      /* 
+       * if we got here means we couldnt find the subdir 
+       */
+      return (NULL);
+    }
+  fprintf(stderr,"We cant get here in search_tree_file :-/ \n");
+}
+
diff --git a/util/mkisofs/write.c b/util/mkisofs/write.c
new file mode 100644 (file)
index 0000000..cfc9b76
--- /dev/null
@@ -0,0 +1,1142 @@
+/*
+ * Program write.c - dump memory  structures to  file for iso9660 filesystem.
+
+   Written by Eric Youngdale (1993).
+
+   Copyright 1993 Yggdrasil Computing, Incorporated
+
+   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.  */
+
+static char rcsid[] ="$Id: write.c,v 1.6.1.3 1997/11/13 05:07:13 eric Exp $";
+
+#include <string.h>
+#include <stdlib.h>
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <time.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+#ifdef VMS
+extern char * strdup(const char *);
+#endif
+
+
+/* Max number of sectors we will write at  one time */
+#define NSECT 16
+
+/* Counters for statistics */
+
+static int table_size = 0;
+static int total_dir_size = 0;
+static int rockridge_size = 0;
+static struct directory ** pathlist;
+static next_path_index = 1;
+
+/* Used to fill in some  of the information in the volume descriptor. */
+static struct tm local;
+static struct tm gmt;
+
+/* Routines to actually write the disc.  We write sequentially so that
+   we could write a tape, or write the disc directly */
+
+
+#define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
+
+void FDECL2(set_721, char *, pnt, unsigned int, i)
+{
+     pnt[0] = i & 0xff;
+     pnt[1] = (i >> 8) &  0xff;
+}
+
+void FDECL2(set_722, char *, pnt, unsigned int, i)
+{
+     pnt[0] = (i >> 8) &  0xff;
+     pnt[1] = i & 0xff;
+}
+
+void FDECL2(set_723, char *, pnt, unsigned int, i)
+{
+     pnt[3] = pnt[0] = i & 0xff;
+     pnt[2] = pnt[1] = (i >> 8) &  0xff;
+}
+
+void FDECL2(set_731, char *, pnt, unsigned int, i)
+{
+     pnt[0] = i & 0xff;
+     pnt[1] = (i >> 8) &  0xff;
+     pnt[2] = (i >> 16) &  0xff;
+     pnt[3] = (i >> 24) &  0xff;
+}
+
+void FDECL2(set_732, char *, pnt, unsigned int, i)
+{
+     pnt[3] = i & 0xff;
+     pnt[2] = (i >> 8) &  0xff;
+     pnt[1] = (i >> 16) &  0xff;
+     pnt[0] = (i >> 24) &  0xff;
+}
+
+int FDECL1(get_733, char *, p)
+{
+     return ((p[0] & 0xff)
+            | ((p[1] & 0xff) << 8)
+            | ((p[2] & 0xff) << 16)
+            | ((p[3] & 0xff) << 24));
+}
+
+void FDECL2(set_733, char *, pnt, unsigned int, i)
+{
+     pnt[7] = pnt[0] = i & 0xff;
+     pnt[6] = pnt[1] = (i >> 8) &  0xff;
+     pnt[5] = pnt[2] = (i >> 16) &  0xff;
+     pnt[4] = pnt[3] = (i >> 24) &  0xff;
+}
+
+void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
+{
+     while(count) 
+     {
+         int got = fwrite(buffer,size,count,file);
+
+         if(got<=0) 
+         {
+              fprintf(stderr,"cannot fwrite %d*%d\n",size,count);
+              exit(1);
+         }
+         count-=got,*(char**)&buffer+=size*got;
+     }
+}
+
+struct deferred_write
+{
+  struct deferred_write * next;
+  char                 * table;
+  unsigned int           extent;
+  unsigned int           size;
+  char                 * name;
+};
+
+static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
+
+static struct directory_entry * sort_dir;
+static struct eltorito_boot_descriptor boot_desc;
+
+unsigned int last_extent_written  =0;
+static struct iso_primary_descriptor vol_desc;
+static path_table_index;
+static time_t begun;
+
+/* We recursively walk through all of the directories and assign extent
+   numbers to them.  We have already assigned extent numbers to everything that
+   goes in front of them */
+
+void FDECL1(assign_directory_addresses, struct directory *, node)
+{
+     int               dir_size;
+     struct directory * dpnt;
+
+     dpnt = node;
+     
+     while (dpnt)
+     {
+         /*
+          * If we already have an extent for this (i.e. it came from
+          * a multisession disc), then don't reassign a new extent.
+          */
+         dpnt->path_index = next_path_index++;
+         if( dpnt->extent == 0 )
+         {
+              dpnt->extent = last_extent;
+              dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
+              
+              last_extent += dir_size;
+              
+              /* 
+               * Leave room for the CE entries for this directory.  Keep them
+               * close to the reference directory so that access will be 
+               * quick. 
+               */
+              if(dpnt->ce_bytes)
+              {
+                   last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
+              }
+         }
+
+         if(dpnt->subdir) 
+         {
+              assign_directory_addresses(dpnt->subdir);
+         }
+
+         dpnt = dpnt->next;
+     }
+}
+
+static void FDECL3(write_one_file, char *, filename, 
+                  unsigned int, size, FILE *, outfile)
+{
+     char                buffer[SECTOR_SIZE * NSECT];
+     FILE              * infile;
+     int                 remain;
+     int                 use;
+
+
+     if ((infile = fopen(filename, "rb")) == NULL) 
+     {
+#if defined(sun) || defined(_AUX_SOURCE)
+         fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
+#else
+         fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
+#endif
+         exit(1);
+     }
+     remain = size;
+
+     while(remain > 0)
+     {
+         use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
+         use = ROUND_UP(use); /* Round up to nearest sector boundary */
+         memset(buffer, 0, use);
+         if (fread(buffer, 1, use, infile) == 0) 
+         {
+              fprintf(stderr,"cannot read from %s\n",filename); 
+              exit(1);
+         }
+         xfwrite(buffer, 1, use, outfile);
+         last_extent_written += use/SECTOR_SIZE;
+#if 0
+         if((last_extent_written % 1000) < use/SECTOR_SIZE) 
+         {
+              fprintf(stderr,"%d..", last_extent_written);
+         }
+#else
+         if((last_extent_written % 5000) < use/SECTOR_SIZE)
+         {
+              time_t now;
+              time_t the_end;
+              double frac;
+              
+              time(&now);
+              frac = last_extent_written / (double)last_extent;
+              the_end = begun + (now - begun) / frac;
+              fprintf(stderr, "%6.2f%% done, estimate finish %s",
+                      frac * 100., ctime(&the_end));
+         }
+#endif
+         remain -= use;
+     }
+     fclose(infile);
+} /* write_one_file(... */
+
+static void FDECL1(write_files, FILE *, outfile)
+{
+     struct deferred_write * dwpnt, *dwnext;
+     dwpnt = dw_head;
+     while(dwpnt)
+     {
+         if(dwpnt->table) 
+         {
+              xfwrite(dwpnt->table,  1, ROUND_UP(dwpnt->size), outfile);
+              last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
+              table_size += dwpnt->size;
+/*               fprintf(stderr,"Size %d ", dwpnt->size); */
+              free(dwpnt->table);
+         } 
+         else 
+         {
+
+#ifdef VMS
+              vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
+#else
+              write_one_file(dwpnt->name, dwpnt->size, outfile);
+#endif
+              free(dwpnt->name);
+         }
+
+         dwnext = dwpnt;
+         dwpnt = dwpnt->next;
+         free(dwnext);
+     }
+} /* write_files(... */
+
+#if 0
+static void dump_filelist()
+{
+     struct deferred_write * dwpnt;
+     dwpnt = dw_head;
+     while(dwpnt)
+     {
+         fprintf(stderr, "File %s\n",dwpnt->name);
+         dwpnt = dwpnt->next;
+     }
+     fprintf(stderr,"\n");
+}
+#endif
+
+int FDECL2(compare_dirs, const void *, rr, const void *, ll) 
+{
+     char * rpnt, *lpnt;
+     struct directory_entry ** r, **l;
+     
+     r = (struct directory_entry **) rr;
+     l = (struct directory_entry **) ll;
+     rpnt = (*r)->isorec.name;
+     lpnt = (*l)->isorec.name;
+     
+     /*
+      *  Put the '.' and '..' entries on the head of the sorted list.
+      *  For normal ASCII, this always happens to be the case, but out of
+      *  band characters cause this not to be the case sometimes.
+      */
+     if( strcmp(rpnt, ".") == 0 ) return -1;
+     if( strcmp(lpnt, ".") == 0 ) return  1;
+
+     if( strcmp(rpnt, "..") == 0 ) return -1;
+     if( strcmp(lpnt, "..") == 0 ) return  1;
+
+     while(*rpnt && *lpnt) 
+     {
+         if(*rpnt == ';' && *lpnt != ';') return -1;
+         if(*rpnt != ';' && *lpnt == ';') return 1;
+         
+         if(*rpnt == ';' && *lpnt == ';') return 0;
+         
+         if(*rpnt == '.' && *lpnt != '.') return -1;
+         if(*rpnt != '.' && *lpnt == '.') return 1;
+         
+         if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1;
+         if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1;
+         rpnt++;  lpnt++;
+     }
+     if(*rpnt) return 1;
+     if(*lpnt) return -1;
+     return 0;
+}
+
+void FDECL1(sort_directory, struct directory_entry **, sort_dir)
+{
+     int dcount = 0;
+     int i, len;
+     struct directory_entry * s_entry;
+     struct directory_entry ** sortlist;
+     
+     s_entry = *sort_dir;
+     while(s_entry)
+     {
+         dcount++;
+         s_entry = s_entry->next;
+     }
+
+     /*
+      * OK, now we know how many there are.  Build a vector for sorting. 
+      */
+     sortlist =   (struct directory_entry **) 
+         e_malloc(sizeof(struct directory_entry *) * dcount);
+
+     dcount = 0;
+     s_entry = *sort_dir;
+     while(s_entry)
+     {
+         sortlist[dcount] = s_entry;
+         len = s_entry->isorec.name_len[0];
+         s_entry->isorec.name[len] = 0;
+         dcount++;
+         s_entry = s_entry->next;
+     }
+  
+     qsort(sortlist, dcount, sizeof(struct directory_entry *), 
+          (int (*)(const void *, const void *))compare_dirs);
+     
+     /* 
+      * Now reassemble the linked list in the proper sorted order 
+      */
+     for(i=0; i<dcount-1; i++)
+     {
+         sortlist[i]->next = sortlist[i+1];
+     }
+
+     sortlist[dcount-1]->next = NULL;
+     *sort_dir = sortlist[0];
+     
+     free(sortlist);
+     
+}
+
+void generate_root_record()
+{
+     time_t ctime;
+     
+     time (&ctime);
+
+     local = *localtime(&ctime);
+     gmt   = *gmtime(&ctime);
+     
+     root_record.length[0] = 1 + sizeof(struct iso_directory_record)
+         - sizeof(root_record.name);
+     root_record.ext_attr_length[0] = 0;
+     set_733((char *) root_record.extent, root->extent);
+     set_733((char *) root_record.size, ROUND_UP(root->size));
+     iso9660_date(root_record.date, ctime);
+     root_record.flags[0] = 2;
+     root_record.file_unit_size[0] = 0;
+     root_record.interleave[0] = 0;
+     set_723(root_record.volume_sequence_number, DEF_VSN);
+     root_record.name_len[0] = 1;
+}
+
+static void FDECL1(assign_file_addresses, struct directory *, dpnt)
+{
+     struct directory * finddir;
+     struct directory_entry * s_entry;
+     struct file_hash *s_hash;
+     struct deferred_write * dwpnt;
+     char whole_path[1024];
+     
+     while (dpnt)
+     {
+         s_entry = dpnt->contents;
+         for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
+         {
+              
+              /*
+               * If we already have an  extent for this entry,
+               * then don't assign a new one.  It must have come
+               * from a previous session on the disc.  Note that
+               * we don't end up scheduling the thing for writing
+               * either.
+               */
+              if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 )
+              {
+                   continue;
+              }
+              
+              /* 
+               * This saves some space if there are symlinks present 
+               */
+              s_hash = find_hash(s_entry->dev, s_entry->inode);
+              if(s_hash)
+              {
+                   if(verbose)
+                   {
+                        fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, 
+                                SPATH_SEPARATOR, s_entry->name);
+                   }
+                   set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
+                   set_733((char *) s_entry->isorec.size, s_hash->size);
+                   continue;
+              }
+
+              /*
+               * If this is for a directory that is not a . or a .. entry, 
+               * then look up the information for the entry.  We have already
+               * assigned extents for directories, so we just need to
+               * fill in the blanks here.
+               */
+              if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && 
+                  s_entry->isorec.flags[0] == 2)
+              {
+                   finddir = dpnt->subdir;
+                   while(1==1)
+                   {
+                        if(finddir->self == s_entry) break;
+                        finddir = finddir->next;
+                        if(!finddir) 
+                        {
+                             fprintf(stderr,"Fatal goof\n"); exit(1);
+                        }
+                   }
+                   set_733((char *) s_entry->isorec.extent, finddir->extent);
+                   s_entry->starting_block = finddir->extent;
+                   s_entry->size = ROUND_UP(finddir->size);
+                   total_dir_size += s_entry->size;
+                   add_hash(s_entry);
+                   set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size));
+                   continue;
+              }
+
+
+              /*
+               * If this is . or .., then look up the relevant info from the
+               * tables.
+               */
+              if(strcmp(s_entry->name,".") == 0) 
+              {
+                   set_733((char *) s_entry->isorec.extent, dpnt->extent);
+                   
+                   /* 
+                    * Set these so that the hash table has the
+                    * correct information
+                    */
+                   s_entry->starting_block = dpnt->extent;
+                   s_entry->size = ROUND_UP(dpnt->size);
+                   
+                   add_hash(s_entry);
+                   s_entry->starting_block = dpnt->extent;
+                   set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size));
+                   continue;
+              }
+
+              if(strcmp(s_entry->name,"..") == 0) 
+              {
+                   if(dpnt == root)
+                   { 
+                        total_dir_size += root->size;
+                   }
+                   set_733((char *) s_entry->isorec.extent, dpnt->parent->extent);
+                   
+                   /* 
+                    * Set these so that the hash table has the
+                    * correct information
+                    */
+                   s_entry->starting_block = dpnt->parent->extent;
+                   s_entry->size = ROUND_UP(dpnt->parent->size);
+                   
+                   add_hash(s_entry);
+                   s_entry->starting_block = dpnt->parent->extent;
+                   set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
+                   continue;
+              }
+
+              /* 
+               * Some ordinary non-directory file.  Just schedule the
+               * file to be written.  This is all quite
+               * straightforward, just make a list and assign extents
+               * as we go.  Once we get through writing all of the
+               * directories, we should be ready write out these
+               * files
+               */
+              if(s_entry->size) 
+              {
+                   dwpnt = (struct deferred_write *) 
+                        e_malloc(sizeof(struct deferred_write));
+                   if(dw_tail)
+                   {
+                        dw_tail->next = dwpnt;
+                        dw_tail = dwpnt;
+                   } 
+                   else 
+                   {
+                        dw_head = dwpnt;
+                        dw_tail = dwpnt;
+                   }
+                   if(s_entry->inode  ==  TABLE_INODE) 
+                   {
+                        dwpnt->table = s_entry->table;
+                        dwpnt->name = NULL;
+                        sprintf(whole_path,"%s%sTRANS.TBL",
+                                s_entry->filedir->whole_name, SPATH_SEPARATOR);
+                   } 
+                   else 
+                   {
+                        dwpnt->table = NULL;
+                        strcpy(whole_path, s_entry->whole_name);
+                        dwpnt->name = strdup(whole_path);
+                   }
+                   dwpnt->next = NULL;
+                   dwpnt->size = s_entry->size;
+                   dwpnt->extent = last_extent;
+                   set_733((char *) s_entry->isorec.extent, last_extent);
+                   s_entry->starting_block = last_extent;
+                   add_hash(s_entry);
+                   last_extent += ROUND_UP(s_entry->size) >> 11;
+                   if(verbose)
+                   {
+                        fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
+                                last_extent-1, whole_path);
+                   }
+#ifdef DBG_ISO
+                   if((ROUND_UP(s_entry->size) >> 11) > 500)
+                   {
+                        fprintf(stderr,"Warning: large file %s\n", whole_path);
+                        fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+                        fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+                        
+                   }
+#endif
+                   if(last_extent > (800000000 >> 11)) 
+                   { 
+                        /*
+                         * More than 800Mb? Punt 
+                         */
+                        fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
+                        fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+                        fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+                        exit(1);
+                   }
+                   continue;
+              }
+
+              /*
+               * This is for zero-length files.  If we leave the extent 0,
+               * then we get screwed, because many readers simply drop files
+               * that have an extent of zero.  Thus we leave the size 0,
+               * and just assign the extent number.
+               */
+              set_733((char *) s_entry->isorec.extent, last_extent);
+         }
+         if(dpnt->subdir) 
+         {
+              assign_file_addresses(dpnt->subdir);
+         }
+         dpnt = dpnt->next;
+     }
+} /* assign_file_addresses(... */
+
+void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
+{
+     unsigned int                        ce_address = 0;
+     char                              * ce_buffer;
+     unsigned int                        ce_index = 0;
+     unsigned int                        ce_size;
+     unsigned int                        dir_index;
+     char                              * directory_buffer;
+     int                                 new_reclen;
+     struct directory_entry            * s_entry;
+     struct directory_entry            * s_entry_d;
+     unsigned int                        total_size;
+     
+     total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
+     directory_buffer = (char *) e_malloc(total_size);
+     memset(directory_buffer, 0, total_size);
+     dir_index = 0;
+     
+     ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
+     ce_buffer = NULL;
+     
+     if(ce_size) 
+     {
+         ce_buffer = (char *) e_malloc(ce_size);
+         memset(ce_buffer, 0, ce_size);
+         
+         ce_index = 0;
+         
+         /*
+          * Absolute byte address of CE entries for this directory 
+          */
+         ce_address = last_extent_written + (total_size >> 11);
+         ce_address = ce_address << 11;
+     }
+     
+     s_entry = dpnt->contents;
+     while(s_entry) 
+     {
+
+         /* 
+          * We do not allow directory entries to cross sector boundaries.  
+          * Simply pad, and then start the next entry at the next sector 
+          */
+         new_reclen = s_entry->isorec.length[0];
+         if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
+         {
+              dir_index = (dir_index + (SECTOR_SIZE - 1)) & 
+                   ~(SECTOR_SIZE - 1);
+         }
+
+         memcpy(directory_buffer + dir_index, &s_entry->isorec, 
+                sizeof(struct iso_directory_record) -
+                sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
+         dir_index += sizeof(struct iso_directory_record) - 
+              sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
+
+         /*
+          * Add the Rock Ridge attributes, if present 
+          */
+         if(s_entry->rr_attr_size)
+         {
+              if(dir_index & 1)
+              {
+                   directory_buffer[dir_index++] = 0;
+              }
+
+              /* 
+               * If the RR attributes were too long, then write the
+               * CE records, as required.
+               */
+              if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) 
+              {
+                   unsigned char * pnt;
+                   int len, nbytes;
+                   
+                   /* 
+                    * Go through the entire record and fix up the CE entries
+                    * so that the extent and offset are correct 
+                    */
+                   
+                   pnt = s_entry->rr_attributes;
+                   len = s_entry->total_rr_attr_size;
+                   while(len > 3)
+                   {
+#ifdef DEBUG
+                        if (!ce_size)
+                        {
+                             fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n",
+                                     ce_index, ce_address);
+                        }
+#endif
+                        
+                        if(pnt[0] == 'C' && pnt[1] == 'E') 
+                        {
+                             nbytes = get_733( (char *) pnt+20);
+                             
+                             if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
+                                SECTOR_SIZE) 
+                             {
+                                  ce_index = ROUND_UP(ce_index);
+                             }
+                             
+                             set_733( (char *) pnt+4, 
+                                      (ce_address + ce_index) >> 11);
+                             set_733( (char *) pnt+12, 
+                                      (ce_address + ce_index) & (SECTOR_SIZE - 1));
+                             
+                             
+                             /* 
+                              * Now store the block in the ce buffer 
+                              */
+                             memcpy(ce_buffer + ce_index, 
+                                    pnt + pnt[2], nbytes);
+                             ce_index += nbytes;
+                             if(ce_index & 1) 
+                             {
+                                  ce_index++;
+                             }
+                        }
+                        len -= pnt[2];
+                        pnt += pnt[2];
+                   }
+                   
+              }
+
+              rockridge_size += s_entry->total_rr_attr_size;
+              memcpy(directory_buffer + dir_index, s_entry->rr_attributes, 
+                     s_entry->rr_attr_size);
+              dir_index += s_entry->rr_attr_size;
+         }
+         if(dir_index & 1)
+         {
+              directory_buffer[dir_index++] = 0;
+         }
+         
+         s_entry_d = s_entry;
+         s_entry = s_entry->next;
+         
+         if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes);
+         if( s_entry_d->name != NULL )
+           {
+             free (s_entry_d->name);
+           }
+         if( s_entry_d->whole_name != NULL )
+           {
+             free (s_entry_d->whole_name);
+           }
+         free (s_entry_d);
+     }
+     sort_dir = NULL;
+
+     if(dpnt->size != dir_index)
+     {
+         fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, 
+           dir_index, dpnt->de_name);
+     }
+
+     xfwrite(directory_buffer, 1, total_size, outfile);
+     last_extent_written += total_size >> 11;
+     free(directory_buffer);
+
+     if(ce_size)
+     {
+         if(ce_index != dpnt->ce_bytes)
+         {
+              fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
+                      ce_index, dpnt->ce_bytes);
+         }
+         xfwrite(ce_buffer, 1, ce_size, outfile);
+         last_extent_written += ce_size >> 11;
+         free(ce_buffer);
+     }
+     
+} /* generate_one_directory(... */
+
+static 
+void FDECL1(build_pathlist, struct directory *, node)
+{
+     struct directory * dpnt;
+     
+     dpnt = node;
+     
+     while (dpnt)
+     {
+         pathlist[dpnt->path_index] = dpnt;
+         if(dpnt->subdir) build_pathlist(dpnt->subdir);
+         dpnt = dpnt->next;
+     }
+} /* build_pathlist(... */
+
+int FDECL2(compare_paths, void const *, r, void const *, l) 
+{
+  struct directory const *ll = *(struct directory * const *)l;
+  struct directory const *rr = *(struct directory * const *)r;
+
+  if (rr->parent->path_index < ll->parent->path_index)
+  {
+       return -1;
+  }
+
+  if (rr->parent->path_index > ll->parent->path_index) 
+  {
+       return 1;
+  }
+
+  return strcmp(rr->self->isorec.name, ll->self->isorec.name);
+  
+} /* compare_paths(... */
+
+void generate_path_tables()
+{
+  struct directory_entry * de;
+  struct directory      * dpnt;
+  int                     fix;
+  int                     i;
+  int                     j;
+  int                     namelen;
+  char                  * npnt;
+  char                  * npnt1;
+  int                     tablesize;
+
+  /*
+   * First allocate memory for the tables and initialize the memory 
+   */
+  tablesize = path_blocks << 11;
+  path_table_m = (char *) e_malloc(tablesize);
+  path_table_l = (char *) e_malloc(tablesize);
+  memset(path_table_l, 0, tablesize);
+  memset(path_table_m, 0, tablesize);
+
+  /*
+   * Now start filling in the path tables.  Start with root directory 
+   */
+  path_table_index = 0;
+  pathlist = (struct directory **) e_malloc(sizeof(struct directory *) 
+                                           * next_path_index);
+  memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
+  build_pathlist(root);
+
+  do
+  {
+       fix = 0;
+       qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), 
+            (int (*)(const void *, const void *))compare_paths);
+
+       for(j=1; j<next_path_index; j++)
+       {
+           if(pathlist[j]->path_index != j)
+           {
+                pathlist[j]->path_index = j;
+                fix++;
+           }
+       }
+  } while(fix);
+
+  for(j=1; j<next_path_index; j++)
+  {
+       dpnt = pathlist[j];
+       if(!dpnt)
+       {
+           fprintf(stderr,"Entry %d not in path tables\n", j);
+           exit(1);
+       }
+       npnt = dpnt->de_name;
+       
+       /* 
+       * So the root comes out OK 
+       */
+       if( (*npnt == 0) || (dpnt == root) ) 
+       {
+           npnt = ".";  
+       }
+       npnt1 = strrchr(npnt, PATH_SEPARATOR);
+       if(npnt1) 
+       { 
+           npnt = npnt1 + 1;
+       }
+       
+       de = dpnt->self;
+       if(!de) 
+       {
+           fprintf(stderr,"Fatal goof\n"); 
+           exit(1);
+       }
+       
+       
+       namelen = de->isorec.name_len[0];
+       
+       path_table_l[path_table_index] = namelen;
+       path_table_m[path_table_index] = namelen;
+       path_table_index += 2;
+       
+       set_731(path_table_l + path_table_index, dpnt->extent); 
+       set_732(path_table_m + path_table_index, dpnt->extent); 
+       path_table_index += 4;
+       
+       set_721(path_table_l + path_table_index, 
+              dpnt->parent->path_index); 
+       set_722(path_table_m + path_table_index, 
+              dpnt->parent->path_index); 
+       path_table_index += 2;
+       
+       for(i =0; i<namelen; i++)
+       {
+           path_table_l[path_table_index] = de->isorec.name[i];
+           path_table_m[path_table_index] = de->isorec.name[i];
+           path_table_index++;
+       }
+       if(path_table_index & 1) 
+       {
+           path_table_index++;  /* For odd lengths we pad */
+       }
+  }
+  
+  free(pathlist);
+  if(path_table_index != path_table_size)
+  {
+       fprintf(stderr,"Path table lengths do not match %d %d\n",
+              path_table_index,
+              path_table_size);
+  }
+} /* generate_path_tables(... */
+
+void
+FDECL3(memcpy_max, char *, to, char *, from, int, max)
+{
+  int n = strlen(from);
+  if (n > max)
+  {
+       n = max;
+  }
+  memcpy(to, from, n);
+
+} /* memcpy_max(... */
+
+int FDECL1(iso_write, FILE *, outfile)
+{
+  char                         buffer[2048];
+  int                          i;
+  char                         iso_time[17];
+  int                          should_write;
+
+  time(&begun);
+  assign_file_addresses(root);
+
+  memset(buffer, 0, sizeof(buffer));
+
+  /*
+   * This will break  in the year  2000, I supose, but there is no good way
+   * to get the top two digits of the year. 
+   */
+  sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local.tm_year,
+         local.tm_mon+1, local.tm_mday,
+         local.tm_hour, local.tm_min, local.tm_sec);
+
+  local.tm_min -= gmt.tm_min;
+  local.tm_hour -= gmt.tm_hour;
+  local.tm_yday -= gmt.tm_yday;
+  iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15;
+
+ /*
+   * First, we output 16 sectors of all zero 
+   */
+
+  for(i=0; i<16; i++)
+    {
+      xfwrite(buffer, 1, sizeof(buffer), outfile);
+    }
+
+  last_extent_written += 16;
+
+  /*
+   * Next we write out the primary descriptor for the disc 
+   */
+  memset(&vol_desc, 0, sizeof(vol_desc));
+  vol_desc.type[0] = ISO_VD_PRIMARY;
+  memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+  vol_desc.version[0] = 1;
+  
+  memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
+  memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
+  
+  memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
+  memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
+  
+  should_write = last_extent - session_start;
+  set_733((char *) vol_desc.volume_space_size, should_write);
+  set_723(vol_desc.volume_set_size, 1);
+  set_723(vol_desc.volume_sequence_number, DEF_VSN);
+  set_723(vol_desc.logical_block_size, 2048);
+  
+  /*
+   * The path tables are used by DOS based machines to cache directory
+   * locations 
+   */
+
+  set_733((char *) vol_desc.path_table_size, path_table_size);
+  set_731(vol_desc.type_l_path_table, path_table[0]);
+  set_731(vol_desc.opt_type_l_path_table, path_table[1]);
+  set_732(vol_desc.type_m_path_table, path_table[2]);
+  set_732(vol_desc.opt_type_m_path_table, path_table[3]);
+
+  /*
+   * Now we copy the actual root directory record 
+   */
+  memcpy(vol_desc.root_directory_record, &root_record, 
+        sizeof(struct iso_directory_record) + 1);
+
+  /*
+   * The rest is just fluff.  It looks nice to fill in many of these fields,
+   * though.
+   */
+  FILL_SPACE(volume_set_id);
+  if(volset_id)  memcpy_max(vol_desc.volume_set_id,  volset_id, strlen(volset_id));
+
+  FILL_SPACE(publisher_id);
+  if(publisher)  memcpy_max(vol_desc.publisher_id,  publisher, strlen(publisher));
+
+  FILL_SPACE(preparer_id);
+  if(preparer)  memcpy_max(vol_desc.preparer_id,  preparer, strlen(preparer));
+
+  FILL_SPACE(application_id);
+  if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
+
+  FILL_SPACE(copyright_file_id);
+  if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, 
+                      strlen(copyright));
+
+  FILL_SPACE(abstract_file_id);
+  if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, 
+                         strlen(abstract));
+
+  FILL_SPACE(bibliographic_file_id);
+  if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, 
+                      strlen(biblio));
+
+  FILL_SPACE(creation_date);
+  FILL_SPACE(modification_date);
+  FILL_SPACE(expiration_date);
+  FILL_SPACE(effective_date);
+  vol_desc.file_structure_version[0] = 1;
+  FILL_SPACE(application_data);
+
+  memcpy(vol_desc.creation_date,  iso_time, 17);
+  memcpy(vol_desc.modification_date,  iso_time, 17);
+  memcpy(vol_desc.expiration_date, "0000000000000000", 17);
+  memcpy(vol_desc.effective_date,  iso_time,  17);
+
+  /*
+   * if not a bootable cd do it the old way 
+   */
+  xfwrite(&vol_desc, 1, 2048, outfile);
+  last_extent_written++;
+  if (use_eltorito) 
+    {
+      /*
+       * Next we write out the boot volume descriptor for the disc 
+       */
+      get_torito_desc(&boot_desc);
+      xfwrite(&boot_desc, 1, 2048, outfile);
+      last_extent_written ++;
+    }
+  
+  /*
+   * Now write the end volume descriptor.  Much simpler than the other one 
+   */
+  memset(&vol_desc, 0, sizeof(vol_desc));
+  vol_desc.type[0] = ISO_VD_END;
+  memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+  vol_desc.version[0] = 1;
+  xfwrite(&vol_desc, 1, 2048, outfile);
+  last_extent_written += 1;
+
+  /*
+   * Next we write the path tables 
+   */
+  xfwrite(path_table_l, 1, path_blocks << 11, outfile);
+  xfwrite(path_table_m, 1, path_blocks << 11, outfile);
+  last_extent_written += 2*path_blocks;
+  free(path_table_l);
+  free(path_table_m);
+  path_table_l = NULL;
+  path_table_m = NULL;
+
+  /*
+   * OK, all done with that crap.  Now write out the directories.
+   * This is where the fur starts to fly, because we need to keep track of
+   * each file as we find it and keep track of where we put it. 
+   */
+
+#ifdef DBG_ISO
+  fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
+#endif
+#if 0 
+ generate_one_directory(root, outfile);
+#endif
+  generate_iso9660_directories(root, outfile);
+
+  if(extension_record) 
+    {
+      xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
+      last_extent_written++;
+    }
+
+  /* 
+   * Now write all of the files that we need. 
+   */
+  fprintf(stderr,"Total extents scheduled to be written = %d\n", 
+         last_extent - session_start);
+  write_files(outfile);
+  
+  fprintf(stderr,"Total extents actually written = %d\n", 
+         last_extent_written - session_start);
+  /* 
+   * Hard links throw us off here 
+   */
+  if(should_write != last_extent - session_start)
+    {
+      fprintf(stderr,"Number of extents written not what was predicted.  Please fix.\n");
+      fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
+    }
+
+  fprintf(stderr,"Total translation table size: %d\n", table_size);
+  fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
+  fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
+  fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
+
+#ifdef DEBUG
+  fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
+         next_extent, last_extent, last_extent_written);
+#endif
+
+  return 0;
+
+} /* iso_write(... */