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

index 91e678992576f2379778011e3b27132dfdb7b2cd..9e8f3331ad68a9fc81c8f1a2f86f549c9bbfc0c3 100644 (file)
@@ -2,7 +2,7 @@
  * 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 $
+ *     $Id: defaults.h,v 1.6 1998/06/02 02:40:37 eric Exp $
  */
 
 #define  PREPARER_DEFAULT      NULL
 #endif
 
 #ifdef __sun
-#define  SYSTEM_ID_DEFAULT     "Solaris"
+#ifdef __svr4__
+#define  SYSTEM_ID_DEFAULT    "Solaris"
+#else
+#define  SYSTEM_ID_DEFAULT    "SunOS"
+#endif
 #endif
 
 #ifdef __hpux
 #define  SYSTEM_ID_DEFAULT     "AIX"
 #endif
 
+#ifdef _WIN
+#define        SYSTEM_ID_DEFAULT       "Win32"
+#endif /* _WIN */
+
 #ifndef SYSTEM_ID_DEFAULT
 #define  SYSTEM_ID_DEFAULT     "LINUX"
 #endif
index 0ac5a129036151f3dd09a0d0ece7abf67bbebbc2..3ff50e92e7a9e25146fff37314abd237da795bd8 100644 (file)
@@ -21,7 +21,7 @@
    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 $";
+static char rcsid[] ="$Id: eltorito.c,v 1.12 1998/06/02 02:40:37 eric Exp $";
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -30,14 +30,22 @@ static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $";
 #include <fcntl.h>
 #include <stdlib.h>
 
+#include "config.h"
 #include "mkisofs.h"
 #include "iso9660.h"
 
+/* used by Win32 for opening binary file - not used by Unix */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif /* O_BINARY */
+
 #undef MIN
 #define MIN(a, b) (((a) < (b))? (a): (b))
 
 static struct eltorito_validation_entry valid_desc;
 static struct eltorito_defaultboot_entry default_desc;
+static struct eltorito_boot_descriptor boot_desc;
+
 
 /*
  * Check for presence of boot catalog. If it does not exist then make it 
@@ -63,7 +71,7 @@ void FDECL1(init_boot_catalog, const char *, path)
      * check for the file existing 
      */
 #ifdef DEBUG_TORITO
-    printf("Looking for boot catalog file %s\n",bootpath);
+    fprintf(stderr,"Looking for boot catalog file %s\n",bootpath);
 #endif
     
     if (!stat_filter(bootpath, &statbuf)) 
@@ -93,7 +101,7 @@ void FDECL1(init_boot_catalog, const char *, path)
      * 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 );
+    bcat = open(bootpath, O_WRONLY | O_CREAT | O_BINARY, S_IROTH | S_IRGRP | S_IRWXU );
     if (bcat == -1) 
     {
        fprintf(stderr, "Error creating boot catalog, exiting...\n");
@@ -207,7 +215,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
      * assume 512 bytes/sector on a bootable floppy
      */
     nsectors = ((de->size + 511) & ~(511))/512;
-    printf("\nSize of boot image is %d sectors -> ", nsectors); 
+    fprintf(stderr, "\nSize of boot image is %d sectors -> ", nsectors); 
     
     /*
      * choose size of emulated floppy based on boot image size 
@@ -215,17 +223,17 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
     if (nsectors == 2880 ) 
     {
        default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP;
-       printf("Emulating a 1.44 meg floppy\n");
+       fprintf(stderr, "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");
+       fprintf(stderr,"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");
+       fprintf(stderr,"Emulating a 1.2 meg floppy\n");
     }
     else 
     {
@@ -240,7 +248,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
     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));
+    fprintf(stderr,"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));
@@ -248,7 +256,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
     /*
      * now write it to disk 
      */
-    bootcat = open(de2->whole_name, O_RDWR);
+    bootcat = open(de2->whole_name, O_RDWR | O_BINARY);
     if (bootcat == -1) 
     {
        fprintf(stderr,"Error opening boot catalog for update.\n");
@@ -263,3 +271,19 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
     write(bootcat, &default_desc, 32);
     close(bootcat);
 } /* get_torito_desc(... */
+
+/*
+ * Function to write the EVD for the disc.
+ */
+int FDECL1(tvd_write, FILE *, outfile)
+{
+  /*
+   * 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 ++;
+  return 0;
+}
+
+struct output_fragment torito_desc    = {NULL, oneblock_size, NULL,     tvd_write};
diff --git a/util/mkisofs/getopt.c b/util/mkisofs/getopt.c
new file mode 100644 (file)
index 0000000..79080aa
--- /dev/null
@@ -0,0 +1,760 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95
+       Free Software Foundation, Inc.
+
+This file is part of the libiberty library.  This library 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 library 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As a special exception, if you link this library with files
+compiled with a GNU compiler to produce an executable, this does not cause
+the resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why
+the executable file might be covered by the GNU General Public License. */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+   (which it would do because it found this file in $srcdir).  */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* 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.  */
+/* Many versions of the Linux C library include older, broken versions
+   of these routines, which will break the linker's command-line
+   parsing.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined (__linux__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define        my_index        strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#ifndef __STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+static const char *
+_getopt_initialize (optstring)
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (getenv ("POSIXLY_CORRECT") != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+  return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0)
+    optstring = _getopt_initialize (optstring);
+
+  if (argc == 0)
+    return EOF;
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* The special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+         || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+       /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+        or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+       if (!strncmp (p->name, nextchar, nameend - nextchar))
+         {
+           if (nameend - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second or later nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*nameend)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = nameend + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+           /* 1003.2 specifies the format of this message.  */
+           fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+         }
+       optopt = c;
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = NULL;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr, "%s: option requires an argument -- %c\n",
+                            argv[0], c);
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/util/mkisofs/getopt1.c b/util/mkisofs/getopt1.c
new file mode 100644 (file)
index 0000000..c3400e5
--- /dev/null
@@ -0,0 +1,190 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library 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 Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+   (which it would do because it found this file in $srcdir).  */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* 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.  */
+/* Many versions of the Linux C library include older, broken versions
+   of these routines, which will break the linker's command-line
+   parsing.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined (__linux__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
index 67098d580adc023478ba70de03e2d57abb0ac2dc..eb673393e65969797a1b3edc2f0e2aefcf3bc8ab 100644 (file)
    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 $";
+static char rcsid[] ="$Id: hash.c,v 1.4 1997/12/06 21:05:04 eric Exp $";
 
 #include <stdlib.h>
+#include "config.h"
 #include "mkisofs.h"
 
 #define NR_HASH 1024
@@ -44,7 +45,7 @@ void FDECL1(add_hash, struct directory_entry *, spnt){
   hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
 
 #if 0
-  if (verbose) fprintf(stderr,"%s ",spnt->name);
+  if (verbose > 1) fprintf(stderr,"%s ",spnt->name);
 #endif
   s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
   s_hash->next = hash_table[hash_number];
index a58f96f0da38eb3be41f1256da0f512ea12281e8..65320121def89ffbaa92feb4e38c55d1d416a7b3 100644 (file)
@@ -21,7 +21,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /*
- *     $Id: iso9660.h,v 1.1 1997/02/23 15:55:25 eric Rel $
+ *     $Id: iso9660.h,v 1.2 1997/05/17 15:46:44 eric Exp $
  */
 
 #ifndef _ISOFS_FS_H
@@ -42,8 +42,9 @@ struct iso_volume_descriptor {
 };
 
 /* volume descriptor types */
-#define ISO_VD_PRIMARY 1
-#define ISO_VD_END 255
+#define ISO_VD_PRIMARY       1
+#define ISO_VD_SUPPLEMENTARY 2     /* Used by Joliet */
+#define ISO_VD_END           255
 
 #define ISO_STANDARD_ID "CD001"
 
