* 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
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>
#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
* 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))
* 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");
* 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
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
{
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));
/*
* 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");
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};
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
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
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];
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
};
/* 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"
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 */
--- /dev/null
+/*
+ * 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};
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"
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;
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;
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;
{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;}
}
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))
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);
}
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();
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
*/
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;
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;
exit(1);
};
break;
+ case OPTION_PRINT_SIZE:
+ print_size++;
+ break;
case 'P':
publisher = optarg;
if(strlen(publisher) > 128) {
exit(1);
};
break;
+ case OPTION_QUIET:
+ verbose = 0;
+ break;
case 'R':
use_RockRidge++;
break;
rationalize++;
use_RockRidge++;
break;
+ case OPTION_SPLIT_OUTPUT:
+ split_output++;
+ break;
case 'T':
generate_tables++;
break;
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;
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) )
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();
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");
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
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
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;
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
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 */
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{
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 */
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 *));
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 *));
* 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.
*/
* 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>
while(len >= 4){
if(pnt[3] != 1) {
- printf("**BAD RRVERSION");
+ fprintf(stderr,"**BAD RRVERSION");
return -1;
};
if(strncmp((char *) pnt, "NM", 2) == 0) {
*/
while(len >= 4){
if(pnt[3] != 1) {
- printf("**BAD RRVERSION");
+ fprintf(stderr,"**BAD RRVERSION");
return -1;
};
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
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 )
{
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;
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];
*/
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;
}
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;
+}
+
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>
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';
* 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
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>
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));
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';
} 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;
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 */
#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;
* 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;
}
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;
int d3;
int new_reclen;
char * c;
+ int status = 0;
int tablesize = 0;
char newname[34];
char rootname[34];
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 (¤t_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();
*/
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) +
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) +
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));
}
}
+ /*
+ * 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,".."))
{
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 */
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;
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;
}
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)
}
s_entry = s_entry->next;
}
+ return status;
}
static void generate_reloc_directory()
{
- int new_reclen;
time_t current_time;
struct directory_entry *s_entry;
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 *)
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;
/* 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(){
};
}
-/*
- * 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);
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
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;
/* 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");
#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;
* 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){
}
}
+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
*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;
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 ));
}
if (!strcmp(filename, depnt->name))
{
#ifdef DEBUG_TORITO
- printf("Found our file %s", filename);
+ fprintf(stderr,"Found our file %s", filename);
#endif
return(depnt);
}
fprintf(stderr,"We cant get here in search_tree_file :-/ \n");
}
+void init_fstatbuf()
+{
+ time_t current_time;
+
+ if(fstatbuf.st_ctime == 0)
+ {
+ time (¤t_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;
+ }
+}
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>
/* 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 */
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)
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;
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;
dpnt = dpnt->next;
}
+ return 0;
}
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;
}
#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;
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;
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;
s_entry = s_entry->next;
}
+ if( dcount == 0 )
+ {
+ return 0;
+ }
+
/*
* OK, now we know how many there are. Build a vector for sorting.
*/
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)
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);
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);
}
#endif
+#ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */
if(last_extent > (800000000 >> 11))
{
/*
*/
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;
}
}
} /* 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;
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)
{
}
} /* 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;
} /* compare_paths(... */
-void generate_path_tables()
+static int generate_path_tables()
{
struct directory_entry * de;
struct directory * dpnt;
path_table_index,
path_table_size);
}
+ return 0;
} /* generate_path_tables(... */
void
} /* 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
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
*/
* 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,
*/
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
*/
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
*/
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};