diff --git a/util/mkisofs/defaults.h b/util/mkisofs/defaults.h index 91e678992..9e8f3331a 100644 --- a/util/mkisofs/defaults.h +++ b/util/mkisofs/defaults.h @@ -2,7 +2,7 @@ * Header file defaults.h - assorted default values for character strings in * the volume descriptor. * - * $Id: defaults.h,v 1.4 1997/04/10 03:31:53 eric Rel $ + * $Id: defaults.h,v 1.6 1998/06/02 02:40:37 eric Exp $ */ #define PREPARER_DEFAULT NULL @@ -24,7 +24,11 @@ #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 @@ -39,6 +43,10 @@ #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 diff --git a/util/mkisofs/eltorito.c b/util/mkisofs/eltorito.c index 0ac5a1290..3ff50e92e 100644 --- a/util/mkisofs/eltorito.c +++ b/util/mkisofs/eltorito.c @@ -21,7 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $"; +static char rcsid[] ="$Id: eltorito.c,v 1.12 1998/06/02 02:40:37 eric Exp $"; #include #include @@ -30,14 +30,22 @@ static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $"; #include #include +#include "config.h" #include "mkisofs.h" #include "iso9660.h" +/* used by Win32 for opening binary file - not used by Unix */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ + #undef MIN #define MIN(a, b) (((a) < (b))? (a): (b)) static struct eltorito_validation_entry valid_desc; static struct eltorito_defaultboot_entry default_desc; +static struct eltorito_boot_descriptor boot_desc; + /* * Check for presence of boot catalog. If it does not exist then make it @@ -63,7 +71,7 @@ void FDECL1(init_boot_catalog, const char *, path) * check for the file existing */ #ifdef DEBUG_TORITO - printf("Looking for boot catalog file %s\n",bootpath); + fprintf(stderr,"Looking for boot catalog file %s\n",bootpath); #endif if (!stat_filter(bootpath, &statbuf)) @@ -93,7 +101,7 @@ void FDECL1(init_boot_catalog, const char *, path) * file does not exist, so we create it * make it one CD sector long */ - bcat = open(bootpath, O_WRONLY | O_CREAT, S_IROTH | S_IRGRP | S_IRWXU ); + bcat = open(bootpath, O_WRONLY | O_CREAT | O_BINARY, S_IROTH | S_IRGRP | S_IRWXU ); if (bcat == -1) { fprintf(stderr, "Error creating boot catalog, exiting...\n"); @@ -207,7 +215,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) * assume 512 bytes/sector on a bootable floppy */ nsectors = ((de->size + 511) & ~(511))/512; - printf("\nSize of boot image is %d sectors -> ", nsectors); + fprintf(stderr, "\nSize of boot image is %d sectors -> ", nsectors); /* * choose size of emulated floppy based on boot image size @@ -215,17 +223,17 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) if (nsectors == 2880 ) { default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; - printf("Emulating a 1.44 meg floppy\n"); + fprintf(stderr, "Emulating a 1.44 meg floppy\n"); } else if (nsectors == 5760 ) { default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; - printf("Emulating a 2.88 meg floppy\n"); + fprintf(stderr,"Emulating a 2.88 meg floppy\n"); } else if (nsectors == 2400 ) { default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; - printf("Emulating a 1.2 meg floppy\n"); + fprintf(stderr,"Emulating a 1.2 meg floppy\n"); } else { @@ -240,7 +248,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) nsectors = 1; set_721(default_desc.nsect, (unsigned int) nsectors ); #ifdef DEBUG_TORITO - printf("Extent of boot images is %d\n",get_733(de->isorec.extent)); + fprintf(stderr,"Extent of boot images is %d\n",get_733(de->isorec.extent)); #endif set_731(default_desc.bootoff, (unsigned int) get_733(de->isorec.extent)); @@ -248,7 +256,7 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) /* * now write it to disk */ - bootcat = open(de2->whole_name, O_RDWR); + bootcat = open(de2->whole_name, O_RDWR | O_BINARY); if (bootcat == -1) { fprintf(stderr,"Error opening boot catalog for update.\n"); @@ -263,3 +271,19 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) write(bootcat, &default_desc, 32); close(bootcat); } /* get_torito_desc(... */ + +/* + * Function to write the EVD for the disc. + */ +int FDECL1(tvd_write, FILE *, outfile) +{ + /* + * Next we write out the boot volume descriptor for the disc + */ + get_torito_desc(&boot_desc); + xfwrite(&boot_desc, 1, 2048, outfile); + last_extent_written ++; + return 0; +} + +struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write}; diff --git a/util/mkisofs/getopt.c b/util/mkisofs/getopt.c new file mode 100644 index 000000000..79080aa54 --- /dev/null +++ b/util/mkisofs/getopt.c @@ -0,0 +1,760 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95 + Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#if defined (emacs) || defined (CONFIG_BROKETS) +/* We use 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 +#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 + +/* 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 +#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; + +#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 +#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__ */ + +/* 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; +} + +/* 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__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/util/mkisofs/getopt1.c b/util/mkisofs/getopt1.c new file mode 100644 index 000000000..c3400e5b6 --- /dev/null +++ b/util/mkisofs/getopt1.c @@ -0,0 +1,190 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#if defined (emacs) || defined (CONFIG_BROKETS) +/* We use 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 +#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 + +/* 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 +#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__. */ + +#ifdef TEST + +#include + +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 */ diff --git a/util/mkisofs/hash.c b/util/mkisofs/hash.c index 67098d580..eb673393e 100644 --- a/util/mkisofs/hash.c +++ b/util/mkisofs/hash.c @@ -19,9 +19,10 @@ 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 +#include "config.h" #include "mkisofs.h" #define NR_HASH 1024 @@ -44,7 +45,7 @@ void FDECL1(add_hash, struct directory_entry *, spnt){ hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode); #if 0 - if (verbose) fprintf(stderr,"%s ",spnt->name); + if (verbose > 1) fprintf(stderr,"%s ",spnt->name); #endif s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); s_hash->next = hash_table[hash_number]; diff --git a/util/mkisofs/iso9660.h b/util/mkisofs/iso9660.h index a58f96f0d..65320121d 100644 --- a/util/mkisofs/iso9660.h +++ b/util/mkisofs/iso9660.h @@ -21,7 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* - * $Id: iso9660.h,v 1.1 1997/02/23 15:55:25 eric Rel $ + * $Id: iso9660.h,v 1.2 1997/05/17 15:46:44 eric Exp $ */ #ifndef _ISOFS_FS_H @@ -42,8 +42,9 @@ struct iso_volume_descriptor { }; /* volume descriptor types */ -#define ISO_VD_PRIMARY 1 -#define ISO_VD_END 255 +#define ISO_VD_PRIMARY 1 +#define ISO_VD_SUPPLEMENTARY 2 /* Used by Joliet */ +#define ISO_VD_END 255 #define ISO_STANDARD_ID "CD001" @@ -67,7 +68,7 @@ struct iso_primary_descriptor { char volume_id [ISODCL ( 41, 72)]; /* dchars */ char unused2 [ISODCL ( 73, 80)]; char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ - char unused3 [ISODCL ( 89, 120)]; + char escape_sequences [ISODCL ( 89, 120)]; char volume_set_size [ISODCL (121, 124)]; /* 723 */ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ char logical_block_size [ISODCL (129, 132)]; /* 723 */ diff --git a/util/mkisofs/joliet.c b/util/mkisofs/joliet.c new file mode 100644 index 000000000..d3e8cb0e3 --- /dev/null +++ b/util/mkisofs/joliet.c @@ -0,0 +1,972 @@ +/* + * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660. + + Copyright 1997 Eric Youngdale. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: joliet.c,v 1.12 1998/06/02 02:40:37 eric Exp $"; + + +/* + * Joliet extensions for ISO9660. These are spottily documented by + * Microsoft. In their infinite stupidity, they completely ignored + * the possibility of using an SUSP record with the long filename + * in it, and instead wrote out a duplicate directory tree with the + * long filenames in it. + * + * I am not sure why they did this. One reason is that they get the path + * tables with the long filenames in them. + * + * There are two basic principles to Joliet, and the non-Unicode variant + * known as Romeo. Long filenames seem to be the main one, and the second + * is that the character set and a few other things is substantially relaxed. + * + * The SVD is identical to the PVD, except: + * + * Id is 2, not 1 (indicates SVD). + * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3). + * The root directory record points to a different extent (with different + * size). + * There are different path tables for the two sets of directory trees. + * + * The following fields are recorded in Unicode: + * system_id + * volume_id + * volume_set_id + * publisher_id + * preparer_id + * application_id + * copyright_file_id + * abstract_file_id + * bibliographic_file_id + * + * Unicode strings are always encoded in big-endian format. + * + * In a directory record, everything is the same as with iso9660, except + * that the name is recorded in unicode. The name length is specified in + * total bytes, not in number of unicode characters. + * + * The character set used for the names is different with UCS - the + * restrictions are that the following are not allowed: + * + * Characters (00)(00) through (00)(1f) (control chars) + * (00)(2a) '*' + * (00)(2f) '/' + * (00)(3a) ':' + * (00)(3b) ';' + * (00)(3f) '?' + * (00)(5c) '\' + */ +#include "config.h" +#include "mkisofs.h" +#include "iso9660.h" + +#include +#include + +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; jjpath_index != j) + { + jpathlist[j]->jpath_index = j; + fix++; + } + } + } while(fix); + + for(j=1; jde_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; ijnext = 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}; diff --git a/util/mkisofs/mkisofs.c b/util/mkisofs/mkisofs.c index a2e2d1874..3344a921a 100644 --- a/util/mkisofs/mkisofs.c +++ b/util/mkisofs/mkisofs.c @@ -20,16 +20,16 @@ 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 -#include "mkisofs.h" #include "config.h" +#include "mkisofs.h" #ifdef linux #include +#else +#include "getopt.h" #endif #include "iso9660.h" @@ -60,7 +60,7 @@ static char rcsid[] ="$Id: mkisofs.c,v 1.10.1.3 1998/06/02 03:36:16 eric Exp $"; struct directory * root = NULL; -static char version_string[] = "mkisofs v1.11.3"; +static char version_string[] = "mkisofs 1.12b4"; FILE * discimage; unsigned int next_extent = 0; @@ -69,19 +69,30 @@ unsigned int session_start = 0; unsigned int path_table_size = 0; unsigned int path_table[4] = {0,}; unsigned int path_blocks = 0; + + +unsigned int jpath_table_size = 0; +unsigned int jpath_table[4] = {0,}; +unsigned int jpath_blocks = 0; + struct iso_directory_record root_record; +struct iso_directory_record jroot_record; + char * extension_record = NULL; int extension_record_extent = 0; -static int extension_record_size = 0; +int extension_record_size = 0; /* These variables are associated with command line options */ int use_eltorito = 0; int use_RockRidge = 0; -int verbose = 0; +int use_Joliet = 0; +int verbose = 1; int all_files = 0; int follow_links = 0; int rationalize = 0; int generate_tables = 0; +int print_size = 0; +int split_output = 0; char * preparer = PREPARER_DEFAULT; char * publisher = PUBLISHER_DEFAULT; char * appid = APPID_DEFAULT; @@ -101,6 +112,8 @@ int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with DOS */ int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ +int split_SL_component = 1; /* circumvent a bug in the SunOS driver */ +int split_SL_field = 1; /* circumvent a bug in the SunOS */ struct rcopts{ char * tag; @@ -120,6 +133,110 @@ struct rcopts rcopt[] = { {NULL, NULL} }; +/* + * In case it isn't obvious, the option handling code was ripped off from GNU-ld. + */ +struct ld_option +{ + /* The long option information. */ + struct option opt; + /* The short option with the same meaning ('\0' if none). */ + char shortopt; + /* The name of the argument (NULL if none). */ + const char *arg; + /* The documentation string. If this is NULL, this is a synonym for + the previous option. */ + const char *doc; + enum + { + /* Use one dash before long option name. */ + ONE_DASH, + /* Use two dashes before long option name. */ + TWO_DASHES, + /* Don't mention this option in --help output. */ + NO_HELP + } control; +}; + +/* Codes used for the long options with no short synonyms. 150 isn't + special; it's just an arbitrary non-ASCII char value. */ +#define OPTION_HELP 150 +#define OPTION_QUIET 151 +#define OPTION_NOSPLIT_SL_COMPONENT 152 +#define OPTION_NOSPLIT_SL_FIELD 153 +#define OPTION_PRINT_SIZE 154 +#define OPTION_SPLIT_OUTPUT 155 + +static const struct ld_option ld_options[] = +{ + { {"all-files", no_argument, NULL, 'a'}, + 'a', NULL, "Process all files (don't skip backup files)", ONE_DASH }, + { {"appid", required_argument, NULL, 'A'}, + 'A', "ID", "Set Application ID" , ONE_DASH }, + { {"eltorito-boot", required_argument, NULL, 'b'}, + 'b', "FILE", "Set El Torito boot image name" , ONE_DASH }, + { {"eltorito-catalog", required_argument, NULL, 'c'}, + 'c', "FILE", "Set El Torito boot catalog name" , ONE_DASH }, + { {"cdwrite-params", required_argument, NULL, 'C'}, + 'C', "PARAMS", "Magic paramters from cdwrite" , ONE_DASH }, + { {"omit-period", no_argument, NULL, 'd'}, + 'd', NULL, "Omit trailing periods from filenames", ONE_DASH }, + { {"disable-deep-relocation", no_argument, NULL, 'D'}, + 'D', NULL, "Disable deep directory relocation", ONE_DASH }, + { {"follow-links", no_argument, NULL, 'f'}, + 'f', NULL, "Follow symbolic links", ONE_DASH }, + { {"help", no_argument, NULL, OPTION_HELP}, + '\0', NULL, "Print option help", ONE_DASH }, + { {NULL, required_argument, NULL, 'i'}, + 'i', "ADD_FILES", "No longer supported" , TWO_DASHES }, + { {"joliet", no_argument, NULL, 'J'}, + 'J', NULL, "Generate Joliet directory information", ONE_DASH }, + { {"full-iso9660-filenames", no_argument, NULL, 'l'}, + 'l', NULL, "Allow full 32 character filenames for iso9660 names", ONE_DASH }, + { {"allow-leading-dots", no_argument, NULL, 'L'}, + 'L', NULL, "Allow iso9660 filenames to start with '.'", ONE_DASH }, + { {"exclude", required_argument, NULL, 'm'}, + 'm', "GLOBFILE", "Exclude file name" , ONE_DASH }, + { {"prev-session", required_argument, NULL, 'M'}, + 'M', "FILE", "Set path to previous session to merge" , ONE_DASH }, + { {"omit-version-number", no_argument, NULL, 'N'}, + 'N', NULL, "Omit version number from iso9660 filename", ONE_DASH }, + { {"no-split-symlink-components", no_argument, NULL, 0}, + 0, NULL, "Inhibit splitting symlink components" , ONE_DASH }, + { {"no-split-symlink-fields", no_argument, NULL, 0}, + 0, NULL, "Inhibit splitting symlink fields" , ONE_DASH }, + { {"output", required_argument, NULL, 'o'}, + 'o', "FILE", "Set output file name" , ONE_DASH }, + { {"preparer", required_argument, NULL, 'p'}, + 'p', "PREP", "Set Volume preparer" , ONE_DASH }, + { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE}, + '\0', NULL, "Print estimated filesystem size and exit", ONE_DASH }, + { {"publisher", required_argument, NULL, 'P'}, + 'P', "PUB", "Set Volume publisher" , ONE_DASH }, + { {"quiet", no_argument, NULL, OPTION_QUIET}, + '\0', NULL, "Run quietly", ONE_DASH }, + { {"rational-rock", no_argument, NULL, 'r'}, + 'r', NULL, "Generate rationalized Rock Ridge directory information", ONE_DASH }, + { {"rock", no_argument, NULL, 'R'}, + 'R', NULL, "Generate Rock Ridge directory information", ONE_DASH }, + { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT}, + '\0', NULL, "Split output into files of approx. 1GB size", ONE_DASH }, + { {"translation-table", no_argument, NULL, 'T'}, + 'T', NULL, "Generate translation tables for systems that don't understand long filenames", ONE_DASH }, + { {"verbose", no_argument, NULL, 'v'}, + 'v', NULL, "Verbose", ONE_DASH }, + { {"volid", required_argument, NULL, 'V'}, + 'V', "ID", "Set Volume ID" , ONE_DASH }, + { {"old-exclude", required_argument, NULL, 'x'}, + 'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH } +#ifdef ERIC_neverdef + { {"transparent-compression", no_argument, NULL, 'z'}, + 'z', NULL, "Enable transparent compression of files", ONE_DASH }, +#endif +}; + +#define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0]) + #if defined(ultrix) || defined(_AUX_SOURCE) char *strdup(s) char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} @@ -179,7 +296,11 @@ void FDECL1(read_rcfile, char *, appname) } if (!rcfile) return; - fprintf(stderr, "Using \"%s\"\n", filename); + if ( verbose > 0 ) + { + fprintf(stderr, "Using \"%s\"\n", filename); + } + /* OK, we got it. Now read in the lines and parse them */ linum = 0; while (fgets(linebuffer, sizeof(linebuffer), rcfile)) @@ -260,20 +381,113 @@ void FDECL1(read_rcfile, char *, appname) char * path_table_l = NULL; char * path_table_m = NULL; + +char * jpath_table_l = NULL; +char * jpath_table_m = NULL; + int goof = 0; +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + void usage(){ + const char * program_name = "mkisofs"; +#if 0 fprintf(stderr,"Usage:\n"); fprintf(stderr, "mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ [-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" -#ifdef ADD_FILES -"[-i file] \n" -#endif "[-P publisher] [ -A app_id ] [-z] \n \ [-b boot_image_name] [-c boot_catalog-name] \ [-x path -x path ...] path\n"); - exit(1); +#endif + + int i; + const char **targets, **pp; + + fprintf (stderr, "Usage: %s [options] file...\n", program_name); + + fprintf (stderr, "Options:\n"); + for (i = 0; i < OPTION_COUNT; i++) + { + if (ld_options[i].doc != NULL) + { + int comma; + int len; + int j; + + fprintf (stderr, " "); + + comma = FALSE; + len = 2; + + j = i; + do + { + if (ld_options[j].shortopt != '\0' + && ld_options[j].control != NO_HELP) + { + fprintf (stderr, "%s-%c", comma ? ", " : "", ld_options[j].shortopt); + len += (comma ? 2 : 0) + 2; + if (ld_options[j].arg != NULL) + { + if (ld_options[j].opt.has_arg != optional_argument) + { + fprintf (stderr, " "); + ++len; + } + fprintf (stderr, "%s", ld_options[j].arg); + len += strlen (ld_options[j].arg); + } + comma = TRUE; + } + ++j; + } + while (j < OPTION_COUNT && ld_options[j].doc == NULL); + + j = i; + do + { + if (ld_options[j].opt.name != NULL + && ld_options[j].control != NO_HELP) + { + fprintf (stderr, "%s-%s%s", + comma ? ", " : "", + ld_options[j].control == TWO_DASHES ? "-" : "", + ld_options[j].opt.name); + len += ((comma ? 2 : 0) + + 1 + + (ld_options[j].control == TWO_DASHES ? 1 : 0) + + strlen (ld_options[j].opt.name)); + if (ld_options[j].arg != NULL) + { + fprintf (stderr, " %s", ld_options[j].arg); + len += 1 + strlen (ld_options[j].arg); + } + comma = TRUE; + } + ++j; + } + while (j < OPTION_COUNT && ld_options[j].doc == NULL); + + if (len >= 30) + { + fprintf (stderr, "\n"); + len = 0; + } + + for (; len < 30; len++) + fputc (' ', stderr); + + fprintf (stderr, "%s\n", ld_options[i].doc); + } + } + exit(1); } @@ -326,15 +540,18 @@ extern char * cdwrite_data; int FDECL2(main, int, argc, char **, argv){ char * outfile; struct directory_entry de; +#ifdef HAVE_SBRK unsigned long mem_start; +#endif struct stat statbuf; char * scan_tree; char * merge_image = NULL; struct iso_directory_record * mrootp = NULL; + struct output_fragment * opnt; + int longind; + char shortopts[OPTION_COUNT * 3 + 2]; + struct option longopts[OPTION_COUNT + 1]; int c; -#ifdef ADD_FILES - char *add_file_file = NULL; -#endif if (argc < 2) usage(); @@ -343,9 +560,56 @@ int FDECL2(main, int, argc, char **, argv){ read_rcfile(argv[0]); outfile = NULL; - while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF) + + /* + * Copy long option initialization from GNU-ld. + */ + /* Starting the short option string with '-' is for programs that + expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. */ + { + int i, is, il; + shortopts[0] = '-'; + is = 1; + il = 0; + for (i = 0; i < OPTION_COUNT; i++) + { + if (ld_options[i].shortopt != '\0') + { + shortopts[is] = ld_options[i].shortopt; + ++is; + if (ld_options[i].opt.has_arg == required_argument + || ld_options[i].opt.has_arg == optional_argument) + { + shortopts[is] = ':'; + ++is; + if (ld_options[i].opt.has_arg == optional_argument) + { + shortopts[is] = ':'; + ++is; + } + } + } + if (ld_options[i].opt.name != NULL) + { + longopts[il] = ld_options[i].opt; + ++il; + } + } + shortopts[is] = '\0'; + longopts[il].name = NULL; + } + + while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF) switch (c) { + case 1: + /* + * A filename that we take as input. + */ + optind--; + goto parse_input_files; case 'C': /* * This is a temporary hack until cdwrite gets the proper hooks in @@ -353,6 +617,13 @@ int FDECL2(main, int, argc, char **, argv){ */ cdwrite_data = optarg; break; + case 'i': + fprintf(stderr, "-i option no longer supported.\n"); + exit(1); + break; + case 'J': + use_Joliet++; + break; case 'a': all_files++; break; @@ -388,14 +659,6 @@ int FDECL2(main, int, argc, char **, argv){ case 'f': follow_links++; break; - case 'i': -#ifdef ADD_FILES - add_file_file = optarg; - break; -#else - usage(); - exit(1); -#endif case 'l': full_iso9660_filenames++; break; @@ -418,6 +681,9 @@ int FDECL2(main, int, argc, char **, argv){ exit(1); }; break; + case OPTION_PRINT_SIZE: + print_size++; + break; case 'P': publisher = optarg; if(strlen(publisher) > 128) { @@ -425,6 +691,9 @@ int FDECL2(main, int, argc, char **, argv){ exit(1); }; break; + case OPTION_QUIET: + verbose = 0; + break; case 'R': use_RockRidge++; break; @@ -432,6 +701,9 @@ int FDECL2(main, int, argc, char **, argv){ rationalize++; use_RockRidge++; break; + case OPTION_SPLIT_OUTPUT: + split_output++; + break; case 'T': generate_tables++; break; @@ -449,16 +721,32 @@ int FDECL2(main, int, argc, char **, argv){ transparent_compression++; #endif break; + case 'x': case 'm': + /* + * Somehow two options to do basically the same thing got added somewhere along + * the way. The 'match' code supports limited globbing, so this is the one + * that got selected. Unfortunately the 'x' switch is probably more intuitive. + */ add_match(optarg); break; - case 'x': - exclude(optarg); + case OPTION_HELP: + usage (); + exit (0); + break; + case OPTION_NOSPLIT_SL_COMPONENT: + split_SL_component = 0; + break; + case OPTION_NOSPLIT_SL_FIELD: + split_SL_field = 0; break; default: usage(); exit(1); } + +parse_input_files: + #ifdef __NetBSD__ { int resource; @@ -476,7 +764,7 @@ int FDECL2(main, int, argc, char **, argv){ mem_start = (unsigned long) sbrk(0); #endif - if(verbose) fprintf(stderr,"%s\n", version_string); + if(verbose > 1) fprintf(stderr,"%s\n", version_string); if( (cdwrite_data != NULL && merge_image == NULL) || (cdwrite_data == NULL && merge_image != NULL) ) @@ -489,12 +777,6 @@ int FDECL2(main, int, argc, char **, argv){ scan_tree = argv[optind]; -#ifdef ADD_FILES - if (add_file_file) { - add_file(add_file_file); - } - add_file_list (argc, argv, optind+1); -#endif if(!scan_tree){ usage(); @@ -557,28 +839,186 @@ int FDECL2(main, int, argc, char **, argv){ } /* - * Scan the actual directory (and any we find below it) - * for files to write out to the output image. + * Create an empty root directory. If we ever scan it for real, we will fill in the + * contents. */ - if (!scan_directory_tree(argv[optind], &de, mrootp)) + 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. Note - we + * take multiple source directories and keep merging them + * onto the image. + */ + while(optind < argc) { - exit(1); + 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( merge_image != NULL ) + { + merge_previous_session(root, mrootp); } /* - * Fix a couple of things in the root directory so that everything - * is self consistent. + * Sort the directories in the required order (by ISO9660). Also, + * choose the names for the 8.3 filesystem if required, and do + * any other post-scan work. */ - root->self = root->contents; /* Fix this up so that the path tables get done right */ + goof += sort_tree(root); - if(reloc_dir) sort_n_finish(reloc_dir); + if( use_Joliet ) + { + goof += joliet_sort_tree(root); + } if (goof) exit(1); + /* + * Fix a couple of things in the root directory so that everything + * is self consistent. + */ + root->self = root->contents; /* Fix this up so that the path + tables get done right */ + /* * OK, ready to write the file. Open it up, and generate the thing. */ - if (outfile){ + if (print_size){ + discimage = fopen("/dev/null", "w"); + if (!discimage){ + fprintf(stderr,"Unable to open /dev/null\n"); + exit(1); + } + } else if (outfile){ discimage = fopen(outfile, "w"); if (!discimage){ fprintf(stderr,"Unable to open disc image file\n"); @@ -593,54 +1033,120 @@ int FDECL2(main, int, argc, char **, argv){ path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; if (path_blocks & 1) path_blocks++; - path_table[0] = session_start + 0x10 + 2 + (use_eltorito ? 1 : 0); - path_table[1] = 0; - path_table[2] = path_table[0] + path_blocks; - path_table[3] = 0; + jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11; + if (jpath_blocks & 1) jpath_blocks++; - last_extent += path_table[2] - session_start + path_blocks; - /* The next free block */ + /* + * Start to set up the linked list that we use to track the + * contents of the disc. + */ + outputlist_insert(&padblock_desc); - /* The next step is to go through the directory tree and assign extent - numbers for all of the directories */ + /* + * PVD for disc. + */ + outputlist_insert(&voldesc_desc); - assign_directory_addresses(root); + /* + * SVD for El Torito. MUST be immediately after the PVD! + */ + if( use_eltorito) + { + outputlist_insert(&torito_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); - }; + /* + * SVD for Joliet. + */ + if( use_Joliet) + { + outputlist_insert(&joliet_desc); + } - if (use_RockRidge && reloc_dir) - finish_cl_pl_entries(); + /* + * Finally the last volume desctiptor. + */ + outputlist_insert(&end_vol); - /* Now we generate the path tables that are used by DOS to improve directory - access times. */ - generate_path_tables(); - /* Generate root record for volume descriptor. */ - generate_root_record(); + outputlist_insert(&pathtable_desc); + if( use_Joliet) + { + outputlist_insert(&jpathtable_desc); + } - if (verbose) - dump_tree(root); + outputlist_insert(&dirtree_desc); + if( use_Joliet) + { + outputlist_insert(&jdirtree_desc); + } + + outputlist_insert(&dirtree_clean); + + if(extension_record) + { + outputlist_insert(&extension_desc); + } + + outputlist_insert(&files_desc); + + /* + * 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); + } + } + + /* + * 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 diff --git a/util/mkisofs/mkisofs.h b/util/mkisofs/mkisofs.h index bc264d99a..b512a2865 100644 --- a/util/mkisofs/mkisofs.h +++ b/util/mkisofs/mkisofs.h @@ -20,11 +20,9 @@ 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 /* This symbol is used to indicate that we do not have things like @@ -41,16 +39,39 @@ #ifdef VMS #include #define dirent direct -#else -#include #endif +#ifdef _WIN32 +#define NON_UNIXFS +#endif /* _WIN32 */ + #include #include #include -#ifdef linux -#include +#if defined(HAVE_DIRENT_H) +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if defined(HAVE_SYS_NDIR_H) +# include +# endif +# if defined(HAVE_SYS_DIR_H) +# include +# endif +# if defined(HAVE_NDIR_H) +# include +# endif +#endif + +#if defined(HAVE_STRING_H) +#include +#else +#if defined(HAVE_STRINGS_H) +#include +#endif #endif #ifdef ultrix @@ -100,10 +121,12 @@ extern char *optarg; struct directory_entry{ struct directory_entry * next; + struct directory_entry * jnext; struct iso_directory_record isorec; unsigned int starting_block; unsigned int size; - unsigned int priority; + unsigned short priority; + unsigned char jreclen; /* Joliet record len */ char * name; char * table; char * whole_name; @@ -125,6 +148,52 @@ struct file_hash{ unsigned int size; }; + +/* + * This structure is used to control the output of fragments to the cdrom + * image. Everything that will be written to the output image will eventually + * go through this structure. There are two pieces - first is the sizing where + * we establish extent numbers for everything, and the second is when we actually + * generate the contents and write it to the output image. + * + * This makes it trivial to extend mkisofs to write special things in the image. + * All you need to do is hook an additional structure in the list, and the rest + * works like magic. + * + * The three passes each do the following: + * + * The 'size' pass determines the size of each component and assigns the extent number + * for that component. + * + * The 'generate' pass will adjust the contents and pointers as required now that extent + * numbers are assigned. In some cases, the contents of the record are also generated. + * + * The 'write' pass actually writes the data to the disc. + */ +struct output_fragment +{ + struct output_fragment * of_next; + int (*of_size)(int); + int (*of_generate)(void); + int (*of_write)(FILE *); +}; + +extern struct output_fragment * out_list; +extern struct output_fragment * out_tail; + +extern struct output_fragment padblock_desc; +extern struct output_fragment voldesc_desc; +extern struct output_fragment joliet_desc; +extern struct output_fragment torito_desc; +extern struct output_fragment end_vol; +extern struct output_fragment pathtable_desc; +extern struct output_fragment jpathtable_desc; +extern struct output_fragment dirtree_desc; +extern struct output_fragment dirtree_clean; +extern struct output_fragment jdirtree_desc; +extern struct output_fragment extension_desc; +extern struct output_fragment files_desc; + /* * This structure describes one complete directory. It has pointers * to other directories in the overall tree so that it is clear where @@ -138,6 +207,7 @@ struct directory{ struct directory * subdir; /* First subdirectory in this directory */ struct directory * parent; struct directory_entry * contents; + struct directory_entry * jcontents; struct directory_entry * self; char * whole_name; /* Entire path */ char * de_name; /* Entire path */ @@ -145,7 +215,12 @@ struct directory{ unsigned int depth; unsigned int size; unsigned int extent; + unsigned int jsize; + unsigned int jextent; unsigned short path_index; + unsigned short jpath_index; + unsigned short dir_flags; + unsigned short dir_nlink; }; struct deferred{ @@ -163,57 +238,82 @@ extern unsigned int next_extent; extern unsigned int last_extent; extern unsigned int last_extent_written; extern unsigned int session_start; + extern unsigned int path_table_size; extern unsigned int path_table[4]; extern unsigned int path_blocks; extern char * path_table_l; extern char * path_table_m; + +extern unsigned int jpath_table_size; +extern unsigned int jpath_table[4]; +extern unsigned int jpath_blocks; +extern char * jpath_table_l; +extern char * jpath_table_m; + extern struct iso_directory_record root_record; +extern struct iso_directory_record jroot_record; extern int use_eltorito; extern int use_RockRidge; +extern int use_Joliet; extern int rationalize; extern int follow_links; extern int verbose; extern int all_files; extern int generate_tables; +extern int print_size; +extern int split_output; extern int omit_period; extern int omit_version_number; extern int transparent_compression; extern int RR_relocation_depth; extern int full_iso9660_filenames; +extern int split_SL_component; +extern int split_SL_field; /* tree.c */ extern int DECL(stat_filter, (char *, struct stat *)); -extern void DECL(sort_n_finish,(struct directory *)); -extern void finish_cl_pl_entries(); -extern int DECL(scan_directory_tree,(char * path, - struct directory_entry * self, - struct iso_directory_record *)); +extern int DECL(lstat_filter, (char *, struct stat *)); +extern int DECL(sort_tree,(struct directory *)); +extern struct directory * + DECL(find_or_create_directory,(struct directory *, const char *, + struct directory_entry * self, int)); +extern void DECL (finish_cl_pl_entries, (void)); +extern int DECL(scan_directory_tree,(struct directory * this_dir, + char * path, + struct directory_entry * self)); +extern int DECL(insert_file_entry,(struct directory *, char *, + char *)); + extern void DECL(generate_iso9660_directories,(struct directory *, FILE*)); extern void DECL(dump_tree,(struct directory * node)); extern struct directory_entry * DECL(search_tree_file, (struct directory * node,char * filename)); +extern void DECL(update_nlink_field,(struct directory * node)); +extern void DECL (init_fstatbuf, (void)); +extern struct stat root_statbuf; /* eltorito.c */ extern void DECL(init_boot_catalog, (const char * path )); extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path )); /* write.c */ -extern void DECL(assign_directory_addresses,(struct directory * root)); extern int DECL(get_733,(char *)); extern int DECL(isonum_733,(unsigned char *)); extern void DECL(set_723,(char *, unsigned int)); extern void DECL(set_731,(char *, unsigned int)); extern void DECL(set_721,(char *, unsigned int)); extern void DECL(set_733,(char *, unsigned int)); -extern void DECL(sort_directory,(struct directory_entry **)); -extern void generate_root_record(); +extern int DECL(sort_directory,(struct directory_entry **)); extern void DECL(generate_one_directory,(struct directory *, FILE*)); -extern void generate_path_tables(); -extern int DECL(iso_write,(FILE * outfile)); extern void DECL(memcpy_max, (char *, char *, int)); - +extern int DECL(oneblock_size, (int starting_extent)); +extern struct iso_primary_descriptor vol_desc; +extern void DECL(xfwrite, (void * buffer, int count, int size, FILE * file)); +extern void DECL(set_732, (char * pnt, unsigned int i)); +extern void DECL(set_722, (char * pnt, unsigned int i)); +extern void DECL(outputlist_insert, (struct output_fragment * frag)); /* multi.c */ @@ -228,6 +328,12 @@ extern struct directory_entry ** extern void DECL(merge_remaining_entries, (struct directory *, struct directory_entry **, int)); +extern int + DECL(merge_previous_session, (struct directory *, + struct iso_directory_record *)); + +/* joliet.c */ +int DECL(joliet_sort_tree, (struct directory * node)); /* match.c */ extern int DECL(matches, (char *)); @@ -245,7 +351,7 @@ extern void DECL(add_hash,(struct directory_entry *)); extern struct file_hash * DECL(find_hash,(dev_t, ino_t)); extern void DECL(add_directory_hash,(dev_t, ino_t)); extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t)); -extern void flush_file_hash(); +extern void DECL (flush_file_hash, (void)); extern int DECL(delete_file_hash,(struct directory_entry *)); extern struct directory_entry * DECL(find_file_hash,(char *)); extern void DECL(add_file_hash,(struct directory_entry *)); @@ -320,7 +426,13 @@ extern void * DECL(e_malloc,(size_t)); * is set for all entries in a directory, it means we can just * reuse the TRANS.TBL and not generate a new one. */ -#define SAFE_TO_REUSE_TABLE_ENTRY 1 +#define SAFE_TO_REUSE_TABLE_ENTRY 0x01 +#define DIR_HAS_DOT 0x02 +#define DIR_HAS_DOTDOT 0x04 +#define INHIBIT_JOLIET_ENTRY 0x08 +#define INHIBIT_RR_ENTRY 0x10 +#define RELOCATED_DIRECTORY 0x20 + /* * Volume sequence number to use in all of the iso directory records. */ diff --git a/util/mkisofs/multi.c b/util/mkisofs/multi.c index 13ba6f6d1..e49d1c34e 100644 --- a/util/mkisofs/multi.c +++ b/util/mkisofs/multi.c @@ -19,7 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: multi.c,v 1.6.1.3 1998/06/02 03:00:25 eric Exp $"; +static char rcsid[] ="$Id: multi.c,v 1.12 1998/06/02 02:40:38 eric Exp $"; #include #include @@ -137,7 +137,7 @@ FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) while(len >= 4){ if(pnt[3] != 1) { - printf("**BAD RRVERSION"); + fprintf(stderr,"**BAD RRVERSION"); return -1; }; if(strncmp((char *) pnt, "NM", 2) == 0) { @@ -193,7 +193,7 @@ FDECL4(check_rr_dates, struct directory_entry *, dpnt, */ while(len >= 4){ if(pnt[3] != 1) { - printf("**BAD RRVERSION"); + fprintf(stderr,"**BAD RRVERSION"); return -1; }; @@ -750,6 +750,7 @@ void FDECL3(merge_remaining_entries, struct directory *, this_dir, struct directory_entry * s_entry; unsigned int ttbl_extent = 0; unsigned int ttbl_index = 0; + char whole_path[1024]; /* * Whatever is leftover in the list needs to get merged back @@ -762,6 +763,18 @@ void FDECL3(merge_remaining_entries, struct directory *, this_dir, continue; } + if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL) + { + /* + * Set the name for this directory. + */ + strcpy(whole_path, this_dir->de_name); + strcat(whole_path, SPATH_SEPARATOR); + strcat(whole_path, pnt[i]->name); + + pnt[i]->whole_name = strdup(whole_path); + } + if( pnt[i]->name != NULL && strcmp(pnt[i]->name, "") == 0 ) { @@ -884,6 +897,7 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, char whole_path[1024]; this_dir = (struct directory *) e_malloc(sizeof(struct directory)); + memset(this_dir, 0, sizeof(struct directory)); this_dir->next = NULL; this_dir->subdir = NULL; this_dir->self = dpnt; @@ -939,8 +953,23 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, if( (contents[i]->isorec.flags[0] & 2) != 0 ) { memset(contents[i]->isorec.extent, 0, 8); + + if( strcmp(contents[i]->name, ".") == 0 ) + this_dir->dir_flags |= DIR_HAS_DOT; + + if( strcmp(contents[i]->name, "..") == 0 ) + this_dir->dir_flags |= DIR_HAS_DOTDOT; } + /* + * Set the whole name for this file. + */ + strcpy(whole_path, this_dir->whole_name); + strcat(whole_path, SPATH_SEPARATOR); + strcat(whole_path, contents[i]->name); + + contents[i]->whole_name = strdup(whole_path); + contents[i]->next = this_dir->contents; contents[i]->filedir = this_dir; this_dir->contents = contents[i]; @@ -957,7 +986,13 @@ FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, */ merge_remaining_entries(this_dir, contents, n_orig); free_mdinfo(contents, n_orig); +#if 0 + /* + * This is no longer required. The post-scan sort will handle + * all of this for us. + */ sort_n_finish(this_dir); +#endif return 0; } @@ -1016,3 +1051,99 @@ FDECL1(get_session_start, int *, file_addr) return 0; } +/* + * This function scans the directory tree, looking for files, and it makes + * note of everything that is found. We also begin to construct the ISO9660 + * directory entries, so that we can determine how large each directory is. + */ + +int +FDECL2(merge_previous_session,struct directory *, this_dir, + struct iso_directory_record *, mrootp) +{ + struct directory_entry **orig_contents = NULL; + struct directory_entry * odpnt = NULL; + int n_orig; + struct directory_entry * s_entry; + int dflag; + int status, lstatus; + struct stat statbuf, lstatbuf; + + /* + * Parse the same directory in the image that we are merging + * for multisession stuff. + */ + orig_contents = read_merging_directory(mrootp, &n_orig); + if( orig_contents == NULL ) + { + return 0; + } + + +/* Now we scan the directory itself, and look at what is inside of it. */ + + dflag = 0; + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + status = stat_filter(s_entry->whole_name, &statbuf); + lstatus = lstat_filter(s_entry->whole_name, &lstatbuf); + + /* + * We always should create an entirely new directory tree whenever + * we generate a new session, unless there were *no* changes whatsoever + * to any of the directories, in which case it would be kind of pointless + * to generate a new session. + * + * I believe it is possible to rigorously prove that any change anywhere + * in the filesystem will force the entire tree to be regenerated + * because the modified directory will get a new extent number. Since + * each subdirectory of the changed directory has a '..' entry, all of + * them will need to be rewritten too, and since the parent directory + * of the modified directory will have an extent pointer to the directory + * it too will need to be rewritten. Thus we will never be able to reuse + * any directory information when writing new sessions. + * + * We still check the previous session so we can mark off the equivalent + * entry in the list we got from the original disc, however. + */ + + /* + * The check_prev_session function looks for an identical entry in + * the previous session. If we see it, then we copy the extent + * number to s_entry, and cross it off the list. + */ + check_prev_session(orig_contents, n_orig, s_entry, + &statbuf, &lstatbuf, &odpnt); + + if(S_ISDIR(statbuf.st_mode) && odpnt != NULL) + { + int dflag; + + if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) + { + struct directory * child; + + child = find_or_create_directory(this_dir, + s_entry->whole_name, + s_entry, 1); + dflag = merge_previous_session(child, + &odpnt->isorec); + /* If unable to scan directory, mark this as a non-directory */ + if(!dflag) + lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; + free(odpnt); + odpnt = NULL; + } + } + } + + /* + * Whatever is left over, are things which are no longer in the tree + * on disk. We need to also merge these into the tree. + */ + merge_remaining_entries(this_dir, orig_contents, n_orig); + free_mdinfo(orig_contents, n_orig); + + return 1; +} + diff --git a/util/mkisofs/name.c b/util/mkisofs/name.c index 10475d43e..fb88fc9d0 100644 --- a/util/mkisofs/name.c +++ b/util/mkisofs/name.c @@ -21,8 +21,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: name.c,v 1.7 1997/11/09 16:42:51 eric Exp $"; +static char rcsid[] ="$Id: name.c,v 1.10 1998/06/02 02:40:38 eric Exp $"; +#include "config.h" #include "mkisofs.h" #include @@ -105,8 +106,7 @@ int FDECL3(iso9660_file_length, last_dot = strrchr (pnt,'.'); if( (last_dot != NULL) && ( (last_dot[1] == '~') - || (last_dot[1] == '\0') - || (last_dot[1] == '\0')) ) + || (last_dot[1] == '\0')) ) { c = last_dot; *c = '\0'; @@ -154,13 +154,19 @@ int FDECL3(iso9660_file_length, * a silly thing to do on a Unix box, but we check for it * anyways. If we see this, then we don't have to add our * own version number at the end. + * UNLESS the ';' is part of the filename and no version + * number is following. [VK] */ - if(*pnt == ';') - { - seen_semic = 1; - *result++ = *pnt++; - continue; - } + if(*pnt == ';') + { + /* [VK] */ + if (pnt[1] != '\0' && (pnt[1] < '0' || pnt[1] > '9')) + { + pnt++; + ignore++; + continue; + } + } /* * If we have a name with multiple '.' characters, we ignore everything diff --git a/util/mkisofs/rock.c b/util/mkisofs/rock.c index 47cba5527..d851b96fb 100644 --- a/util/mkisofs/rock.c +++ b/util/mkisofs/rock.c @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: rock.c,v 1.3 1997/05/17 15:45:26 eric Exp $"; +static char rcsid[] ="$Id: rock.c,v 1.7 1998/02/18 04:48:23 eric Exp $"; #include @@ -225,7 +225,7 @@ int deep_opt; Rock[ipnt++] = PN_SIZE; Rock[ipnt++] = SU_VERSION; flagval |= (1<<1); -#if !defined(MAJOR_IN_SYSMACROS) && !defined(MAJOR_IN_MKDEV) +#if defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV) set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev )); ipnt += 8; set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev)); @@ -268,10 +268,36 @@ int deep_opt; unsigned char * cpnt, *cpnt1; nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff)); symlink_buff[nchar < 0 ? 0 : nchar] = 0; + nchar = strlen((char *) symlink_buff); set_733(s_entry->isorec.size, 0); cpnt = &symlink_buff[0]; flagval |= (1<<2); + if (! split_SL_field) + { + int sl_bytes = 0; + for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) + { + if (*cpnt1 == '/') + { + sl_bytes += 4; + } + else + { + sl_bytes += 1; + } + } + if (sl_bytes > 250) + { + /* + * the symbolic link won't fit into one SL System Use Field + * print an error message and continue with splited one + */ + fprintf(stderr,"symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt); + } + if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry(); + } + while(nchar){ if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry(); Rock[ipnt++] ='S'; @@ -309,15 +335,18 @@ int deep_opt; } else { /* If we do not have enough room for a component, start a new continuations segment now */ - if(MAYBE_ADD_CE_ENTRY(6)) { - add_CE_entry(); - if(cpnt1){ - *cpnt1 = '/'; - nchar++; - cpnt1 = NULL; /* A kluge so that we can restart properly */ - } - break; - } + if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) : + MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt))) + { + add_CE_entry(); + if(cpnt1) + { + *cpnt1 = '/'; + nchar++; + cpnt1 = NULL; /* A kluge so that we can restart properly */ + } + break; + } j0 = strlen((char *) cpnt); while(j0) { j1 = j0; diff --git a/util/mkisofs/tree.c b/util/mkisofs/tree.c index 7180905df..e5ddbb365 100644 --- a/util/mkisofs/tree.c +++ b/util/mkisofs/tree.c @@ -20,7 +20,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: tree.c,v 1.9.1.2 1998/06/02 03:17:31 eric Exp $"; +static char rcsid[] ="$Id: tree.c,v 1.26 1998/06/02 03:14:58 eric Exp $"; /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ @@ -88,6 +88,9 @@ extern char * strdup(const char *); #endif static unsigned char symlink_buff[256]; +static void DECL(attach_dot_entries, (struct directory * dirnode, + struct stat * parent_stat)); +static void DECL(delete_directory, (struct directory * parent, struct directory * child)); extern int verbose; @@ -112,7 +115,9 @@ FDECL1(stat_fix, struct stat *, st) * are useless, and with uid+gid 0 don't want set-id bits, either). */ st->st_mode |= 0444; +#ifndef _WIN32 /* make all file "executable" */ if (st->st_mode & 0111) +#endif /* _WIN32 */ st->st_mode |= 0111; st->st_mode &= ~07222; } @@ -135,11 +140,10 @@ FDECL2(lstat_filter, char *, path, struct stat *, st) return result; } -void FDECL1(sort_n_finish, struct directory *, this_dir) +static int FDECL1(sort_n_finish, struct directory *, this_dir) { struct directory_entry * s_entry; struct directory_entry * s_entry1; - time_t current_time; struct directory_entry * table; int count; int d1; @@ -147,6 +151,7 @@ void FDECL1(sort_n_finish, struct directory *, this_dir) int d3; int new_reclen; char * c; + int status = 0; int tablesize = 0; char newname[34]; char rootname[34]; @@ -156,14 +161,17 @@ void FDECL1(sort_n_finish, struct directory *, this_dir) table = NULL; - if(fstatbuf.st_ctime == 0) + init_fstatbuf(); + + /* + * If we had artificially created this directory, then we might be + * missing the required '.' entries. Create these now if we need + * them. + */ + if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) != + (DIR_HAS_DOT | DIR_HAS_DOTDOT) ) { - time (¤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(); @@ -253,7 +261,12 @@ got_valid_name: */ if(s_entry->priority < s_entry1->priority) { - fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry->name, s_entry1->name); + if( verbose > 0 ) + { + fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, + this_dir->whole_name, SPATH_SEPARATOR, + s_entry->name, s_entry1->name); + } s_entry->isorec.name_len[0] = strlen(newname); new_reclen = sizeof(struct iso_directory_record) - sizeof(s_entry->isorec.name) + @@ -270,7 +283,12 @@ got_valid_name: else { delete_file_hash(s_entry1); - fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry1->name, s_entry->name); + if( verbose > 0 ) + { + fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, + this_dir->whole_name, SPATH_SEPARATOR, + s_entry1->name, s_entry->name); + } s_entry1->isorec.name_len[0] = strlen(newname); new_reclen = sizeof(struct iso_directory_record) - sizeof(s_entry1->isorec.name) + @@ -324,6 +342,9 @@ got_valid_name: set_733((char *) table->isorec.size, tablesize); table->size = tablesize; table->filedir = this_dir; +#ifdef ERIC_neverdef + table->de_flags |= INHIBIT_JOLIET_ENTRY; +#endif table->name = strdup(""); table->table = (char *) e_malloc(ROUND_UP(tablesize)); memset(table->table, 0, ROUND_UP(tablesize)); @@ -339,10 +360,17 @@ got_valid_name: } } + /* + * We have now chosen the 8.3 names and we should now know the length + * of every entry in the directory. + */ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) { new_reclen = strlen(s_entry->isorec.name); + /* + * First update the path table sizes for directories. + */ if(s_entry->isorec.flags[0] == 2) { if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) @@ -354,7 +382,9 @@ got_valid_name: { new_reclen = 1; if (this_dir == root && strlen(s_entry->name) == 1) - path_table_size += sizeof(struct iso_path_table); + { + path_table_size += sizeof(struct iso_path_table); + } } } if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */ @@ -380,8 +410,17 @@ got_valid_name: s_entry->isorec.length[0] = new_reclen; } - sort_directory(&this_dir->contents); + status = sort_directory(&this_dir->contents); + if( status > 0 ) + { + fprintf(stderr, "Unable to sort directory %s\n", + this_dir->whole_name); + } + /* + * If we are filling out a TRANS.TBL, generate the entries that will + * go in the thing. + */ if(table) { count = 0; @@ -390,10 +429,15 @@ got_valid_name: if(!s_entry->table) continue; if(strcmp(s_entry->name, ".") == 0 || strcmp(s_entry->name, "..") == 0) continue; - +#if (defined(__sun) && !defined(__svr4__)) + count += strlen(sprintf(table->table + count, "%c %-34s%s", + s_entry->table[0], + s_entry->isorec.name, s_entry->table+1)); +#else count += sprintf(table->table + count, "%c %-34s%s", s_entry->table[0], s_entry->isorec.name, s_entry->table+1); +#endif /* __sun && !__svr4__ */ free(s_entry->table); s_entry->table = NULL; } @@ -419,7 +463,7 @@ got_valid_name: this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); this_dir->size += new_reclen; - + /* See if continuation entries were used on disc */ if(use_RockRidge && s_entry->rr_attr_size != s_entry->total_rr_attr_size) @@ -455,11 +499,11 @@ got_valid_name: } s_entry = s_entry->next; } + return status; } static void generate_reloc_directory() { - int new_reclen; time_t current_time; struct directory_entry *s_entry; @@ -476,7 +520,6 @@ static void generate_reloc_directory() reloc_dir->de_name = strdup("rr_moved"); reloc_dir->extent = 0; - new_reclen = strlen(reloc_dir->de_name); /* Now create an actual directory entry */ s_entry = (struct directory_entry *) @@ -485,6 +528,12 @@ static void generate_reloc_directory() s_entry->next = root->contents; reloc_dir->self = s_entry; + /* + * The rr_moved entry will not appear in the Joliet tree. + */ + reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY; + s_entry->de_flags |= INHIBIT_JOLIET_ENTRY; + root->contents = s_entry; root->contents->name = strdup(reloc_dir->de_name); root->contents->filedir = root; @@ -506,57 +555,134 @@ static void generate_reloc_directory() /* Now create the . and .. entries in rr_moved */ /* Now create an actual directory entry */ - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry, root->contents, - sizeof(struct directory_entry)); - s_entry->name = strdup("."); - iso9660_file_length (".", s_entry, 1); - - s_entry->filedir = reloc_dir; - reloc_dir->contents = s_entry; - - if(use_RockRidge){ - fstatbuf.st_mode = 0555 | S_IFDIR; - fstatbuf.st_nlink = 2; - generate_rock_ridge_attributes("", - ".", s_entry, - &fstatbuf, &fstatbuf, 0); - }; - - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry, root->contents, - sizeof(struct directory_entry)); - s_entry->name = strdup(".."); - iso9660_file_length ("..", s_entry, 1); - s_entry->filedir = root; - reloc_dir->contents->next = s_entry; - reloc_dir->contents->next->next = NULL; - if(use_RockRidge){ - fstatbuf.st_mode = 0555 | S_IFDIR; - fstatbuf.st_nlink = 2; - generate_rock_ridge_attributes("", - "..", s_entry, - &root_statbuf, &root_statbuf, 0); - }; + attach_dot_entries(reloc_dir, &root_statbuf); } -static void FDECL1(increment_nlink, struct directory_entry *, s_entry){ - unsigned char * pnt; - int len, nlink; +/* + * 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; - 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]; - }; + 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, + 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, + &fstatbuf, &fstatbuf, deep_flag); + } + + dirnode->dir_flags |= DIR_HAS_DOT; + } + +} + +static void FDECL2(update_nlink, struct directory_entry *, s_entry, int, value) +{ + unsigned char * pnt; + int len; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len) + { + if(pnt[0] == 'P' && pnt[1] == 'X') + { + set_733((char *) pnt+12, value); + break; + } + len -= pnt[2]; + pnt += pnt[2]; + } +} + +static void FDECL1(increment_nlink, struct directory_entry *, s_entry) +{ + unsigned char * pnt; + int len, nlink; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len) + { + if(pnt[0] == 'P' && pnt[1] == 'X') + { + nlink = get_733((char *) pnt+12); + set_733((char *) pnt+12, nlink+1); + break; + } + len -= pnt[2]; + pnt += pnt[2]; + } } void finish_cl_pl_entries(){ @@ -601,29 +727,25 @@ void finish_cl_pl_entries(){ }; } -/* - * This function scans the directory tree, looking for files, and it makes - * note of everything that is found. We also begin to construct the ISO9660 - * directory entries, so that we can determine how large each directory is. +/* + * Function: scan_directory_tree + * + * Purpose: Walk through a directory on the local machine + * filter those things we don't want to include + * and build our representation of a dir. + * + * Notes: */ - int -FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, - struct iso_directory_record *, mrootp){ +FDECL3(scan_directory_tree,struct directory *, this_dir, + char *, path, + struct directory_entry *, de) +{ DIR * current_dir; char whole_path[1024]; struct dirent * d_entry; - struct directory_entry * s_entry, *s_entry1; - struct directory * this_dir, *next_brother, *parent; - struct stat statbuf, lstatbuf; - int status, dflag; - int lstatus; - int n_orig; - struct directory_entry **orig_contents = NULL; - struct directory_entry * odpnt = NULL; - char * cpnt; - int new_reclen; - int deep_flag; + struct directory * parent; + int dflag; char * old_path; current_dir = opendir(path); @@ -634,14 +756,15 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, old_path = path; - if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir); + if(current_dir) d_entry = readdir(current_dir); - if(!current_dir || !d_entry) { - fprintf(stderr,"Unable to open directory %s\n", path); - de->isorec.flags[0] &= ~2; /* Mark as not a directory */ - if(current_dir) closedir(current_dir); - return 0; - }; + if(!current_dir || !d_entry) + { + fprintf(stderr,"Unable to open directory %s\n", path); + de->isorec.flags[0] &= ~2; /* Mark as not a directory */ + if(current_dir) closedir(current_dir); + return 0; + } parent = de->filedir; /* Set up the struct for the current directory, and insert it into the @@ -651,77 +774,16 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, vms_path_fixup(path); #endif - this_dir = (struct directory *) e_malloc(sizeof(struct directory)); - this_dir->next = NULL; - new_reclen = 0; - this_dir->subdir = NULL; - this_dir->self = de; - this_dir->contents = NULL; - this_dir->whole_name = strdup(path); - cpnt = strrchr(path, PATH_SEPARATOR); - if(cpnt) - cpnt++; - else - cpnt = path; - this_dir->de_name = strdup(cpnt); - this_dir->size = 0; - this_dir->extent = 0; - - if(!parent || parent == root){ - if (!root) { - root = this_dir; /* First time through for root directory only */ - root->depth = 0; - root->parent = root; - } else { - this_dir->depth = 1; - if(!root->subdir) - root->subdir = this_dir; - else { - next_brother = root->subdir; - while(next_brother->next) next_brother = next_brother->next; - next_brother->next = this_dir; - }; - this_dir->parent = parent; - }; - } else { - /* Come through here for normal traversal of tree */ -#ifdef DEBUG - fprintf(stderr,"%s(%d) ", path, this_dir->depth); -#endif - if(parent->depth > RR_relocation_depth) { - fprintf(stderr,"Directories too deep %s\n", path); - exit(1); - }; - - this_dir->parent = parent; - this_dir->depth = parent->depth + 1; - - if(!parent->subdir) - parent->subdir = this_dir; - else { - next_brother = parent->subdir; - while(next_brother->next) next_brother = next_brother->next; - next_brother->next = this_dir; - } - } - - /* - * Parse the same directory in the image that we are merging - * for multisession stuff. + + /* + * Now we scan the directory itself, and look at what is inside of it. */ - if( mrootp != NULL ) - { - orig_contents = read_merging_directory(mrootp, &n_orig); - } - -/* Now we scan the directory itself, and look at what is inside of it. */ - dflag = 0; while(1==1){ /* The first time through, skip this, since we already asked for the first entry when we opened the directory. */ - if(dflag) d_entry = readdir_add_files(&path, old_path, current_dir); + if(dflag) d_entry = readdir(current_dir); dflag++; if(!d_entry) break; @@ -730,9 +792,16 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, /* If we do not want all files, then pitch the backups. */ if(!all_files){ - if(strchr(d_entry->d_name,'~')) continue; - if(strchr(d_entry->d_name,'#')) continue; - }; + if( strchr(d_entry->d_name,'~') + || strchr(d_entry->d_name,'#')) + { + if( verbose > 0 ) + { + fprintf(stderr, "Ignoring file %s\n", d_entry->d_name); + } + continue; + } + } if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){ fprintf(stderr, "Overflow of stat buffer\n"); @@ -747,16 +816,9 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, #endif strcat(whole_path, d_entry->d_name); - /* Should we exclude this file? */ - if (is_excluded(whole_path)) { - if (verbose) { - fprintf(stderr, "Excluded: %s\n",whole_path); - } - continue; - } /** Should we exclude this file ? */ - if (matches(d_entry->d_name)) { - if (verbose) { + if (matches(d_entry->d_name) || matches(whole_path)) { + if (verbose > 1) { fprintf(stderr, "Excluded by match: %s\n", whole_path); } continue; @@ -770,402 +832,498 @@ FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, * versions of these files, and we need to ignore any * originals that we might have found. */ - if (verbose) + if (verbose > 1) { fprintf(stderr, "Excluded: %s\n",whole_path); } continue; } -#if 0 - if (verbose) fprintf(stderr, "%s\n",whole_path); -#endif - status = stat_filter(whole_path, &statbuf); - - lstatus = lstat_filter(whole_path, &lstatbuf); - - if( (status == -1) && (lstatus == -1) ) + /* + * 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 ) { - /* - * This means that the file doesn't exist, or isn't accessible. - * Sometimes this is because of NFS permissions problems - * or it could mean that the user has attempted to 'add' something - * with the -i option and the directory being added doesn't exist. - */ - fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path); continue; } - if(this_dir == root && strcmp(d_entry->d_name, ".") == 0) - root_statbuf = statbuf; /* Save this for later on */ - - /* We do this to make sure that the root entries are consistent */ - if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) { - statbuf = root_statbuf; - lstatbuf = root_statbuf; - }; - - if(S_ISLNK(lstatbuf.st_mode)){ - - /* Here we decide how to handle the symbolic links. Here - we handle the general case - if we are not following - links or there is an error, then we must change - something. If RR is in use, it is easy, we let RR - describe the file. If not, then we punt the file. */ - - if((status || !follow_links)){ - if(use_RockRidge){ - status = 0; - statbuf.st_size = 0; - STAT_INODE(statbuf) = UNCACHED_INODE; - statbuf.st_dev = (dev_t) UNCACHED_DEVICE; - statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; - } else { - if(follow_links) fprintf(stderr, - "Unable to stat file %s - ignoring and continuing.\n", - whole_path); - else fprintf(stderr, - "Symlink %s ignored - continuing.\n", - whole_path); - continue; /* Non Rock Ridge discs - ignore all symlinks */ - }; - } - - /* Here we handle a different kind of case. Here we have - a symlink, but we want to follow symlinks. If we run - across a directory loop, then we need to pretend that - we are not following symlinks for this file. If this - is the first time we have seen this, then make this - seem as if there was no symlink there in the first - place */ - - if( follow_links - && S_ISDIR(statbuf.st_mode) ) - { - if( strcmp(d_entry->d_name, ".") - && strcmp(d_entry->d_name, "..") ) - { - if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) - { - if(!use_RockRidge) - { - fprintf(stderr, "Already cached directory seen (%s)\n", - whole_path); - continue; - } - statbuf.st_size = 0; - STAT_INODE(statbuf) = UNCACHED_INODE; - statbuf.st_dev = (dev_t) UNCACHED_DEVICE; - statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; - } else { - lstatbuf = statbuf; - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - } - } - } - - /* - * For non-directories, we just copy the stat information over - * so we correctly include this file. - */ - if( follow_links - && !S_ISDIR(statbuf.st_mode) ) - { - lstatbuf = statbuf; - } - } - - /* - * Add directories to the cache so that we don't waste space even - * if we are supposed to be following symlinks. - */ - if( follow_links - && strcmp(d_entry->d_name, ".") - && strcmp(d_entry->d_name, "..") - && S_ISDIR(statbuf.st_mode) ) - { - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - } -#ifdef VMS - if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && - statbuf.st_fab_rfm != FAB$C_STMLF)) { - fprintf(stderr,"Warning - file %s has an unsupported VMS record" - " format (%d)\n", - whole_path, statbuf.st_fab_rfm); - } -#endif - - if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){ - fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", - whole_path, errno); - continue; - } - - /* Add this so that we can detect directory loops with hard links. - If we are set up to follow symlinks, then we skip this checking. */ - if( !follow_links - && S_ISDIR(lstatbuf.st_mode) - && strcmp(d_entry->d_name, ".") - && strcmp(d_entry->d_name, "..") ) + if( strcmp(d_entry->d_name, "..") == 0 + && this_dir->dir_flags & DIR_HAS_DOTDOT ) { - if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) { - fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).\n", - whole_path, (unsigned long) statbuf.st_dev, - (unsigned long) STAT_INODE(statbuf)); - exit(1); - }; - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - }; - - if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) && - !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) - && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) && - !S_ISDIR(lstatbuf.st_mode)) { - fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n", - whole_path); - continue; - }; - - /* Who knows what trash this is - ignore and continue */ - - if(status) { - fprintf(stderr, - "Unable to stat file %s - ignoring and continuing.\n", - whole_path); - continue; - }; - - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - s_entry->next = this_dir->contents; - memset(s_entry->isorec.extent, 0, 8); - this_dir->contents = s_entry; - deep_flag = 0; - s_entry->table = NULL; - - s_entry->name = strdup(d_entry->d_name); - s_entry->whole_name = strdup (whole_path); - - s_entry->de_flags = 0; - s_entry->filedir = this_dir; - s_entry->isorec.flags[0] = 0; - s_entry->isorec.ext_attr_length[0] = 0; - iso9660_date(s_entry->isorec.date, statbuf.st_mtime); - s_entry->isorec.file_unit_size[0] = 0; - s_entry->isorec.interleave[0] = 0; - if(parent && parent == reloc_dir && strcmp(d_entry->d_name, "..") == 0){ - s_entry->inode = UNCACHED_INODE; - s_entry->dev = (dev_t) UNCACHED_DEVICE; - deep_flag = NEED_PL; - } else { - s_entry->inode = STAT_INODE(statbuf); - s_entry->dev = statbuf.st_dev; - }; - set_723(s_entry->isorec.volume_sequence_number, DEF_VSN); - iso9660_file_length(d_entry->d_name, s_entry, S_ISDIR(statbuf.st_mode)); - s_entry->rr_attr_size = 0; - s_entry->total_rr_attr_size = 0; - s_entry->rr_attributes = NULL; - - /* Directories are assigned sizes later on */ - if (!S_ISDIR(statbuf.st_mode)) { - set_733((char *) s_entry->isorec.size, statbuf.st_size); - - if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || - S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode) - || S_ISLNK(lstatbuf.st_mode)) - s_entry->size = 0; - else - s_entry->size = statbuf.st_size; - } else - s_entry->isorec.flags[0] = 2; - - /* - * We always should create an entirely new directory tree whenever - * we generate a new session, unless there were *no* changes whatsoever - * to any of the directories, in which case it would be kind of pointless - * to generate a new session. - * - * I believe it is possible to rigorously prove that any change anywhere - * in the filesystem will force the entire tree to be regenerated - * because the modified directory will get a new extent number. Since - * each subdirectory of the changed directory has a '..' entry, all of - * them will need to be rewritten too, and since the parent directory - * of the modified directory will have an extent pointer to the directory - * it too will need to be rewritten. Thus we will never be able to reuse - * any directory information when writing new sessions. - * - * We still check the previous session so we can mark off the equivalent - * entry in the list we got from the original disc, however. - */ - if(S_ISDIR(statbuf.st_mode) && orig_contents != NULL){ - check_prev_session(orig_contents, n_orig, s_entry, - &statbuf, &lstatbuf, &odpnt); - } - - if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") && - S_ISDIR(statbuf.st_mode) && this_dir->depth > RR_relocation_depth){ - if(!reloc_dir) generate_reloc_directory(); - - s_entry1 = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry1, this_dir->contents, - sizeof(struct directory_entry)); - s_entry1->table = NULL; - s_entry1->name = strdup(this_dir->contents->name); - s_entry1->whole_name = strdup(this_dir->contents->whole_name); - s_entry1->next = reloc_dir->contents; - reloc_dir->contents = s_entry1; - s_entry1->priority = 32768; - s_entry1->parent_rec = this_dir->contents; - - deep_flag = NEED_RE; - - if(use_RockRidge) { - generate_rock_ridge_attributes(whole_path, - d_entry->d_name, s_entry1, - &statbuf, &lstatbuf, deep_flag); - } - - deep_flag = 0; - - /* We need to set this temporarily so that the parent to this is correctly - determined. */ - s_entry1->filedir = reloc_dir; - if( odpnt != NULL ) - { - scan_directory_tree(whole_path, s_entry1, &odpnt->isorec); - } - else - { - scan_directory_tree(whole_path, s_entry1, NULL); - } - if( odpnt != NULL ) - { - free(odpnt); - odpnt = NULL; - } - s_entry1->filedir = this_dir; - - statbuf.st_size = 0; - statbuf.st_mode &= 0777; - set_733((char *) s_entry->isorec.size, 0); - s_entry->size = 0; - s_entry->isorec.flags[0] = 0; - s_entry->inode = UNCACHED_INODE; - deep_flag = NEED_CL; - }; - - if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) { - char buffer[2048]; - int nchar; - switch(lstatbuf.st_mode & S_IFMT){ - case S_IFDIR: - sprintf(buffer,"D\t%s\n", - s_entry->name); - break; -#ifndef NON_UNIXFS - case S_IFBLK: - sprintf(buffer,"B\t%s\t%lu %lu\n", - s_entry->name, - (unsigned long) major(statbuf.st_rdev), - (unsigned long) minor(statbuf.st_rdev)); - break; - case S_IFIFO: - sprintf(buffer,"P\t%s\n", - s_entry->name); - break; - case S_IFCHR: - sprintf(buffer,"C\t%s\t%lu %lu\n", - s_entry->name, - (unsigned long) major(statbuf.st_rdev), - (unsigned long) minor(statbuf.st_rdev)); - break; - case S_IFLNK: - nchar = readlink(whole_path, - symlink_buff, - sizeof(symlink_buff)); - symlink_buff[nchar < 0 ? 0 : nchar] = 0; - sprintf(buffer,"L\t%s\t%s\n", - s_entry->name, symlink_buff); - break; -#ifdef S_IFSOCK - case S_IFSOCK: - sprintf(buffer,"S\t%s\n", - s_entry->name); - break; -#endif -#endif /* NON_UNIXFS */ - case S_IFREG: - default: - sprintf(buffer,"F\t%s\n", - s_entry->name); - break; - }; - s_entry->table = strdup(buffer); - }; - - /* - * See if we have an entry for this guy in the previous session. - */ - if( orig_contents != NULL && !S_ISDIR(statbuf.st_mode)) - { - check_prev_session(orig_contents, n_orig, s_entry, - &statbuf, &lstatbuf, NULL); + continue; } - if(S_ISDIR(statbuf.st_mode)){ - int dflag; - if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) { - if( odpnt != NULL ) +#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); + + 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) { - dflag = scan_directory_tree(whole_path, s_entry, - &odpnt->isorec); + fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); } else { - dflag = scan_directory_tree(whole_path, s_entry, NULL); + fprintf(stderr, + "Symlink %s ignored - continuing.\n", + whole_path); + return 0; /* Non Rock Ridge discs - ignore all symlinks */ } - /* If unable to scan directory, mark this as a non-directory */ - if(!dflag) - lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; - if( odpnt != NULL ) - { - free(odpnt); - odpnt = NULL; - } - } - } - - if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".") == 0) - deep_flag |= NEED_CE | NEED_SP; /* For extension record */ - - /* Now figure out how much room this file will take in the directory */ - - if(use_RockRidge) { - generate_rock_ridge_attributes(whole_path, - d_entry->d_name, s_entry, - &statbuf, &lstatbuf, deep_flag); - - } - } - closedir(current_dir); - - if( orig_contents != NULL ) - { - merge_remaining_entries(this_dir, orig_contents, n_orig); - free_mdinfo(orig_contents, n_orig); - } - - if( this_dir->contents == NULL ) - { + } + } + + /* 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; + } + 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)); + } + } + } + /* - * This directory must have been inaccessible. + * For non-directories, we just copy the stat information over + * so we correctly include this file. */ + if( follow_links + && !S_ISDIR(statbuf.st_mode) ) + { + lstatbuf = statbuf; + } + } + + /* + * Add directories to the cache so that we don't waste space even + * if we are supposed to be following symlinks. + */ + if( follow_links + && strcmp(short_name, ".") + && strcmp(short_name, "..") + && S_ISDIR(statbuf.st_mode) ) + { + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + } +#ifdef VMS + if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && + statbuf.st_fab_rfm != FAB$C_STMLF)) { + fprintf(stderr,"Warning - file %s has an unsupported VMS record" + " format (%d)\n", + whole_path, statbuf.st_fab_rfm); + } +#endif + + if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))) + { + fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", + whole_path, errno); return 0; } - sort_n_finish(this_dir); + + /* Add this so that we can detect directory loops with hard links. + If we are set up to follow symlinks, then we skip this checking. */ + if( !follow_links + && S_ISDIR(lstatbuf.st_mode) + && strcmp(short_name, ".") + && strcmp(short_name, "..") ) + { + if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) { + 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); + 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( strcmp(short_name, "..") == 0) + { + this_dir->dir_flags |= DIR_HAS_DOTDOT; + } + + if( this_dir->parent + && this_dir->parent == reloc_dir + && strcmp(short_name, "..") == 0) + { + s_entry->inode = UNCACHED_INODE; + s_entry->dev = (dev_t) UNCACHED_DEVICE; + deep_flag = NEED_PL; + } + else + { + 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; + statbuf.st_size = 0; + } + else + { + s_entry->size = statbuf.st_size; + } + + 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(!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; +#ifdef S_IFSOCK + case S_IFSOCK: + sprintf(buffer,"S\t%s\n", + s_entry->name); + break; +#endif +#endif /* NON_UNIXFS */ + case S_IFREG: + default: + sprintf(buffer,"F\t%s\n", + s_entry->name); + break; + }; + s_entry->table = strdup(buffer); + } + + 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; } @@ -1185,6 +1343,254 @@ void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfi } } +/* + * 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; + + orig_de = de; + + pnt = strrchr(path, PATH_SEPARATOR); + if( pnt == NULL ) + { + pnt = path; + } + else + { + pnt++; + } + + if( parent != NULL ) + { + dpnt = parent->subdir; + + while (dpnt) + { + /* + * Weird hack time - if there are two directories by the + * same name in the reloc_dir, they are not treated as the + * same thing unless the entire path matches completely. + */ + if( flag && strcmp(dpnt->de_name, pnt) == 0 ) + { + return dpnt; + } + dpnt = dpnt->next; + } + } + + /* + * We don't know if we have a valid directory entry for this one + * yet. If not, we need to create one. + */ + if( de == NULL ) + { + de = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memset(de, 0, sizeof(struct directory_entry)); + de->next = parent->contents; + parent->contents = de; + de->name = strdup(pnt); + de->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 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; + + /* + * 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. + */ + sts = stat_filter(parent->whole_name, &xstatbuf); + if( sts == 0 ) + { + attach_dot_entries(dpnt, &xstatbuf); + } + else + { + attach_dot_entries(dpnt, &fstatbuf); + } + } + + 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; + + 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){ + goof = sort_n_finish(dpnt); + if( goof ) + { + break; + } + + if(dpnt->subdir) sort_tree(dpnt->subdir); + dpnt = dpnt->next; + } + return goof; +} + void FDECL1(dump_tree, struct directory *, node){ struct directory * dpnt; @@ -1197,6 +1603,59 @@ void FDECL1(dump_tree, struct directory *, node){ } } +void FDECL1(update_nlink_field, struct directory *, node) +{ + struct directory * dpnt; + struct directory * xpnt; + struct directory_entry * s_entry; + int i; + + dpnt = node; + + while (dpnt) + { + /* + * First, count up the number of subdirectories this guy has. + */ + for(i=0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next, i++) + continue; + + /* + * Next check to see if we have any relocated directories + * in this directory. The nlink field will include these + * as real directories when they are properly relocated. + * + * In the non-rockridge disk, the relocated entries appear + * as zero length files. + */ + for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) + { + if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 ) + { + i++; + } + } + /* + * Now update the field in the Rock Ridge entry. + */ + update_nlink(dpnt->self, i + 2); + + /* + * Update the '.' entry for this directory. + */ + update_nlink(dpnt->contents, i + 2); + + /* + * Update all of the '..' entries that point to this guy. + */ + for(xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) + update_nlink(xpnt->contents->next, i + 2); + + if(dpnt->subdir) update_nlink_field(dpnt->subdir); + dpnt = dpnt->next; + } +} + /* * something quick and dirty to locate a file given a path * recursively walks down path in filename until it finds the @@ -1232,13 +1691,13 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *, *p1 = '\0'; #ifdef DEBUG_TORITO - printf("Looking for subdir called %s\n",p1); + fprintf(stderr,"Looking for subdir called %s\n",p1); #endif rest = p1+1; #ifdef DEBUG_TORITO - printf("Remainder of path name is now %s\n", rest); + fprintf(stderr,"Remainder of path name is now %s\n", rest); #endif dpnt = node->subdir; @@ -1251,7 +1710,7 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *, if (!strcmp(subdir, dpnt->de_name)) { #ifdef DEBUG_TORITO - printf("Calling next level with filename = %s", rest); + fprintf(stderr,"Calling next level with filename = %s", rest); #endif return(search_tree_file( dpnt, rest )); } @@ -1276,7 +1735,7 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *, if (!strcmp(filename, depnt->name)) { #ifdef DEBUG_TORITO - printf("Found our file %s", filename); + fprintf(stderr,"Found our file %s", filename); #endif return(depnt); } @@ -1290,3 +1749,25 @@ struct directory_entry * FDECL2(search_tree_file, struct directory *, fprintf(stderr,"We cant get here in search_tree_file :-/ \n"); } +void init_fstatbuf() +{ + time_t current_time; + + if(fstatbuf.st_ctime == 0) + { + time (¤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; + } +} diff --git a/util/mkisofs/write.c b/util/mkisofs/write.c index cfc9b763c..1976679b4 100644 --- a/util/mkisofs/write.c +++ b/util/mkisofs/write.c @@ -19,10 +19,11 @@ 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 #include +#include "config.h" #include "mkisofs.h" #include "iso9660.h" #include @@ -50,15 +51,17 @@ extern char * strdup(const char *); /* Counters for statistics */ -static int table_size = 0; -static int total_dir_size = 0; -static int rockridge_size = 0; +static int table_size = 0; +static int total_dir_size = 0; +static int rockridge_size = 0; static struct directory ** pathlist; -static next_path_index = 1; +static next_path_index = 1; +static int sort_goof; -/* Used to fill in some of the information in the volume descriptor. */ -static struct tm local; -static struct tm gmt; +struct output_fragment * out_tail; +struct output_fragment * out_list; + +struct iso_primary_descriptor vol_desc; /* Routines to actually write the disc. We write sequentially so that we could write a tape, or write the disc directly */ @@ -118,8 +121,30 @@ void FDECL2(set_733, char *, pnt, unsigned int, i) void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file) { - while(count) - { + /* + * This is a hack that could be made better. XXXIs this the only place? + * It is definitely needed on Operating Systems that do not + * allow to write files that are > 2GB. + * If the system is fast enough to be able to feed 1400 KB/s + * writing speed of a DVD-R drive, use stdout. + * If the system cannot do this reliable, you need to use this + * hacky option. + */ + if (split_output != 0 && ftell(file) > (1024 * 1024 * 1024) ) { + static int idx = 0; + char nbuf[128]; + + sprintf(nbuf, "part_%02d", idx++); + file = freopen(nbuf, "w", file); + if (file == NULL) { + fprintf(stderr, "Cannot open '%s'.\n", nbuf); + exit(1); + } + + } + + while(count) + { int got = fwrite(buffer,size,count,file); if(got<=0) @@ -142,11 +167,7 @@ struct deferred_write static struct deferred_write * dw_head = NULL, * dw_tail = NULL; -static struct directory_entry * sort_dir; -static struct eltorito_boot_descriptor boot_desc; - unsigned int last_extent_written =0; -static struct iso_primary_descriptor vol_desc; static path_table_index; static time_t begun; @@ -154,7 +175,7 @@ static time_t begun; numbers to them. We have already assigned extent numbers to everything that goes in front of them */ -void FDECL1(assign_directory_addresses, struct directory *, node) +static int FDECL1(assign_directory_addresses, struct directory *, node) { int dir_size; struct directory * dpnt; @@ -193,6 +214,7 @@ void FDECL1(assign_directory_addresses, struct directory *, node) dpnt = dpnt->next; } + return 0; } static void FDECL3(write_one_file, char *, filename, @@ -222,8 +244,8 @@ static void FDECL3(write_one_file, char *, filename, memset(buffer, 0, use); if (fread(buffer, 1, use, infile) == 0) { - fprintf(stderr,"cannot read from %s\n",filename); - exit(1); + fprintf(stderr,"cannot read from %s\n",filename); + exit(1); } xfwrite(buffer, 1, use, outfile); last_extent_written += use/SECTOR_SIZE; @@ -296,7 +318,7 @@ static void dump_filelist() } #endif -int FDECL2(compare_dirs, const void *, rr, const void *, ll) +static int FDECL2(compare_dirs, const void *, rr, const void *, ll) { char * rpnt, *lpnt; struct directory_entry ** r, **l; @@ -305,11 +327,24 @@ int FDECL2(compare_dirs, const void *, rr, const void *, ll) l = (struct directory_entry **) ll; rpnt = (*r)->isorec.name; lpnt = (*l)->isorec.name; + + /* + * If the entries are the same, this is an error. + */ + if( strcmp(rpnt, lpnt) == 0 ) + { + sort_goof++; + } /* * Put the '.' and '..' entries on the head of the sorted list. * For normal ASCII, this always happens to be the case, but out of * band characters cause this not to be the case sometimes. + * + * FIXME(eric) - these tests seem redundant, in taht the name is + * never assigned these values. It will instead be \000 or \001, + * and thus should always be sorted correctly. I need to figure + * out why I thought I needed this in the first place. */ if( strcmp(rpnt, ".") == 0 ) return -1; if( strcmp(lpnt, ".") == 0 ) return 1; @@ -336,7 +371,15 @@ int FDECL2(compare_dirs, const void *, rr, const void *, ll) return 0; } -void FDECL1(sort_directory, struct directory_entry **, sort_dir) +/* + * Function: sort_directory + * + * Purpose: Sort the directory in the appropriate ISO9660 + * order. + * + * Notes: Returns 0 if OK, returns > 0 if an error occurred. + */ +int FDECL1(sort_directory, struct directory_entry **, sort_dir) { int dcount = 0; int i, len; @@ -350,6 +393,11 @@ void FDECL1(sort_directory, struct directory_entry **, sort_dir) s_entry = s_entry->next; } + if( dcount == 0 ) + { + return 0; + } + /* * OK, now we know how many there are. Build a vector for sorting. */ @@ -367,44 +415,52 @@ void FDECL1(sort_directory, struct directory_entry **, sort_dir) s_entry = s_entry->next; } - qsort(sortlist, dcount, sizeof(struct directory_entry *), - (int (*)(const void *, const void *))compare_dirs); - - /* - * Now reassemble the linked list in the proper sorted order + /* + * Each directory is required to contain at least . and .. */ - for(i=0; inext = 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; inext = sortlist[i+1]; + } + + sortlist[dcount-1]->next = NULL; + *sort_dir = sortlist[0]; + } - sortlist[dcount-1]->next = NULL; - *sort_dir = sortlist[0]; - free(sortlist); - + return sort_goof; } -void generate_root_record() +static int root_gen() { - time_t ctime; - - time (&ctime); - - local = *localtime(&ctime); - gmt = *gmtime(&ctime); + init_fstatbuf(); root_record.length[0] = 1 + sizeof(struct iso_directory_record) - sizeof(root_record.name); root_record.ext_attr_length[0] = 0; set_733((char *) root_record.extent, root->extent); set_733((char *) root_record.size, ROUND_UP(root->size)); - iso9660_date(root_record.date, ctime); + iso9660_date(root_record.date, root_statbuf.st_mtime); root_record.flags[0] = 2; root_record.file_unit_size[0] = 0; root_record.interleave[0] = 0; set_723(root_record.volume_sequence_number, DEF_VSN); root_record.name_len[0] = 1; + return 0; } static void FDECL1(assign_file_addresses, struct directory *, dpnt) @@ -439,7 +495,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt) s_hash = find_hash(s_entry->dev, s_entry->inode); if(s_hash) { - if(verbose) + if(verbose > 1) { fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, SPATH_SEPARATOR, s_entry->name); @@ -562,7 +618,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt) s_entry->starting_block = last_extent; add_hash(s_entry); last_extent += ROUND_UP(s_entry->size) >> 11; - if(verbose) + if(verbose > 1) { fprintf(stderr,"%d %d %s\n", s_entry->starting_block, last_extent-1, whole_path); @@ -576,6 +632,7 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt) } #endif +#ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */ if(last_extent > (800000000 >> 11)) { /* @@ -583,9 +640,10 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt) */ fprintf(stderr,"Extent overflow processing file %s\n", whole_path); fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); - fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); + fprintf(stderr,"Reported file size is %d bytes\n", s_entry->size); exit(1); } +#endif continue; } @@ -605,6 +663,40 @@ static void FDECL1(assign_file_addresses, struct directory *, dpnt) } } /* assign_file_addresses(... */ +static void FDECL1(free_one_directory, struct directory *, dpnt) +{ + struct directory_entry * s_entry; + struct directory_entry * s_entry_d; + + s_entry = dpnt->contents; + while(s_entry) + { + s_entry_d = s_entry; + s_entry = s_entry->next; + + if( s_entry_d->name != NULL ) + { + free (s_entry_d->name); + } + if( s_entry_d->whole_name != NULL ) + { + free (s_entry_d->whole_name); + } + free (s_entry_d); + } + dpnt->contents = NULL; +} /* free_one_directory(... */ + +static void FDECL1(free_directories, struct directory *, dpnt) +{ + while (dpnt) + { + free_one_directory(dpnt); + if(dpnt->subdir) free_directories(dpnt->subdir); + dpnt = dpnt->next; + } +} + void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile) { unsigned int ce_address = 0; @@ -743,18 +835,15 @@ void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile) s_entry_d = s_entry; s_entry = s_entry->next; - if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes); - if( s_entry_d->name != NULL ) + /* + * Joliet doesn't use the Rock Ridge attributes, so we free it here. + */ + if (s_entry_d->rr_attributes) { - free (s_entry_d->name); + free(s_entry_d->rr_attributes); + s_entry_d->rr_attributes = NULL; } - if( s_entry_d->whole_name != NULL ) - { - free (s_entry_d->whole_name); - } - free (s_entry_d); } - sort_dir = NULL; if(dpnt->size != dir_index) { @@ -795,7 +884,7 @@ void FDECL1(build_pathlist, struct directory *, node) } } /* build_pathlist(... */ -int FDECL2(compare_paths, void const *, r, void const *, l) +static int FDECL2(compare_paths, void const *, r, void const *, l) { struct directory const *ll = *(struct directory * const *)l; struct directory const *rr = *(struct directory * const *)r; @@ -814,7 +903,7 @@ int FDECL2(compare_paths, void const *, r, void const *, l) } /* compare_paths(... */ -void generate_path_tables() +static int generate_path_tables() { struct directory_entry * de; struct directory * dpnt; @@ -926,6 +1015,7 @@ void generate_path_tables() path_table_index, path_table_size); } + return 0; } /* generate_path_tables(... */ void @@ -940,17 +1030,102 @@ FDECL3(memcpy_max, char *, to, char *, from, int, max) } /* memcpy_max(... */ -int FDECL1(iso_write, FILE *, outfile) +void FDECL1(outputlist_insert, struct output_fragment *, frag) +{ + if( out_tail == NULL ) + { + out_list = out_tail = frag; + } + else + { + out_tail->of_next = frag; + out_tail = frag; + } +} + +static int FDECL1(file_write, FILE *, outfile) { - char buffer[2048]; - int i; - char iso_time[17]; int should_write; - time(&begun); - assign_file_addresses(root); + /* + * 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. + */ - memset(buffer, 0, sizeof(buffer)); + 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 iso_time[17]; + int should_write; + struct tm local; + struct tm gmt; + + + time(&begun); + + local = *localtime(&begun); + gmt = *gmtime(&begun); /* * This will break in the year 2000, I supose, but there is no good way @@ -965,17 +1140,6 @@ int FDECL1(iso_write, FILE *, outfile) local.tm_yday -= gmt.tm_yday; iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15; - /* - * First, we output 16 sectors of all zero - */ - - for(i=0; i<16; i++) - { - xfwrite(buffer, 1, sizeof(buffer), outfile); - } - - last_extent_written += 16; - /* * Next we write out the primary descriptor for the disc */ @@ -1011,7 +1175,7 @@ int FDECL1(iso_write, FILE *, outfile) * Now we copy the actual root directory record */ memcpy(vol_desc.root_directory_record, &root_record, - sizeof(struct iso_directory_record) + 1); + sizeof(struct iso_directory_record)); /* * The rest is just fluff. It looks nice to fill in many of these fields, @@ -1058,16 +1222,16 @@ int FDECL1(iso_write, FILE *, outfile) */ xfwrite(&vol_desc, 1, 2048, outfile); last_extent_written++; - if (use_eltorito) - { - /* - * Next we write out the boot volume descriptor for the disc - */ - get_torito_desc(&boot_desc); - xfwrite(&boot_desc, 1, 2048, outfile); - last_extent_written ++; - } - + return 0; +} + +/* + * Function to write the EVD for the disc. + */ +static int FDECL1(evd_write, FILE *, outfile) +{ + struct iso_primary_descriptor vol_desc; + /* * Now write the end volume descriptor. Much simpler than the other one */ @@ -1077,7 +1241,14 @@ int FDECL1(iso_write, FILE *, outfile) vol_desc.version[0] = 1; xfwrite(&vol_desc, 1, 2048, outfile); last_extent_written += 1; + return 0; +} +/* + * Function to write the EVD for the disc. + */ +static int FDECL1(pathtab_write, FILE *, outfile) +{ /* * Next we write the path tables */ @@ -1088,55 +1259,121 @@ int FDECL1(iso_write, FILE *, outfile) free(path_table_m); path_table_l = NULL; path_table_m = NULL; - - /* - * OK, all done with that crap. Now write out the directories. - * This is where the fur starts to fly, because we need to keep track of - * each file as we find it and keep track of where we put it. - */ - -#ifdef DBG_ISO - fprintf(stderr,"Total directory extents being written = %d\n", last_extent); -#endif -#if 0 - generate_one_directory(root, outfile); -#endif - generate_iso9660_directories(root, outfile); - - if(extension_record) - { - xfwrite(extension_record, 1, SECTOR_SIZE, outfile); - last_extent_written++; - } - - /* - * Now write all of the files that we need. - */ - fprintf(stderr,"Total extents scheduled to be written = %d\n", - last_extent - session_start); - write_files(outfile); - - fprintf(stderr,"Total extents actually written = %d\n", - last_extent_written - session_start); - /* - * Hard links throw us off here - */ - if(should_write != last_extent - session_start) - { - fprintf(stderr,"Number of extents written not what was predicted. Please fix.\n"); - fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent); - } - - fprintf(stderr,"Total translation table size: %d\n", table_size); - fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size); - fprintf(stderr,"Total directory bytes: %d\n", total_dir_size); - fprintf(stderr,"Path table size(bytes): %d\n", path_table_size); - -#ifdef DEBUG - fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n", - next_extent, last_extent, last_extent_written); -#endif - return 0; +} -} /* iso_write(... */ +static int FDECL1(exten_write, FILE *, outfile) +{ + xfwrite(extension_record, 1, SECTOR_SIZE, outfile); + last_extent_written++; + return 0; +} + +/* + * 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; +} + +static int FDECL1(dirtree_cleanup, FILE *, outfile) +{ + free_directories(root); + return 0; +} + +static int FDECL1(padblock_write, FILE *, outfile) +{ + char buffer[2048]; + int i; + + memset(buffer, 0, sizeof(buffer)); + + for(i=0; i<16; i++) + { + xfwrite(buffer, 1, sizeof(buffer), outfile); + } + + last_extent_written += 16; + return 0; +} + +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};