@@ -67,7 +68,7 @@ struct iso_primary_descriptor {
        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 escape_sequences           [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 */
diff --git a/util/mkisofs/joliet.c b/util/mkisofs/joliet.c
new file mode 100644 (file)
index 0000000..d3e8cb0
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
+
+   Copyright 1997 Eric Youngdale.
+
+   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: joliet.c,v 1.12 1998/06/02 02:40:37 eric Exp $";
+
+
+/*
+ * Joliet extensions for ISO9660.  These are spottily documented by
+ * Microsoft.  In their infinite stupidity, they completely ignored
+ * the possibility of using an SUSP record with the long filename
+ * in it, and instead wrote out a duplicate directory tree with the
+ * long filenames in it.
+ *
+ * I am not sure why they did this.  One reason is that they get the path
+ * tables with the long filenames in them.
+ *
+ * There are two basic principles to Joliet, and the non-Unicode variant
+ * known as Romeo.  Long filenames seem to be the main one, and the second
+ * is that the character set and a few other things is substantially relaxed.
+ *
+ * The SVD is identical to the PVD, except:
+ *
+ *     Id is 2, not 1 (indicates SVD).
+ *     escape_sequences contains UCS-2 indicator (levels 1, 2 or 3).
+ *     The root directory record points to a different extent (with different
+ *             size).
+ *     There are different path tables for the two sets of directory trees.
+ *
+ * The following fields are recorded in Unicode:
+ *     system_id
+ *     volume_id
+ *     volume_set_id
+ *     publisher_id
+ *     preparer_id
+ *     application_id
+ *     copyright_file_id
+ *     abstract_file_id
+ *     bibliographic_file_id
+ *
+ * Unicode strings are always encoded in big-endian format.
+ *
+ * In a directory record, everything is the same as with iso9660, except
+ * that the name is recorded in unicode.  The name length is specified in
+ * total bytes, not in number of unicode characters.
+ *
+ * The character set used for the names is different with UCS - the
+ * restrictions are that the following are not allowed:
+ *
+ *     Characters (00)(00) through (00)(1f) (control chars)
+ *     (00)(2a) '*'
+ *     (00)(2f) '/'
+ *     (00)(3a) ':'
+ *     (00)(3b) ';'
+ *     (00)(3f) '?'
+ *     (00)(5c) '\'
+ */
+#include "config.h"
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+static jpath_table_index;
+static struct directory ** jpathlist;
+static     next_jpath_index  = 1;
+static int sort_goof;
+
+static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir));
+static void DECL(assign_joliet_directory_addresses, (struct directory * node));
+
+/* 
+ * Function:           convert_to_unicode
+ *
+ * Purpose:            Perform a 1/2 assed unicode conversion on a text
+ *                     string.
+ *
+ * Notes:              
+ */
+static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char *, source )
+{
+  unsigned char * tmpbuf;
+  int i;
+  int j;
+
+  /*
+   * If we get a NULL pointer for the source, it means we have an inplace
+   * copy, and we need to make a temporary working copy first.
+   */
+  if( source == NULL )
+    {
+      tmpbuf = (u_char *) e_malloc(size);
+      memcpy( tmpbuf, buffer, size);
+    }
+  else
+    {
+      tmpbuf = (u_char *)source;
+    }
+
+  /*
+   * Now start copying characters.  If the size was specified to be 0, then
+   * assume the input was 0 terminated.
+   */
+  j = 0;
+  for(i=0; i < size ; i += 2, j++)
+    {
+      buffer[i]       = 0;
+      if( tmpbuf[j] < 0x1f && tmpbuf[j] != 0 )
+       {
+         buffer[i+1]     = '_';
+       }
+      else
+       {
+         switch(tmpbuf[j])
+           {
+           case '*':
+           case '/':
+           case ':':
+           case ';':
+           case '?':
+           case '\\':
+             /*
+              * Even Joliet has some standards as to what is allowed in a pathname.
+              * Pretty tame in comparison to what DOS restricts you to.
+              */
+             buffer[i+1]     = '_';
+             break;
+           default:
+             buffer[i+1]     = tmpbuf[j];
+             break;
+           }
+       }
+    }
+
+  if( source == NULL )
+    {
+      free(tmpbuf);
+    }
+}
+
+/* 
+ * Function:           joliet_strlen
+ *
+ * Purpose:            Return length in bytes of string after conversion to unicode.
+ *
+ * Notes:              This is provided mainly as a convenience so that when more intelligent
+ *                     Unicode conversion for either Multibyte or 8-bit codes is available that
+ *                     we can easily adapt.
+ */
+static int FDECL1(joliet_strlen, const char *, string)
+{
+  int rtn;
+  struct iso_directory_record foobar;
+
+  rtn = strlen(string) << 1;
+
+  /* 
+   * We do clamp the maximum length of a Joliet string to be the
+   * maximum path size.  This helps to ensure that we don't completely
+   * bolix things up with very long paths.    The Joliet specs say
+   * that the maximum length is 128 bytes, or 64 unicode characters.
+   */
+  if( rtn > 0x80)
+    {
+      rtn = 0x80;
+    }
+  return rtn;
+}
+
+/* 
+ * Function:           get_joliet_vol_desc
+ *
+ * Purpose:            generate a Joliet compatible volume desc.
+ *
+ * Notes:              Assume that we have the non-joliet vol desc
+ *                     already present in the buffer.  Just modifiy the
+ *                     appropriate fields.
+ */
+static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, vol_desc)
+{
+  vol_desc->type[0] = ISO_VD_SUPPLEMENTARY;
+
+  /*
+   * For now, always do Unicode level 3.  I don't really know what 1 and 2
+   * are - perhaps a more limited Unicode set.
+   *
+   * FIXME(eric) - how does Romeo fit in here?
+   */
+  strcpy(vol_desc->escape_sequences, "%/E");
+
+  /*
+   * Until we have Unicode path tables, leave these unset.
+   */
+  set_733((char *) vol_desc->path_table_size, jpath_table_size);
+  set_731(vol_desc->type_l_path_table,     jpath_table[0]);
+  set_731(vol_desc->opt_type_l_path_table, jpath_table[1]);
+  set_732(vol_desc->type_m_path_table,     jpath_table[2]);
+  set_732(vol_desc->opt_type_m_path_table, jpath_table[3]);
+
+  /*
+   * Set this one up.
+   */
+  memcpy(vol_desc->root_directory_record, &jroot_record, 
+        sizeof(struct iso_directory_record) + 1);
+
+  /*
+   * Finally, we have a bunch of strings to convert to Unicode.
+   * FIXME(eric) - I don't know how to do this in general, so we will
+   * just be really lazy and do a char -> short conversion.  We probably
+   * will want to filter any characters >= 0x80.
+   */
+  convert_to_unicode((u_char *)vol_desc->system_id, sizeof(vol_desc->system_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->volume_id, sizeof(vol_desc->volume_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->volume_set_id, sizeof(vol_desc->volume_set_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->publisher_id, sizeof(vol_desc->publisher_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->preparer_id, sizeof(vol_desc->preparer_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->application_id, sizeof(vol_desc->application_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->copyright_file_id, sizeof(vol_desc->copyright_file_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->abstract_file_id, sizeof(vol_desc->abstract_file_id), NULL);
+  convert_to_unicode((u_char *)vol_desc->bibliographic_file_id, sizeof(vol_desc->bibliographic_file_id), NULL);
+
+
+}
+
+static void FDECL1(assign_joliet_directory_addresses, struct directory *, node)
+{
+     int               dir_size;
+     struct directory * dpnt;
+
+     dpnt = node;
+     
+     while (dpnt)
+     {
+        if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
+        {
+            /*
+             * If we already have an extent for this (i.e. it came from
+             * a multisession disc), then don't reassign a new extent.
+             */
+            dpnt->jpath_index = next_jpath_index++;
+            if( dpnt->jextent == 0 )
+            {
+                dpnt->jextent = last_extent;
+                dir_size = (dpnt->jsize + (SECTOR_SIZE - 1)) >> 11;
+                last_extent += dir_size;
+            }
+        }
+        
+        if(dpnt->subdir) 
+        {
+            assign_joliet_directory_addresses(dpnt->subdir);
+        }
+        dpnt = dpnt->next;
+     }
+}
+
+static 
+void FDECL1(build_jpathlist, struct directory *, node)
+{
+     struct directory * dpnt;
+     
+     dpnt = node;
+     
+     while (dpnt)
+
+     {
+       if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
+        {
+          jpathlist[dpnt->jpath_index] = dpnt;
+        }
+       if(dpnt->subdir) build_jpathlist(dpnt->subdir);
+       dpnt = dpnt->next;
+     }
+} /* build_jpathlist(... */
+
+static int FDECL2(joliet_compare_paths, void const *, r, void const *, l) 
+{
+  struct directory const *ll = *(struct directory * const *)l;
+  struct directory const *rr = *(struct directory * const *)r;
+  int rparent, lparent;
+
+  rparent = rr->parent->jpath_index;
+  lparent = ll->parent->jpath_index;
+  if( rr->parent == reloc_dir )
+    {
+      rparent = rr->self->parent_rec->filedir->jpath_index;
+    }
+
+  if( ll->parent == reloc_dir )
+    {
+      lparent = ll->self->parent_rec->filedir->jpath_index;
+    }
+
+  if (rparent < lparent)
+  {
+       return -1;
+  }
+
+  if (rparent > lparent) 
+  {
+       return 1;
+  }
+
+  return strcmp(rr->self->name, ll->self->name);
+  
+} /* compare_paths(... */
+
+static int generate_joliet_path_tables()
+{
+  struct directory_entry * de;
+  struct directory      * dpnt;
+  int                     fix;
+  int                     j;
+  int                     namelen;
+  char                  * npnt;
+  char                  * npnt1;
+  int                     tablesize;
+
+  /*
+   * First allocate memory for the tables and initialize the memory 
+   */
+  tablesize = jpath_blocks << 11;
+  jpath_table_m = (char *) e_malloc(tablesize);
+  jpath_table_l = (char *) e_malloc(tablesize);
+  memset(jpath_table_l, 0, tablesize);
+  memset(jpath_table_m, 0, tablesize);
+
+  /*
+   * Now start filling in the path tables.  Start with root directory 
+   */
+  jpath_table_index = 0;
+  jpathlist = (struct directory **) e_malloc(sizeof(struct directory *) 
+                                           * next_jpath_index);
+  memset(jpathlist, 0, sizeof(struct directory *) * next_jpath_index);
+  build_jpathlist(root);
+
+  do
+  {
+       fix = 0;
+       qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), 
+            (int (*)(const void *, const void *))joliet_compare_paths);
+
+       for(j=1; j<next_jpath_index; j++)
+       {
+           if(jpathlist[j]->jpath_index != j)
+           {
+                jpathlist[j]->jpath_index = j;
+                fix++;
+           }
+       }
+  } while(fix);
+
+  for(j=1; j<next_jpath_index; j++)
+  {
+       dpnt = jpathlist[j];
+       if(!dpnt)
+       {
+           fprintf(stderr,"Entry %d not in path tables\n", j);
+           exit(1);
+       }
+       npnt = dpnt->de_name;
+       
+       npnt1 = strrchr(npnt, PATH_SEPARATOR);
+       if(npnt1) 
+       { 
+           npnt = npnt1 + 1;
+       }
+       
+       de = dpnt->self;
+       if(!de) 
+       {
+           fprintf(stderr,"Fatal goof - directory has amnesia\n"); 
+           exit(1);
+       }
+       
+       namelen = joliet_strlen(de->name);
+
+       if( dpnt == root )
+        {
+          jpath_table_l[jpath_table_index] = 1;
+          jpath_table_m[jpath_table_index] = 1;
+        }
+       else
+        {
+          jpath_table_l[jpath_table_index] = namelen;
+          jpath_table_m[jpath_table_index] = namelen;
+        }
+       jpath_table_index += 2;
+       
+       set_731(jpath_table_l + jpath_table_index, dpnt->jextent); 
+       set_732(jpath_table_m + jpath_table_index, dpnt->jextent); 
+       jpath_table_index += 4;
+       
+       if( dpnt->parent != reloc_dir )
+        {
+          set_721(jpath_table_l + jpath_table_index, 
+                  dpnt->parent->jpath_index); 
+          set_722(jpath_table_m + jpath_table_index, 
+                  dpnt->parent->jpath_index); 
+        }
+       else
+        {
+          set_721(jpath_table_l + jpath_table_index, 
+                  dpnt->self->parent_rec->filedir->jpath_index); 
+          set_722(jpath_table_m + jpath_table_index, 
+                  dpnt->self->parent_rec->filedir->jpath_index); 
+        }
+
+       jpath_table_index += 2;
+       
+       /*
+       * The root directory is still represented in non-unicode fashion.
+       */
+       if( dpnt == root )
+        {
+          jpath_table_l[jpath_table_index] = 0;
+          jpath_table_m[jpath_table_index] = 0;
+          jpath_table_index ++;
+        }
+       else
+        {
+          convert_to_unicode((u_char *)jpath_table_l + jpath_table_index,  
+                             namelen, de->name);
+          convert_to_unicode((u_char *)jpath_table_m + jpath_table_index, 
+                             namelen, de->name);
+          jpath_table_index += namelen;
+        }
+
+       if(jpath_table_index & 1) 
+       {
+           jpath_table_index++;  /* For odd lengths we pad */
+       }
+  }
+  
+  free(jpathlist);
+  if(jpath_table_index != jpath_table_size)
+  {
+       fprintf(stderr,"Joliet path table lengths do not match %d %d\n",
+              jpath_table_index,
+              jpath_table_size);
+  }
+  return 0;
+} /* generate_path_tables(... */
+
+static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE *, outfile)
+{
+     unsigned int                        dir_index;
+     char                              * directory_buffer;
+     int                                 new_reclen;
+     struct directory_entry            * s_entry;
+     struct directory_entry            * s_entry1;
+     struct iso_directory_record         jrec;
+     unsigned int                        total_size;
+     int                                 cvt_len;
+     struct directory                  * finddir;
+     
+     total_size = (dpnt->jsize + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
+     directory_buffer = (char *) e_malloc(total_size);
+     memset(directory_buffer, 0, total_size);
+     dir_index = 0;
+     
+     s_entry = dpnt->jcontents;
+     while(s_entry) 
+     {
+        if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) == 0 )
+        {
+            /*
+             * If this entry was a directory that was relocated, we have a bit
+             * of trouble here.  We need to dig out the real thing and put it
+             * back here.  In the Joliet tree, there is no relocated rock
+             * ridge, as there are no depth limits to a directory tree.
+             */
+            if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
+            {
+                for(s_entry1 = reloc_dir->contents; s_entry1; s_entry1 = s_entry1->next)
+                {
+                    if( s_entry1->parent_rec == s_entry )
+                    {
+                        break;
+                    }
+                }
+                if( s_entry1 == NULL )
+                {
+                    /*
+                     * We got trouble.
+                     */
+                    fprintf(stderr, "Unable to locate relocated directory\n");
+                    exit(1);
+                }
+            }
+            else
+            {
+                s_entry1 = 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_entry1->jreclen;
+            if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
+            {
+                dir_index = (dir_index + (SECTOR_SIZE - 1)) & 
+                    ~(SECTOR_SIZE - 1);
+            }
+            
+            memcpy(&jrec, &s_entry1->isorec, sizeof(struct iso_directory_record) -
+                   sizeof(s_entry1->isorec.name));
+            
+            cvt_len = joliet_strlen(s_entry1->name);
+            
+            /*
+             * Fix the record length - this was the non-Joliet version we
+             * were seeing.
+             */
+            jrec.name_len[0] = cvt_len;
+            jrec.length[0] = s_entry1->jreclen;
+            
+            /*
+             * If this is a directory, fix the correct size and extent
+             * number.
+             */
+            if( (jrec.flags[0] & 2) != 0 )
+            {
+                if(strcmp(s_entry1->name,".") == 0) 
+                {
+                    jrec.name_len[0] = 1;
+                    set_733((char *) jrec.extent, dpnt->jextent);
+                    set_733((char *) jrec.size, ROUND_UP(dpnt->jsize));
+                }
+                else if(strcmp(s_entry1->name,"..") == 0) 
+                {
+                    jrec.name_len[0] = 1;
+                    if( dpnt->parent == reloc_dir )
+                    {
+                        set_733((char *) jrec.extent, dpnt->self->parent_rec->filedir->jextent);
+                        set_733((char *) jrec.size, ROUND_UP(dpnt->self->parent_rec->filedir->jsize));
+                    }
+                    else
+
+                    {
+                        set_733((char *) jrec.extent, dpnt->parent->jextent);
+                        set_733((char *) jrec.size, ROUND_UP(dpnt->parent->jsize));
+                    }
+                }
+                else
+                {
+                    if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 )
+                    {
+                        finddir = reloc_dir->subdir;
+                    }
+                    else
+                    {
+                        finddir = dpnt->subdir;
+                    }
+                    while(1==1)
+                    {
+                        if(finddir->self == s_entry1) break;
+                        finddir = finddir->next;
+                        if(!finddir) 
+                        {
+                            fprintf(stderr,"Fatal goof - unable to find directory location\n"); exit(1);
+                        }
+                    }
+                    set_733((char *) jrec.extent, finddir->jextent);
+                    set_733((char *) jrec.size, ROUND_UP(finddir->jsize));
+                }
+            }
+            
+            memcpy(directory_buffer + dir_index, &jrec, 
+                   sizeof(struct iso_directory_record) -
+                   sizeof(s_entry1->isorec.name));
+            
+            
+            dir_index += sizeof(struct iso_directory_record) - 
+                sizeof (s_entry1->isorec.name);
+            
+            /*
+             * Finally dump the Unicode version of the filename.
+             * Note - . and .. are the same as with non-Joliet discs.
+             */
+            if( (jrec.flags[0] & 2) != 0 
+                && strcmp(s_entry1->name, ".") == 0 )
+            {
+                directory_buffer[dir_index++] = 0;
+            }
+            else if( (jrec.flags[0] & 2) != 0 
+                     && strcmp(s_entry1->name, "..") == 0 )
+            {
+                directory_buffer[dir_index++] = 1;
+            }
+            else
+            {
+                convert_to_unicode((u_char *)directory_buffer + dir_index,
+                                   cvt_len,
+                                   s_entry1->name);
+                dir_index += cvt_len;
+            }
+            
+            if(dir_index & 1)
+            {
+                directory_buffer[dir_index++] = 0;
+            }
+        }
+        s_entry = s_entry->jnext;
+     }
+     
+     if(dpnt->jsize != dir_index)
+     {
+        fprintf(stderr,"Unexpected joliet directory length %d %d %s\n",dpnt->jsize, 
+                dir_index, dpnt->de_name);
+     }
+     
+     xfwrite(directory_buffer, 1, total_size, outfile);
+     last_extent_written += total_size >> 11;
+     free(directory_buffer);
+} /* generate_one_joliet_directory(... */
+
+static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir)
+{
+  struct directory_entry  * s_entry;
+  int                      status = 0;
+
+  for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+    {
+      if(  (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
+       {
+         continue;
+       }
+         
+      /*
+       * First update the path table sizes for directories.
+       *
+       * Finally, set the length of the directory entry if Joliet is used.
+       * The name is longer, but no Rock Ridge is ever used here, so
+       * depending upon the options the entry size might turn out to be about
+       * the same.  The Unicode name is always a multiple of 2 bytes, so
+       * we always add 1 to make it an even number.
+       */
+      if(s_entry->isorec.flags[0] ==  2)
+       {
+         if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 
+           {
+             jpath_table_size += joliet_strlen(s_entry->name) + sizeof(struct iso_path_table) - 1;
+             if (jpath_table_size & 1) 
+               {
+                 jpath_table_size++;
+               }
+           }
+         else 
+           {
+             if (this_dir == root && strlen(s_entry->name) == 1)
+               {
+                 jpath_table_size += sizeof(struct iso_path_table);
+                 if (jpath_table_size & 1) jpath_table_size++;
+               }
+           }
+       }
+
+      if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 
+       {
+         s_entry->jreclen =    sizeof(struct iso_directory_record)
+           - sizeof(s_entry->isorec.name)
+           + joliet_strlen(s_entry->name) 
+           + 1;
+       }
+      else
+       {
+         /*
+          * Special - for '.' and '..' we generate the same records we
+          * did for non-Joliet discs.
+          */
+         s_entry->jreclen =    sizeof(struct iso_directory_record)
+           - sizeof(s_entry->isorec.name)
+           + 1;
+       }
+
+
+    }
+
+  if( (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0 )
+    {
+      return 0;
+    }
+
+  this_dir->jcontents = this_dir->contents;
+  status = joliet_sort_directory(&this_dir->jcontents);
+
+  /* 
+   * 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->jcontents;
+  for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext)
+    {
+      int jreclen;
+
+      if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 )
+       {
+         continue;
+       }
+
+      jreclen = s_entry->jreclen;
+      
+      if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >= SECTOR_SIZE)
+       {
+         this_dir->jsize = (this_dir->jsize + (SECTOR_SIZE - 1)) & 
+           ~(SECTOR_SIZE - 1);
+       }
+      this_dir->jsize += jreclen;
+    }
+  return status;
+}
+
+/*
+ * Similar to the iso9660 case, except here we perform a full sort based upon the
+ * regular name of the file, not the 8.3 version.
+ */
+static int FDECL2(joliet_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)->name;
+     lpnt = (*l)->name;
+
+     /*
+      * If the entries are the same, this is an error.
+      */
+     if( strcmp(rpnt, lpnt) == 0 )
+       {
+        sort_goof++;
+       }
+     
+     /*
+      *  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;
+         
+         /*
+          * Extensions are not special here.  Don't treat the dot as something that
+          * must be bumped to the start of the list.
+          */
+#if 0
+         if(*rpnt == '.' && *lpnt != '.') return -1;
+         if(*rpnt != '.' && *lpnt == '.') return 1;
+#endif
+         
+         if(*rpnt < *lpnt) return -1;
+         if(*rpnt > *lpnt) return 1;
+         rpnt++;  lpnt++;
+     }
+     if(*rpnt) return 1;
+     if(*lpnt) return -1;
+     return 0;
+}
+
+
+/* 
+ * Function:           sort_directory
+ *
+ * Purpose:            Sort the directory in the appropriate ISO9660
+ *                     order.
+ *
+ * Notes:              Returns 0 if OK, returns > 0 if an error occurred.
+ */
+static int FDECL1(joliet_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;
+         dcount++;
+         s_entry = s_entry->next;
+     }
+  
+     sort_goof = 0;
+     qsort(sortlist, dcount, sizeof(struct directory_entry *), 
+          (int (*)(const void *, const void *))joliet_compare_dirs);
+     
+     /* 
+      * Now reassemble the linked list in the proper sorted order 
+      */
+     for(i=0; i<dcount-1; i++)
+     {
+         sortlist[i]->jnext = sortlist[i+1];
+     }
+
+     sortlist[dcount-1]->jnext = NULL;
+     *sort_dir = sortlist[0];
+     
+     free(sortlist);
+     return sort_goof;
+}
+
+int FDECL1(joliet_sort_tree, struct directory *, node)
+{
+  struct directory * dpnt;
+  int goof = 0;
+
+  dpnt = node;
+
+  while (dpnt){
+    goof = joliet_sort_n_finish(dpnt);
+    if( goof )
+      {
+       break;
+      }
+    if(dpnt->subdir) goof = joliet_sort_tree(dpnt->subdir);
+    if( goof )
+      {
+       break;
+      }
+    dpnt = dpnt->next;
+  }
+  return goof;
+}
+
+static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){
+  struct directory * dpnt;
+
+  dpnt = node;
+
+  while (dpnt)
+    {
+      if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 )
+       {
+         /*
+          * In theory we should never reuse a directory, so this doesn't
+          * make much sense.
+          */
+         if( dpnt->extent > session_start )
+           {
+             generate_one_joliet_directory(dpnt, outfile);
+           }
+       }
+      if(dpnt->subdir) generate_joliet_directories(dpnt->subdir, outfile);
+      dpnt = dpnt->next;
+    }
+}
+
+
+/*
+ * Function to write the EVD for the disc.
+ */
+static int FDECL1(jpathtab_write, FILE *, outfile)
+{
+  /*
+   * Next we write the path tables 
+   */
+  xfwrite(jpath_table_l, 1, jpath_blocks << 11, outfile);
+  xfwrite(jpath_table_m, 1, jpath_blocks << 11, outfile);
+  last_extent_written += 2*jpath_blocks;
+  free(jpath_table_l);
+  free(jpath_table_m);
+  jpath_table_l = NULL;
+  jpath_table_m = NULL;
+  return 0;
+}
+
+static int FDECL1(jdirtree_size, int, starting_extent)
+{
+  assign_joliet_directory_addresses(root);
+  return 0;
+}
+
+static int jroot_gen()
+{
+     jroot_record.length[0] = 1 + sizeof(struct iso_directory_record)
+         - sizeof(jroot_record.name);
+     jroot_record.ext_attr_length[0] = 0;
+     set_733((char *) jroot_record.extent, root->jextent);
+     set_733((char *) jroot_record.size, ROUND_UP(root->jsize));
+     iso9660_date(jroot_record.date, root_statbuf.st_mtime);
+     jroot_record.flags[0] = 2;
+     jroot_record.file_unit_size[0] = 0;
+     jroot_record.interleave[0] = 0;
+     set_723(jroot_record.volume_sequence_number, DEF_VSN);
+     jroot_record.name_len[0] = 1;
+     return 0;
+}
+
+static int FDECL1(jdirtree_write, FILE *, outfile)
+{
+  generate_joliet_directories(root, outfile);
+  return 0;
+}
+
+/*
+ * Function to write the EVD for the disc.
+ */
+static int FDECL1(jvd_write, FILE *, outfile)
+{
+  struct iso_primary_descriptor jvol_desc;
+
+  /*
+   * Next we write out the boot volume descriptor for the disc 
+   */
+  jvol_desc = vol_desc;
+  get_joliet_vol_desc(&jvol_desc);
+  xfwrite(&jvol_desc, 1, 2048, outfile);
+  last_extent_written ++;
+  return 0;
+}
+
+/*
+ * Functions to describe padding block at the start of the disc.
+ */
+static int FDECL1(jpathtab_size, int, starting_extent)
+{
+  jpath_table[0] = starting_extent;
+  jpath_table[1] = 0;
+  jpath_table[2] = jpath_table[0] + jpath_blocks;
+  jpath_table[3] = 0;
+  
+  last_extent += 2*jpath_blocks;
+  return 0;
+}
+
+struct output_fragment joliet_desc    = {NULL, oneblock_size, jroot_gen,jvd_write};
+struct output_fragment jpathtable_desc= {NULL, jpathtab_size, generate_joliet_path_tables,     jpathtab_write};
+struct output_fragment jdirtree_desc  = {NULL, jdirtree_size, NULL,     jdirtree_write};
index a2e2d1874af0dc3ccf25252ff45fef58b182fd93..3344a921aa473dd9baafb5757e399f34488e4d96 100644 (file)
    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 */
+static char rcsid[] ="$Id: mkisofs.c,v 1.29 1998/06/02 03:43:45 eric Exp $";
 
 #include <errno.h>
-#include "mkisofs.h"
 #include "config.h"
+#include "mkisofs.h"
 
 #ifdef linux
 #include <getopt.h>
+#else
+#include "getopt.h"
 #endif
 
 #include "iso9660.h"
@@ -60,7 +60,7 @@ static char rcsid[] ="$Id: mkisofs.c,v 1.10.1.3 1998/06/02 03:36:16 eric Exp $";
 
 struct directory * root = NULL;
 
-static char version_string[] = "mkisofs v1.11.3";
+static char version_string[] = "mkisofs 1.12b4";
 
 FILE * discimage;
 unsigned int next_extent = 0;
@@ -69,19 +69,30 @@ unsigned int session_start = 0;
 unsigned int path_table_size = 0;
 unsigned int path_table[4] = {0,};
 unsigned int path_blocks = 0;
+
+
+unsigned int jpath_table_size = 0;
+unsigned int jpath_table[4] = {0,};
+unsigned int jpath_blocks = 0;
+
 struct iso_directory_record root_record;
+struct iso_directory_record jroot_record;
+
 char * extension_record = NULL;
 int extension_record_extent = 0;
-static  int extension_record_size = 0;
+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 use_Joliet = 0;
+int verbose = 1;
 int all_files  = 0;
 int follow_links = 0;
 int rationalize = 0;
 int generate_tables = 0;
+int print_size = 0;
+int split_output = 0;
 char * preparer = PREPARER_DEFAULT;
 char * publisher = PUBLISHER_DEFAULT;
 char * appid = APPID_DEFAULT;
@@ -101,6 +112,8 @@ 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 */
+int split_SL_component = 1;    /* circumvent a bug in the SunOS driver */
+int split_SL_field = 1;                /* circumvent a bug in the SunOS */
 
 struct rcopts{
   char * tag;
@@ -120,6 +133,110 @@ struct rcopts rcopt[] = {
   {NULL, NULL}
 };
 
+/*
+ * In case it isn't obvious, the option handling code was ripped off from GNU-ld.
+ */
+struct ld_option
+{
+  /* The long option information.  */
+  struct option opt;
+  /* The short option with the same meaning ('\0' if none).  */
+  char shortopt;
+  /* The name of the argument (NULL if none).  */
+  const char *arg;
+  /* The documentation string.  If this is NULL, this is a synonym for
+     the previous option.  */
+  const char *doc;
+  enum
+    {
+      /* Use one dash before long option name.  */
+      ONE_DASH,
+      /* Use two dashes before long option name.  */
+      TWO_DASHES,
+      /* Don't mention this option in --help output.  */
+      NO_HELP
+    } control;
+};
+
+/* Codes used for the long options with no short synonyms.  150 isn't
+   special; it's just an arbitrary non-ASCII char value.  */
+#define OPTION_HELP                    150
+#define OPTION_QUIET                   151
+#define OPTION_NOSPLIT_SL_COMPONENT    152
+#define OPTION_NOSPLIT_SL_FIELD                153
+#define OPTION_PRINT_SIZE              154
+#define OPTION_SPLIT_OUTPUT            155
+
+static const struct ld_option ld_options[] =
+{
+  { {"all-files", no_argument, NULL, 'a'},
+      'a', NULL, "Process all files (don't skip backup files)", ONE_DASH },
+  { {"appid", required_argument, NULL, 'A'},
+      'A', "ID", "Set Application ID" , ONE_DASH },
+  { {"eltorito-boot", required_argument, NULL, 'b'},
+      'b', "FILE", "Set El Torito boot image name" , ONE_DASH },
+  { {"eltorito-catalog", required_argument, NULL, 'c'},
+      'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH },
+  { {"cdwrite-params", required_argument, NULL, 'C'},
+      'C', "PARAMS", "Magic paramters from cdwrite" , ONE_DASH },
+  { {"omit-period", no_argument, NULL, 'd'},
+      'd', NULL, "Omit trailing periods from filenames", ONE_DASH },
+  { {"disable-deep-relocation", no_argument, NULL, 'D'},
+      'D', NULL, "Disable deep directory relocation", ONE_DASH },
+  { {"follow-links", no_argument, NULL, 'f'},
+      'f', NULL, "Follow symbolic links", ONE_DASH },
+  { {"help", no_argument, NULL, OPTION_HELP},
+      '\0', NULL, "Print option help", ONE_DASH },
+  { {NULL, required_argument, NULL, 'i'},
+      'i', "ADD_FILES", "No longer supported" , TWO_DASHES },
+  { {"joliet", no_argument, NULL, 'J'},
+      'J', NULL, "Generate Joliet directory information", ONE_DASH },
+  { {"full-iso9660-filenames", no_argument, NULL, 'l'},
+      'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH },
+  { {"allow-leading-dots", no_argument, NULL, 'L'},
+      'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH },
+  { {"exclude", required_argument, NULL, 'm'},
+      'm', "GLOBFILE", "Exclude file name" , ONE_DASH },
+  { {"prev-session", required_argument, NULL, 'M'},
+      'M', "FILE", "Set path to previous session to merge" , ONE_DASH },
+  { {"omit-version-number", no_argument, NULL, 'N'},
+      'N', NULL, "Omit version number from iso9660 filename", ONE_DASH },
+  { {"no-split-symlink-components", no_argument, NULL, 0},
+      0, NULL, "Inhibit splitting symlink components" , ONE_DASH },
+  { {"no-split-symlink-fields", no_argument, NULL, 0},
+      0, NULL, "Inhibit splitting symlink fields" , ONE_DASH },
+  { {"output", required_argument, NULL, 'o'},
+      'o', "FILE", "Set output file name" , ONE_DASH },
+  { {"preparer", required_argument, NULL, 'p'},
+      'p', "PREP", "Set Volume preparer" , ONE_DASH },
+  { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE},
+      '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH },
+  { {"publisher", required_argument, NULL, 'P'},
+      'P', "PUB", "Set Volume publisher" , ONE_DASH },
+  { {"quiet", no_argument, NULL, OPTION_QUIET},
+      '\0', NULL, "Run quietly", ONE_DASH },
+  { {"rational-rock", no_argument, NULL, 'r'},
+      'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH },
+  { {"rock", no_argument, NULL, 'R'},
+      'R', NULL, "Generate Rock Ridge directory information", ONE_DASH },
+  { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT},
+      '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH },
+  { {"translation-table", no_argument, NULL, 'T'},
+      'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH },
+  { {"verbose", no_argument, NULL, 'v'},
+      'v', NULL, "Verbose", ONE_DASH },
+  { {"volid", required_argument, NULL, 'V'},
+      'V', "ID", "Set Volume ID" , ONE_DASH },
+  { {"old-exclude", required_argument, NULL, 'x'},
+      'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH }
+#ifdef ERIC_neverdef
+  { {"transparent-compression", no_argument, NULL, 'z'},
+      'z', NULL, "Enable transparent compression of files", ONE_DASH },
+#endif
+};
+
+#define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0])
+
 #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;}
@@ -179,7 +296,11 @@ void FDECL1(read_rcfile, char *, appname)
     }
   if (!rcfile)
     return;
-  fprintf(stderr, "Using \"%s\"\n", filename);
+  if ( verbose > 0 )
+    {
+      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))
@@ -260,20 +381,113 @@ void FDECL1(read_rcfile, char *, appname)
 
 char * path_table_l = NULL;
 char * path_table_m = NULL;
+
+char * jpath_table_l = NULL;
+char * jpath_table_m = NULL;
+
 int goof = 0;
 
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
 void usage(){
+  const char * program_name = "mkisofs";
+#if 0
        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);
+#endif
+
+  int i;
+  const char **targets, **pp;
+
+  fprintf (stderr, "Usage: %s [options] file...\n", program_name);
+
+  fprintf (stderr, "Options:\n");
+  for (i = 0; i < OPTION_COUNT; i++)
+    {
+      if (ld_options[i].doc != NULL)
+       {
+         int comma;
+         int len;
+         int j;
+
+         fprintf (stderr, "  ");
+
+         comma = FALSE;
+         len = 2;
+
+         j = i;
+         do
+           {
+             if (ld_options[j].shortopt != '\0'
+                 && ld_options[j].control != NO_HELP)
+               {
+                 fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt);
+                 len += (comma ? 2 : 0) + 2;
+                 if (ld_options[j].arg != NULL)
+                   {
+                     if (ld_options[j].opt.has_arg != optional_argument)
+                       {
+                         fprintf (stderr, " ");
+                         ++len;
+                       }
+                     fprintf (stderr, "%s", ld_options[j].arg);
+                     len += strlen (ld_options[j].arg);
+                   }
+                 comma = TRUE;
+               }
+             ++j;
+           }
+         while (j < OPTION_COUNT && ld_options[j].doc == NULL);
+
+         j = i;
+         do
+           {
+             if (ld_options[j].opt.name != NULL
+                 && ld_options[j].control != NO_HELP)
+               {
+                 fprintf (stderr, "%s-%s%s",
+                         comma ? ", " : "",
+                         ld_options[j].control == TWO_DASHES ? "-" : "",
+                         ld_options[j].opt.name);
+                 len += ((comma ? 2 : 0)
+                         + 1
+                         + (ld_options[j].control == TWO_DASHES ? 1 : 0)
+                         + strlen (ld_options[j].opt.name));
+                 if (ld_options[j].arg != NULL)
+                   {
+                     fprintf (stderr, " %s", ld_options[j].arg);
+                     len += 1 + strlen (ld_options[j].arg);
+                   }
+                 comma = TRUE;
+               }
+             ++j;
+           }
+         while (j < OPTION_COUNT && ld_options[j].doc == NULL);
+
+         if (len >= 30)
+           {
+             fprintf (stderr, "\n");
+             len = 0;
+           }
+
+         for (; len < 30; len++)
+           fputc (' ', stderr);
+
+         fprintf (stderr, "%s\n", ld_options[i].doc);
+       }
+    }
+  exit(1);
 }
 
 
@@ -326,15 +540,18 @@ extern char * cdwrite_data;
 int FDECL2(main, int, argc, char **, argv){
   char * outfile;
   struct directory_entry de;
+#ifdef HAVE_SBRK
   unsigned long mem_start;
+#endif
   struct stat statbuf;
   char * scan_tree;
   char * merge_image = NULL;
   struct iso_directory_record * mrootp = NULL;
+  struct output_fragment * opnt;
+  int longind;
+  char shortopts[OPTION_COUNT * 3 + 2];
+  struct option longopts[OPTION_COUNT + 1];
   int c;
-#ifdef ADD_FILES
-  char *add_file_file = NULL;
-#endif
 
   if (argc < 2)
     usage();
@@ -343,9 +560,56 @@ int FDECL2(main, int, argc, char **, argv){
   read_rcfile(argv[0]);
 
   outfile = NULL;
-  while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF)
+
+  /*
+   * Copy long option initialization from GNU-ld.
+   */
+  /* Starting the short option string with '-' is for programs that
+     expect options and other ARGV-elements in any order and that care about
+     the ordering of the two.  We describe each non-option ARGV-element
+     as if it were the argument of an option with character code 1.  */
+  {
+    int i, is, il;
+    shortopts[0] = '-';
+    is = 1;
+    il = 0;
+    for (i = 0; i < OPTION_COUNT; i++)
+      {
+       if (ld_options[i].shortopt != '\0')
+         {
+           shortopts[is] = ld_options[i].shortopt;
+           ++is;
+           if (ld_options[i].opt.has_arg == required_argument
+               || ld_options[i].opt.has_arg == optional_argument)
+             {
+               shortopts[is] = ':';
+               ++is;
+               if (ld_options[i].opt.has_arg == optional_argument)
+                 {
+                   shortopts[is] = ':';
+                   ++is;
+                 }
+             }
+         }
+       if (ld_options[i].opt.name != NULL)
+         {
+           longopts[il] = ld_options[i].opt;
+           ++il;
+         }
+      }
+    shortopts[is] = '\0';
+    longopts[il].name = NULL;
+  }
+
+  while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF)
     switch (c)
       {
+      case 1:
+       /*
+        * A filename that we take as input.
+        */
+       optind--;
+       goto parse_input_files;
       case 'C':
        /*
         * This is a temporary hack until cdwrite gets the proper hooks in
@@ -353,6 +617,13 @@ int FDECL2(main, int, argc, char **, argv){
         */
        cdwrite_data = optarg;
        break;
+      case 'i':
+       fprintf(stderr, "-i option no longer supported.\n");
+       exit(1);
+       break;
+      case 'J':
+       use_Joliet++;
+       break;
       case 'a':
        all_files++;
        break;
@@ -388,14 +659,6 @@ int FDECL2(main, int, argc, char **, argv){
       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;
@@ -418,6 +681,9 @@ int FDECL2(main, int, argc, char **, argv){
                exit(1);
        };
        break;
+      case OPTION_PRINT_SIZE:
+       print_size++;
+       break;
       case 'P':
        publisher = optarg;
        if(strlen(publisher) > 128) {
@@ -425,6 +691,9 @@ int FDECL2(main, int, argc, char **, argv){
                exit(1);
        };
        break;
+      case OPTION_QUIET:
+       verbose = 0;
+       break;
       case 'R':
        use_RockRidge++;
        break;
@@ -432,6 +701,9 @@ int FDECL2(main, int, argc, char **, argv){
        rationalize++;
        use_RockRidge++;
        break;
+      case OPTION_SPLIT_OUTPUT:
+       split_output++;
+       break;
       case 'T':
        generate_tables++;
        break;
@@ -449,16 +721,32 @@ int FDECL2(main, int, argc, char **, argv){
        transparent_compression++;
 #endif
        break;
+      case 'x':
       case 'm':
+       /*
+        * Somehow two options to do basically the same thing got added somewhere along
+        * the way.  The 'match' code supports limited globbing, so this is the one
+        * that got selected.  Unfortunately the 'x' switch is probably more intuitive.
+        */
         add_match(optarg);
        break;
-      case 'x':
-        exclude(optarg);
+      case OPTION_HELP:
+       usage ();
+       exit (0);
+       break;
+      case OPTION_NOSPLIT_SL_COMPONENT:
+       split_SL_component = 0;
+       break;
+      case OPTION_NOSPLIT_SL_FIELD:
+       split_SL_field = 0;
        break;
       default:
        usage();
        exit(1);
       }
+
+parse_input_files:
+
 #ifdef __NetBSD__
     {
        int resource;
@@ -476,7 +764,7 @@ int FDECL2(main, int, argc, char **, argv){
   mem_start = (unsigned long) sbrk(0);
 #endif
 
-  if(verbose) fprintf(stderr,"%s\n", version_string);
+  if(verbose > 1) fprintf(stderr,"%s\n", version_string);
 
   if(     (cdwrite_data != NULL && merge_image == NULL)
        || (cdwrite_data == NULL && merge_image != NULL) )
@@ -489,12 +777,6 @@ int FDECL2(main, int, argc, char **, argv){
 
   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();
@@ -556,29 +838,187 @@ int FDECL2(main, int, argc, char **, argv){
       memcpy(&de.isorec.extent, mrootp->extent, 8);      
     }
 
+  /*
+   * Create an empty root directory. If we ever scan it for real, we will fill in the
+   * contents.
+   */
+  find_or_create_directory(NULL, "", &de, TRUE);
+
   /*
    * Scan the actual directory (and any we find below it)
-   * for files to write out to the output image.
+   * for files to write out to the output image.  Note - we
+   * take multiple source directories and keep merging them
+   * onto the image.
+   */
+  while(optind < argc)
+    {
+      char * node;
+      struct directory * graft_dir;
+      struct stat        st;
+      char             * short_name;
+      int                status;
+      char   graft_point[1024];
+
+      /*
+       * We would like a syntax like:
+       *
+       * /tmp=/usr/tmp/xxx
+       *
+       * where the user can specify a place to graft each
+       * component of the tree.  To do this, we may have to create
+       * directories along the way, of course.
+       * Secondly, I would like to allow the user to do something
+       * like:
+       *
+       * /home/baz/RMAIL=/u3/users/baz/RMAIL
+       *
+       * so that normal files could also be injected into the tree
+       * at an arbitrary point.
+       *
+       * The idea is that the last component of whatever is being
+       * entered would take the name from the last component of
+       * whatever the user specifies.
+       *
+       * The default will be that the file is injected at the
+       * root of the image tree.
+       */
+      node = strchr(argv[optind], '=');
+      short_name = NULL;
+
+      if( node != NULL )
+       {
+         char * pnt;
+         char * xpnt;
+
+         *node = '\0';
+         strcpy(graft_point, argv[optind]);
+         *node = '=';
+         node++;
+
+         graft_dir = root;
+         xpnt = graft_point;
+         if( *xpnt == PATH_SEPARATOR )
+           {
+             xpnt++;
+           }
+
+         /*
+          * Loop down deeper and deeper until we
+          * find the correct insertion spot.
+          */
+         while(1==1)
+           {
+             pnt = strchr(xpnt, PATH_SEPARATOR);
+             if( pnt == NULL )
+               {
+                 if( *xpnt != '\0' )
+                   {
+                     short_name = xpnt;
+                   }
+                 break;
+               }
+             *pnt = '\0';
+             graft_dir = find_or_create_directory(graft_dir, 
+                                                  graft_point, 
+                                                  NULL, TRUE);
+             *pnt = PATH_SEPARATOR;
+             xpnt = pnt + 1;
+           }
+       }
+      else
+       {
+         graft_dir = root;
+         node = argv[optind];
+       }
+
+      /*
+       * Now see whether the user wants to add a regular file,
+       * or a directory at this point.
+       */
+      status = stat_filter(node, &st);
+      if( status != 0 )
+       {
+         /*
+          * This is a fatal error - the user won't be getting what
+          * they want if we were to proceed.
+          */
+         fprintf(stderr, "Invalid node - %s\n", node);
+         exit(1);
+       }
+      else
+       {
+         if( S_ISDIR(st.st_mode) )
+           {
+             if (!scan_directory_tree(graft_dir, node, &de))
+               {
+                 exit(1);
+               }
+           }
+         else
+           {
+             if( short_name == NULL )
+               {
+                 short_name = strrchr(node, PATH_SEPARATOR);
+                 if( short_name == NULL || short_name < node )
+                   {
+                     short_name = node;
+                   }
+                 else
+                   {
+                     short_name++;
+                   }
+               }
+             if( !insert_file_entry(graft_dir, node, short_name) )
+               {
+                exit(1);
+               }
+           }
+       }
+
+      optind++;
+    }
+
+
+  /*
+   * Now merge in any previous sessions.  This is driven on the source
+   * side, since we may need to create some additional directories.
    */
-  if (!scan_directory_tree(argv[optind], &de, mrootp))
+  if( merge_image != NULL )
     {
-      exit(1);
+      merge_previous_session(root, mrootp);
     }
 
   /*
-   * Fix a couple of things in the root directory so that everything
-   * is self consistent.
+   * Sort the directories in the required order (by ISO9660).  Also,
+   * choose the names for the 8.3 filesystem if required, and do
+   * any other post-scan work.
    */
-  root->self = root->contents;  /* Fix this up so that the path tables get done right */
+  goof += sort_tree(root);
 
-  if(reloc_dir) sort_n_finish(reloc_dir);
+  if( use_Joliet )
+    {
+      goof += joliet_sort_tree(root);
+    }
 
   if (goof) 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 */
+
   /*
    * OK, ready to write the file.  Open it up, and generate the thing.
    */
-  if (outfile){
+  if (print_size){
+         discimage = fopen("/dev/null", "w");
+         if (!discimage){
+                 fprintf(stderr,"Unable to open /dev/null\n");
+                 exit(1);
+         }
+  } else if (outfile){
          discimage = fopen(outfile, "w");
          if (!discimage){
                  fprintf(stderr,"Unable to open disc image file\n");
@@ -593,54 +1033,120 @@ int FDECL2(main, int, argc, char **, argv){
   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;
+  jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11;
+  if (jpath_blocks & 1) jpath_blocks++;
+
+  /*
+   * Start to set up the linked list that we use to track the
+   * contents of the disc.
+   */
+  outputlist_insert(&padblock_desc);
+
+  /*
+   * PVD for disc.
+   */
+  outputlist_insert(&voldesc_desc);
+
+  /*
+   * SVD for El Torito. MUST be immediately after the PVD!
+   */
+  if( use_eltorito)
+    {
+      outputlist_insert(&torito_desc);
+    }
+
+  /*
+   * SVD for Joliet.
+   */
+  if( use_Joliet)
+    {
+      outputlist_insert(&joliet_desc);
+    }
+
+  /*
+   * Finally the last volume desctiptor.
+   */
+  outputlist_insert(&end_vol);
 
-  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 */
+  outputlist_insert(&pathtable_desc);
+  if( use_Joliet)
+    {
+      outputlist_insert(&jpathtable_desc);
+    }
 
-  assign_directory_addresses(root);
+  outputlist_insert(&dirtree_desc);
+  if( use_Joliet)
+    {
+      outputlist_insert(&jdirtree_desc);
+    }
 
-  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);
-  };
+  outputlist_insert(&dirtree_clean);
 
-  if (use_RockRidge && reloc_dir)
-         finish_cl_pl_entries();
+  if(extension_record) 
+    { 
+      outputlist_insert(&extension_desc);
+    }
 
-  /* Now we generate the path tables that are used by DOS to improve directory
-     access times. */
-  generate_path_tables();
+  outputlist_insert(&files_desc);
 
-  /* Generate root record for volume descriptor. */
-  generate_root_record();
+  /*
+   * Allow room for the various headers we will be writing.  There
+   * will always be a primary and an end volume descriptor.
+   */
+  last_extent = session_start;
+  
+  /*
+   * Calculate the size of all of the components of the disc, and assign
+   * extent numbers.
+   */
+  for(opnt = out_list; opnt; opnt = opnt->of_next )
+    {
+      if( opnt->of_size != NULL )
+       {
+         (*opnt->of_size)(last_extent);
+       }
+    }
 
-  if (verbose)
-    dump_tree(root);
+  /*
+   * Generate the contents of any of the sections that we want to generate.
+   * Not all of the fragments will do anything here - most will generate the
+   * data on the fly when we get to the write pass.
+   */
+  for(opnt = out_list; opnt; opnt = opnt->of_next )
+    {
+      if( opnt->of_generate != NULL )
+       {
+         (*opnt->of_generate)();
+       }
+    }
 
   if( in_image != NULL )
     {
       fclose(in_image);
     }
 
-  iso_write(discimage);
+  /*
+   * Now go through the list of fragments and write the data that corresponds to
+   * each one.
+   */
+  for(opnt = out_list; opnt; opnt = opnt->of_next )
+    {
+      if( opnt->of_write != NULL )
+       {
+         (*opnt->of_write)(discimage);
+       }
+    }
 
+  if( verbose > 0 )
+    {
 #ifdef HAVE_SBRK
-  fprintf(stderr,"Max brk space used %x\n", 
-         (unsigned int)(((unsigned long)sbrk(0)) - mem_start));
+      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);
+      fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
+    }
+
 #ifdef VMS
   return 1;
 #else
index bc264d99a1080c6f13cb9029f8156ce01ec13154..b512a28654cfb169ed960f6a4f2c5fc4b22b5add 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /*
- *     $Id: mkisofs.h,v 1.5 1997/05/17 15:50:28 eric Exp $
+ *     $Id: mkisofs.h,v 1.17 1998/06/02 02:40:38 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
 #ifdef VMS
 #include <sys/dir.h>
 #define dirent direct
-#else
-#include <dirent.h>
 #endif
 
+#ifdef _WIN32
+#define NON_UNIXFS
+#endif /* _WIN32 */
+
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#ifdef linux
-#include <sys/dir.h>
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if defined(HAVE_SYS_NDIR_H)
+#  include <sys/ndir.h>
+# endif
+# if defined(HAVE_SYS_DIR_H)
+#  include <sys/dir.h>
+# endif
+# if defined(HAVE_NDIR_H)
+#  include <ndir.h>
+# endif
+#endif
+
+#if defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#if defined(HAVE_STRINGS_H)
+#include <strings.h>
+#endif
 #endif
 
 #ifdef ultrix
@@ -100,10 +121,12 @@ extern char *optarg;
 
 struct directory_entry{
   struct directory_entry * next;
+  struct directory_entry * jnext;
   struct iso_directory_record isorec;
   unsigned int starting_block;
   unsigned int size;
-  unsigned int priority;
+  unsigned short priority;
+  unsigned char jreclen;       /* Joliet record len */
   char * name;
   char * table;
   char * whole_name;
@@ -125,6 +148,52 @@ struct file_hash{
   unsigned int size;
 };
   
+
+/*
+ * This structure is used to control the output of fragments to the cdrom
+ * image.  Everything that will be written to the output image will eventually
+ * go through this structure.   There are two pieces - first is the sizing where
+ * we establish extent numbers for everything, and the second is when we actually
+ * generate the contents and write it to the output image.
+ *
+ * This makes it trivial to extend mkisofs to write special things in the image.
+ * All you need to do is hook an additional structure in the list, and the rest
+ * works like magic.
+ *
+ * The three passes each do the following:
+ *
+ * The 'size' pass determines the size of each component and assigns the extent number
+ * for that component.
+ *
+ * The 'generate' pass will adjust the contents and pointers as required now that extent
+ * numbers are assigned.   In some cases, the contents of the record are also generated.
+ *
+ * The 'write' pass actually writes the data to the disc.
+ */
+struct output_fragment
+{
+  struct output_fragment * of_next;
+  int                      (*of_size)(int);
+  int                     (*of_generate)(void);
+  int                     (*of_write)(FILE *);
+};
+
+extern struct output_fragment * out_list;
+extern struct output_fragment * out_tail;
+
+extern struct output_fragment padblock_desc;
+extern struct output_fragment voldesc_desc;
+extern struct output_fragment joliet_desc;
+extern struct output_fragment torito_desc;
+extern struct output_fragment end_vol;
+extern struct output_fragment pathtable_desc;
+extern struct output_fragment jpathtable_desc;
+extern struct output_fragment dirtree_desc;
+extern struct output_fragment dirtree_clean;
+extern struct output_fragment jdirtree_desc;
+extern struct output_fragment extension_desc;
+extern struct output_fragment files_desc;
+
 /* 
  * This structure describes one complete directory.  It has pointers
  * to other directories in the overall tree so that it is clear where
@@ -138,6 +207,7 @@ struct directory{
   struct directory * subdir; /* First subdirectory in this directory */
   struct directory * parent;
   struct directory_entry * contents;
+  struct directory_entry * jcontents;
   struct directory_entry * self;
   char * whole_name;  /* Entire path */
   char * de_name;  /* Entire path */
@@ -145,7 +215,12 @@ struct directory{
   unsigned int depth;
   unsigned int size;
   unsigned int extent;
+  unsigned int jsize;
+  unsigned int jextent;
   unsigned short path_index;
+  unsigned short jpath_index;
+  unsigned short dir_flags;
+  unsigned short dir_nlink;
 };
 
 struct deferred{
@@ -163,57 +238,82 @@ 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 unsigned int jpath_table_size;
+extern unsigned int jpath_table[4];
+extern unsigned int jpath_blocks;
+extern char * jpath_table_l;
+extern char * jpath_table_m;
+
 extern struct iso_directory_record root_record;
+extern struct iso_directory_record jroot_record;
 
 extern int use_eltorito;
 extern int use_RockRidge;
+extern int use_Joliet;
 extern int rationalize;
 extern int follow_links;
 extern int verbose;
 extern int all_files;
 extern int generate_tables;
+extern int print_size;
+extern int split_output;
 extern int omit_period;
 extern int omit_version_number;
 extern int transparent_compression;
 extern int RR_relocation_depth;
 extern int full_iso9660_filenames;
+extern int split_SL_component;
+extern int split_SL_field;
 
 /* 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 int DECL(lstat_filter, (char *, struct stat *));
+extern int DECL(sort_tree,(struct directory *));
+extern struct directory *
+           DECL(find_or_create_directory,(struct directory *, const char *,
+                                         struct directory_entry * self, int));
+extern void DECL (finish_cl_pl_entries, (void));
+extern int DECL(scan_directory_tree,(struct directory * this_dir,
+                                    char * path, 
+                                    struct directory_entry * self));
+extern int DECL(insert_file_entry,(struct directory *, char *, 
+                                  char *));
+
 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));
+extern void DECL(update_nlink_field,(struct directory * node));
+extern void DECL (init_fstatbuf, (void));
+extern struct stat root_statbuf;
 
 /* 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 int  DECL(sort_directory,(struct directory_entry **));
 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));
-
+extern int DECL(oneblock_size, (int starting_extent));
+extern struct iso_primary_descriptor vol_desc;
+extern void DECL(xfwrite, (void * buffer, int count, int size, FILE * file));
+extern void DECL(set_732, (char * pnt, unsigned int i));
+extern void DECL(set_722, (char * pnt, unsigned int i));
+extern void DECL(outputlist_insert, (struct output_fragment * frag));
 
 /* multi.c */
 
@@ -228,6 +328,12 @@ extern struct directory_entry **
 extern void 
        DECL(merge_remaining_entries, (struct directory *, 
                                       struct directory_entry **, int));
+extern int 
+       DECL(merge_previous_session, (struct directory *, 
+                                     struct iso_directory_record *));
+
+/* joliet.c */
+int DECL(joliet_sort_tree, (struct directory * node));
 
 /* match.c */
 extern int DECL(matches, (char *));
@@ -245,7 +351,7 @@ 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 void DECL (flush_file_hash, (void));
 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 *));
@@ -320,7 +426,13 @@ extern void * DECL(e_malloc,(size_t));
  * 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
+#define SAFE_TO_REUSE_TABLE_ENTRY  0x01
+#define DIR_HAS_DOT               0x02
+#define DIR_HAS_DOTDOT            0x04
+#define INHIBIT_JOLIET_ENTRY      0x08
+#define INHIBIT_RR_ENTRY          0x10
+#define RELOCATED_DIRECTORY       0x20
+
 /*
  * Volume sequence number to use in all of the iso directory records.
  */
index 13ba6f6d1b3cd1fbabba89c310549b0e555d578e..e49d1c34e162287709b466305b60ad117e5fc50a 100644 (file)
@@ -19,7 +19,7 @@
  * 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 $";
+static char rcsid[] ="$Id: multi.c,v 1.12 1998/06/02 02:40:38 eric Exp $";
 
 #include <stdlib.h>
 #include <string.h>
@@ -137,7 +137,7 @@ FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
 
        while(len >= 4){
                if(pnt[3] != 1) {
-                 printf("**BAD RRVERSION");
+                 fprintf(stderr,"**BAD RRVERSION");
                  return -1;
                };
                if(strncmp((char *) pnt, "NM", 2) == 0) {
@@ -193,7 +193,7 @@ FDECL4(check_rr_dates, struct directory_entry *, dpnt,
         */
        while(len >= 4){
                if(pnt[3] != 1) {
-                 printf("**BAD RRVERSION");
+                 fprintf(stderr,"**BAD RRVERSION");
                  return -1;
                };
 
@@ -750,6 +750,7 @@ void FDECL3(merge_remaining_entries, struct directory *, this_dir,
   struct directory_entry * s_entry;
   unsigned int ttbl_extent = 0;
   unsigned int ttbl_index  = 0;
+  char whole_path[1024];
 
   /*
    * Whatever is leftover in the list needs to get merged back
@@ -762,6 +763,18 @@ void FDECL3(merge_remaining_entries, struct directory *, this_dir,
          continue;
        }
       
+      if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL)
+       {
+         /*
+          * Set the name for this directory.
+          */
+         strcpy(whole_path, this_dir->de_name);
+         strcat(whole_path, SPATH_SEPARATOR);
+         strcat(whole_path, pnt[i]->name);
+
+         pnt[i]->whole_name = strdup(whole_path);
+       }
+
       if( pnt[i]->name != NULL
          && strcmp(pnt[i]->name, "<translation table>") == 0 )
        {
@@ -884,6 +897,7 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
   char                           whole_path[1024];
 
   this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+  memset(this_dir, 0, sizeof(struct directory));
   this_dir->next = NULL;
   this_dir->subdir = NULL;
   this_dir->self = dpnt;
@@ -939,8 +953,23 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
       if( (contents[i]->isorec.flags[0] & 2) != 0 )
        {
          memset(contents[i]->isorec.extent, 0, 8);
+
+         if( strcmp(contents[i]->name, ".") == 0 )
+             this_dir->dir_flags |= DIR_HAS_DOT;
+
+         if( strcmp(contents[i]->name, "..") == 0 )
+             this_dir->dir_flags |= DIR_HAS_DOTDOT;
        }
 
+      /*
+       * Set the whole name for this file.
+       */
+      strcpy(whole_path, this_dir->whole_name);
+      strcat(whole_path, SPATH_SEPARATOR);
+      strcat(whole_path, contents[i]->name);
+
+      contents[i]->whole_name = strdup(whole_path);
+
       contents[i]->next = this_dir->contents;
       contents[i]->filedir = this_dir;
       this_dir->contents = contents[i];
@@ -957,7 +986,13 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
    */
   merge_remaining_entries(this_dir, contents, n_orig);
   free_mdinfo(contents, n_orig);
+#if 0
+  /*
+   * This is no longer required.  The post-scan sort will handle
+   * all of this for us.
+   */
   sort_n_finish(this_dir);
+#endif
 
   return 0;
 }
@@ -1016,3 +1051,99 @@ FDECL1(get_session_start, int *, file_addr)
   return 0;
 }
 
+/*
+ * 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
+FDECL2(merge_previous_session,struct directory *, this_dir,
+       struct iso_directory_record *, mrootp)
+{
+  struct directory_entry       **orig_contents = NULL;
+  struct directory_entry        * odpnt = NULL;
+  int                            n_orig;
+  struct directory_entry       * s_entry;
+  int                            dflag;
+  int                            status, lstatus;
+  struct stat                    statbuf, lstatbuf;
+
+  /*
+   * Parse the same directory in the image that we are merging
+   * for multisession stuff.
+   */
+  orig_contents = read_merging_directory(mrootp, &n_orig);
+  if( orig_contents == NULL )
+    {
+      return 0;
+    }
+
+
+/* Now we scan the directory itself, and look at what is inside of it. */
+
+  dflag = 0;
+  for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+    {
+      status  =  stat_filter(s_entry->whole_name, &statbuf);
+      lstatus = lstat_filter(s_entry->whole_name, &lstatbuf);
+
+      /*
+       * 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.
+       */
+
+      /*
+       * The check_prev_session function looks for an identical entry in
+       * the previous session.  If we see it, then we copy the extent
+       * number to s_entry, and cross it off the list.
+       */
+      check_prev_session(orig_contents, n_orig, s_entry,
+                        &statbuf, &lstatbuf, &odpnt);
+
+      if(S_ISDIR(statbuf.st_mode) && odpnt != NULL)
+       {
+         int dflag;
+
+         if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 
+           {
+             struct directory * child;
+
+             child = find_or_create_directory(this_dir, 
+                                              s_entry->whole_name, 
+                                              s_entry, 1);
+             dflag = merge_previous_session(child, 
+                                            &odpnt->isorec);
+             /* If unable to scan directory, mark this as a non-directory */
+             if(!dflag)
+               lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+             free(odpnt);
+             odpnt = NULL;
+           }
+       }
+    }
+  
+  /*
+   * Whatever is left over, are things which are no longer in the tree
+   * on disk.  We need to also merge these into the tree.
+   */
+   merge_remaining_entries(this_dir, orig_contents, n_orig);
+   free_mdinfo(orig_contents, n_orig);
+  
+  return 1;
+}
+
index 10475d43e95640fa90a64dfd64d19a6e28b5af16..fb88fc9d073af6a66bbbd1d67d466e91183097d0 100644 (file)
@@ -21,8 +21,9 @@
    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 $";
+static char rcsid[] ="$Id: name.c,v 1.10 1998/06/02 02:40:38 eric Exp $";
 
+#include "config.h"
 #include "mkisofs.h"
 
 #include <ctype.h>
@@ -105,8 +106,7 @@ int FDECL3(iso9660_file_length,
   last_dot = strrchr (pnt,'.');
   if(    (last_dot != NULL)
       && (    (last_dot[1] == '~')
-          || (last_dot[1] == '\0')
-          || (last_dot[1] == '\0')) )
+          || (last_dot[1] == '\0')) )
     {
       c = last_dot;
       *c = '\0';
@@ -154,13 +154,19 @@ int FDECL3(iso9660_file_length,
        * 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.
+       * UNLESS the ';' is part of the filename and no version
+       * number is following. [VK]
        */
-      if(*pnt == ';') 
-       {
-         seen_semic = 1; 
-         *result++ = *pnt++; 
-         continue; 
-       }
+       if(*pnt == ';')
+        {
+          /* [VK] */
+          if (pnt[1] != '\0' && (pnt[1] < '0' || pnt[1] > '9'))
+            {
+              pnt++;
+              ignore++;
+              continue;
+            }
+        }
 
       /*
        * If we have a name with multiple '.' characters, we ignore everything
index 47cba55271079e9445c11321fe3821141f480f4f..d851b96fbcc3d324682852363d3347d7a2fad7ff 100644 (file)
@@ -19,7 +19,7 @@
    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 $";
+static char rcsid[] ="$Id: rock.c,v 1.7 1998/02/18 04:48:23 eric Exp $";
 
 #include <stdlib.h>
 
@@ -225,7 +225,7 @@ int deep_opt;
     Rock[ipnt++] = PN_SIZE;
     Rock[ipnt++] = SU_VERSION;  
     flagval |= (1<<1);
-#if !defined(MAJOR_IN_SYSMACROS) && !defined(MAJOR_IN_MKDEV)
+#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));
@@ -268,10 +268,36 @@ int deep_opt;
     unsigned char * cpnt, *cpnt1;
     nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff));
     symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+    nchar = strlen((char *) symlink_buff);
     set_733(s_entry->isorec.size, 0);
     cpnt = &symlink_buff[0];
     flagval |= (1<<2);
 
+    if (! split_SL_field) 
+      {
+       int sl_bytes = 0;
+       for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) 
+         {
+           if (*cpnt1 == '/') 
+             {
+               sl_bytes += 4;
+             } 
+           else 
+             {
+               sl_bytes += 1;
+             }
+         }
+       if (sl_bytes > 250) 
+         {
+           /* 
+            * the symbolic link won't fit into one SL System Use Field
+            * print an error message and continue with splited one 
+            */
+           fprintf(stderr,"symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt);
+         }
+       if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry();
+     }
+
     while(nchar){
       if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
       Rock[ipnt++] ='S';
@@ -309,15 +335,18 @@ int deep_opt;
        } 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;
-         }
+         if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) :
+                                 MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt))) 
+          {
+            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;
index 7180905df0f3c542a2125cd6ba88df502b8c884d..e5ddbb365550cf0b814895c06d6ea8bc92851343 100644 (file)
@@ -20,7 +20,7 @@
    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 $";
+static char rcsid[] ="$Id: tree.c,v 1.26 1998/06/02 03:14:58 eric Exp $";
 
 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
 
@@ -88,6 +88,9 @@ extern char * strdup(const char *);
 #endif
 
 static unsigned char symlink_buff[256];
+static void DECL(attach_dot_entries, (struct directory * dirnode,
+                  struct stat * parent_stat));
+static void DECL(delete_directory, (struct directory * parent, struct directory * child));
 
 extern int verbose;
 
@@ -112,7 +115,9 @@ FDECL1(stat_fix, struct stat *, st)
   * are useless, and with uid+gid 0 don't want set-id bits, either).
   */
   st->st_mode |= 0444;
+#ifndef _WIN32         /* make all file "executable" */
   if (st->st_mode & 0111)
+#endif /* _WIN32 */
     st->st_mode |= 0111;
   st->st_mode &= ~07222;
 }
@@ -135,11 +140,10 @@ FDECL2(lstat_filter, char *, path, struct stat *, st)
   return result;
 }
 
-void FDECL1(sort_n_finish, struct directory *, this_dir)
+static int 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;
@@ -147,6 +151,7 @@ void FDECL1(sort_n_finish, struct directory *, this_dir)
   int                      d3;
   int                      new_reclen;
   char                  *  c;
+  int                      status = 0;
   int                      tablesize = 0;
   char                     newname[34];
   char                     rootname[34];
@@ -156,14 +161,17 @@ void FDECL1(sort_n_finish, struct directory *, this_dir)
 
   table = NULL;
 
-  if(fstatbuf.st_ctime == 0)
+  init_fstatbuf();
+
+  /*
+   * If we had artificially created this directory, then we might be
+   * missing the required '.' entries.  Create these now if we need
+   * them.
+   */
+  if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) != 
+      (DIR_HAS_DOT | DIR_HAS_DOTDOT) )
     {
-      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;
+      attach_dot_entries(this_dir, &fstatbuf);
     }
 
   flush_file_hash();
@@ -253,7 +261,12 @@ got_valid_name:
        */
       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);
+         if( verbose > 0 )
+           {
+             fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,  
+                     this_dir->whole_name, SPATH_SEPARATOR, 
+                     s_entry->name, s_entry1->name);
+           }
          s_entry->isorec.name_len[0] =  strlen(newname);
          new_reclen =  sizeof(struct iso_directory_record) -
            sizeof(s_entry->isorec.name) +
@@ -270,7 +283,12 @@ got_valid_name:
       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);
+         if( verbose > 0 )
+           {
+             fprintf(stderr,"Using %s for  %s%s%s (%s)\n", newname,  
+                     this_dir->whole_name, SPATH_SEPARATOR, 
+                     s_entry1->name, s_entry->name);
+           }
          s_entry1->isorec.name_len[0] =  strlen(newname);
          new_reclen =  sizeof(struct iso_directory_record) -
            sizeof(s_entry1->isorec.name) +
@@ -324,6 +342,9 @@ got_valid_name:
       set_733((char *) table->isorec.size, tablesize);
       table->size = tablesize;
       table->filedir = this_dir;
+#ifdef ERIC_neverdef
+      table->de_flags    |= INHIBIT_JOLIET_ENTRY;
+#endif
       table->name = strdup("<translation table>");
       table->table = (char *) e_malloc(ROUND_UP(tablesize));
       memset(table->table, 0, ROUND_UP(tablesize));
@@ -339,10 +360,17 @@ got_valid_name:
        }
     }
   
+  /*
+   * We have now chosen the 8.3 names and we should now know the length
+   * of every entry in the directory.
+   */
   for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
     {
       new_reclen = strlen(s_entry->isorec.name);
          
+      /*
+       * First update the path table sizes for directories.
+       */
       if(s_entry->isorec.flags[0] ==  2)
        {
          if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 
@@ -354,7 +382,9 @@ got_valid_name:
            {
              new_reclen = 1;
              if (this_dir == root && strlen(s_entry->name) == 1)
-               path_table_size += sizeof(struct iso_path_table);
+               {
+                 path_table_size += sizeof(struct iso_path_table);
+               }
            }
        }
       if(path_table_size & 1) path_table_size++;  /* For odd lengths we pad */
@@ -380,8 +410,17 @@ got_valid_name:
       s_entry->isorec.length[0] = new_reclen;
     }
 
-  sort_directory(&this_dir->contents);
+  status = sort_directory(&this_dir->contents);
+  if( status > 0 )
+    {
+      fprintf(stderr, "Unable to sort directory %s\n", 
+             this_dir->whole_name);
+    }
 
+  /*
+   * If we are filling out a TRANS.TBL, generate the entries that will
+   * go in the thing.
+   */
   if(table)
     {
       count = 0;
@@ -390,10 +429,15 @@ got_valid_name:
        if(!s_entry->table) continue;
        if(strcmp(s_entry->name, ".") == 0  ||
           strcmp(s_entry->name, "..") == 0) continue;
-       
+#if (defined(__sun) && !defined(__svr4__))
+       count += strlen(sprintf(table->table + count, "%c %-34s%s",
+                        s_entry->table[0],
+                        s_entry->isorec.name, s_entry->table+1));
+#else
        count += sprintf(table->table + count, "%c %-34s%s",
                         s_entry->table[0],
                         s_entry->isorec.name, s_entry->table+1);
+#endif /* __sun && !__svr4__ */
        free(s_entry->table);
        s_entry->table = NULL;
       }
@@ -419,7 +463,7 @@ got_valid_name:
        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) 
@@ -455,11 +499,11 @@ got_valid_name:
        }
       s_entry = s_entry->next;
     }
+  return status;
 }
 
 static void generate_reloc_directory()
 {
-       int new_reclen;
        time_t current_time;
        struct directory_entry  *s_entry;
 
@@ -476,7 +520,6 @@ static void generate_reloc_directory()
        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 *) 
@@ -485,6 +528,12 @@ static void generate_reloc_directory()
        s_entry->next = root->contents;
        reloc_dir->self = s_entry;
 
+       /*
+        * The rr_moved entry will not appear in the Joliet tree.
+        */
+       reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
+       s_entry->de_flags    |= INHIBIT_JOLIET_ENTRY;
+
        root->contents = s_entry;
        root->contents->name = strdup(reloc_dir->de_name);
        root->contents->filedir = root;
@@ -506,57 +555,134 @@ static void generate_reloc_directory()
        
        /* 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);
+       attach_dot_entries(reloc_dir, &root_statbuf);
+}
 
-       s_entry->filedir = reloc_dir;
-       reloc_dir->contents = s_entry;
+/* 
+ * Function:           attach_dot_entries
+ *
+ * Purpose:            Create . and .. entries for a new directory.
+ *
+ * Notes:              Only used for artificial directories that
+ *                     we are creating.
+ */
+static void FDECL2(attach_dot_entries, struct directory *, dirnode,
+                  struct stat *, parent_stat)
+{
+       struct directory_entry  *s_entry;
+       struct directory_entry  *orig_contents;
+       int deep_flag = 0;
 
-       if(use_RockRidge){
-               fstatbuf.st_mode = 0555 | S_IFDIR;
-               fstatbuf.st_nlink = 2;
+       init_fstatbuf();
+
+       orig_contents = dirnode->contents;
+
+       if( (dirnode->dir_flags & DIR_HAS_DOTDOT) == 0 )
+         {
+           s_entry = (struct directory_entry *) 
+             e_malloc(sizeof (struct directory_entry));
+           memcpy(s_entry, dirnode->self, 
+                  sizeof(struct directory_entry));
+           s_entry->name = strdup("..");
+           s_entry->whole_name = NULL;
+           s_entry->isorec.name_len[0] = 1;
+           s_entry->isorec.flags[0] = 2; /* Mark as a directory */
+           iso9660_file_length ("..", s_entry, 1);
+           iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
+           s_entry->filedir = dirnode->parent;
+
+           dirnode->contents = s_entry;
+           dirnode->contents->next = orig_contents;
+           orig_contents = s_entry;
+
+           if(use_RockRidge)
+             {
+               if( parent_stat == NULL )
+                 {
+                   parent_stat = &fstatbuf;
+                 }
                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){
+                                              "..", s_entry,
+                                              parent_stat, 
+                                              parent_stat, 0);
+             }
+           dirnode->dir_flags |= DIR_HAS_DOTDOT;
+         }
+
+       if( (dirnode->dir_flags & DIR_HAS_DOT) == 0 )
+         {
+           s_entry = (struct directory_entry *) 
+             e_malloc(sizeof (struct directory_entry));
+           memcpy(s_entry, dirnode->self, 
+                  sizeof(struct directory_entry));
+           s_entry->name = strdup(".");
+           s_entry->whole_name = NULL;
+           s_entry->isorec.name_len[0] = 1;
+           s_entry->isorec.flags[0] = 2; /* Mark as a directory */
+           iso9660_file_length (".", s_entry, 1);
+           iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime);
+           s_entry->filedir = dirnode;
+           
+           dirnode->contents = s_entry;
+           dirnode->contents->next = orig_contents;
+
+           if(use_RockRidge)
+             {
                fstatbuf.st_mode = 0555 | S_IFDIR;
                fstatbuf.st_nlink = 2;
+               
+               if( dirnode == root )
+                 {
+                   deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
+                 }
+               
                generate_rock_ridge_attributes("",
-                                              "..", s_entry,
-                                              &root_statbuf, &root_statbuf, 0);
-       };
+                                              ".", s_entry,
+                                              &fstatbuf, &fstatbuf, deep_flag);
+             }
+           
+           dirnode->dir_flags |= DIR_HAS_DOT;
+         }
+
 }
 
-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];
-  };
+static void FDECL2(update_nlink, struct directory_entry *, s_entry, int, value)
+{
+    unsigned char * pnt;
+    int len;
+    
+    pnt = s_entry->rr_attributes;
+    len = s_entry->total_rr_attr_size;
+    while(len)
+    {
+       if(pnt[0] == 'P' && pnt[1] == 'X') 
+       {
+           set_733((char *) pnt+12, value);
+           break;
+       }
+       len -= pnt[2];
+       pnt += pnt[2];
+    }
+}
+
+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(){
@@ -601,29 +727,25 @@ void finish_cl_pl_entries(){
   };
 }
 
-/*
- * 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.
+/* 
+ * Function:           scan_directory_tree
+ *
+ * Purpose:            Walk through a directory on the local machine
+ *                     filter those things we don't want to include
+ *                     and build our representation of a dir.
+ *
+ * Notes:
  */
-
 int
-FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
-       struct iso_directory_record *, mrootp){
+FDECL3(scan_directory_tree,struct directory *, this_dir,
+       char *, path, 
+       struct directory_entry *, de)
+{
   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;
+  struct directory             * parent;
+  int                            dflag;
   char                         * old_path;
 
   current_dir = opendir(path);
@@ -634,14 +756,15 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
 
   old_path = path;
 
-  if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir);
+  if(current_dir) d_entry = readdir(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;
-  };
+  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
@@ -651,77 +774,16 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
   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.
+  
+  /* 
+   * Now we scan the directory itself, and look at what is inside of it. 
    */
-  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);
+    if(dflag) d_entry = readdir(current_dir);
     dflag++;
 
     if(!d_entry) break;
@@ -730,9 +792,16 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
 
     /* 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(   strchr(d_entry->d_name,'~')
+              || strchr(d_entry->d_name,'#'))
+             {
+               if( verbose > 0 )
+                 {
+                   fprintf(stderr, "Ignoring file %s\n", d_entry->d_name);
+                 }
+               continue;
+             }
+    }
 
     if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){
       fprintf(stderr, "Overflow of stat buffer\n");
@@ -747,16 +816,9 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
 #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) {
+    if (matches(d_entry->d_name) || matches(whole_path)) {
+      if (verbose > 1) {
        fprintf(stderr, "Excluded by match: %s\n", whole_path);
       }
       continue;
@@ -770,419 +832,763 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de,
         * versions of these files, and we need to ignore any
         * originals that we might have found.
         */
-       if (verbose) 
+       if (verbose > 1
          {
            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 we already have a '.' or a '..' entry, then don't
+     * insert new ones.
+     */
+    if( strcmp(d_entry->d_name, ".") == 0 
+       && this_dir->dir_flags & DIR_HAS_DOT )
+      {
+       continue;
+      }
 
-    if( (status == -1) && (lstatus == -1) )
+    if( strcmp(d_entry->d_name, "..") == 0 
+       && this_dir->dir_flags & DIR_HAS_DOTDOT )
       {
-       /*
-        * 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 */
+#if 0
+    if (verbose > 1)  fprintf(stderr, "%s\n",whole_path);
+#endif
+    /*
+     * This actually adds the entry to the directory in question.
+     */
+    insert_file_entry(this_dir, whole_path, d_entry->d_name);
+  }
+  closedir(current_dir);
+  
+  return 1;
+}
+
+
+/* 
+ * Function:           insert_file_entry
+ *
+ * Purpose:            Insert one entry into our directory node.
+ *
+ * Note:
+ * This function inserts a single entry into the directory.  It
+ * is assumed that all filtering and decision making regarding what
+ * we want to include has already been made, so the purpose of this
+ * is to insert one entry (file, link, dir, etc), into this directory.
+ * Note that if the entry is a dir (or if we are following links,
+ * and the thing it points to is a dir), then we will scan those
+ * trees before we return.
+ */
+int
+FDECL3(insert_file_entry,struct directory *, this_dir,
+       char *, whole_path,
+       char *, short_name)
+{
+  struct stat                    statbuf, lstatbuf;
+  struct directory_entry       * s_entry, *s_entry1;
+  int                            lstatus;
+  int                            status;
+  int                            deep_flag;
+
+  status = stat_filter(whole_path, &statbuf);
 
-    /* We do this to make sure that the root entries are consistent */
-    if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) {
+  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.
+       */
+      fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path);
+      return 0;
+    }
+  
+  if(this_dir == root && strcmp(short_name, ".") == 0)
+    root_statbuf = statbuf;  /* Save this for later on */
+  
+  /* We do this to make sure that the root entries are consistent */
+  if(this_dir == root && strcmp(short_name, "..") == 0) 
+    {
       statbuf = root_statbuf;
       lstatbuf = root_statbuf;
-    };
+    }
 
-    if(S_ISLNK(lstatbuf.st_mode)){
-
-           /* Here we decide how to handle the symbolic links.  Here
-              we handle the general case - if we are not following
-              links or there is an error, then we must change
-              something.  If RR is in use, it is easy, we let RR
-              describe the file.  If not, then we punt the file. */
-
-           if((status || !follow_links)){
-                   if(use_RockRidge){
-                           status = 0;
-                           statbuf.st_size = 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 */
-                   };
+  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);
+                 return 0;  /* Non Rock Ridge discs - ignore all symlinks */
+               }
            }
-           
-           /* Here we handle a different kind of case.  Here we have
-              a symlink, but we want to follow symlinks.  If we run
-              across a directory loop, then we need to pretend that
-              we are not following symlinks for this file.  If this
-              is the first time we have seen this, then make this
-              seem as if there was no symlink there in the first
-              place */
-                      
-           if( follow_links
-              && S_ISDIR(statbuf.st_mode) ) 
-             {
-               if(   strcmp(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));
+       }
+      
+      /* Here we handle a different kind of case.  Here we have
+        a symlink, but we want to follow symlinks.  If we run
+        across a directory loop, then we need to pretend that
+        we are not following symlinks for this file.  If this
+        is the first time we have seen this, then make this
+        seem as if there was no symlink there in the first
+        place */
+      
+      if( follow_links
+         && S_ISDIR(statbuf.st_mode) ) 
+       {
+         if(   strcmp(short_name, ".")
+               && strcmp(short_name, "..") )
+           {
+             if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)))
+               {
+                 if(!use_RockRidge) 
+                   {
+                     fprintf(stderr, "Already cached directory seen (%s)\n", 
+                             whole_path);
+                     return 0;
                    }
-                 }
-             }
-
-           /*
-            * 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;
-             }
+                 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);
+  
+  /*
+   * Add directories to the cache so that we don't waste space even
+   * if we are supposed to be following symlinks.
+   */
+  if( follow_links
+      && strcmp(short_name, ".")
+      && strcmp(short_name, "..")
+      && S_ISDIR(statbuf.st_mode) ) 
+    {
+      add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
     }
+#ifdef VMS
+  if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && 
+                                   statbuf.st_fab_rfm != FAB$C_STMLF)) {
+    fprintf(stderr,"Warning - file %s has an unsupported VMS record"
+           " format (%d)\n",
+           whole_path, statbuf.st_fab_rfm);
+  }
 #endif
-
-    if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){
+  
+  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;
+      return 0;
     }
-
-    /* Add this so that we can detect directory loops with hard links.
+  
+  /* 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",
+  if(   !follow_links 
+       && S_ISDIR(lstatbuf.st_mode) 
+       && strcmp(short_name, ".") 
+       && strcmp(short_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);
+    return 0;
+  }
+  
+  /* 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;
-    };
-
-    /* Who knows what trash this is - ignore and continue */
+      return 0; 
+    }
+  
+  /*
+   * Check to see if we have already seen this directory node.
+   * If so, then we don't create a new entry for it, but we do want
+   * to recurse beneath it and add any new files we do find.
+   */
+  if (S_ISDIR(statbuf.st_mode)) 
+    {
+      int dflag;
+      
+      for( s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+       {
+         if( strcmp(s_entry->name, short_name) == 0 )
+           {
+             break;
+           }
+       }
+      if ( s_entry != NULL 
+          && strcmp(short_name,".") 
+          && strcmp(short_name,"..")) 
+       {
+         struct directory * child;
+         
+         if ( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0)
+           {
+             for( s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next)
+               {
+                 if( strcmp(s_entry->name, short_name) == 0 )
+                   {
+                     break;
+                   }
+               }
+             child = find_or_create_directory(reloc_dir, whole_path, 
+                                              s_entry, 1);
+           }
+         else
+           {
+             child = find_or_create_directory(this_dir, whole_path, 
+                                              s_entry, 1);
+             /* If unable to scan directory, mark this as a non-directory */
+           }
+         dflag = scan_directory_tree(child, whole_path, s_entry);
+         if(!dflag)
+           {
+             lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+           }
+         return 0;
+       }
+    }
+  
+  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(short_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( strcmp(short_name,  ".") == 0)
+    {
+      this_dir->dir_flags |= DIR_HAS_DOT;
+    } 
 
-    if(status) {
-           fprintf(stderr,
-                   "Unable to stat file %s - ignoring and continuing.\n",
-                   whole_path);
-           continue; 
-    };
+  if( strcmp(short_name,  "..") == 0)
+    {
+      this_dir->dir_flags |= DIR_HAS_DOTDOT;
+    } 
 
-    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)
+  if(   this_dir->parent 
+     && this_dir->parent == reloc_dir 
+     && strcmp(short_name,  "..") == 0)
+    {
+      s_entry->inode = UNCACHED_INODE;
+      s_entry->dev = (dev_t) UNCACHED_DEVICE;
+      deep_flag  = NEED_PL;
+    } 
+  else
+    {
+      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(short_name, s_entry, S_ISDIR(statbuf.st_mode));
+  s_entry->rr_attr_size = 0;
+  s_entry->total_rr_attr_size = 0;
+  s_entry->rr_attributes = NULL;
+  
+  /* Directories are assigned sizes later on */
+  if (!S_ISDIR(statbuf.st_mode)) 
+    {
+      if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || 
+         S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode)
          || S_ISLNK(lstatbuf.st_mode))
+       {
          s_entry->size = 0; 
-       else
+         statbuf.st_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);
+      set_733((char *) s_entry->isorec.size, statbuf.st_size); 
+    } 
+  else
+    {
+      s_entry->isorec.flags[0] = 2;
     }
+  
+  if (strcmp(short_name,".") && strcmp(short_name,"..") && 
+      S_ISDIR(statbuf.st_mode) && this_dir->depth >  RR_relocation_depth)
+    {
+      struct directory * child;
 
-    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;
+      if(!reloc_dir) generate_reloc_directory();
+      
+      /*
+       * Replicate the entry for this directory.  The old one will stay where it
+       * is, and it will be neutered so that it no longer looks like a directory.
+       * The new one will look like a directory, and it will be put in the reloc_dir.
+       */
+      s_entry1 = (struct directory_entry *) 
+       e_malloc(sizeof (struct directory_entry));
+      memcpy(s_entry1, s_entry,  sizeof(struct directory_entry));
+      s_entry1->table = NULL;
+      s_entry1->name = strdup(this_dir->contents->name);
+      s_entry1->whole_name = strdup(this_dir->contents->whole_name);
+      s_entry1->next = reloc_dir->contents;
+      reloc_dir->contents = s_entry1;
+      s_entry1->priority  =  32768;
+      s_entry1->parent_rec = this_dir->contents;
+      
+      deep_flag = NEED_RE;
+      
+      if(use_RockRidge) 
+       {
+         generate_rock_ridge_attributes(whole_path,
+                                        short_name, s_entry1,
+                                        &statbuf, &lstatbuf, deep_flag);
+       }
+      
+      deep_flag = 0;
+      
+      /* We need to set this temporarily so that the parent to this
+        is correctly determined. */
+      s_entry1->filedir = reloc_dir;
+      child = find_or_create_directory(reloc_dir, whole_path, 
+                                      s_entry1, 0);
+      scan_directory_tree(child, whole_path, s_entry1);
+      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;
+      s_entry->de_flags |= RELOCATED_DIRECTORY;
+      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;
+       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;
+       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))
+       case S_IFREG:
+       default:
+         sprintf(buffer,"F\t%s\n",
+                 s_entry->name);
+         break;
+       };
+      s_entry->table = strdup(buffer);
+    }
+  
+  if(S_ISDIR(statbuf.st_mode))
+    {
+      int dflag;
+      if (strcmp(short_name,".") && strcmp(short_name,"..")) 
+       {
+         struct directory * child;
+         
+         child = find_or_create_directory(this_dir, whole_path, 
+                                          s_entry, 1);
+         dflag = scan_directory_tree(child, whole_path, s_entry);
+         
+         if(!dflag)
+           {
+             lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
+             if( child->contents == NULL )
+               {
+                 delete_directory(this_dir, child);
+               }
+           }
+       }
+      /* If unable to scan directory, mark this as a non-directory */
+    }
+  
+  if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")  == 0)
+    {
+      deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
+    }
+  
+  /* Now figure out how much room this file will take in the
+     directory */
+  
+  if(use_RockRidge) 
+    {
+      generate_rock_ridge_attributes(whole_path,
+                                    short_name, s_entry,
+                                    &statbuf, &lstatbuf, deep_flag);
+      
+    }
+  
+  return 1;
+}
+
+
+void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
+  struct directory * dpnt;
+
+  dpnt = node;
+
+  while (dpnt){
+    if( dpnt->extent > session_start )
       {
-       check_prev_session(orig_contents, n_orig, s_entry, 
-                          &statbuf, &lstatbuf, NULL);
+       generate_one_directory(dpnt, outfile);
       }
+    if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
+    dpnt = dpnt->next;
+  }
+}
 
-    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;
-                 }
-             }
-         }
+/*
+ * Function:   find_or_create_directory
+ *
+ * Purpose:    Locate a directory entry in the tree, create if needed.
+ *
+ * Arguments:
+ */
+struct directory * FDECL4(find_or_create_directory, struct directory *, parent,
+                         const char *, path,
+                         struct directory_entry *, de, int, flag)
+{
+  struct directory             * dpnt;
+  struct directory_entry       * orig_de;
+  struct directory             * next_brother;
+  const char                    * cpnt;
+  const char                   * pnt;
 
-  if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".")  == 0)
-         deep_flag |= NEED_CE | NEED_SP;  /* For extension record */
+  orig_de = de;
 
-    /* Now figure out how much room this file will take in the directory */
+  pnt = strrchr(path, PATH_SEPARATOR);
+  if( pnt == NULL )
+    {
+      pnt = path;
+    }
+  else
+    {
+      pnt++;
+    }
 
-    if(use_RockRidge) {
-           generate_rock_ridge_attributes(whole_path,
-                                          d_entry->d_name, s_entry,
-                                          &statbuf, &lstatbuf, deep_flag);
-           
+  if( parent != NULL )
+    {
+      dpnt = parent->subdir;
+
+      while (dpnt)
+       {
+         /*
+          * Weird hack time - if there are two directories by the
+          * same name in the reloc_dir, they are not treated as the
+          * same thing unless the entire path matches completely.
+          */
+         if( flag && strcmp(dpnt->de_name, pnt) == 0 )
+           {
+             return dpnt;
+           }
+         dpnt = dpnt->next;
+       }
     }
-  }
-  closedir(current_dir);
 
-  if( orig_contents != NULL )
+  /*
+   * We don't know if we have a valid directory entry for this one
+   * yet.  If not, we need to create one.
+   */
+  if( de == NULL )
     {
-      merge_remaining_entries(this_dir, orig_contents, n_orig);
-      free_mdinfo(orig_contents, n_orig);
+      de = (struct directory_entry *) 
+       e_malloc(sizeof (struct directory_entry));
+      memset(de, 0, sizeof(struct directory_entry));
+      de->next            = parent->contents;
+      parent->contents    = de;
+      de->name            = strdup(pnt);
+      de->filedir         = parent;
+      de->isorec.flags[0] = 2;
+      de->priority        = 32768;
+      de->inode           = UNCACHED_INODE;
+      de->dev             = (dev_t) UNCACHED_DEVICE;
+      set_723(de->isorec.volume_sequence_number, DEF_VSN);
+      iso9660_file_length (pnt, de, 1);
+
+      init_fstatbuf();
+      /*
+       * It doesn't exist for real, so we cannot add any Rock Ridge.
+       */
+      if(use_RockRidge)
+       {
+         fstatbuf.st_mode = 0555 | S_IFDIR;
+         fstatbuf.st_nlink = 2;
+         generate_rock_ridge_attributes("",
+                                        (char *) pnt, de,
+                                        &fstatbuf, 
+                                        &fstatbuf, 0);
+       }
+      iso9660_date(de->isorec.date, fstatbuf.st_mtime);
+
     }
 
-  if( this_dir->contents == NULL )
+  /*
+   * If we don't have a directory for this one yet, then allocate it
+   * now, and patch it into the tree in the appropriate place.
+   */
+  dpnt             = (struct directory *) e_malloc(sizeof(struct directory));
+  memset(dpnt, 0, sizeof(struct directory));
+  dpnt->next       = NULL;
+  dpnt->subdir     = NULL;
+  dpnt->self       = de;
+  dpnt->contents   = NULL;
+  dpnt->whole_name = strdup(path);
+  cpnt             = strrchr(path, PATH_SEPARATOR);
+  if(cpnt)
+    cpnt++;
+  else
+    cpnt = path;
+  dpnt->de_name    = strdup(cpnt);
+  dpnt->size       = 0;
+  dpnt->extent     = 0;
+  dpnt->jextent    = 0;
+  dpnt->jsize      = 0;
+
+  if( orig_de == NULL )
     {
+      struct stat xstatbuf;
+      int sts;
+
       /*
-       * This directory must have been inaccessible.
+       * Now add a . and .. entry in the directory itself.
+       * This is a little tricky - if the real directory
+       * exists, we need to stat it first.  Otherwise, we
+       * use the fictitious fstatbuf which points to the time
+       * at which mkisofs was started.
        */
-      return 0;
+      sts = stat_filter(parent->whole_name, &xstatbuf);
+      if( sts == 0 )
+       {
+         attach_dot_entries(dpnt, &xstatbuf);
+       }
+      else
+       {
+         attach_dot_entries(dpnt, &fstatbuf);
+       }
     }
-  sort_n_finish(this_dir);
 
-  return 1;
+  if(!parent || parent == root)
+    {
+      if (!root) 
+       {
+         root = dpnt;  /* First time through for root directory only */
+         root->depth = 0;
+         root->parent = root;
+       } else {
+         dpnt->depth = 1;
+         if(!root->subdir)
+           {
+             root->subdir = dpnt;
+           }
+         else 
+           {
+             next_brother = root->subdir;
+             while(next_brother->next) next_brother = next_brother->next;
+             next_brother->next = dpnt;
+           }
+         dpnt->parent = parent;
+       }
+    } 
+  else 
+    {
+      /* Come through here for  normal traversal of  tree */
+#ifdef DEBUG
+      fprintf(stderr,"%s(%d) ", path, dpnt->depth);
+#endif
+      if(parent->depth >  RR_relocation_depth) 
+       {
+         fprintf(stderr,"Directories too deep  %s\n", path);
+         exit(1);
+       }
+      
+      dpnt->parent = parent; 
+      dpnt->depth = parent->depth + 1;
+      
+      if(!parent->subdir)
+       {
+         parent->subdir = dpnt;
+       }
+      else 
+       {
+         next_brother = parent->subdir;
+         while(next_brother->next) next_brother = next_brother->next;
+         next_brother->next = dpnt;
+       }
+    }
+
+  return dpnt;
 }
 
+/*
+ * Function:   delete_directory
+ *
+ * Purpose:    Locate a directory entry in the tree, create if needed.
+ *
+ * Arguments:
+ */
+static void FDECL2(delete_directory, struct directory *, parent, struct directory *, child)
+{
+  struct directory             * tdir;
 
-void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){
+  if( child->contents != NULL )
+    {
+      fprintf(stderr, "Unable to delete non-empty directory\n");
+      exit(1);
+    }
+
+  free(child->whole_name);
+  child->whole_name = NULL;
+
+  free(child->de_name);
+  child->de_name = NULL;
+
+  if( parent->subdir == child )
+    {
+      parent->subdir = child->next;
+    }
+  else
+    {
+      for( tdir = parent->subdir; tdir->next != NULL; tdir = tdir->next )
+       {
+         if( tdir->next == child )
+           {
+             tdir->next = child->next;
+             break;
+           }
+       }
+      if( tdir == NULL )
+       {
+         fprintf(stderr, "Unable to locate child directory in parent list\n");
+         exit(1);
+       }
+    }
+  free(child);
+  return;
+}
+
+int FDECL1(sort_tree, struct directory *, node){
   struct directory * dpnt;
+  int goof = 0;
 
   dpnt = node;
 
   while (dpnt){
-    if( dpnt->extent > session_start )
+    goof = sort_n_finish(dpnt);
+    if( goof )
       {
-       generate_one_directory(dpnt, outfile);
+       break;
       }
-    if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile);
+    
+    if(dpnt->subdir) sort_tree(dpnt->subdir);
     dpnt = dpnt->next;
   }
+  return goof;
 }
 
 void FDECL1(dump_tree, struct directory *, node){
@@ -1197,6 +1603,59 @@ void FDECL1(dump_tree, struct directory *, node){
   }
 }
 
+void FDECL1(update_nlink_field, struct directory *, node)
+{
+    struct directory           * dpnt;
+    struct directory           * xpnt;
+    struct directory_entry     * s_entry;
+    int                                  i;
+
+    dpnt = node;
+    
+    while (dpnt)
+    {
+       /*
+        * First, count up the number of subdirectories this guy has.
+        */
+       for(i=0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next, i++)
+           continue;
+
+       /*
+        * Next check to see if we have any relocated directories
+        * in this directory.   The nlink field will include these
+        * as real directories when they are properly relocated.
+        *
+        * In the non-rockridge disk, the relocated entries appear
+        * as zero length files.
+        */
+       for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
+       {
+               if( (s_entry->de_flags  & RELOCATED_DIRECTORY) != 0 )
+               {
+                       i++;
+               }
+       }
+       /*
+        * Now update the field in the Rock Ridge entry.
+        */
+       update_nlink(dpnt->self, i + 2);
+
+       /*
+        * Update the '.' entry for this directory.
+        */
+       update_nlink(dpnt->contents, i + 2);
+
+       /*
+        * Update all of the '..' entries that point to this guy.
+        */
+       for(xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next)
+           update_nlink(xpnt->contents->next, i + 2);
+
+       if(dpnt->subdir) update_nlink_field(dpnt->subdir);
+       dpnt = dpnt->next;
+    }
+}
+
 /*
  * something quick and dirty to locate a file given a path
  * recursively walks down path in filename until it finds the
@@ -1232,13 +1691,13 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *,
       *p1 = '\0';
 
 #ifdef DEBUG_TORITO
-      printf("Looking for subdir called %s\n",p1); 
+      fprintf(stderr,"Looking for subdir called %s\n",p1); 
 #endif
 
       rest = p1+1;
 
 #ifdef DEBUG_TORITO
-      printf("Remainder of path name is now %s\n", rest); 
+      fprintf(stderr,"Remainder of path name is now %s\n", rest); 
 #endif
       
       dpnt = node->subdir;
@@ -1251,7 +1710,7 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *,
         if (!strcmp(subdir, dpnt->de_name)) 
           {
 #ifdef DEBUG_TORITO
-            printf("Calling next level with filename = %s", rest); 
+            fprintf(stderr,"Calling next level with filename = %s", rest); 
 #endif
             return(search_tree_file( dpnt, rest ));
           }
@@ -1276,7 +1735,7 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *,
          if (!strcmp(filename, depnt->name)) 
            {
 #ifdef DEBUG_TORITO
-             printf("Found our file %s", filename); 
+             fprintf(stderr,"Found our file %s", filename); 
 #endif
              return(depnt);
            }
@@ -1290,3 +1749,25 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *,
   fprintf(stderr,"We cant get here in search_tree_file :-/ \n");
 }
 
+void init_fstatbuf()
+{
+  time_t                   current_time;
+
+  if(fstatbuf.st_ctime == 0)
+    {
+      time (&current_time);
+      if( rationalize )
+       {
+         fstatbuf.st_uid = 0;
+         fstatbuf.st_gid = 0;
+       }
+      else
+       {
+         fstatbuf.st_uid = getuid();
+         fstatbuf.st_gid = getgid();
+       }
+      fstatbuf.st_ctime = current_time;
+      fstatbuf.st_mtime = current_time;
+      fstatbuf.st_atime = current_time;
+    }
+}
index cfc9b763c968aea2c92e6e4b8b9e8f9883e25b9b..1976679b44a87a2cd22f770ad6f89b8a857ca8d1 100644 (file)
    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 $";
+static char rcsid[] ="$Id: write.c,v 1.18 1998/06/02 02:40:39 eric Exp $";
 
 #include <string.h>
 #include <stdlib.h>
+#include "config.h"
 #include "mkisofs.h"
 #include "iso9660.h"
 #include <time.h>
@@ -50,15 +51,17 @@ extern char * strdup(const char *);
 
 /* Counters for statistics */
 
-static int table_size = 0;
-static int total_dir_size = 0;
-static int rockridge_size = 0;
+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;
+static     next_path_index  = 1;
+static int sort_goof;
 
-/* Used to fill in some  of the information in the volume descriptor. */
-static struct tm local;
-static struct tm gmt;
+struct output_fragment * out_tail;
+struct output_fragment * out_list;
+
+struct iso_primary_descriptor vol_desc;
 
 /* Routines to actually write the disc.  We write sequentially so that
    we could write a tape, or write the disc directly */
@@ -118,8 +121,30 @@ void FDECL2(set_733, char *, pnt, unsigned int, i)
 
 void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
 {
-     while(count) 
-     {
+    /*
+     * This is a hack that could be made better. XXXIs this the only place?
+     * It is definitely needed on Operating Systems that do not
+     * allow to write files that are > 2GB.
+     * If the system is fast enough to be able to feed 1400 KB/s
+     * writing speed of a DVD-R drive, use stdout.
+     * If the system cannot do this reliable, you need to use this
+     * hacky option.
+     */
+    if (split_output != 0 && ftell(file) > (1024 * 1024 * 1024) ) {
+       static int      idx = 0;
+       char    nbuf[128];
+       
+       sprintf(nbuf, "part_%02d", idx++);
+       file = freopen(nbuf, "w", file);
+       if (file == NULL) {
+           fprintf(stderr, "Cannot open '%s'.\n", nbuf);
+           exit(1);
+       }
+       
+    }
+
+    while(count) 
+    {
          int got = fwrite(buffer,size,count,file);
 
          if(got<=0) 
@@ -142,11 +167,7 @@ struct deferred_write
 
 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;
 
@@ -154,7 +175,7 @@ static time_t begun;
    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)
+static int FDECL1(assign_directory_addresses, struct directory *, node)
 {
      int               dir_size;
      struct directory * dpnt;
@@ -193,6 +214,7 @@ void FDECL1(assign_directory_addresses, struct directory *, node)
 
          dpnt = dpnt->next;
      }
+     return 0;
 }
 
 static void FDECL3(write_one_file, char *, filename, 
@@ -222,8 +244,8 @@ static void FDECL3(write_one_file, char *, filename,
          memset(buffer, 0, use);
          if (fread(buffer, 1, use, infile) == 0) 
          {
-              fprintf(stderr,"cannot read from %s\n",filename); 
-              exit(1);
+               fprintf(stderr,"cannot read from %s\n",filename); 
+               exit(1);
          }
          xfwrite(buffer, 1, use, outfile);
          last_extent_written += use/SECTOR_SIZE;
@@ -296,7 +318,7 @@ static void dump_filelist()
 }
 #endif
 
-int FDECL2(compare_dirs, const void *, rr, const void *, ll) 
+static int FDECL2(compare_dirs, const void *, rr, const void *, ll) 
 {
      char * rpnt, *lpnt;
      struct directory_entry ** r, **l;
@@ -305,11 +327,24 @@ int FDECL2(compare_dirs, const void *, rr, const void *, ll)
      l = (struct directory_entry **) ll;
      rpnt = (*r)->isorec.name;
      lpnt = (*l)->isorec.name;
+
+     /*
+      * If the entries are the same, this is an error.
+      */
+     if( strcmp(rpnt, lpnt) == 0 )
+       {
+        sort_goof++;
+       }
      
      /*
       *  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.
+      *
+      * FIXME(eric) - these tests seem redundant, in taht the name is
+      * never assigned these values.  It will instead be \000 or \001,
+      * and thus should always be sorted correctly.   I need to figure
+      * out why I thought I needed this in the first place.
       */
      if( strcmp(rpnt, ".") == 0 ) return -1;
      if( strcmp(lpnt, ".") == 0 ) return  1;
@@ -336,7 +371,15 @@ int FDECL2(compare_dirs, const void *, rr, const void *, ll)
      return 0;
 }
 
-void FDECL1(sort_directory, struct directory_entry **, sort_dir)
+/* 
+ * Function:           sort_directory
+ *
+ * Purpose:            Sort the directory in the appropriate ISO9660
+ *                     order.
+ *
+ * Notes:              Returns 0 if OK, returns > 0 if an error occurred.
+ */
+int FDECL1(sort_directory, struct directory_entry **, sort_dir)
 {
      int dcount = 0;
      int i, len;
@@ -350,6 +393,11 @@ void FDECL1(sort_directory, struct directory_entry **, sort_dir)
          s_entry = s_entry->next;
      }
 
+     if( dcount == 0 )
+     {
+          return 0;
+     }
+
      /*
       * OK, now we know how many there are.  Build a vector for sorting. 
       */
@@ -367,44 +415,52 @@ void FDECL1(sort_directory, struct directory_entry **, sort_dir)
          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 
+     /*
+      * Each directory is required to contain at least . and ..
       */
-     for(i=0; i<dcount-1; i++)
-     {
-         sortlist[i]->next = sortlist[i+1];
-     }
+     if( dcount < 2 )
+       {
+        sort_goof = 1;
+        
+       }
+     else
+       {
+        sort_goof = 0;
+        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];
+       }
 
-     sortlist[dcount-1]->next = NULL;
-     *sort_dir = sortlist[0];
-     
      free(sortlist);
-     
+     return sort_goof;
 }
 
-void generate_root_record()
+static int root_gen()
 {
-     time_t ctime;
-     
-     time (&ctime);
-
-     local = *localtime(&ctime);
-     gmt   = *gmtime(&ctime);
+     init_fstatbuf();
      
      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);
+     iso9660_date(root_record.date, root_statbuf.st_mtime);
      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;
+     return 0;
 }
 
 static void FDECL1(assign_file_addresses, struct directory *, dpnt)
@@ -439,7 +495,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt)
               s_hash = find_hash(s_entry->dev, s_entry->inode);
               if(s_hash)
               {
-                   if(verbose)
+                   if(verbose > 1)
                    {
                         fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, 
                                 SPATH_SEPARATOR, s_entry->name);
@@ -562,7 +618,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt)
                    s_entry->starting_block = last_extent;
                    add_hash(s_entry);
                    last_extent += ROUND_UP(s_entry->size) >> 11;
-                   if(verbose)
+                   if(verbose > 1)
                    {
                         fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
                                 last_extent-1, whole_path);
@@ -576,6 +632,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt)
                         
                    }
 #endif
+#ifdef NOT_NEEDED      /* Never use this code if you like to create a DVD */
                    if(last_extent > (800000000 >> 11)) 
                    { 
                         /*
@@ -583,9 +640,10 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt)
                          */
                         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);
+                        fprintf(stderr,"Reported file size is %d bytes\n", s_entry->size);
                         exit(1);
                    }
+#endif
                    continue;
               }
 
@@ -605,6 +663,40 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt)
      }
 } /* assign_file_addresses(... */
 
+static void FDECL1(free_one_directory, struct directory *, dpnt)
+{
+     struct directory_entry            * s_entry;
+     struct directory_entry            * s_entry_d;
+     
+     s_entry = dpnt->contents;
+     while(s_entry) 
+     {
+        s_entry_d = s_entry;
+        s_entry = s_entry->next;
+        
+        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);
+     }
+     dpnt->contents = NULL;
+} /* free_one_directory(... */
+
+static void FDECL1(free_directories, struct directory *, dpnt)
+{
+  while (dpnt)
+    {
+      free_one_directory(dpnt);
+      if(dpnt->subdir) free_directories(dpnt->subdir);
+      dpnt = dpnt->next;
+    }
+}
+
 void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
 {
      unsigned int                        ce_address = 0;
@@ -743,18 +835,15 @@ void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
          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 )
+         /*
+          * Joliet doesn't use the Rock Ridge attributes, so we free it here.
+          */
+         if (s_entry_d->rr_attributes) 
            {
-             free (s_entry_d->whole_name);
+             free(s_entry_d->rr_attributes);
+             s_entry_d->rr_attributes = NULL;
            }
-         free (s_entry_d);
      }
-     sort_dir = NULL;
 
      if(dpnt->size != dir_index)
      {
@@ -795,7 +884,7 @@ void FDECL1(build_pathlist, struct directory *, node)
      }
 } /* build_pathlist(... */
 
-int FDECL2(compare_paths, void const *, r, void const *, l) 
+static 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;
@@ -814,7 +903,7 @@ int FDECL2(compare_paths, void const *, r, void const *, l)
   
 } /* compare_paths(... */
 
-void generate_path_tables()
+static int generate_path_tables()
 {
   struct directory_entry * de;
   struct directory      * dpnt;
@@ -926,6 +1015,7 @@ void generate_path_tables()
               path_table_index,
               path_table_size);
   }
+  return 0;
 } /* generate_path_tables(... */
 
 void
@@ -940,17 +1030,102 @@ FDECL3(memcpy_max, char *, to, char *, from, int, max)
 
 } /* memcpy_max(... */
 
-int FDECL1(iso_write, FILE *, outfile)
+void FDECL1(outputlist_insert, struct output_fragment *, frag)
+{
+  if( out_tail == NULL )
+    {
+      out_list = out_tail = frag;
+    }
+  else
+    {
+      out_tail->of_next = frag;
+      out_tail = frag;
+    }
+}
+
+static int FDECL1(file_write, FILE *, outfile)
+{
+  int                          should_write;
+
+  /*
+   * 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. 
+   */
+
+  should_write = last_extent - session_start;
+
+  if( print_size > 0 )
+    {
+      fprintf(stderr,"Total extents scheduled to be written = %d\n", 
+             last_extent - session_start);
+       exit(0);
+    }
+
+  if( verbose > 0 )
+    {
+#ifdef DBG_ISO
+      fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
+#endif
+      
+      fprintf(stderr,"Total extents scheduled to be written = %d\n", 
+             last_extent - session_start);
+    }
+
+  /* 
+   * Now write all of the files that we need. 
+   */
+  write_files(outfile);
+  
+  /*
+   * The rest is just fluff.
+   */
+  if( verbose == 0 )
+    {
+      return 0;
+    }
+
+  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(... */
+
+/*
+ * Function to write the PVD for the disc.
+ */
+static int FDECL1(pvd_write, FILE *, outfile)
 {
-  char                         buffer[2048];
-  int                          i;
   char                         iso_time[17];
   int                          should_write;
+  struct tm                    local;
+  struct tm                    gmt;
+
 
   time(&begun);
-  assign_file_addresses(root);
 
-  memset(buffer, 0, sizeof(buffer));
+  local = *localtime(&begun);
+  gmt   = *gmtime(&begun);
 
   /*
    * This will break  in the year  2000, I supose, but there is no good way
@@ -965,17 +1140,6 @@ int FDECL1(iso_write, FILE *, outfile)
   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 
    */
@@ -1011,7 +1175,7 @@ int FDECL1(iso_write, FILE *, outfile)
    * Now we copy the actual root directory record 
    */
   memcpy(vol_desc.root_directory_record, &root_record, 
-        sizeof(struct iso_directory_record) + 1);
+        sizeof(struct iso_directory_record));
 
   /*
    * The rest is just fluff.  It looks nice to fill in many of these fields,
@@ -1058,16 +1222,16 @@ int FDECL1(iso_write, FILE *, outfile)
    */
   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 ++;
-    }
-  
+  return 0;
+}
+
+/*
+ * Function to write the EVD for the disc.
+ */
+static int FDECL1(evd_write, FILE *, outfile)
+{
+  struct iso_primary_descriptor vol_desc;
+
   /*
    * Now write the end volume descriptor.  Much simpler than the other one 
    */
@@ -1077,7 +1241,14 @@ int FDECL1(iso_write, FILE *, outfile)
   vol_desc.version[0] = 1;
   xfwrite(&vol_desc, 1, 2048, outfile);
   last_extent_written += 1;
+  return 0;
+}
 
+/*
+ * Function to write the EVD for the disc.
+ */
+static int FDECL1(pathtab_write, FILE *, outfile)
+{
   /*
    * Next we write the path tables 
    */
@@ -1088,55 +1259,121 @@ int FDECL1(iso_write, FILE *, outfile)
   free(path_table_m);
   path_table_l = NULL;
   path_table_m = NULL;
+  return 0;
+}
 
-  /*
-   * 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. 
-   */
+static int FDECL1(exten_write, FILE *, outfile)
+{
+  xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
+  last_extent_written++;
+  return 0;
+}
 
-#ifdef DBG_ISO
-  fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
-#endif
-#if 0 
- generate_one_directory(root, outfile);
-#endif
+/*
+ * Functions to describe padding block at the start of the disc.
+ */
+int FDECL1(oneblock_size, int, starting_extent)
+{
+  last_extent++;
+  return 0;
+}
+
+/*
+ * Functions to describe padding block at the start of the disc.
+ */
+static int FDECL1(pathtab_size, int, starting_extent)
+{
+  path_table[0] = starting_extent;
+
+  path_table[1] = 0;
+  path_table[2] = path_table[0] + path_blocks;
+  path_table[3] = 0;
+  last_extent += 2*path_blocks;
+  return 0;
+}
+
+static int FDECL1(padblock_size, int, starting_extent)
+{
+  last_extent += 16;
+  return 0;
+}
+
+static int file_gen()
+{
+  assign_file_addresses(root);
+  return 0;
+}
+
+static int dirtree_dump()
+{
+  if (verbose > 1)
+    dump_tree(root);
+  return 0;
+}
+
+static int FDECL1(dirtree_fixup, int, starting_extent)
+{
+  if (use_RockRidge && reloc_dir)
+         finish_cl_pl_entries();
+
+  if (use_RockRidge )
+         update_nlink_field(root);
+  return 0;
+}
+
+static int FDECL1(dirtree_size, int, starting_extent)
+{
+  assign_directory_addresses(root);
+  return 0;
+}
+
+static int FDECL1(ext_size, int, starting_extent)
+{
+  extern int extension_record_size;
+  struct directory_entry * s_entry;
+  extension_record_extent = starting_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);
+  last_extent++;
+  return 0;
+}
+
+static int FDECL1(dirtree_write, FILE *, outfile)
+{
   generate_iso9660_directories(root, outfile);
+  return 0;
+}
 
-  if(extension_record) 
-    {
-      xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
-      last_extent_written++;
-    }
+static int FDECL1(dirtree_cleanup, FILE *, outfile)
+{
+  free_directories(root);
+  return 0;
+}
 
-  /* 
-   * 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);
-    }
+static int FDECL1(padblock_write, FILE *, outfile)
+{
+  char                         buffer[2048];
+  int                          i;
 
-  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);
+  memset(buffer, 0, sizeof(buffer));
 
-#ifdef DEBUG
-  fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
-         next_extent, last_extent, last_extent_written);
-#endif
+  for(i=0; i<16; i++)
+    {
+      xfwrite(buffer, 1, sizeof(buffer), outfile);
+    }
 
+  last_extent_written += 16;
   return 0;
+}
 
-} /* iso_write(... */
+struct output_fragment padblock_desc  = {NULL, padblock_size, NULL,     padblock_write};
+struct output_fragment voldesc_desc   = {NULL, oneblock_size, root_gen, pvd_write};
+struct output_fragment end_vol       = {NULL, oneblock_size, NULL,     evd_write};
+struct output_fragment pathtable_desc = {NULL, pathtab_size,  generate_path_tables,     pathtab_write};
+struct output_fragment dirtree_desc   = {NULL, dirtree_size,  NULL,     dirtree_write};
+struct output_fragment dirtree_clean  = {NULL, dirtree_fixup, dirtree_dump,     dirtree_cleanup};
+struct output_fragment extension_desc = {NULL, ext_size,      NULL,     exten_write};
+struct output_fragment files_desc     = {NULL, NULL,          file_gen, file_write};