From 9155bc1796e65baff75c36732e7daf34d7aab2c5 Mon Sep 17 00:00:00 2001 From: robertmh Date: Wed, 14 Oct 2009 16:49:22 +0000 Subject: [PATCH 001/146] 2009-10-14 Robert Millan Refer to kernel of FreeBSD "kFreeBSD" to avoid confusion between the Operating System (FreeBSD) and its kernel (kernel of FreeBSD). * loader/i386/bsd.c (grub_freebsd_boot): Read kernel environment from "kFreeBSD" namespace (rather than "FreeBSD"). Update all users. (GRUB_MOD_INIT (bsd)): Rename "freebsd" command to "kfreebsd", "openbsd" to "kopenbsd", "netbsd" to "knetbsd", "freebsd_loadenv" to "kfreebsd_loadenv", "freebsd_module" to "kfreebsd_module", and "freebsd_module_elf" to "kfreebsd_module_elf". Update all users. --- ChangeLog | 15 +++++++++++++++ loader/i386/bsd.c | 26 +++++++++++++------------- util/grub.d/10_freebsd.in | 8 ++++---- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index bc2a350cf..911aa8c5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-10-14 Robert Millan + + Refer to kernel of FreeBSD "kFreeBSD" to avoid confusion between + the Operating System (FreeBSD) and its kernel (kernel of FreeBSD). + + * loader/i386/bsd.c (grub_freebsd_boot): Read kernel environment + from "kFreeBSD" namespace (rather than "FreeBSD"). Update all + users. + + (GRUB_MOD_INIT (bsd)): Rename "freebsd" command to "kfreebsd", + "openbsd" to "kopenbsd", "netbsd" to "knetbsd", "freebsd_loadenv" + to "kfreebsd_loadenv", "freebsd_module" to "kfreebsd_module", + and "freebsd_module_elf" to "kfreebsd_module_elf". Update all + users. + 2009-10-12 Robert Millan * term/tparm.c: Switch to GPLv3. diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index afe1825a5..fc292444f 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -444,9 +444,9 @@ grub_freebsd_boot (void) auto int iterate_env (struct grub_env_var *var); int iterate_env (struct grub_env_var *var) { - if ((!grub_memcmp (var->name, "FreeBSD.", 8)) && (var->name[8])) + if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1])) { - grub_strcpy (p, &var->name[8]); + grub_strcpy (p, &var->name[sizeof("kFreeBSD.") - 1]); p += grub_strlen (p); *(p++) = '='; grub_strcpy (p, var->value); @@ -1112,12 +1112,12 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), if (*curr) { - char name[grub_strlen (curr) + 8 + 1]; + char name[grub_strlen (curr) + sizeof("kFreeBSD.")]; if (*p == '"') p++; - grub_sprintf (name, "FreeBSD.%s", curr); + grub_sprintf (name, "kFreeBSD.%s", curr); if (grub_env_set (name, p)) goto fail; } @@ -1252,26 +1252,26 @@ static grub_command_t cmd_freebsd_module_elf; GRUB_MOD_INIT (bsd) { - cmd_freebsd = grub_register_extcmd ("freebsd", grub_cmd_freebsd, + cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, GRUB_COMMAND_FLAG_BOTH, - "freebsd FILE", "Load kernel of FreeBSD.", + "kfreebsd FILE", "Load kernel of FreeBSD.", freebsd_opts); - cmd_openbsd = grub_register_extcmd ("openbsd", grub_cmd_openbsd, + cmd_openbsd = grub_register_extcmd ("kopenbsd", grub_cmd_openbsd, GRUB_COMMAND_FLAG_BOTH, - "openbsd FILE", "Load kernel of OpenBSD.", + "kopenbsd FILE", "Load kernel of OpenBSD.", openbsd_opts); - cmd_netbsd = grub_register_extcmd ("netbsd", grub_cmd_netbsd, + cmd_netbsd = grub_register_extcmd ("knetbsd", grub_cmd_netbsd, GRUB_COMMAND_FLAG_BOTH, - "netbsd FILE", "Load kernel of NetBSD.", + "knetbsd FILE", "Load kernel of NetBSD.", netbsd_opts); cmd_freebsd_loadenv = - grub_register_command ("freebsd_loadenv", grub_cmd_freebsd_loadenv, + grub_register_command ("kfreebsd_loadenv", grub_cmd_freebsd_loadenv, 0, "load FreeBSD env"); cmd_freebsd_module = - grub_register_command ("freebsd_module", grub_cmd_freebsd_module, + grub_register_command ("kfreebsd_module", grub_cmd_freebsd_module, 0, "load FreeBSD kernel module"); cmd_freebsd_module_elf = - grub_register_command ("freebsd_module_elf", grub_cmd_freebsd_module_elf, + grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf, 0, "load FreeBSD kernel module (ELF)"); my_mod = mod; diff --git a/util/grub.d/10_freebsd.in b/util/grub.d/10_freebsd.in index 1e3a0de1f..02694d3e7 100644 --- a/util/grub.d/10_freebsd.in +++ b/util/grub.d/10_freebsd.in @@ -60,17 +60,17 @@ menuentry "${OS}" { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" cat << EOF - freebsd ${kfreebsd_rel_dirname}/${kfreebsd_basename} + kfreebsd ${kfreebsd_rel_dirname}/${kfreebsd_basename} EOF if [ x"$devices" != "x" ] ; then cat << EOF - freebsd_loadenv ${devices_rel_dirname}/${devices_basename} + kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} EOF fi cat << EOF - set FreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${GRUB_DEVICE} - set FreeBSD.vfs.root.mountfrom.options=rw + set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${GRUB_DEVICE} + set kFreeBSD.vfs.root.mountfrom.options=rw } EOF fi From e9d66f6d6a8f6bf92f3d570747a364b2bd530905 Mon Sep 17 00:00:00 2001 From: robertmh Date: Wed, 14 Oct 2009 18:23:40 +0000 Subject: [PATCH 002/146] 2009-10-14 Robert Millan * conf/common.rmk (grub-dumpbios): Remove rule. (sbin_SCRIPTS, CLEANFILES): Remove `grub-dumpbios'. * util/grub-dumpbios.in: Remove file. --- ChangeLog | 6 +++++ conf/common.rmk | 7 ------ util/grub-dumpbios.in | 58 ------------------------------------------- 3 files changed, 6 insertions(+), 65 deletions(-) delete mode 100644 util/grub-dumpbios.in diff --git a/ChangeLog b/ChangeLog index 911aa8c5b..e7fc70728 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-14 Robert Millan + + * conf/common.rmk (grub-dumpbios): Remove rule. + (sbin_SCRIPTS, CLEANFILES): Remove `grub-dumpbios'. + * util/grub-dumpbios.in: Remove file. + 2009-10-14 Robert Millan Refer to kernel of FreeBSD "kFreeBSD" to avoid confusion between diff --git a/conf/common.rmk b/conf/common.rmk index 26407d06b..c1f0bbdcf 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -161,13 +161,6 @@ CLEANFILES += $(grub-mkconfig_SCRIPTS) grub-mkconfig_DATA += util/grub.d/README -# For grub-dumpbios -grub-dumpbios: util/grub-dumpbios.in config.status - ./config.status --file=$@:$< - chmod +x $@ -sbin_SCRIPTS += grub-dumpbios -CLEANFILES += grub-dumpbios - # Filing systems. pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod ntfs.mod \ ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod \ diff --git a/util/grub-dumpbios.in b/util/grub-dumpbios.in deleted file mode 100644 index 396503936..000000000 --- a/util/grub-dumpbios.in +++ /dev/null @@ -1,58 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2009 Free Software Foundation, Inc. -# -# GRUB 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 3 of the License, or -# (at your option) any later version. -# -# GRUB 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 GRUB. If not, see . - -# Usage: usage -# Print the usage. -usage () { - cat <. -EOF -} - -# Check the arguments. -for option in "$@"; do - case "$option" in - -h | --help) - usage - exit 0 ;; - -v | --version) - echo "$0 (GNU GRUB @PACKAGE_VERSION@)" - exit 0 ;; - -o) - shift - output_dir=$1 - ;; - --output=) - output_dir=`echo "$option" | sed 's/--output=//'` - ;; - -*) - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - ;; - esac -done - -dd if=/dev/mem of=${output_dir}vbios.bin bs=65536 skip=12 count=1 -dd if=/dev/mem of=${output_dir}int10.bin bs=4 skip=16 count=1 From 6b5886ba66fa9df9a48a68fb27d0f11ca25e97ee Mon Sep 17 00:00:00 2001 From: phcoder Date: Thu, 15 Oct 2009 11:55:06 +0000 Subject: [PATCH 003/146] 2009-10-15 Vladimir Serbinenko Revert 2009-06-10 Pavel Roskin * configure.ac: Put checks for __bswapsi2 and __bswapdi2. * include/grub/powerpc/libgcc.h: Don't use weak attribute for all exports. * include/grub/sparc64/libgcc.h: Likewise. Use preprocessor conditionals. --- ChangeLog | 10 ++++++++++ configure.ac | 3 +++ include/grub/powerpc/libgcc.h | 12 ++++++------ include/grub/sparc64/libgcc.h | 8 ++++++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index e7fc70728..f92d8da3a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-10-15 Vladimir Serbinenko + + Revert 2009-06-10 Pavel Roskin + + * configure.ac: Put checks for __bswapsi2 and __bswapdi2. + * include/grub/powerpc/libgcc.h: Don't use weak attribute for all + exports. + * include/grub/sparc64/libgcc.h: Likewise. Use + preprocessor conditionals. + 2009-10-14 Robert Millan * conf/common.rmk (grub-dumpbios): Remove rule. diff --git a/configure.ac b/configure.ac index 3e4da66c8..447f13fcc 100644 --- a/configure.ac +++ b/configure.ac @@ -417,6 +417,9 @@ fi CPPFLAGS="$TARGET_CPPFLAGS" LDFLAGS="$TARGET_LDFLAGS" +# Check for target functions. +AC_CHECK_FUNCS(__bswapsi2 __bswapdi2) + # Defined in aclocal.m4. grub_PROG_TARGET_CC if test "x$TARGET_APPLE_CC" != x1 ; then diff --git a/include/grub/powerpc/libgcc.h b/include/grub/powerpc/libgcc.h index ea4b073a0..0ff8964b7 100644 --- a/include/grub/powerpc/libgcc.h +++ b/include/grub/powerpc/libgcc.h @@ -16,9 +16,9 @@ * along with GRUB. If not, see . */ -void EXPORT_FUNC (memset) (void) __attribute__ ((weak)); -void EXPORT_FUNC (__ashldi3) (void) __attribute__ ((weak)); -void EXPORT_FUNC (__ashrdi3) (void) __attribute__ ((weak)); -void EXPORT_FUNC (__lshrdi3) (void) __attribute__ ((weak)); -void EXPORT_FUNC (__trampoline_setup) (void) __attribute__ ((weak)); -void EXPORT_FUNC (__ucmpdi2) (void) __attribute__ ((weak)); +void EXPORT_FUNC (memset) (void); +void EXPORT_FUNC (__ashldi3) (void); +void EXPORT_FUNC (__ashrdi3) (void); +void EXPORT_FUNC (__lshrdi3) (void); +void EXPORT_FUNC (__trampoline_setup) (void); +void EXPORT_FUNC (__ucmpdi2) (void); diff --git a/include/grub/sparc64/libgcc.h b/include/grub/sparc64/libgcc.h index 5d18c5c81..4a6b6194d 100644 --- a/include/grub/sparc64/libgcc.h +++ b/include/grub/sparc64/libgcc.h @@ -20,8 +20,12 @@ void EXPORT_FUNC (memset) (void); +#ifdef HAVE___BSWAPSI2 typedef int SItype __attribute__ ((mode (SI))); -SItype EXPORT_FUNC (__bswapsi2) (SItype) __attribute__ ((weak)); +SItype EXPORT_FUNC (__bswapsi2) (SItype); +#endif +#ifdef HAVE___BSWAPDI2 typedef int DItype __attribute__ ((mode (DI))); -DItype EXPORT_FUNC (__bswapdi2) (DItype) __attribute__ ((weak)); +DItype EXPORT_FUNC (__bswapdi2) (DItype); +#endif From c6f3b249e46b83ce21f941dd9c4e95d84f748e27 Mon Sep 17 00:00:00 2001 From: phcoder Date: Thu, 15 Oct 2009 12:09:56 +0000 Subject: [PATCH 004/146] 2009-10-15 Vladimir Serbinenko * configure.ac: Add missing dollar. --- ChangeLog | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f92d8da3a..8ad2c0362 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-15 Vladimir Serbinenko + + * configure.ac: Add missing dollar. + 2009-10-15 Vladimir Serbinenko Revert 2009-06-10 Pavel Roskin diff --git a/configure.ac b/configure.ac index 447f13fcc..946179966 100644 --- a/configure.ac +++ b/configure.ac @@ -544,7 +544,7 @@ AC_CHECK_LIB([usb], [usb_claim_interface], [LIBUSB="-lusb"], AC_CHECK_HEADERS([usb.h], [], [grub_emu_usb_excuse=["need libusb headers"]]) [fi] -if test x"enable_grub_emu_usb" = xyes && test x"$grub_emu_usb_excuse" != x ; then +if test x"$enable_grub_emu_usb" = xyes && test x"$grub_emu_usb_excuse" != x ; then AC_MSG_ERROR([USB support for grub-emu was explicitly requested but can't be compiled]) fi if test x"$grub_emu_usb_excuse" = x ; then From cd2851b3dd7d3dcd2a02739ab675d48fc03f527e Mon Sep 17 00:00:00 2001 From: phcoder Date: Thu, 15 Oct 2009 12:26:30 +0000 Subject: [PATCH 005/146] 2009-10-15 Vladimir Serbinenko * commands/xnu_uuid.c (grub_cmd_xnu_uuid): Remove duplicated bitwise operations. --- ChangeLog | 5 +++++ commands/xnu_uuid.c | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ad2c0362..78a02e592 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-15 Vladimir Serbinenko + + * commands/xnu_uuid.c (grub_cmd_xnu_uuid): Remove duplicated bitwise + operations. + 2009-10-15 Vladimir Serbinenko * configure.ac: Add missing dollar. diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index d5c272d03..06e88e560 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -349,8 +349,6 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); - xnu_uuid[6] = (xnu_uuid[6] & 0xf) | 0x30; - xnu_uuid[8] = (xnu_uuid[8] & 0x3f) | 0x80; grub_sprintf (uuid_string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], From 44998e589332535da3ae656285347ce1427da8eb Mon Sep 17 00:00:00 2001 From: phcoder Date: Thu, 15 Oct 2009 12:40:13 +0000 Subject: [PATCH 006/146] 2009-10-15 Vladimir Serbinenko * loader/i386/pc/xnu.c (grub_xnu_set_video): Fix loading splash image. --- ChangeLog | 4 ++++ loader/i386/pc/xnu.c | 50 ++++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 78a02e592..b0864a9b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-15 Vladimir Serbinenko + + * loader/i386/pc/xnu.c (grub_xnu_set_video): Fix loading splash image. + 2009-10-15 Vladimir Serbinenko * commands/xnu_uuid.c (grub_cmd_xnu_uuid): Remove duplicated bitwise diff --git a/loader/i386/pc/xnu.c b/loader/i386/pc/xnu.c index 69a9405c6..ebb176bb4 100644 --- a/loader/i386/pc/xnu.c +++ b/loader/i386/pc/xnu.c @@ -43,7 +43,6 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) { struct grub_video_mode_info mode_info; int ret; - int x,y; char *tmp, *modevar; void *framebuffer; grub_err_t err; @@ -66,32 +65,37 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) if (err) return err; + if (grub_xnu_bitmap) + { + int x, y; + + x = mode_info.width - grub_xnu_bitmap->mode_info.width; + x /= 2; + y = mode_info.height - grub_xnu_bitmap->mode_info.height; + y /= 2; + err = grub_video_blit_bitmap (grub_xnu_bitmap, + GRUB_VIDEO_BLIT_REPLACE, + x > 0 ? x : 0, + y > 0 ? y : 0, + x < 0 ? -x : 0, + y < 0 ? -y : 0, + min (grub_xnu_bitmap->mode_info.width, + mode_info.width), + min (grub_xnu_bitmap->mode_info.height, + mode_info.height)); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + grub_xnu_bitmap = 0; + } + err = GRUB_ERR_NONE; + } + ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); if (ret) return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); - err = GRUB_ERR_NONE; - x = mode_info.width - grub_xnu_bitmap->mode_info.width; - x /= 2; - y = mode_info.height - grub_xnu_bitmap->mode_info.height; - y /= 2; - err = grub_video_blit_bitmap (grub_xnu_bitmap, - GRUB_VIDEO_BLIT_REPLACE, - x > 0 ? x : 0, - y > 0 ? y : 0, - x < 0 ? -x : 0, - y < 0 ? -y : 0, - min (grub_xnu_bitmap->mode_info.width, - mode_info.width), - min (grub_xnu_bitmap->mode_info.height, - mode_info.height)); - if (err) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - grub_xnu_bitmap = 0; - } - params->lfb_width = mode_info.width; params->lfb_height = mode_info.height; params->lfb_depth = mode_info.bpp; From 035f7122046ca8eaad631f5aa6a3006e464c30c7 Mon Sep 17 00:00:00 2001 From: robertmh Date: Thu, 15 Oct 2009 20:34:27 +0000 Subject: [PATCH 007/146] 2009-10-15 Robert Millan Make entry text a bit more readable. * util/grub.d/10_linux.in: Add `with' before `Linux'. --- ChangeLog | 6 ++++++ util/grub.d/10_linux.in | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b0864a9b9..b90033393 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-15 Robert Millan + + Make entry text a bit more readable. + + * util/grub.d/10_linux.in: Add `with' before `Linux'. + 2009-10-15 Vladimir Serbinenko * loader/i386/pc/xnu.c (grub_xnu_set_video): Fix loading splash image. diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 381a0c3d5..1473a42a2 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -91,10 +91,10 @@ while [ "x$list" != "x" ] ; do linux_root_device_thisversion=${GRUB_DEVICE} fi - linux_entry "${OS}, Linux ${version}" \ + linux_entry "${OS}, with Linux ${version}" \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then - linux_entry "${OS}, Linux ${version} (recovery mode)" \ + linux_entry "${OS}, with Linux ${version} (recovery mode)" \ "single ${GRUB_CMDLINE_LINUX}" fi From 6f3cd880e9ea91441f4aa318234a8ad590fed9af Mon Sep 17 00:00:00 2001 From: cjwatson Date: Fri, 16 Oct 2009 15:38:42 +0000 Subject: [PATCH 008/146] 2009-10-16 Colin Watson * configure.ac (TARGET_CFLAGS): Add -mno-mmx -mno-sse -mno-sse2 -mno-3dnow on x86 architectures. Some toolchains enable these features by default, but they rely on registers that aren't enabled in GRUB. Thanks to Vladimir Serbinenko for the suggestion. --- ChangeLog | 7 +++++++ configure.ac | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index b90033393..eb874f93e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-16 Colin Watson + + * configure.ac (TARGET_CFLAGS): Add -mno-mmx -mno-sse -mno-sse2 + -mno-3dnow on x86 architectures. Some toolchains enable these + features by default, but they rely on registers that aren't enabled + in GRUB. Thanks to Vladimir Serbinenko for the suggestion. + 2009-10-15 Robert Millan Make entry text a bit more readable. diff --git a/configure.ac b/configure.ac index 946179966..f26b92447 100644 --- a/configure.ac +++ b/configure.ac @@ -252,6 +252,10 @@ if test "x$TARGET_CFLAGS" = x; then else TARGET_CFLAGS="$TARGET_CFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1" fi + + # Some toolchains enable these features by default, but they need + # registers that aren't set up properly in GRUB. + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-3dnow" fi # By default, GCC 4.4 generates .eh_frame sections containing unwind From f1d29d87ad9ed67346fa78fa12e55f63b875bf7f Mon Sep 17 00:00:00 2001 From: robertmh Date: Fri, 16 Oct 2009 17:43:26 +0000 Subject: [PATCH 009/146] 2009-10-16 Robert Millan * configure.ac: Bump version to 1.97. --- ChangeLog | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index eb874f93e..5f58ef12f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-16 Robert Millan + + * configure.ac: Bump version to 1.97. + 2009-10-16 Colin Watson * configure.ac (TARGET_CFLAGS): Add -mno-mmx -mno-sse -mno-sse2 diff --git a/configure.ac b/configure.ac index f26b92447..ca837b6e5 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ dnl (such as TARGET_CC, TARGET_CFLAGS, etc.) are used for the target dnl type. -AC_INIT([GRUB],[1.97~beta4],[bug-grub@gnu.org]) +AC_INIT([GRUB],[1.97],[bug-grub@gnu.org]) AC_PREREQ(2.59) AC_CONFIG_SRCDIR([include/grub/dl.h]) AC_CONFIG_HEADER([config.h]) From 421bd7ac69dd3caee5806b0b7c5fd81581011150 Mon Sep 17 00:00:00 2001 From: phcoder Date: Fri, 16 Oct 2009 18:11:45 +0000 Subject: [PATCH 010/146] 2009-10-16 Vladimir Serbinenko * NEWS: Mentioned XNU, ACPI, gptsync, password and parttool. --- ChangeLog | 4 ++++ NEWS | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/ChangeLog b/ChangeLog index 5f58ef12f..f4f2914d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-16 Vladimir Serbinenko + + * NEWS: Mentioned XNU, ACPI, gptsync, password and parttool. + 2009-10-16 Robert Millan * configure.ac: Bump version to 1.97. diff --git a/NEWS b/NEWS index 03ba6a268..e4080de94 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,15 @@ New in 1.97 - : +* Add support for XNU kernels. + +* ACPI override support. + +* Integrated gptsync. + +* Password protection support. + +* Partition manipulation tool. + * Add `keystatus' command. * Unicode fonts are now used by default. From d2b6b7fc9af3dfd958783cdc51de19b15e858721 Mon Sep 17 00:00:00 2001 From: robertmh Date: Fri, 16 Oct 2009 18:46:51 +0000 Subject: [PATCH 011/146] 2009-10-16 Robert Millan * NEWS: Misc adjustments. --- ChangeLog | 4 ++++ NEWS | 12 ++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index f4f2914d8..8eb911eaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-16 Robert Millan + + * NEWS: Misc adjustments. + 2009-10-16 Vladimir Serbinenko * NEWS: Mentioned XNU, ACPI, gptsync, password and parttool. diff --git a/NEWS b/NEWS index e4080de94..7c29cc948 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ New in 1.97 - : -* Add support for XNU kernels. +* Add support for loading XNU (MacOS X kernel). * ACPI override support. @@ -22,9 +22,7 @@ New in 1.97 - : * Add support for RAID levels 4,6 and 10. -* Add support for lua scripts. - -* update-grub is renamed to grub-mkconfig. +* update-grub is replaced by grub-mkconfig. * When booting from PXE, PXE can be used to load files. @@ -36,8 +34,6 @@ New in 1.97 - : * Add Cygwin support. -* Add grub-pe2elf to convert PE modules to ELF modules. - * Add x86_64 EFI support. * Use LZMA compression instead of LZO. @@ -57,13 +53,13 @@ New in 1.97 - : * grub-mkconfig supports os-prober to add operating systems to the boot menu. -* The ATA driver supports filesystems bigger than 2TB. +* The ATA driver supports devices bigger than 2 TiB. * Add support for the UDF, AFS and EXT4 filesystems. * The ISO9660 filesystem supports the Joliet extension -* Add aout and BSD kernel loaders. +* Add support for loading kernels of FreeBSD, NetBSD and OpenBSD. * Add new command `sleep'. From 46695a62e6b3ffa53f224cf82de871afe36cf2d9 Mon Sep 17 00:00:00 2001 From: phcoder Date: Fri, 16 Oct 2009 20:21:12 +0000 Subject: [PATCH 012/146] 2009-10-16 Vladimir Serbinenko Let user specify OpenBSD root device. * loader/i386/bsd.c (openbsd_root): New variable. (openbsd_opts): New option 'root'. (OPENBSD_ROOT_ARG): New macro. (grub_openbsd_boot): Use 'openbsd_root'. (grub_cmd_openbsd): Fill 'openbsd_root'. --- ChangeLog | 10 ++++++++++ loader/i386/bsd.c | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8eb911eaf..960fc067e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-10-16 Vladimir Serbinenko + + Let user specify OpenBSD root device. + + * loader/i386/bsd.c (openbsd_root): New variable. + (openbsd_opts): New option 'root'. + (OPENBSD_ROOT_ARG): New macro. + (grub_openbsd_boot): Use 'openbsd_root'. + (grub_cmd_openbsd): Fill 'openbsd_root'. + 2009-10-16 Robert Millan * NEWS: Misc adjustments. diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index fc292444f..acc653c9e 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -58,6 +58,7 @@ static char *mod_buf; static grub_uint32_t mod_buf_len, mod_buf_max, kern_end_mdofs; static int is_elf_kernel, is_64bit; static char *netbsd_root = NULL; +static grub_uint32_t openbsd_root; static const struct grub_arg_option freebsd_opts[] = { @@ -94,6 +95,7 @@ static const struct grub_arg_option openbsd_opts[] = {"config", 'c', 0, "Change configured devices.", 0, 0}, {"single", 's', 0, "Boot into single mode.", 0, 0}, {"kdb", 'd', 0, "Enter in KDB on boot.", 0, 0}, + {"root", 'r', 0, "Set root device.", "wdXY", ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -103,6 +105,8 @@ static const grub_uint32_t openbsd_flags[] = OPENBSD_RB_SINGLE, OPENBSD_RB_KDB, 0 }; +#define OPENBSD_ROOT_ARG (ARRAY_SIZE (openbsd_flags) - 1) + static const struct grub_arg_option netbsd_opts[] = { {"no-smp", '1', 0, "Disable SMP.", 0, 0}, @@ -565,7 +569,6 @@ grub_openbsd_boot (void) char *buf = (char *) GRUB_BSD_TEMP_BUFFER; struct grub_openbsd_bios_mmap *pm; struct grub_openbsd_bootargs *pa; - grub_uint32_t bootdev, biosdev, unit, slice, part; auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) @@ -614,11 +617,7 @@ grub_openbsd_boot (void) pa->ba_type = OPENBSD_BOOTARG_END; pa++; - grub_bsd_get_device (&biosdev, &unit, &slice, &part); - bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) + - (part << OPENBSD_B_PARTSHIFT)); - - grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER, + grub_unix_real_boot (entry, bootflags, openbsd_root, OPENBSD_BOOTARG_APIVER, 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), (grub_uint32_t) (grub_mmap_get_lower () >> 10), (char *) pa - buf, buf); @@ -1015,11 +1014,39 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) static grub_err_t grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) { + grub_uint32_t bootdev; + kernel_type = KERNEL_TYPE_OPENBSD; bootflags = grub_bsd_parse_flags (cmd->state, openbsd_flags); + if (cmd->state[OPENBSD_ROOT_ARG].set) + { + const char *arg = cmd->state[OPENBSD_ROOT_ARG].arg; + int unit, part; + if (*(arg++) != 'w' || *(arg++) != 'd') + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Only device specifications of form " + "wd are supported."); + + unit = grub_strtoul (arg, (char **) &arg, 10); + if (! (arg && *arg >= 'a' && *arg <= 'z')) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Only device specifications of form " + "wd are supported."); + + part = *arg - 'a'; + + bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) + + (part << OPENBSD_B_PARTSHIFT)); + } + else + bootdev = 0; + if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) - grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1); + { + grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1); + openbsd_root = bootdev; + } return grub_errno; } From 3b2fe8c2857f9753ce072639c8a547d6c41bce61 Mon Sep 17 00:00:00 2001 From: robertmh Date: Tue, 20 Oct 2009 11:30:37 +0000 Subject: [PATCH 013/146] 2009-10-20 Robert Millan Fix build on sparc64. * configure.ac: Perform checks for libgcc symbols before adding `-nostdlib' to LDFLAGS. --- ChangeLog | 7 +++++++ configure.ac | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 960fc067e..a14da7a14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-20 Robert Millan + + Fix build on sparc64. + + * configure.ac: Perform checks for libgcc symbols before + adding `-nostdlib' to LDFLAGS. + 2009-10-16 Vladimir Serbinenko Let user specify OpenBSD root device. diff --git a/configure.ac b/configure.ac index ca837b6e5..bf113ba68 100644 --- a/configure.ac +++ b/configure.ac @@ -411,6 +411,9 @@ AC_SUBST(TARGET_ASFLAGS) AC_SUBST(TARGET_CPPFLAGS) AC_SUBST(TARGET_LDFLAGS) +# Check for libgcc symbols (must be performed before we add -nostdlib to LDFLAGS) +AC_CHECK_FUNCS(__bswapsi2 __bswapdi2) + # Set them to their new values for the tests below. CC="$TARGET_CC" if test "x$TARGET_APPLE_CC" = x1 ; then @@ -421,9 +424,6 @@ fi CPPFLAGS="$TARGET_CPPFLAGS" LDFLAGS="$TARGET_LDFLAGS" -# Check for target functions. -AC_CHECK_FUNCS(__bswapsi2 __bswapdi2) - # Defined in aclocal.m4. grub_PROG_TARGET_CC if test "x$TARGET_APPLE_CC" != x1 ; then From 0933cdc0ab2789eda662dbd6418f92f21d05bd39 Mon Sep 17 00:00:00 2001 From: fzielcke Date: Wed, 21 Oct 2009 12:22:05 +0000 Subject: [PATCH 014/146] 2009-10-21 Felix Zielcke * config.guess: Update to latest version from config git repository. * config.sub: Likewise. --- ChangeLog | 6 +++ config.guess | 111 +++++++++++++++++---------------------------------- config.sub | 9 +++-- 3 files changed, 47 insertions(+), 79 deletions(-) diff --git a/ChangeLog b/ChangeLog index a14da7a14..2dd370aca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-21 Felix Zielcke + + * config.guess: Update to latest version from config git + repository. + * config.sub: Likewise. + 2009-10-20 Robert Millan Fix build on sparc64. diff --git a/config.guess b/config.guess index bb0b03ea1..e792aac60 100644 --- a/config.guess +++ b/config.guess @@ -4,7 +4,7 @@ # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. -timestamp='2009-08-19' +timestamp='2009-09-18' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -854,6 +854,20 @@ EOF i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -876,6 +890,9 @@ EOF frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-gnu + exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; @@ -911,29 +928,12 @@ EOF or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in @@ -942,8 +942,11 @@ EOF *) echo hppa-unknown-linux-gnu ;; esac exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux @@ -966,58 +969,6 @@ EOF xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both @@ -1247,6 +1198,16 @@ EOF *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} diff --git a/config.sub b/config.sub index 8ca084bf3..5ecc18b6a 100644 --- a/config.sub +++ b/config.sub @@ -4,7 +4,7 @@ # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. -timestamp='2009-08-19' +timestamp='2009-10-07' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -287,6 +287,7 @@ case $basic_machine in | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ + | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ @@ -300,7 +301,7 @@ case $basic_machine in | z8k | z80) basic_machine=$basic_machine-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12) + m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none @@ -371,7 +372,7 @@ case $basic_machine in | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ - | romp-* | rs6000-* \ + | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ @@ -1296,7 +1297,7 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) From f66938909063bff27fc2c3cb5e8e6063f6d0175f Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:03:02 +0000 Subject: [PATCH 015/146] 2009-10-25 Robert Millan Patch from Samuel Thibault * docs/grub.cfg: Compensate for recent change in multiboot loader (since 2009-08-14 it won't pass filename to payload). * util/grub.d/10_hurd.in: Likewise. --- ChangeLog | 7 +++++++ docs/grub.cfg | 4 ++-- util/grub.d/10_hurd.in | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2dd370aca..26a2c8f7c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-25 Robert Millan + + Patch from Samuel Thibault + * docs/grub.cfg: Compensate for recent change in multiboot + loader (since 2009-08-14 it won't pass filename to payload). + * util/grub.d/10_hurd.in: Likewise. + 2009-10-21 Felix Zielcke * config.guess: Update to latest version from config git diff --git a/docs/grub.cfg b/docs/grub.cfg index 4d1582a8e..0a9ab6bc7 100644 --- a/docs/grub.cfg +++ b/docs/grub.cfg @@ -15,13 +15,13 @@ set fallback=1 menuentry "GNU (aka GNU/Hurd)" { set root=(hd0,1) multiboot /boot/gnumach.gz root=device:hd0s1 - module /hurd/ext2fs.static --readonly \ + module /hurd/ext2fs.static ext2fs --readonly \ --multiboot-command-line='${kernel-command-line}' \ --host-priv-port='${host-port}' \ --device-master-port='${device-port}' \ --exec-server-task='${exec-task}' -T typed '${root}' \ '$(task-create)' '$(task-resume)' - module /lib/ld.so.1 /hurd/exec '$(exec-task=task-create)' + module /lib/ld.so.1 exec /hurd/exec '$(exec-task=task-create)' } # For booting GNU/Linux diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index ec78a3532..b52f37498 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -74,12 +74,12 @@ EOF prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" cat << EOF multiboot ${kernel} root=device:${GRUB_DEVICE} - module /hurd/${hurd_fs}.static --readonly \\ + module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ --multiboot-command-line='\${kernel-command-line}' \\ --host-priv-port='\${host-port}' \\ --device-master-port='\${device-port}' \\ --exec-server-task='\${exec-task}' -T typed '\${root}' \\ '\$(task-create)' '\$(task-resume)' - module /lib/ld.so.1 /hurd/exec '\$(exec-task=task-create)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' } EOF From fb26abc22bece052526d65508944dffd0405fa02 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:15:48 +0000 Subject: [PATCH 016/146] 2009-10-25 Robert Millan * fs/cpio.c [MODE_USTAR]: Finish `tar' module instead of `cpio'. [! MODE_USTAR]: Finish `cpio' module instead of `tar'. --- ChangeLog | 6 ++++++ fs/cpio.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26a2c8f7c..51e76499b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-25 Robert Millan + + * fs/cpio.c [MODE_USTAR]: Finish `tar' module instead of + `cpio'. + [! MODE_USTAR]: Finish `cpio' module instead of `tar'. + 2009-10-25 Robert Millan Patch from Samuel Thibault diff --git a/fs/cpio.c b/fs/cpio.c index 1ec4ebeaf..7c6ada9b3 100644 --- a/fs/cpio.c +++ b/fs/cpio.c @@ -362,9 +362,9 @@ GRUB_MOD_INIT (tar) } #ifdef MODE_USTAR -GRUB_MOD_FINI (cpio) -#else GRUB_MOD_FINI (tar) +#else +GRUB_MOD_FINI (cpio) #endif { grub_fs_unregister (&grub_cpio_fs); From cdb308b0e156f2081c77e30b92bad5ebac4fdf11 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:26:42 +0000 Subject: [PATCH 017/146] 2009-10-25 Robert Millan * include/grub/powerpc/libgcc.h (memset): Remove function prototype. * include/grub/sparc64/libgcc.h (memset): Likewise. * include/grub/misc.h (memset, memcmp): New function prototypes. --- ChangeLog | 6 ++++++ include/grub/misc.h | 2 ++ include/grub/powerpc/libgcc.h | 1 - include/grub/sparc64/libgcc.h | 2 -- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 51e76499b..9df444755 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-25 Robert Millan + + * include/grub/powerpc/libgcc.h (memset): Remove function prototype. + * include/grub/sparc64/libgcc.h (memset): Likewise. + * include/grub/misc.h (memset, memcmp): New function prototypes. + 2009-10-25 Robert Millan * fs/cpio.c [MODE_USTAR]: Finish `tar' module instead of diff --git a/include/grub/misc.h b/include/grub/misc.h index a63a0b442..c7ff1e2d2 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -76,8 +76,10 @@ grub_strncat (char *dest, const char *src, int c) /* Prototypes for aliases. */ #if !defined (GRUB_UTIL) || !defined (APPLE_CC) +int EXPORT_FUNC(memcmp) (const void *s1, const void *s2, grub_size_t n); void *EXPORT_FUNC(memmove) (void *dest, const void *src, grub_size_t n); void *EXPORT_FUNC(memcpy) (void *dest, const void *src, grub_size_t n); +void EXPORT_FUNC (memset) (void); #endif int EXPORT_FUNC(grub_memcmp) (const void *s1, const void *s2, grub_size_t n); diff --git a/include/grub/powerpc/libgcc.h b/include/grub/powerpc/libgcc.h index 0ff8964b7..c32fcd87f 100644 --- a/include/grub/powerpc/libgcc.h +++ b/include/grub/powerpc/libgcc.h @@ -16,7 +16,6 @@ * along with GRUB. If not, see . */ -void EXPORT_FUNC (memset) (void); void EXPORT_FUNC (__ashldi3) (void); void EXPORT_FUNC (__ashrdi3) (void); void EXPORT_FUNC (__lshrdi3) (void); diff --git a/include/grub/sparc64/libgcc.h b/include/grub/sparc64/libgcc.h index 4a6b6194d..008821d81 100644 --- a/include/grub/sparc64/libgcc.h +++ b/include/grub/sparc64/libgcc.h @@ -18,8 +18,6 @@ #include -void EXPORT_FUNC (memset) (void); - #ifdef HAVE___BSWAPSI2 typedef int SItype __attribute__ ((mode (SI))); SItype EXPORT_FUNC (__bswapsi2) (SItype); From 346e7fbedb8e728aea4c8400e2d94ba24208ed3b Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:26:53 +0000 Subject: [PATCH 018/146] 2009-10-25 Robert Millan * configure.ac: Check for `__ashldi3', `__ashrdi3', `__lshrdi3', `__trampoline_setup' and `__ucmpdi2'. * include/grub/powerpc/libgcc.h: Only export symbols for functions that libgcc provides. --- ChangeLog | 7 +++++++ configure.ac | 2 +- include/grub/powerpc/libgcc.h | 14 +++++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9df444755..ce28aed16 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-25 Robert Millan + + * configure.ac: Check for `__ashldi3', `__ashrdi3', `__lshrdi3', + `__trampoline_setup' and `__ucmpdi2'. + * include/grub/powerpc/libgcc.h: Only export symbols for functions + that libgcc provides. + 2009-10-25 Robert Millan * include/grub/powerpc/libgcc.h (memset): Remove function prototype. diff --git a/configure.ac b/configure.ac index bf113ba68..048333ba5 100644 --- a/configure.ac +++ b/configure.ac @@ -412,7 +412,7 @@ AC_SUBST(TARGET_CPPFLAGS) AC_SUBST(TARGET_LDFLAGS) # Check for libgcc symbols (must be performed before we add -nostdlib to LDFLAGS) -AC_CHECK_FUNCS(__bswapsi2 __bswapdi2) +AC_CHECK_FUNCS(__bswapsi2 __bswapdi2 __ashldi3 __ashrdi3 __lshrdi3 __trampoline_setup __ucmpdi2) # Set them to their new values for the tests below. CC="$TARGET_CC" diff --git a/include/grub/powerpc/libgcc.h b/include/grub/powerpc/libgcc.h index c32fcd87f..452ad4366 100644 --- a/include/grub/powerpc/libgcc.h +++ b/include/grub/powerpc/libgcc.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2007 Free Software Foundation, Inc. + * Copyright (C) 2004,2007,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,8 +16,20 @@ * along with GRUB. If not, see . */ +#include + +#ifdef HAVE___ASHLDI3 void EXPORT_FUNC (__ashldi3) (void); +#endif +#ifdef HAVE___ASHRDI3 void EXPORT_FUNC (__ashrdi3) (void); +#endif +#ifdef HAVE___LSHRDI3 void EXPORT_FUNC (__lshrdi3) (void); +#endif +#ifdef HAVE___TRAMPOLINE_SETUP void EXPORT_FUNC (__trampoline_setup) (void); +#endif +#ifdef HAVE___UCMPDI2 void EXPORT_FUNC (__ucmpdi2) (void); +#endif From b240e30c478d5665bba66794e9a1c8ccaefbb222 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:31:05 +0000 Subject: [PATCH 019/146] 2009-10-25 Robert Millan * fs/cpio.c [MODE_USTAR]: Initialize `tar' module instead of `cpio'. [! MODE_USTAR]: Initialize `cpio' module instead of `tar'. --- ChangeLog | 6 ++++++ fs/cpio.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index ce28aed16..380dacffd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-25 Robert Millan + + * fs/cpio.c [MODE_USTAR]: Initialize `tar' module instead of + `cpio'. + [! MODE_USTAR]: Initialize `cpio' module instead of `tar'. + 2009-10-25 Robert Millan * configure.ac: Check for `__ashldi3', `__ashrdi3', `__lshrdi3', diff --git a/fs/cpio.c b/fs/cpio.c index 7c6ada9b3..3f3a3d1a0 100644 --- a/fs/cpio.c +++ b/fs/cpio.c @@ -352,9 +352,9 @@ static struct grub_fs grub_cpio_fs = { }; #ifdef MODE_USTAR -GRUB_MOD_INIT (cpio) -#else GRUB_MOD_INIT (tar) +#else +GRUB_MOD_INIT (cpio) #endif { grub_fs_register (&grub_cpio_fs); From 508d42ec11bd3197bd6f3783a27f54ed6796eafd Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 24 Oct 2009 23:36:00 +0000 Subject: [PATCH 020/146] 2009-10-25 Robert Millan 2009-10-25 Vasily Averin * fs/ext2.c (grub_ext2_iterate_dir): Avoid infinite loop when `dirent.direntlen == 0'. --- ChangeLog | 6 ++++++ fs/ext2.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 380dacffd..80c593e4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-25 Robert Millan +2009-10-25 Vasily Averin + + * fs/ext2.c (grub_ext2_iterate_dir): Avoid infinite loop when + `dirent.direntlen == 0'. + 2009-10-25 Robert Millan * fs/cpio.c [MODE_USTAR]: Initialize `tar' module instead of diff --git a/fs/ext2.c b/fs/ext2.c index 0341680ea..8d8c6939e 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -649,6 +649,9 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir, if (grub_errno) return 0; + if (dirent.direntlen == 0) + return 0; + if (dirent.namelen != 0) { char filename[dirent.namelen + 1]; From d64448a72c4d5015ab07c2197e7f1f11717e382a Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 25 Oct 2009 15:14:25 +0000 Subject: [PATCH 021/146] 2009-10-25 Robert Millan * include/grub/misc.h: Fix wrong evaluation of APPLE_CC. (memset): Fix function prototype. --- ChangeLog | 5 +++++ include/grub/misc.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 80c593e4b..daee3ea4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-25 Robert Millan + + * include/grub/misc.h: Fix wrong evaluation of APPLE_CC. + (memset): Fix function prototype. + 2009-10-25 Robert Millan 2009-10-25 Vasily Averin diff --git a/include/grub/misc.h b/include/grub/misc.h index c7ff1e2d2..7589f43a2 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -75,11 +75,11 @@ grub_strncat (char *dest, const char *src, int c) } /* Prototypes for aliases. */ -#if !defined (GRUB_UTIL) || !defined (APPLE_CC) +#if !defined (GRUB_UTIL) && !defined (APPLE_CC) int EXPORT_FUNC(memcmp) (const void *s1, const void *s2, grub_size_t n); void *EXPORT_FUNC(memmove) (void *dest, const void *src, grub_size_t n); void *EXPORT_FUNC(memcpy) (void *dest, const void *src, grub_size_t n); -void EXPORT_FUNC (memset) (void); +void *EXPORT_FUNC(memset) (void *s, int c, grub_size_t n); #endif int EXPORT_FUNC(grub_memcmp) (const void *s1, const void *s2, grub_size_t n); From 042484d78e5a12999aa956caa4feb55ac54a2a3a Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 25 Oct 2009 15:23:48 +0000 Subject: [PATCH 022/146] 2009-10-25 Robert Millan * include/grub/fs.h [GRUB_UTIL] (struct grub_fs): Add `reserved_first_sector' member. * fs/ext2.c [GRUB_UTIL] (grub_ext2_fs): Initialize `reserved_first_sector' to 1. * fs/fat.c [GRUB_UTIL] (grub_fat_fs): Likewise. * fs/ntfs.c [GRUB_UTIL] (grub_ntfs_fs): Likewise. * fs/hfsplus.c [GRUB_UTIL] (grub_hfsplus_fs): Likewise. * util/i386/pc/grub-setup.c (setup): Add safety check that probes for filesystems which begin at first sector. (options): New option --skip-fs-probe. (main): Handle --skip-fs-probe and pass it to setup(). --- ChangeLog | 14 ++++++++++++++ fs/ext2.c | 3 +++ fs/fat.c | 3 +++ fs/hfsplus.c | 3 +++ fs/ntfs.c | 22 +++++++++++++--------- include/grub/fs.h | 5 +++++ util/i386/pc/grub-setup.c | 29 +++++++++++++++++++++++++---- 7 files changed, 66 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index daee3ea4c..81f3ba601 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-10-25 Robert Millan + + * include/grub/fs.h [GRUB_UTIL] (struct grub_fs): Add + `reserved_first_sector' member. + * fs/ext2.c [GRUB_UTIL] (grub_ext2_fs): Initialize + `reserved_first_sector' to 1. + * fs/fat.c [GRUB_UTIL] (grub_fat_fs): Likewise. + * fs/ntfs.c [GRUB_UTIL] (grub_ntfs_fs): Likewise. + * fs/hfsplus.c [GRUB_UTIL] (grub_hfsplus_fs): Likewise. + * util/i386/pc/grub-setup.c (setup): Add safety check that probes for + filesystems which begin at first sector. + (options): New option --skip-fs-probe. + (main): Handle --skip-fs-probe and pass it to setup(). + 2009-10-25 Robert Millan * include/grub/misc.h: Fix wrong evaluation of APPLE_CC. diff --git a/fs/ext2.c b/fs/ext2.c index 8d8c6939e..e7a20a43b 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -927,6 +927,9 @@ static struct grub_fs grub_ext2_fs = .label = grub_ext2_label, .uuid = grub_ext2_uuid, .mtime = grub_ext2_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif .next = 0 }; diff --git a/fs/fat.c b/fs/fat.c index 8440e43fa..e7f01629e 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -855,6 +855,9 @@ static struct grub_fs grub_fat_fs = .close = grub_fat_close, .label = grub_fat_label, .uuid = grub_fat_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif .next = 0 }; diff --git a/fs/hfsplus.c b/fs/hfsplus.c index 5e0ab093f..b306e8d6a 100644 --- a/fs/hfsplus.c +++ b/fs/hfsplus.c @@ -1021,6 +1021,9 @@ static struct grub_fs grub_hfsplus_fs = .label = grub_hfsplus_label, .mtime = grub_hfsplus_mtime, .uuid = grub_hfsplus_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif .next = 0 }; diff --git a/fs/ntfs.c b/fs/ntfs.c index f1d0a374e..163f3e0a8 100644 --- a/fs/ntfs.c +++ b/fs/ntfs.c @@ -1081,15 +1081,19 @@ grub_ntfs_uuid (grub_device_t device, char **uuid) return grub_errno; } -static struct grub_fs grub_ntfs_fs = { - .name = "ntfs", - .dir = grub_ntfs_dir, - .open = grub_ntfs_open, - .read = grub_ntfs_read, - .close = grub_ntfs_close, - .label = grub_ntfs_label, - .uuid = grub_ntfs_uuid, - .next = 0 +static struct grub_fs grub_ntfs_fs = + { + .name = "ntfs", + .dir = grub_ntfs_dir, + .open = grub_ntfs_open, + .read = grub_ntfs_read, + .close = grub_ntfs_close, + .label = grub_ntfs_label, + .uuid = grub_ntfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif + .next = 0 }; GRUB_MOD_INIT (ntfs) diff --git a/include/grub/fs.h b/include/grub/fs.h index 41732e48d..132ab4755 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -68,6 +68,11 @@ struct grub_fs /* Get writing time of filesystem. */ grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf); +#ifdef GRUB_UTIL + /* Whether this filesystem reserves first sector for DOS-style boot. */ + int reserved_first_sector; +#endif + /* The next filesystem. */ struct grub_fs *next; }; diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index ccfbd1d25..5a46e9e24 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -86,7 +86,7 @@ grub_refresh (void) static void setup (const char *dir, const char *boot_file, const char *core_file, - const char *root, const char *dest, int must_embed, int force) + const char *root, const char *dest, int must_embed, int force, int fs_probe) { char *boot_path, *core_path, *core_path_dev; char *boot_img, *core_img; @@ -251,6 +251,21 @@ setup (const char *dir, if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) grub_util_error ("%s", grub_errmsg); + if (dest_dev->disk->partition && fs_probe) + { + grub_fs_t fs; + fs = grub_fs_probe (dest_dev); + if (! fs) + grub_util_error ("Unable to identify a filesystem in %s; safety check can't be performed."); + + if (! fs->reserved_first_sector) + grub_util_error ("%s appears to contain a %s filesystem which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk).", dest_dev->disk->name, fs->name); + } + /* Copy the possible DOS BPB. */ memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START, tmp_img + GRUB_BOOT_MACHINE_BPB_START, @@ -556,6 +571,7 @@ static struct option options[] = {"device-map", required_argument, 0, 'm'}, {"root-device", required_argument, 0, 'r'}, {"force", no_argument, 0, 'f'}, + {"skip-fs-probe", no_argument, 0, 's'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, @@ -580,6 +596,7 @@ DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ -r, --root-device=DEV use DEV as the root device [default=guessed]\n\ -f, --force install even if problems are detected\n\ + -s, --skip-fs-probe do not probe for filesystems in DEVICE\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ @@ -613,7 +630,7 @@ main (int argc, char *argv[]) char *dev_map = 0; char *root_dev = 0; char *dest_dev; - int must_embed = 0, force = 0; + int must_embed = 0, force = 0, fs_probe = 1; progname = "grub-setup"; @@ -666,6 +683,10 @@ main (int argc, char *argv[]) force = 1; break; + case 's': + fs_probe = 0; + break; + case 'h': usage (0); break; @@ -767,7 +788,7 @@ main (int argc, char *argv[]) setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, core_file ? : DEFAULT_CORE_FILE, - root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force); + root_dev, grub_util_get_grub_dev (devicelist[i]), 1, force, fs_probe); } } else @@ -776,7 +797,7 @@ main (int argc, char *argv[]) setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, core_file ? : DEFAULT_CORE_FILE, - root_dev, dest_dev, must_embed, force); + root_dev, dest_dev, must_embed, force, fs_probe); /* Free resources. */ grub_fini_all (); From 4dea1c6f063c5af8a50a8481c0e2ce713190897d Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 25 Oct 2009 17:49:27 +0000 Subject: [PATCH 023/146] 2009-10-25 Robert Millan * util/i386/pc/grub-setup.c (setup): Add missing parameter to grub_util_error() call. --- ChangeLog | 5 +++++ util/i386/pc/grub-setup.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 81f3ba601..123a52cb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-25 Robert Millan + + * util/i386/pc/grub-setup.c (setup): Add missing parameter to + grub_util_error() call. + 2009-10-25 Robert Millan * include/grub/fs.h [GRUB_UTIL] (struct grub_fs): Add diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 5a46e9e24..c536be0c4 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -256,7 +256,8 @@ setup (const char *dir, grub_fs_t fs; fs = grub_fs_probe (dest_dev); if (! fs) - grub_util_error ("Unable to identify a filesystem in %s; safety check can't be performed."); + grub_util_error ("Unable to identify a filesystem in %s; safety check can't be performed.", + dest_dev->disk->name); if (! fs->reserved_first_sector) grub_util_error ("%s appears to contain a %s filesystem which isn't known to " From ee3756ccb3f14b7a3f7d5a967dea15b4104f97c5 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 00:38:26 +0000 Subject: [PATCH 024/146] 2009-10-26 Robert Millan * util/grub.d/10_freebsd.in: Remove. --- ChangeLog | 4 +++ util/grub.d/10_freebsd.in | 76 --------------------------------------- 2 files changed, 4 insertions(+), 76 deletions(-) delete mode 100644 util/grub.d/10_freebsd.in diff --git a/ChangeLog b/ChangeLog index 123a52cb6..597dcafcb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-26 Robert Millan + + * util/grub.d/10_freebsd.in: Remove. + 2009-10-25 Robert Millan * util/i386/pc/grub-setup.c (setup): Add missing parameter to diff --git a/util/grub.d/10_freebsd.in b/util/grub.d/10_freebsd.in deleted file mode 100644 index 02694d3e7..000000000 --- a/util/grub.d/10_freebsd.in +++ /dev/null @@ -1,76 +0,0 @@ -#! /bin/sh -e - -# grub-mkconfig helper script. -# Copyright (C) 2008,2009 Free Software Foundation, Inc. -# -# GRUB 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 3 of the License, or -# (at your option) any later version. -# -# GRUB 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 GRUB. If not, see . - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib - -case "${GRUB_DISTRIBUTOR}" in - Debian) OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" ;; - *) OS="FreeBSD" ;; -esac - -if test -e /boot/device.hints ; then - devices=/boot/device.hints -fi - -if test -e /boot/kernel/kernel ; then - kfreebsd=/boot/kernel/kernel -fi -if test -e /boot/kernel/kernel.gz ; then - kfreebsd=/boot/kernel/kernel.gz -fi - -if [ "x$kfreebsd" != "x" ] ; then - echo "Found kernel of FreeBSD: $kfreebsd" >&2 - - kfreebsd_basename=`basename $kfreebsd` - kfreebsd_dirname=`dirname $kfreebsd` - kfreebsd_rel_dirname=`make_system_path_relative_to_its_root $kfreebsd_dirname` - - if [ x"$devices" != "x" ] ; then - devices_basename=`basename $devices` - devices_dirname=`dirname $devices` - devices_rel_dirname=`make_system_path_relative_to_its_root $devices_dirname` - fi - - case ${GRUB_FS} in - ufs1 | ufs2) kfreebsd_fs=ufs ;; - *) kfreebsd_fs=${GRUB_FS} ;; - esac - - cat << EOF -menuentry "${OS}" { -EOF - prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" - cat << EOF - kfreebsd ${kfreebsd_rel_dirname}/${kfreebsd_basename} -EOF - - if [ x"$devices" != "x" ] ; then - cat << EOF - kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} -EOF - fi - cat << EOF - set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${GRUB_DEVICE} - set kFreeBSD.vfs.root.mountfrom.options=rw -} -EOF -fi From 5c35048e23a02f91b7b910645e8b80993b65eab3 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 00:38:38 +0000 Subject: [PATCH 025/146] 2009-10-26 Robert Millan * docs/grub.cfg: Fix example usage of *BSD loaders. --- ChangeLog | 2 +- docs/grub.cfg | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 597dcafcb..8a3c0dcb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ 2009-10-26 Robert Millan - * util/grub.d/10_freebsd.in: Remove. + * docs/grub.cfg: Fix example usage of *BSD loaders. 2009-10-25 Robert Millan diff --git a/docs/grub.cfg b/docs/grub.cfg index 0a9ab6bc7..e14cdb776 100644 --- a/docs/grub.cfg +++ b/docs/grub.cfg @@ -34,26 +34,26 @@ menuentry "GNU/Linux" { # For booting FreeBSD menuentry "FreeBSD (or GNU/kFreeBSD), direct boot" { set root=(hd0,1,a) - freebsd /boot/kernel/kernel - freebsd_loadenv /boot/device.hints - freebsd_module /boot/splash.bmp type=splash_image_data - set FreeBSD.vfs.root.mountfrom=ufs:ad0s1a + kfreebsd /boot/kernel/kernel + kfreebsd_loadenv /boot/device.hints + kfreebsd_module /boot/splash.bmp type=splash_image_data + set kFreeBSD.vfs.root.mountfrom=ufs:ad0s1a } menuentry "FreeBSD (or GNU/kFreeBSD), via /boot/loader" { set root=(hd0,1,a) - freebsd /boot/loader + kfreebsd /boot/loader } # For booting NetBSD menuentry "NetBSD" { set root=(hd0,1,a) - netbsd /netbsd + knetbsd /netbsd } # For booting OpenBSD menuentry "OpenBSD" { set root=(hd0,1,a) - openbsd /bsd + kopenbsd /bsd } # For booting Microsoft Windows From 67937d4dca09e70d2d0a4ff72629ae1340355451 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 00:41:54 +0000 Subject: [PATCH 026/146] 2009-10-26 Robert Millan * util/grub.d/10_freebsd.in: Remove. * util/grub.d/10_kfreebsd.in: New file (based on 10_linux.in). * configure.ac: Set host_kernel=kfreebsd for FreeBSD and GNU/kFreeBSD. --- ChangeLog | 6 +++ configure.ac | 2 +- util/grub.d/10_kfreebsd.in | 102 +++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 util/grub.d/10_kfreebsd.in diff --git a/ChangeLog b/ChangeLog index 8a3c0dcb7..6ca49a0e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Robert Millan + + * util/grub.d/10_freebsd.in: Remove. + * util/grub.d/10_kfreebsd.in: New file (based on 10_linux.in). + * configure.ac: Set host_kernel=kfreebsd for FreeBSD and GNU/kFreeBSD. + 2009-10-26 Robert Millan * docs/grub.cfg: Fix example usage of *BSD loaders. diff --git a/configure.ac b/configure.ac index 048333ba5..4bd28f2e8 100644 --- a/configure.ac +++ b/configure.ac @@ -107,7 +107,7 @@ esac case "$host_os" in gnu*) host_kernel=hurd ;; linux*) host_kernel=linux ;; - freebsd* | kfreebsd*-gnu) host_kernel=freebsd ;; + freebsd* | kfreebsd*-gnu) host_kernel=kfreebsd ;; cygwin) host_kernel=windows ;; esac diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in new file mode 100644 index 000000000..1473a42a2 --- /dev/null +++ b/util/grub.d/10_kfreebsd.in @@ -0,0 +1,102 @@ +#! /bin/sh -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# +# GRUB 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 3 of the License, or +# (at your option) any later version. +# +# GRUB 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 GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +else + OS="${GRUB_DISTRIBUTOR} GNU/Linux" +fi + +# loop-AES arranges things so that /dev/loop/X can be our root device, but +# the initrds that Linux uses don't like that. +case ${GRUB_DEVICE} in + /dev/loop/*|/dev/loop[0-9]) + GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` + ;; +esac + +if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ + || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then + LINUX_ROOT_DEVICE=${GRUB_DEVICE} +else + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} +fi + +linux_entry () +{ + cat << EOF +menuentry "$1" { +EOF + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + cat << EOF + linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro $2 +EOF + if test -n "${initrd}" ; then + cat << EOF + initrd ${rel_dirname}/${initrd} +EOF + fi + cat << EOF +} +EOF +} + +list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` + +while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + echo "Found linux image: $linux" >&2 + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" + + initrd= + for i in "initrd.img-${version}" "initrd-${version}.img" \ + "initrd-${version}" "initrd.img-${alt_version}" \ + "initrd-${alt_version}.img" "initrd-${alt_version}"; do + if test -e "${dirname}/${i}" ; then + initrd="$i" + break + fi + done + if test -n "${initrd}" ; then + echo "Found initrd image: ${dirname}/${initrd}" >&2 + else + # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. + linux_root_device_thisversion=${GRUB_DEVICE} + fi + + linux_entry "${OS}, with Linux ${version}" \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}, with Linux ${version} (recovery mode)" \ + "single ${GRUB_CMDLINE_LINUX}" + fi + + list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` +done From ba36be41191d89f225a4b981ffcad474955f48e6 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 00:41:58 +0000 Subject: [PATCH 027/146] 2009-10-26 Robert Millan * util/grub.d/10_freebsd.in: Remove. * util/grub.d/10_kfreebsd.in: New file (based on 10_linux.in). * configure.ac: Set host_kernel=kfreebsd for FreeBSD and GNU/kFreeBSD. --- util/grub.d/10_kfreebsd.in | 98 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 1473a42a2..4fb704c49 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -21,82 +21,82 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ . ${libdir}/grub/grub-mkconfig_lib -if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then - OS=GNU/Linux -else - OS="${GRUB_DISTRIBUTOR} GNU/Linux" -fi - -# loop-AES arranges things so that /dev/loop/X can be our root device, but -# the initrds that Linux uses don't like that. -case ${GRUB_DEVICE} in - /dev/loop/*|/dev/loop[0-9]) - GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` - ;; +case "${GRUB_DISTRIBUTOR}" in + Debian) OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" ;; + *) OS="FreeBSD" ;; esac -if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ - || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then - LINUX_ROOT_DEVICE=${GRUB_DEVICE} -else - LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} -fi - -linux_entry () +kfreebsd_entry () { cat << EOF menuentry "$1" { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" cat << EOF - linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro $2 + kfreebsd ${rel_dirname}/${basename} EOF - if test -n "${initrd}" ; then + + if test -n "${devices}" ; then cat << EOF - initrd ${rel_dirname}/${initrd} + kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} EOF fi + + if test -n "${acpi_ko}" ; then + cat << EOF + kfreebsd_module_elf ${acpi_ko_rel_dirname}/${acpi_ko_basename} +EOF + fi + cat << EOF + set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${GRUB_DEVICE} + set kFreeBSD.vfs.root.mountfrom.options=rw } EOF } -list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do +list=`for i in /boot/kfreebsd-* /boot/kernel/kernel ; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` while [ "x$list" != "x" ] ; do - linux=`version_find_latest $list` - echo "Found linux image: $linux" >&2 - basename=`basename $linux` - dirname=`dirname $linux` + kfreebsd=`version_find_latest $list` + echo "Found kernel of FreeBSD: $kfreebsd" >&2 + basename=`basename $kfreebsd` + dirname=`dirname $kfreebsd` rel_dirname=`make_system_path_relative_to_its_root $dirname` - version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` - alt_version=`echo $version | sed -e "s,\.old$,,g"` - linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" - initrd= - for i in "initrd.img-${version}" "initrd-${version}.img" \ - "initrd-${version}" "initrd.img-${alt_version}" \ - "initrd-${alt_version}.img" "initrd-${alt_version}"; do - if test -e "${dirname}/${i}" ; then - initrd="$i" + if [ -f /boot/device.hints ] ; then + devices=/boot/device.hints + devices_basename=`basename $devices` + devices_dirname=`dirname $devices` + devices_rel_dirname=`make_system_path_relative_to_its_root $devices_dirname` + fi + + case ${GRUB_FS} in + ufs1 | ufs2) kfreebsd_fs=ufs ;; + *) kfreebsd_fs=${GRUB_FS} ;; + esac + + version=`echo $basename | sed -e "s,^[^0-9]*-,,g;s/\.gz$//g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + + acpi_ko= + for i in "/lib/modules/${version}/acpi.ko" "/lib/modules/${alt_version}/acpi.ko" \ + "/boot/kernel/acpi.ko"; do + if test -e "$i" ; then + acpi_ko="$i" break fi done - if test -n "${initrd}" ; then - echo "Found initrd image: ${dirname}/${initrd}" >&2 - else - # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. - linux_root_device_thisversion=${GRUB_DEVICE} + if test -n "${acpi_ko}" ; then + echo "Found ACPI module: ${acpi_ko}" >&2 + acpi_ko_basename=`basename ${acpi_ko}` + acpi_ko_dirname=`dirname ${acpi_ko}` + acpi_ko_rel_dirname=`make_system_path_relative_to_its_root $acpi_ko_dirname` fi - linux_entry "${OS}, with Linux ${version}" \ - "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" - if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then - linux_entry "${OS}, with Linux ${version} (recovery mode)" \ - "single ${GRUB_CMDLINE_LINUX}" - fi + kfreebsd_entry "${OS}, kFreeBSD ${version}" - list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` + list=`echo $list | tr ' ' '\n' | grep -vx $kfreebsd | tr '\n' ' '` done From e4f6809bbc51ceac3eea354a3f264b3cf0c483d3 Mon Sep 17 00:00:00 2001 From: cjwatson Date: Mon, 26 Oct 2009 16:28:04 +0000 Subject: [PATCH 028/146] 2009-10-26 Colin Watson Improve grub-mkconfig performance when there are several menu entries on a single filesystem. * util/grub.d/10_linux.in (linux_entry): Cache the output of prepare_grub_to_access_device. * util/grub.d/10_kfreebsd.in (kfreebsd_entry): Likewise. * util/grub.d/30_os-prober.in: Likewise. --- ChangeLog | 10 ++++++++++ util/grub.d/10_kfreebsd.in | 6 +++++- util/grub.d/10_linux.in | 6 +++++- util/grub.d/30_os-prober.in | 6 +++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6ca49a0e2..e7e01fa37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-10-26 Colin Watson + + Improve grub-mkconfig performance when there are several menu + entries on a single filesystem. + + * util/grub.d/10_linux.in (linux_entry): Cache the output of + prepare_grub_to_access_device. + * util/grub.d/10_kfreebsd.in (kfreebsd_entry): Likewise. + * util/grub.d/30_os-prober.in: Likewise. + 2009-10-26 Robert Millan * util/grub.d/10_freebsd.in: Remove. diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 4fb704c49..cd8c186be 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -31,7 +31,10 @@ kfreebsd_entry () cat << EOF menuentry "$1" { EOF - prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" cat << EOF kfreebsd ${rel_dirname}/${basename} EOF @@ -58,6 +61,7 @@ EOF list=`for i in /boot/kfreebsd-* /boot/kernel/kernel ; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` +prepare_boot_cache= while [ "x$list" != "x" ] ; do kfreebsd=`version_find_latest $list` diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 1473a42a2..f17955846 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -47,7 +47,10 @@ linux_entry () cat << EOF menuentry "$1" { EOF - prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" cat << EOF linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro $2 EOF @@ -64,6 +67,7 @@ EOF list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` +prepare_boot_cache= while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 84e227ee7..6fd97fc4e 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -74,6 +74,7 @@ EOF ;; linux) LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`" + prepare_boot_cache= for LINUX in ${LINUXPROBED} ; do LROOT="`echo ${LINUX} | cut -d ':' -f 1`" @@ -90,7 +91,10 @@ EOF cat << EOF menuentry "${LLABEL} (on ${DEVICE})" { EOF - prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" cat << EOF linux ${LKERNEL} ${LPARAMS} EOF From 9031b03aaca8c601f60e13ab5cc9f032094cb119 Mon Sep 17 00:00:00 2001 From: cjwatson Date: Mon, 26 Oct 2009 16:33:13 +0000 Subject: [PATCH 029/146] 2009-10-26 Colin Watson * util/grub-editenv.c (main): If only a command is given, use DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG as a default file name. (usage): FILENAME is now optional and has a default. --- ChangeLog | 6 ++++++ util/grub-editenv.c | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index e7e01fa37..ab7ccf39c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Colin Watson + + * util/grub-editenv.c (main): If only a command is given, use + DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG as a default file name. + (usage): FILENAME is now optional and has a default. + 2009-10-26 Colin Watson Improve grub-mkconfig performance when there are several menu diff --git a/util/grub-editenv.c b/util/grub-editenv.c index a8dc137c5..5b688d9cb 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -72,7 +72,7 @@ usage (int status) fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); else printf ("\ -Usage: grub-editenv [OPTIONS] FILENAME COMMAND\n\ +Usage: grub-editenv [OPTIONS] [FILENAME] COMMAND\n\ \n\ Tool to edit environment block.\n\ \nCommands:\n\ @@ -85,7 +85,10 @@ Tool to edit environment block.\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ \n\ -Report bugs to <%s>.\n", PACKAGE_BUGREPORT); +If not given explicitly, FILENAME defaults to %s.\n\ +\n\ +Report bugs to <%s>.\n", +DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG, PACKAGE_BUGREPORT); exit (status); } @@ -288,12 +291,14 @@ main (int argc, char *argv[]) if (optind + 1 >= argc) { - fprintf (stderr, "no command specified\n"); - usage (1); + filename = DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG; + command = argv[optind]; + } + else + { + filename = argv[optind]; + command = argv[optind + 1]; } - - filename = argv[optind]; - command = argv[optind + 1]; if (strcmp (command, "create") == 0) create_envblk_file (filename); From 94180ff6c7166b80ca18ef30587abc372e0e30fd Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 18:02:19 +0000 Subject: [PATCH 030/146] 2009-10-26 Robert Millan * conf/i386-coreboot.rmk (script/sh/lexer.c_DEPENDENCIES): Moved from here ... * conf/common.rmk (script/sh/lexer.c_DEPENDENCIES): ... to here. * conf/i386-efi.rmk (script/sh/lexer.c_DEPENDENCIES): Remove. * conf/i386-ieee1275.rmk: Likewise. * conf/i386-pc.rmk: Likewise. * conf/powerpc-ieee1275.rmk: Likewise. * conf/sparc64-ieee1275.rmk: Likewise. * conf/x86_64-efi.rmk: Likewise. --- ChangeLog | 12 ++++++++++++ conf/common.rmk | 2 ++ conf/i386-coreboot.rmk | 1 - conf/i386-efi.rmk | 1 - conf/i386-ieee1275.rmk | 1 - conf/i386-pc.rmk | 1 - conf/powerpc-ieee1275.rmk | 1 - conf/sparc64-ieee1275.rmk | 1 - conf/x86_64-efi.rmk | 1 - 9 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index ab7ccf39c..5a1a7b35e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-10-26 Robert Millan + + * conf/i386-coreboot.rmk (script/sh/lexer.c_DEPENDENCIES): Moved + from here ... + * conf/common.rmk (script/sh/lexer.c_DEPENDENCIES): ... to here. + * conf/i386-efi.rmk (script/sh/lexer.c_DEPENDENCIES): Remove. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + 2009-10-26 Colin Watson * util/grub-editenv.c (main): If only a command is given, use diff --git a/conf/common.rmk b/conf/common.rmk index c1f0bbdcf..ce7c33084 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -1,5 +1,7 @@ # -*- makefile -*- +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h + # For grub-mkelfimage. bin_UTILITIES += grub-mkelfimage grub_mkelfimage_SOURCES = util/elf/grub-mkimage.c util/misc.c \ diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 09ec7787c..3c2061b4e 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -5,7 +5,6 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 COMMON_LDFLAGS = -m32 -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 99ab06f64..0440359e5 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -5,7 +5,6 @@ COMMON_CFLAGS = -fno-builtin -m32 COMMON_LDFLAGS = -melf_i386 -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Utilities. bin_UTILITIES = grub-mkimage diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 4b640de49..c70ecf4dd 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -5,7 +5,6 @@ COMMON_CFLAGS = -ffreestanding -mrtd -mregparm=3 COMMON_LDFLAGS = -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_PROGRAMS = kernel.img diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index bf8fbfb9d..30847dfa7 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -7,7 +7,6 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 COMMON_LDFLAGS = -m32 -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index ee7f9ec27..9165e4bc0 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -6,7 +6,6 @@ COMMON_CFLAGS = -ffreestanding COMMON_LDFLAGS += -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 62e951a5e..1156fe2a9 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -6,7 +6,6 @@ COMMON_CFLAGS = -ffreestanding -m64 -mno-app-regs COMMON_LDFLAGS = -melf64_sparc -nostdlib -mno-relax # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_IMAGES = boot.img diskboot.img kernel.img diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 5be1b404f..173227575 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -5,7 +5,6 @@ COMMON_CFLAGS = -fno-builtin -m64 COMMON_LDFLAGS = -melf_x86_64 -nostdlib # Used by various components. These rules need to precede them. -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Utilities. bin_UTILITIES = grub-mkimage From 5947ae32f588d62077cbf341382a78fc9efc2f5b Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 18:02:30 +0000 Subject: [PATCH 031/146] 2009-10-26 Robert Millan * Makefile.in (docs/grub.info): Use make syntax to ignore errors in $(MAKEINFO) invocation. This makes it clear in output that errors are being ignored. --- ChangeLog | 6 ++++++ Makefile.in | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5a1a7b35e..2a9c04844 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Robert Millan + + * Makefile.in (docs/grub.info): Use make syntax to ignore errors + in $(MAKEINFO) invocation. This makes it clear in output that + errors are being ignored. + 2009-10-26 Robert Millan * conf/i386-coreboot.rmk (script/sh/lexer.c_DEPENDENCIES): Moved diff --git a/Makefile.in b/Makefile.in index e0edbdb04..80ed07124 100644 --- a/Makefile.in +++ b/Makefile.in @@ -197,7 +197,7 @@ docs/stamp-vti: docs/grub.texi configure.ac # Use --force until such time as the documentation is cleaned up. docs/grub.info: docs/grub.texi docs/version.texi docs/fdl.texi $(MKDIR_P) docs - $(MAKEINFO) -P $(builddir)/docs --no-split --force $< -o $@ || : + -$(MAKEINFO) -P $(builddir)/docs --no-split --force $< -o $@ ifeq (, $(UNIFONT_BDF)) else From 083d16798e9ab51e3b2cd7fb94c7e960bb92f8de Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 18:04:37 +0000 Subject: [PATCH 032/146] 2009-10-26 Robert Millan * gensymlist.sh.in (COMPILE_TIME_ASSERT): Copy macro declaration from here ... * include/grub/misc.h (COMPILE_TIME_ASSERT): ... to here. --- ChangeLog | 6 ++++++ include/grub/misc.h | 1 + 2 files changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2a9c04844..afe67af2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Robert Millan + + * gensymlist.sh.in (COMPILE_TIME_ASSERT): Copy macro declaration + from here ... + * include/grub/misc.h (COMPILE_TIME_ASSERT): ... to here. + 2009-10-26 Robert Millan * Makefile.in (docs/grub.info): Use make syntax to ignore errors diff --git a/include/grub/misc.h b/include/grub/misc.h index 7589f43a2..e3a062898 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -28,6 +28,7 @@ #define ALIGN_UP(addr, align) \ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) +#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args) /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ From 478df40933d8acb1e6cdae9af4b7eb70cb3ee983 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 18:06:23 +0000 Subject: [PATCH 033/146] 2009-10-26 Robert Millan * disk/scsi.c: Remove `' (not needed). --- ChangeLog | 4 ++++ disk/scsi.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index afe67af2b..769e4fb2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-26 Robert Millan + + * disk/scsi.c: Remove `' (not needed). + 2009-10-26 Robert Millan * gensymlist.sh.in (COMPILE_TIME_ASSERT): Copy macro declaration diff --git a/disk/scsi.c b/disk/scsi.c index 24ebdb6cd..d0e248511 100644 --- a/disk/scsi.c +++ b/disk/scsi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include From 0579b753d611588a50604934253c32e4abb33455 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 18:25:02 +0000 Subject: [PATCH 034/146] 2009-10-26 Robert Millan * Makefile.in (RMKFILES): Rewrite using $(wildcard). --- ChangeLog | 4 ++++ Makefile.in | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 769e4fb2a..1e05f770e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-26 Robert Millan + + * Makefile.in (RMKFILES): Rewrite using $(wildcard). + 2009-10-26 Robert Millan * disk/scsi.c: Remove `' (not needed). diff --git a/Makefile.in b/Makefile.in index 80ed07124..bde80889b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -115,9 +115,7 @@ enable_efiemu = @enable_efiemu@ ### General variables. -RMKFILES = $(addprefix conf/,common.rmk i386-coreboot.rmk i386-efi.rmk \ - i386-qemu.rmk i386-ieee1275.rmk i386-pc.rmk i386.rmk powerpc-ieee1275.rmk \ - sparc64-ieee1275.rmk x86_64-efi.rmk) +RMKFILES = $(wildcard conf/*.rmk) MKFILES = $(patsubst %.rmk,%.mk,$(RMKFILES)) From ed96ab6d201e50fbeb7833f7d85e0a1182a62f40 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 19:39:35 +0000 Subject: [PATCH 035/146] 2009-10-26 Robert Millan * gendistlist.sh: Simplify .svn check. Skip .bzr as well. --- ChangeLog | 4 ++++ gendistlist.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1e05f770e..b59e2d945 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-26 Robert Millan + + * gendistlist.sh: Simplify .svn check. Skip .bzr as well. + 2009-10-26 Robert Millan * Makefile.in (RMKFILES): Rewrite using $(wildcard). diff --git a/gendistlist.sh b/gendistlist.sh index 7f6c32a44..36685a092 100644 --- a/gendistlist.sh +++ b/gendistlist.sh @@ -35,7 +35,7 @@ dir=`dirname $0` cd $dir for dir in $DISTDIRS; do - for d in `find $dir -type d | sed '/\/\.svn$/d;\/\.svn\//d' | sort`; do + for d in `find $dir -type d -not -name .svn -not -name .bzr | sort`; do find $d -maxdepth 1 -name '*.[chSy]' -o -name '*.mk' -o -name '*.rmk' \ -o -name '*.rb' -o -name '*.in' -o -name '*.tex' -o -name '*.texi' \ -o -name '*.info' -o -name 'grub.cfg' -o -name 'README' \ From cefabfe1c4fb58877770034db338d850d2e6f0b9 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 26 Oct 2009 20:04:43 +0000 Subject: [PATCH 036/146] 2009-10-26 Robert Millan * autogen.sh: Support addition of external modules via `GRUB_CONTRIB' variable. * Makefile.in: Likewise. --- ChangeLog | 6 ++++++ Makefile.in | 3 +++ autogen.sh | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b59e2d945..56ff263ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Robert Millan + + * autogen.sh: Support addition of external modules via `GRUB_CONTRIB' + variable. + * Makefile.in: Likewise. + 2009-10-26 Robert Millan * gendistlist.sh: Simplify .svn check. Skip .bzr as well. diff --git a/Makefile.in b/Makefile.in index bde80889b..f99bc3c2a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -148,6 +148,9 @@ $(addprefix $(srcdir)/,$(MKFILES)): %.mk: %.rmk genmk.rb include $(srcdir)/conf/$(target_cpu)-$(platform).mk +# For external modules. +-include $(wildcard $(GRUB_CONTRIB)/*/conf/common.mk) + ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) diff --git a/autogen.sh b/autogen.sh index 6895de221..4fb6bf7db 100644 --- a/autogen.sh +++ b/autogen.sh @@ -5,8 +5,10 @@ set -e autoconf autoheader echo timestamp > stamp-h.in -for rmk in conf/*.rmk; do - ruby genmk.rb < $rmk > `echo $rmk | sed 's/\.rmk$/.mk/'` +for rmk in conf/*.rmk ${GRUB_CONTRIB}/*/conf/*.rmk; do + if test -e $rmk ; then + ruby genmk.rb < $rmk > `echo $rmk | sed 's/\.rmk$/.mk/'` + fi done ./gendistlist.sh > DISTLIST From fdcdde1905d36e3ff8283ae3c9b97ea1d37fde50 Mon Sep 17 00:00:00 2001 From: fzielcke Date: Wed, 28 Oct 2009 18:24:10 +0000 Subject: [PATCH 037/146] 2009-10-28 Felix Zielcke * commands/acpi.c (grub_cmd_acpi): Fix the out of memory error strings. --- ChangeLog | 5 +++++ commands/acpi.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 56ff263ed..1a1be5746 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-28 Felix Zielcke + + * commands/acpi.c (grub_cmd_acpi): Fix the out of memory error + strings. + 2009-10-26 Robert Millan * autogen.sh: Support addition of external modules via `GRUB_CONTRIB' diff --git a/commands/acpi.c b/commands/acpi.c index e7cb9e6b4..9cfd8ef10 100644 --- a/commands/acpi.c +++ b/commands/acpi.c @@ -552,7 +552,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, grub_free (exclude); grub_free (load_only); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could allocate table"); + "Couldn't allocate table"); } grub_memcpy (table_dsdt, dsdt, dsdt->length); } @@ -579,7 +579,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, grub_free (exclude); grub_free (load_only); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could allocate table structure"); + "Couldn't allocate table structure"); } table->size = curtable->length; table->addr = grub_malloc (table->size); @@ -588,7 +588,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, { free_tables (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could allocate table"); + "Couldn't allocate table"); } table->next = acpi_tables; acpi_tables = table; @@ -675,7 +675,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, { free_tables (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could allocate table structure"); + "Couldn't allocate table structure"); } table->size = size; From 2ed19dfdeda64c7319fde370b6e4e14f5ee85894 Mon Sep 17 00:00:00 2001 From: robertmh Date: Wed, 28 Oct 2009 22:02:54 +0000 Subject: [PATCH 038/146] 2009-10-28 Robert Millan * kern/i386/coreboot/init.c (grub_exit): Reimplement in a way that doesn't cause an infinite call loop. --- ChangeLog | 5 +++++ kern/i386/coreboot/init.c | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1a1be5746..a792f04e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-28 Robert Millan + + * kern/i386/coreboot/init.c (grub_exit): Reimplement in a way that + doesn't cause an infinite call loop. + 2009-10-28 Felix Zielcke * commands/acpi.c (grub_cmd_acpi): Fix the out of memory error diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c index 1b9ca3815..0bf4934fb 100644 --- a/kern/i386/coreboot/init.c +++ b/kern/i386/coreboot/init.c @@ -62,7 +62,10 @@ grub_stop_floppy (void) void grub_exit (void) { - grub_fatal ("grub_exit() is not implemented.\n"); + /* We can't use grub_fatal() in this function. This would create an infinite + loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */ + while (1) + grub_cpu_idle (); } void From 95b9239e13de05188c989c1542b936a62b5e8c10 Mon Sep 17 00:00:00 2001 From: robertmh Date: Wed, 28 Oct 2009 22:55:27 +0000 Subject: [PATCH 039/146] 2009-10-28 Robert Millan * include/grub/misc.h: Stop checking for APPLE_CC. --- ChangeLog | 4 ++++ include/grub/misc.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a792f04e5..ff7098c58 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-28 Robert Millan + + * include/grub/misc.h: Stop checking for APPLE_CC. + 2009-10-28 Robert Millan * kern/i386/coreboot/init.c (grub_exit): Reimplement in a way that diff --git a/include/grub/misc.h b/include/grub/misc.h index e3a062898..faa2d5c42 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -76,7 +76,7 @@ grub_strncat (char *dest, const char *src, int c) } /* Prototypes for aliases. */ -#if !defined (GRUB_UTIL) && !defined (APPLE_CC) +#ifndef GRUB_UTIL int EXPORT_FUNC(memcmp) (const void *s1, const void *s2, grub_size_t n); void *EXPORT_FUNC(memmove) (void *dest, const void *src, grub_size_t n); void *EXPORT_FUNC(memcpy) (void *dest, const void *src, grub_size_t n); From cee15086c312902c4e4bfe26829746b67cdd05d3 Mon Sep 17 00:00:00 2001 From: robertmh Date: Wed, 28 Oct 2009 23:16:32 +0000 Subject: [PATCH 040/146] 2009-10-28 Robert Millan * Makefile.in (TARGET_CPPFLAGS): Add `-nostdinc'. --- ChangeLog | 4 ++++ Makefile.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ff7098c58..12e8932e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-28 Robert Millan + + * Makefile.in (TARGET_CPPFLAGS): Add `-nostdinc'. + 2009-10-28 Robert Millan * include/grub/misc.h: Stop checking for APPLE_CC. diff --git a/Makefile.in b/Makefile.in index f99bc3c2a..103d2d3d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -75,7 +75,7 @@ TARGET_ASFLAGS = @TARGET_ASFLAGS@ TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ TARGET_APPLE_CC = @TARGET_APPLE_CC@ OBJCONV = @OBJCONV@ -TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -I$(builddir) -I$(builddir)/include -I$(srcdir)/include \ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -nostdinc -I$(builddir) -I$(builddir)/include -I$(srcdir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ From fa6e945f506c09046acebee1963398daca3b83fe Mon Sep 17 00:00:00 2001 From: robertmh Date: Thu, 29 Oct 2009 10:03:13 +0000 Subject: [PATCH 041/146] 2009-10-29 Robert Millan Revert SVN r2660. * conf/common.rmk (script/sh/lexer.c_DEPENDENCIES): Moved from here ... * conf/i386-coreboot.rmk (script/sh/lexer.c_DEPENDENCIES): ... to here. * conf/i386-efi.rmk (script/sh/lexer.c_DEPENDENCIES): ... and here. * conf/i386-ieee1275.rmk: Likewise. * conf/i386-pc.rmk: Likewise. * conf/powerpc-ieee1275.rmk: Likewise. * conf/sparc64-ieee1275.rmk: Likewise. * conf/x86_64-efi.rmk: Likewise. --- ChangeLog | 13 +++++++++++++ conf/common.rmk | 2 -- conf/i386-coreboot.rmk | 1 + conf/i386-efi.rmk | 1 + conf/i386-ieee1275.rmk | 1 + conf/i386-pc.rmk | 1 + conf/powerpc-ieee1275.rmk | 1 + conf/sparc64-ieee1275.rmk | 1 + conf/x86_64-efi.rmk | 1 + 9 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 12e8932e7..1d504a2cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-10-29 Robert Millan + + Revert SVN r2660. + + * conf/common.rmk (script/sh/lexer.c_DEPENDENCIES): Moved from here ... + * conf/i386-coreboot.rmk (script/sh/lexer.c_DEPENDENCIES): ... to here. + * conf/i386-efi.rmk (script/sh/lexer.c_DEPENDENCIES): ... and here. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + 2009-10-28 Robert Millan * Makefile.in (TARGET_CPPFLAGS): Add `-nostdinc'. diff --git a/conf/common.rmk b/conf/common.rmk index ce7c33084..c1f0bbdcf 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -1,7 +1,5 @@ # -*- makefile -*- -script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h - # For grub-mkelfimage. bin_UTILITIES += grub-mkelfimage grub_mkelfimage_SOURCES = util/elf/grub-mkimage.c util/misc.c \ diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 3c2061b4e..09ec7787c 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -5,6 +5,7 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 COMMON_LDFLAGS = -m32 -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 0440359e5..99ab06f64 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -5,6 +5,7 @@ COMMON_CFLAGS = -fno-builtin -m32 COMMON_LDFLAGS = -melf_i386 -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Utilities. bin_UTILITIES = grub-mkimage diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index c70ecf4dd..4b640de49 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -5,6 +5,7 @@ COMMON_CFLAGS = -ffreestanding -mrtd -mregparm=3 COMMON_LDFLAGS = -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_PROGRAMS = kernel.img diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 30847dfa7..bf8fbfb9d 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -7,6 +7,7 @@ COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 COMMON_LDFLAGS = -m32 -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 9165e4bc0..ee7f9ec27 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -6,6 +6,7 @@ COMMON_CFLAGS = -ffreestanding COMMON_LDFLAGS += -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 1156fe2a9..62e951a5e 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -6,6 +6,7 @@ COMMON_CFLAGS = -ffreestanding -m64 -mno-app-regs COMMON_LDFLAGS = -melf64_sparc -nostdlib -mno-relax # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Images. pkglib_IMAGES = boot.img diskboot.img kernel.img diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 173227575..5be1b404f 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -5,6 +5,7 @@ COMMON_CFLAGS = -fno-builtin -m64 COMMON_LDFLAGS = -melf_x86_64 -nostdlib # Used by various components. These rules need to precede them. +script/sh/lexer.c_DEPENDENCIES = grub_script.tab.h # Utilities. bin_UTILITIES = grub-mkimage From 805111a4fd4183d134e5da13530b57fd0b3677b3 Mon Sep 17 00:00:00 2001 From: robertmh Date: Fri, 30 Oct 2009 22:37:38 +0000 Subject: [PATCH 042/146] 2009-10-30 Robert Millan * util/i386/pc/grub-install.in: Remove hint that device.map should be checked (grub-install doesn't currently rely on it). --- ChangeLog | 5 +++++ util/i386/pc/grub-install.in | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1d504a2cc..26de80e89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-30 Robert Millan + + * util/i386/pc/grub-install.in: Remove hint that device.map should be + checked (grub-install doesn't currently rely on it). + 2009-10-29 Robert Millan Revert SVN r2660. diff --git a/util/i386/pc/grub-install.in b/util/i386/pc/grub-install.in index 69028b662..8a06213cb 100644 --- a/util/i386/pc/grub-install.in +++ b/util/i386/pc/grub-install.in @@ -319,14 +319,7 @@ else $grub_mkimage -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 fi -# Prompt the user to check if the device map is correct. echo "Installation finished. No error reported." -echo "This is the contents of the device map $device_map." -echo "Check if this is correct or not. If any of the lines is incorrect," -echo "fix it and re-run the script \`grub-install'." -echo - -cat $device_map # Bye. exit 0 From d9e2cd701b71fd46a344f1e9b1075c8fe4499658 Mon Sep 17 00:00:00 2001 From: robertmh Date: Fri, 30 Oct 2009 22:51:52 +0000 Subject: [PATCH 043/146] 2009-10-30 Robert Millan Fix build problem. * Makefile.in (TARGET_CPPFLAGS): Replace `-nostdinc' with `-isystem=$(srcdir)/include'. --- ChangeLog | 7 +++++++ Makefile.in | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 26de80e89..25d7b753d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-30 Robert Millan + + Fix build problem. + + * Makefile.in (TARGET_CPPFLAGS): Replace `-nostdinc' with + `-isystem=$(srcdir)/include'. + 2009-10-30 Robert Millan * util/i386/pc/grub-install.in: Remove hint that device.map should be diff --git a/Makefile.in b/Makefile.in index 103d2d3d2..2776fff17 100644 --- a/Makefile.in +++ b/Makefile.in @@ -75,7 +75,7 @@ TARGET_ASFLAGS = @TARGET_ASFLAGS@ TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ TARGET_APPLE_CC = @TARGET_APPLE_CC@ OBJCONV = @OBJCONV@ -TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -nostdinc -I$(builddir) -I$(builddir)/include -I$(srcdir)/include \ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -isystem=$(srcdir)/include -I$(builddir) -I$(builddir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ From 5b1538672ef1c87b9fb88b43a46fb5c00b210630 Mon Sep 17 00:00:00 2001 From: fzielcke Date: Sun, 1 Nov 2009 18:19:04 +0000 Subject: [PATCH 044/146] 2009-11-01 Felix Zielcke * Makefile.in (TARGET_CPPFLAGS): Add `-I$(srcdir)/include'. --- ChangeLog | 4 ++++ Makefile.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 25d7b753d..2e5c7484d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-11-01 Felix Zielcke + + * Makefile.in (TARGET_CPPFLAGS): Add `-I$(srcdir)/include'. + 2009-10-30 Robert Millan Fix build problem. diff --git a/Makefile.in b/Makefile.in index 2776fff17..61b966995 100644 --- a/Makefile.in +++ b/Makefile.in @@ -75,7 +75,7 @@ TARGET_ASFLAGS = @TARGET_ASFLAGS@ TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ TARGET_APPLE_CC = @TARGET_APPLE_CC@ OBJCONV = @OBJCONV@ -TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -isystem=$(srcdir)/include -I$(builddir) -I$(builddir)/include \ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -isystem=$(srcdir)/include -I$(srcdir)/include -I$(builddir) -I$(builddir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ From a50569e135f5be747a5b66f63843c5e5eadf8022 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 1 Nov 2009 23:03:09 +0000 Subject: [PATCH 045/146] 2009-11-01 Robert Millan Based on patch from BVK Chaitanya * kern/misc.c (grub_strchr, grub_strrchr): Fix to handle c == '\0' case. --- ChangeLog | 6 ++++++ kern/misc.c | 10 +++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e5c7484d..5a3f80e05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-11-01 Robert Millan + + Based on patch from BVK Chaitanya + * kern/misc.c (grub_strchr, grub_strrchr): Fix to handle c == '\0' + case. + 2009-11-01 Felix Zielcke * Makefile.in (TARGET_CPPFLAGS): Add `-I$(srcdir)/include'. diff --git a/kern/misc.c b/kern/misc.c index 1c38fe661..cacfbc753 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -223,12 +223,12 @@ grub_strncmp (const char *s1, const char *s2, grub_size_t n) char * grub_strchr (const char *s, int c) { - while (*s) + do { if (*s == c) return (char *) s; - s++; } + while (*s++); return 0; } @@ -236,14 +236,14 @@ grub_strchr (const char *s, int c) char * grub_strrchr (const char *s, int c) { - char *p = 0; + char *p = NULL; - while (*s) + do { if (*s == c) p = (char *) s; - s++; } + while (*s++); return p; } From 61697d9c7017da7b84f760b4171144f167be32f4 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 2 Nov 2009 13:55:25 +0000 Subject: [PATCH 046/146] 2009-11-02 Samuel Thibault * util/grub.d/10_hurd.in: Call prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} before loading /boot kernel. --- ChangeLog | 5 +++++ util/grub.d/10_hurd.in | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5a3f80e05..24dbdbf31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-02 Samuel Thibault + + * util/grub.d/10_hurd.in: Call prepare_grub_to_access_device + ${GRUB_DEVICE_BOOT} before loading /boot kernel. + 2009-11-01 Robert Millan Based on patch from BVK Chaitanya diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index b52f37498..fdfb7acb7 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -71,9 +71,12 @@ fi cat << EOF menuentry "${OS}" { EOF -prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" +prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" cat << EOF multiboot ${kernel} root=device:${GRUB_DEVICE} +EOF +prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" +cat << EOF module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ --multiboot-command-line='\${kernel-command-line}' \\ --host-priv-port='\${host-port}' \\ From ff1a9bca3a3884a00b4156ffc4ea7f06b053c521 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 2 Nov 2009 19:14:00 +0000 Subject: [PATCH 047/146] 2009-11-02 Samuel Thibault * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Subtract 1 from GNU partition number to get internal GRUB partition number. --- ChangeLog | 5 +++++ util/hostdisk.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 24dbdbf31..38b9ffed1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-02 Samuel Thibault + + * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Subtract 1 from + GNU partition number to get internal GRUB partition number. + 2009-11-02 Samuel Thibault * util/grub.d/10_hurd.in: Call prepare_grub_to_access_device diff --git a/util/hostdisk.c b/util/hostdisk.c index 22b856e29..e1058a100 100644 --- a/util/hostdisk.c +++ b/util/hostdisk.c @@ -1057,7 +1057,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) n = strtol (p, &q, 10); if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) { - dos_part = (int) n; + dos_part = (int) n - 1; if (*q >= 'a' && *q <= 'g') bsd_part = *q - 'a'; From b82bd5e192aa6776be2214b7d578d662a0a098a7 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 2 Nov 2009 19:32:12 +0000 Subject: [PATCH 048/146] 2009-11-02 Samuel Thibault * util/grub.d/10_hurd.in: Drop /dev/ prefix from root device path before giving it to GNU Mach. --- ChangeLog | 5 +++++ util/grub.d/10_hurd.in | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 38b9ffed1..e2aacd760 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-02 Samuel Thibault + + * util/grub.d/10_hurd.in: Drop /dev/ prefix from root device path before + giving it to GNU Mach. + 2009-11-02 Samuel Thibault * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Subtract 1 from diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index fdfb7acb7..e693c7dfa 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -73,7 +73,7 @@ menuentry "${OS}" { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" cat << EOF - multiboot ${kernel} root=device:${GRUB_DEVICE} + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} EOF prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" cat << EOF From 4f9dfb3701f46297395151c1e57b3936f5ae1da7 Mon Sep 17 00:00:00 2001 From: robertmh Date: Mon, 2 Nov 2009 21:01:14 +0000 Subject: [PATCH 049/146] 2009-11-02 Samuel Thibault * util/grub.d/30_os-prober.in: Add GNU/Hurd support --- ChangeLog | 4 ++++ util/grub.d/30_os-prober.in | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e2aacd760..ea2145770 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-11-02 Samuel Thibault + + * util/grub.d/30_os-prober.in: Add GNU/Hurd support + 2009-11-02 Samuel Thibault * util/grub.d/10_hurd.in: Drop /dev/ prefix from root device path before diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 6fd97fc4e..e14a07316 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -159,7 +159,28 @@ EOF EOF ;; hurd|*) - echo " ${LONGNAME} is not yet supported by grub-mkconfig." >&2 + cat << EOF +menuentry "${LONGNAME} (on ${DEVICE})" { +EOF + prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + grub_device="`${grub_probe} --device ${DEVICE} --target=drive`" + mach_device="`echo "${grub_device}" | tr -d '()' | tr , s`" + grub_fs="`${grub_probe} --device ${DEVICE} --target=fs`" + case "${grub_fs}" in + *fs) hurd_fs="${grub_fs}" ;; + *) hurd_fs="${grub_fs}fs" ;; + esac + cat << EOF + multiboot /boot/gnumach.gz root=device:${mach_device} + module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ + --multiboot-command-line='\${kernel-command-line}' \\ + --host-priv-port='\${host-port}' \\ + --device-master-port='\${device-port}' \\ + --exec-server-task='\${exec-task}' -T typed '\${root}' \\ + '\$(task-create)' '\$(task-resume)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' +} +EOF ;; esac done From 246cd78f70fd3a9a89c2b2c97cc33854b2f86e4c Mon Sep 17 00:00:00 2001 From: fzielcke Date: Tue, 3 Nov 2009 14:25:34 +0000 Subject: [PATCH 050/146] 2009-11-03 Samuel Thibault * util/grub.d/30_os-prober.in: Restore default behavior for unsupported OSes. --- ChangeLog | 5 +++++ util/grub.d/30_os-prober.in | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ea2145770..ffe8911d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-03 Samuel Thibault + + * util/grub.d/30_os-prober.in: Restore default behavior for unsupported + OSes. + 2009-11-02 Samuel Thibault * util/grub.d/30_os-prober.in: Add GNU/Hurd support diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index e14a07316..c5728866c 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -158,7 +158,7 @@ EOF } EOF ;; - hurd|*) + hurd) cat << EOF menuentry "${LONGNAME} (on ${DEVICE})" { EOF @@ -182,5 +182,8 @@ EOF } EOF ;; + *) + echo " ${LONGNAME} is not yet supported by grub-mkconfig." >&2 + ;; esac done From 86e5b1dbb75accb880e243344044639055c5fc25 Mon Sep 17 00:00:00 2001 From: fzielcke Date: Wed, 4 Nov 2009 08:20:53 +0000 Subject: [PATCH 051/146] 2009-11-04 Felix Zielcke * configure.ac (AC_PREREQ): Bump to 2.59d. * INSTALL: Make it more clear when Autoconf and Ruby are needed and when to run `./autogen.sh'. --- ChangeLog | 6 ++++++ INSTALL | 17 +++++++++++------ configure.ac | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index ffe8911d8..c4fecdd40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-11-04 Felix Zielcke + + * configure.ac (AC_PREREQ): Bump to 2.59d. + * INSTALL: Make it more clear when Autoconf and Ruby are + needed and when to run `./autogen.sh'. + 2009-11-03 Samuel Thibault * util/grub.d/30_os-prober.in: Restore default behavior for unsupported diff --git a/INSTALL b/INSTALL index e751d508f..f9ae8f9d2 100644 --- a/INSTALL +++ b/INSTALL @@ -16,8 +16,12 @@ configuring the GRUB. * GNU Bison 2.3 or later * GNU binutils 2.9.1.0.23 or later * Other standard GNU/Unix tools + +If you use a development snapshot or want to hack on GRUB you may +need the following. + * Ruby 1.6 or later -* Autoconf 2.59 or later +* Autoconf 2.59d or later Configuring the GRUB ==================== @@ -48,11 +52,12 @@ Building the GRUB The simplest way to compile this package is: - 1. `cd' to the directory containing the package's source code and - type `./autogen.sh' and then `./configure' to configure the - package for your system. If you're using `csh' on an old version - of System V, you might need to type `sh ./configure' instead to - prevent `csh' from trying to execute `configure' itself. + 1. `cd' to the directory containing the package's source code. If + you don't use a release tarball you have to type `./autogen.sh'. + Type `./configure' to configure the package for your system. + If you're using `csh' on an old version of System V, you might + need to type `sh ./configure' instead to prevent `csh' from trying + to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. diff --git a/configure.ac b/configure.ac index 4bd28f2e8..0953e0410 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ dnl type. AC_INIT([GRUB],[1.97],[bug-grub@gnu.org]) -AC_PREREQ(2.59) +AC_PREREQ(2.59d) AC_CONFIG_SRCDIR([include/grub/dl.h]) AC_CONFIG_HEADER([config.h]) From c926e1d58502bff159ebd12aa11684341db5b8a4 Mon Sep 17 00:00:00 2001 From: robertmh Date: Sat, 7 Nov 2009 21:06:30 +0000 Subject: [PATCH 052/146] 2009-11-07 Robert Millan Fix build with GNU gold. * conf/i386-pc.rmk (boot_img_LDFLAGS, pxeboot_img_LDFLAGS) (diskboot_img_LDFLAGS, lnxboot_img_LDFLAGS) (cdboot_img_LDFLAGS): Prepend `0x' qualifier to hexadecimal link addresses. * aclocal.m4: Likewise. --- ChangeLog | 10 ++++++++++ aclocal.m4 | 2 +- conf/i386-pc.rmk | 10 +++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index c4fecdd40..843be6dc5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-11-07 Robert Millan + + Fix build with GNU gold. + + * conf/i386-pc.rmk (boot_img_LDFLAGS, pxeboot_img_LDFLAGS) + (diskboot_img_LDFLAGS, lnxboot_img_LDFLAGS) + (cdboot_img_LDFLAGS): Prepend `0x' qualifier to hexadecimal + link addresses. + * aclocal.m4: Likewise. + 2009-11-04 Felix Zielcke * configure.ac (AC_PREREQ): Bump to 2.59d. diff --git a/aclocal.m4 b/aclocal.m4 index 899eca409..6f9baf18f 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -92,7 +92,7 @@ else AC_MSG_ERROR([${CC-cc} cannot compile C source code]) fi grub_cv_prog_objcopy_absolute=yes -for link_addr in 2000 8000 7C00; do +for link_addr in 0x2000 0x8000 0x7C00; do if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC} -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : else AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr]) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index bf8fbfb9d..373b942cc 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -16,31 +16,31 @@ pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \ # For boot.img. boot_img_SOURCES = boot/i386/pc/boot.S boot_img_ASFLAGS = $(COMMON_ASFLAGS) -boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)7C00 +boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x7C00 boot_img_FORMAT = binary # For pxeboot.img pxeboot_img_SOURCES = boot/i386/pc/pxeboot.S pxeboot_img_ASFLAGS = $(COMMON_ASFLAGS) -pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)7C00 +pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x7C00 pxeboot_img_FORMAT = binary # For diskboot.img. diskboot_img_SOURCES = boot/i386/pc/diskboot.S diskboot_img_ASFLAGS = $(COMMON_ASFLAGS) -diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)8000 +diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x8000 diskboot_img_FORMAT = binary # For lnxboot.img. lnxboot_img_SOURCES = boot/i386/pc/lnxboot.S lnxboot_img_ASFLAGS = $(COMMON_ASFLAGS) -lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)6000 +lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x6000 lnxboot_img_FORMAT = binary # For cdboot.img. cdboot_img_SOURCES = boot/i386/pc/cdboot.S cdboot_img_ASFLAGS = $(COMMON_ASFLAGS) -cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)7C00 +cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x7C00 cdboot_img_FORMAT = binary # For kernel.img. From e4eb23732d11fa03938ae053449eae66d07a3971 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 16:23:23 +0000 Subject: [PATCH 053/146] 2009-11-08 Robert Millan * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve error message for coreboot users. --- ChangeLog | 5 +++++ kern/i386/multiboot_mmap.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 843be6dc5..57cb49d95 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-08 Robert Millan + + * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve error + message for coreboot users. + 2009-11-07 Robert Millan Fix build with GNU gold. diff --git a/kern/i386/multiboot_mmap.c b/kern/i386/multiboot_mmap.c index 8331bd5df..6578a4834 100644 --- a/kern/i386/multiboot_mmap.c +++ b/kern/i386/multiboot_mmap.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,7 @@ void grub_machine_mmap_init () { if (! startup_multiboot_info) - grub_fatal ("Must be loaded using Multiboot specification (is this an old version of coreboot?)"); + grub_fatal ("Unable to find Multiboot Information (is CONFIG_MULTIBOOT disabled in coreboot?)"); /* Move MBI to a safe place. */ grub_memmove (&kern_multiboot_info, startup_multiboot_info, sizeof (struct grub_multiboot_info)); From 31bd05ccca276daabd65eb26de6207af13f0f3ab Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 16:40:24 +0000 Subject: [PATCH 054/146] Add exec bit. --- autogen.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 autogen.sh diff --git a/autogen.sh b/autogen.sh old mode 100644 new mode 100755 From 0411481297c20dfc8b7913f32538cc738019a887 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 16:43:36 +0000 Subject: [PATCH 055/146] 2009-11-08 Robert Millan * autogen.sh: Use `sh gendistlist.sh' to avoid reliing on executable bit. --- ChangeLog | 5 +++++ autogen.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 57cb49d95..525a6d5e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-08 Robert Millan + + * autogen.sh: Use `sh gendistlist.sh' to avoid reliing on + executable bit. + 2009-11-08 Robert Millan * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve error diff --git a/autogen.sh b/autogen.sh index 4fb6bf7db..6751c8adc 100755 --- a/autogen.sh +++ b/autogen.sh @@ -10,6 +10,6 @@ for rmk in conf/*.rmk ${GRUB_CONTRIB}/*/conf/*.rmk; do ruby genmk.rb < $rmk > `echo $rmk | sed 's/\.rmk$/.mk/'` fi done -./gendistlist.sh > DISTLIST +sh gendistlist.sh > DISTLIST exit 0 From c02a7334960edaf716bd936efa1e7babd67406c6 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 16:57:31 +0000 Subject: [PATCH 056/146] Add a few files that were lost during transition from svn. --- include/grub/i386/coreboot/boot.h | 1 + include/grub/i386/coreboot/init.h | 28 ++++++++++++++++++++++++++++ include/grub/i386/coreboot/loader.h | 1 + include/grub/i386/coreboot/serial.h | 1 + include/grub/i386/coreboot/time.h | 1 + 5 files changed, 32 insertions(+) create mode 100644 include/grub/i386/coreboot/boot.h create mode 100644 include/grub/i386/coreboot/init.h create mode 100644 include/grub/i386/coreboot/loader.h create mode 100644 include/grub/i386/coreboot/serial.h create mode 100644 include/grub/i386/coreboot/time.h diff --git a/include/grub/i386/coreboot/boot.h b/include/grub/i386/coreboot/boot.h new file mode 100644 index 000000000..6cd23aa83 --- /dev/null +++ b/include/grub/i386/coreboot/boot.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/coreboot/init.h b/include/grub/i386/coreboot/init.h new file mode 100644 index 000000000..e67007414 --- /dev/null +++ b/include/grub/i386/coreboot/init.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_INIT_I386_LINUXBIOS_HEADER +#define GRUB_INIT_I386_LINUXBIOS_HEADER 1 + +#include +#include + +void EXPORT_FUNC(grub_stop) (void) __attribute__ ((noreturn)); +void EXPORT_FUNC(grub_stop_floppy) (void); + +#endif diff --git a/include/grub/i386/coreboot/loader.h b/include/grub/i386/coreboot/loader.h new file mode 100644 index 000000000..d3f36bba5 --- /dev/null +++ b/include/grub/i386/coreboot/loader.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/coreboot/serial.h b/include/grub/i386/coreboot/serial.h new file mode 100644 index 000000000..2c527f626 --- /dev/null +++ b/include/grub/i386/coreboot/serial.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/coreboot/time.h b/include/grub/i386/coreboot/time.h new file mode 100644 index 000000000..2298ee8f4 --- /dev/null +++ b/include/grub/i386/coreboot/time.h @@ -0,0 +1 @@ +#include From b97b7b914b09a757533119d818332a089b671c8d Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 20:02:16 +0000 Subject: [PATCH 057/146] 2009-11-08 Robert Millan * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve error message for excessively large memory map. --- ChangeLog | 5 +++++ kern/i386/multiboot_mmap.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 525a6d5e0..ac3950f2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-08 Robert Millan + + * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve + error message for excessively large memory map. + 2009-11-08 Robert Millan * autogen.sh: Use `sh gendistlist.sh' to avoid reliing on diff --git a/kern/i386/multiboot_mmap.c b/kern/i386/multiboot_mmap.c index 6578a4834..67d824313 100644 --- a/kern/i386/multiboot_mmap.c +++ b/kern/i386/multiboot_mmap.c @@ -51,7 +51,8 @@ grub_machine_mmap_init () /* Move the memory map to a safe place. */ if (kern_multiboot_info.mmap_length > sizeof (mmap_entries)) { - grub_printf ("WARNING: Memory map size exceeds limit; it will be truncated\n"); + grub_printf ("WARNING: Memory map size exceeds limit (0x%x > 0x%x); it will be truncated\n", + kern_multiboot_info.mmap_length, sizeof (mmap_entries)); kern_multiboot_info.mmap_length = sizeof (mmap_entries); } grub_memmove (mmap_entries, (void *) kern_multiboot_info.mmap_addr, kern_multiboot_info.mmap_length); From ef4b915ad982877fbc2e41f9fdb4a4bb57c853d2 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 20:56:32 +0000 Subject: [PATCH 058/146] Implement grub-mkrescue for coreboot (needs external grub-mkisofs) --- ChangeLog.branch | 5 + conf/i386-coreboot.rmk | 3 + util/i386/coreboot/grub-mkrescue.in | 144 ++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 ChangeLog.branch create mode 100644 util/i386/coreboot/grub-mkrescue.in diff --git a/ChangeLog.branch b/ChangeLog.branch new file mode 100644 index 000000000..4794498ff --- /dev/null +++ b/ChangeLog.branch @@ -0,0 +1,5 @@ +2009-11-08 Robert Millan + + * util/i386/coreboot/grub-mkrescue.in: New file. + * conf/i386-coreboot.rmk (bin_SCRIPTS, grub_mkrescue_SOURCES): New + variables. diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 09ec7787c..5645395b8 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -152,6 +152,9 @@ grub_emu_LDFLAGS = $(LIBCURSES) sbin_SCRIPTS += grub-install grub_install_SOURCES = util/i386/pc/grub-install.in +bin_SCRIPTS += grub-mkrescue +grub_mkrescue_SOURCES = util/i386/coreboot/grub-mkrescue.in + # Modules. pkglib_MODULES = linux.mod multiboot.mod \ aout.mod play.mod serial.mod ata.mod \ diff --git a/util/i386/coreboot/grub-mkrescue.in b/util/i386/coreboot/grub-mkrescue.in new file mode 100644 index 000000000..fbfc13841 --- /dev/null +++ b/util/i386/coreboot/grub-mkrescue.in @@ -0,0 +1,144 @@ +#! /bin/sh -e + +# Make GRUB rescue image +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. +# +# GRUB 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 3 of the License, or +# (at your option) any later version. +# +# GRUB 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 GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +platform=@platform@ +pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` + +grub_mkimage=${bindir}/`echo grub-mkelfimage | sed ${transform}` + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +input_dir=${pkglibdir} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "grub-mkrescue (GNU GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + --overlay=*) + overlay=${overlay}${overlay:+ }`echo "$option" | sed 's/--overlay=//'` ;; + --pkglibdir=*) + input_dir=`echo "$option" | sed 's/--pkglibdir=//'` ;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$output_image" != x; then + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + fi + output_image="${option}" ;; + esac +done + +if test "x$output_image" = x; then + usage + exit 1 +fi + +memdisk_dir=`mktemp -d` +iso9660_dir=`mktemp -d` +mkdir -p ${memdisk_dir}/boot/grub ${iso9660_dir}/boot/grub + +for file in ${input_dir}/*.mod ${input_dir}/efiemu??.o \ + ${input_dir}/command.lst ${input_dir}/moddep.lst ${input_dir}/fs.lst \ + ${input_dir}/handler.lst ${input_dir}/parttool.lst; do + if test -f "$file"; then + cp -f "$file" ${iso9660_dir}/boot/grub/ + fi +done + +# obtain date-based UUID +iso_uuid=$(date +%Y-%m-%d-%H-%M-%S-00) + +# first-stage grub.cfg +cat << EOF >> ${memdisk_dir}/boot/grub/grub.cfg +search --fs-uuid --set ${iso_uuid} +set prefix=(\${root})/boot/grub +source /boot/grub/grub.cfg +EOF + +# build memdisk +memdisk_img=`mktemp` +tar -C ${memdisk_dir} -cf ${memdisk_img} boot +rm -rf ${memdisk_dir} + +# build core.img +mkdir -p ${iso9660_dir}/boot/grub +${grub_mkimage} -d ${input_dir}/ -m ${memdisk_img} -o ${iso9660_dir}/boot/multiboot.img \ + at_keyboard memdisk tar ata search iso9660 configfile sh +rm -f ${memdisk_img} + +for d in ${overlay}; do + echo "Overlaying $d" + cp -dpR "${d}"/* "${iso9660_dir}"/ +done + +# second-stage grub.cfg +modules="`cat ${input_dir}/partmap.lst` ${modules}" +for i in ${modules} ; do + echo "insmod $i" +done > ${iso9660_dir}/boot/grub/grub.cfg + +# build iso image +grub-mkisofs \ + --modification-date=$(echo ${iso_uuid} | sed -e s/-//g) \ + -o ${output_image} -r -J ${iso9660_dir} + +exit 0 From 79cb3a568b3f7c7ea1f2fe42d37bc67aba40a6c9 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 21:52:59 +0000 Subject: [PATCH 059/146] Fix miss-identification as `grub-mkimage' (and use `$0' when possible). --- util/i386/pc/grub-mkrescue.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/i386/pc/grub-mkrescue.in b/util/i386/pc/grub-mkrescue.in index da937768b..cc581bffe 100644 --- a/util/i386/pc/grub-mkrescue.in +++ b/util/i386/pc/grub-mkrescue.in @@ -36,7 +36,7 @@ grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` # Print the usage. usage () { cat <. EOF @@ -67,7 +67,7 @@ for option in "$@"; do usage exit 0 ;; -v | --version) - echo "grub-mkrescue (GNU GRUB ${PACKAGE_VERSION})" + echo "$0 (GNU GRUB ${PACKAGE_VERSION})" exit 0 ;; --modules=*) modules=`echo "$option" | sed 's/--modules=//'` ;; From 3716b12ce271668bb02677dca7175fbea0f5dd86 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 21:55:25 +0000 Subject: [PATCH 060/146] 2009-11-08 Robert Millan * util/i386/pc/grub-mkrescue.in: Fix miss-identification as `grub-mkimage' (and use $0 when possible). --- ChangeLog | 5 +++++ util/i386/pc/grub-mkrescue.in | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ac3950f2e..d6c3b7927 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-08 Robert Millan + + * util/i386/pc/grub-mkrescue.in: Fix miss-identification as + `grub-mkimage' (and use $0 when possible). + 2009-11-08 Robert Millan * kern/i386/multiboot_mmap.c (grub_machine_mmap_init): Improve diff --git a/util/i386/pc/grub-mkrescue.in b/util/i386/pc/grub-mkrescue.in index da937768b..cc581bffe 100644 --- a/util/i386/pc/grub-mkrescue.in +++ b/util/i386/pc/grub-mkrescue.in @@ -36,7 +36,7 @@ grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` # Print the usage. usage () { cat <. EOF @@ -67,7 +67,7 @@ for option in "$@"; do usage exit 0 ;; -v | --version) - echo "grub-mkrescue (GNU GRUB ${PACKAGE_VERSION})" + echo "$0 (GNU GRUB ${PACKAGE_VERSION})" exit 0 ;; --modules=*) modules=`echo "$option" | sed 's/--modules=//'` ;; From 4b4c4f64002ab606034c8f7e1d76a74269b92018 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 22:51:08 +0000 Subject: [PATCH 061/146] Import http://www.tux.org/pub/people/eric-youngdale/mkisofs/mkisofs-1.11.3.tar.gz --- util/mkisofs/defaults.h | 44 ++ util/mkisofs/eltorito.c | 265 ++++++++ util/mkisofs/exclude.h | 10 + util/mkisofs/fnmatch.c | 226 +++++++ util/mkisofs/hash.c | 226 +++++++ util/mkisofs/iso9660.h | 157 +++++ util/mkisofs/match.c | 56 ++ util/mkisofs/match.h | 14 + util/mkisofs/mkisofs.c | 660 ++++++++++++++++++++ util/mkisofs/mkisofs.h | 339 ++++++++++ util/mkisofs/multi.c | 1018 ++++++++++++++++++++++++++++++ util/mkisofs/name.c | 390 ++++++++++++ util/mkisofs/rock.c | 556 +++++++++++++++++ util/mkisofs/tree.c | 1292 +++++++++++++++++++++++++++++++++++++++ util/mkisofs/write.c | 1142 ++++++++++++++++++++++++++++++++++ 15 files changed, 6395 insertions(+) create mode 100644 util/mkisofs/defaults.h create mode 100644 util/mkisofs/eltorito.c create mode 100644 util/mkisofs/exclude.h create mode 100644 util/mkisofs/fnmatch.c create mode 100644 util/mkisofs/hash.c create mode 100644 util/mkisofs/iso9660.h create mode 100644 util/mkisofs/match.c create mode 100644 util/mkisofs/match.h create mode 100644 util/mkisofs/mkisofs.c create mode 100644 util/mkisofs/mkisofs.h create mode 100644 util/mkisofs/multi.c create mode 100644 util/mkisofs/name.c create mode 100644 util/mkisofs/rock.c create mode 100644 util/mkisofs/tree.c create mode 100644 util/mkisofs/write.c diff --git a/util/mkisofs/defaults.h b/util/mkisofs/defaults.h new file mode 100644 index 000000000..91e678992 --- /dev/null +++ b/util/mkisofs/defaults.h @@ -0,0 +1,44 @@ +/* + * Header file defaults.h - assorted default values for character strings in + * the volume descriptor. + * + * $Id: defaults.h,v 1.4 1997/04/10 03:31:53 eric Rel $ + */ + +#define PREPARER_DEFAULT NULL +#define PUBLISHER_DEFAULT NULL +#define APPID_DEFAULT NULL +#define COPYRIGHT_DEFAULT NULL +#define BIBLIO_DEFAULT NULL +#define ABSTRACT_DEFAULT NULL +#define VOLSET_ID_DEFAULT NULL +#define VOLUME_ID_DEFAULT "CDROM" +#define BOOT_CATALOG_DEFAULT "boot.catalog" +#define BOOT_IMAGE_DEFAULT NULL +#ifdef __QNX__ +#define SYSTEM_ID_DEFAULT "QNX" +#endif + +#ifdef __osf__ +#define SYSTEM_ID_DEFAULT "OSF" +#endif + +#ifdef __sun +#define SYSTEM_ID_DEFAULT "Solaris" +#endif + +#ifdef __hpux +#define SYSTEM_ID_DEFAULT "HP-UX" +#endif + +#ifdef __sgi +#define SYSTEM_ID_DEFAULT "SGI" +#endif + +#ifdef _AIX +#define SYSTEM_ID_DEFAULT "AIX" +#endif + +#ifndef SYSTEM_ID_DEFAULT +#define SYSTEM_ID_DEFAULT "LINUX" +#endif diff --git a/util/mkisofs/eltorito.c b/util/mkisofs/eltorito.c new file mode 100644 index 000000000..0ac5a1290 --- /dev/null +++ b/util/mkisofs/eltorito.c @@ -0,0 +1,265 @@ +/* + * Program eltorito.c - Handle El Torito specific extensions to iso9660. + * + + Written by Michael Fulbright (1996). + + Copyright 1996 RedHat Software, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $"; + +#include +#include +#include +#include +#include +#include + +#include "mkisofs.h" +#include "iso9660.h" + +#undef MIN +#define MIN(a, b) (((a) < (b))? (a): (b)) + +static struct eltorito_validation_entry valid_desc; +static struct eltorito_defaultboot_entry default_desc; + +/* + * Check for presence of boot catalog. If it does not exist then make it + */ +void FDECL1(init_boot_catalog, const char *, path) +{ + + int bcat; + char * bootpath; /* filename of boot catalog */ + char * buf; + struct stat statbuf; + + bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2); + strcpy(bootpath, path); + if (bootpath[strlen(bootpath)-1] != '/') + { + strcat(bootpath,"/"); + } + + strcat(bootpath, boot_catalog); + + /* + * check for the file existing + */ +#ifdef DEBUG_TORITO + printf("Looking for boot catalog file %s\n",bootpath); +#endif + + if (!stat_filter(bootpath, &statbuf)) + { + /* + * make sure its big enough to hold what we want + */ + if (statbuf.st_size == 2048) + { + /* + * printf("Boot catalog exists, so we do nothing\n"); + */ + free(bootpath); + return; + } + else + { + fprintf(stderr, "A boot catalog exists and appears corrupted.\n"); + fprintf(stderr, "Please check the following file: %s.\n",bootpath); + fprintf(stderr, "This file must be removed before a bootable CD can be done.\n"); + free(bootpath); + exit(1); + } + } + + /* + * file does not exist, so we create it + * make it one CD sector long + */ + bcat = open(bootpath, O_WRONLY | O_CREAT, S_IROTH | S_IRGRP | S_IRWXU ); + if (bcat == -1) + { + fprintf(stderr, "Error creating boot catalog, exiting...\n"); + perror(""); + exit(1); + } + + buf = (char *) e_malloc( 2048 ); + write(bcat, buf, 2048); + close(bcat); + free(bootpath); +} /* init_boot_catalog(... */ + +void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) +{ + int bootcat; + int checksum; + unsigned char * checksum_ptr; + struct directory_entry * de; + struct directory_entry * de2; + int i; + int nsectors; + + memset(boot_desc, 0, sizeof(*boot_desc)); + boot_desc->id[0] = 0; + memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + boot_desc->version[0] = 1; + + memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID)); + + /* + * search from root of iso fs to find boot catalog + */ + de2 = search_tree_file(root, boot_catalog); + if (!de2) + { + fprintf(stderr,"Uh oh, I cant find the boot catalog!\n"); + exit(1); + } + + set_731(boot_desc->bootcat_ptr, + (unsigned int) get_733(de2->isorec.extent)); + + /* + * now adjust boot catalog + * lets find boot image first + */ + de=search_tree_file(root, boot_image); + if (!de) + { + fprintf(stderr,"Uh oh, I cant find the boot image!\n"); + exit(1); + } + + /* + * we have the boot image, so write boot catalog information + * Next we write out the primary descriptor for the disc + */ + memset(&valid_desc, 0, sizeof(valid_desc)); + valid_desc.headerid[0] = 1; + valid_desc.arch[0] = EL_TORITO_ARCH_x86; + + /* + * we'll shove start of publisher id into id field, may get truncated + * but who really reads this stuff! + */ + if (publisher) + memcpy_max(valid_desc.id, publisher, MIN(23, strlen(publisher))); + + valid_desc.key1[0] = 0x55; + valid_desc.key2[0] = 0xAA; + + /* + * compute the checksum + */ + checksum=0; + checksum_ptr = (unsigned char *) &valid_desc; + for (i=0; isize + 511) & ~(511))/512; + printf("\nSize of boot image is %d sectors -> ", nsectors); + + /* + * choose size of emulated floppy based on boot image size + */ + if (nsectors == 2880 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; + printf("Emulating a 1.44 meg floppy\n"); + } + else if (nsectors == 5760 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; + printf("Emulating a 2.88 meg floppy\n"); + } + else if (nsectors == 2400 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; + printf("Emulating a 1.2 meg floppy\n"); + } + else + { + fprintf(stderr,"\nError - boot image is not the an allowable size.\n"); + exit(1); + } + + + /* + * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!! + */ + nsectors = 1; + set_721(default_desc.nsect, (unsigned int) nsectors ); +#ifdef DEBUG_TORITO + printf("Extent of boot images is %d\n",get_733(de->isorec.extent)); +#endif + set_731(default_desc.bootoff, + (unsigned int) get_733(de->isorec.extent)); + + /* + * now write it to disk + */ + bootcat = open(de2->whole_name, O_RDWR); + if (bootcat == -1) + { + fprintf(stderr,"Error opening boot catalog for update.\n"); + perror(""); + exit(1); + } + + /* + * write out + */ + write(bootcat, &valid_desc, 32); + write(bootcat, &default_desc, 32); + close(bootcat); +} /* get_torito_desc(... */ diff --git a/util/mkisofs/exclude.h b/util/mkisofs/exclude.h new file mode 100644 index 000000000..b9581a9e9 --- /dev/null +++ b/util/mkisofs/exclude.h @@ -0,0 +1,10 @@ +/* + * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de: + * added 'exclude' option (-x) to specify pathnames NOT to be included in + * CD image. + * + * $Id: exclude.h,v 1.1 1997/02/23 15:53:19 eric Rel $ + */ + +void exclude(); +int is_excluded(); diff --git a/util/mkisofs/fnmatch.c b/util/mkisofs/fnmatch.c new file mode 100644 index 000000000..cd5c0b27c --- /dev/null +++ b/util/mkisofs/fnmatch.c @@ -0,0 +1,226 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $"; + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifndef FNM_FILE_NAME +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#endif + +#ifndef FNM_LEADING_DIR +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#endif + +#ifndef FNM_CASEFOLD +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + + +#include + +#if defined (STDC_HEADERS) || !defined (isascii) +#define ISASCII(c) 1 +#else +#define ISASCII(c) isascii(c) +#endif + +#define ISUPPER(c) (ISASCII (c) && isupper (c)) + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/util/mkisofs/hash.c b/util/mkisofs/hash.c new file mode 100644 index 000000000..67098d580 --- /dev/null +++ b/util/mkisofs/hash.c @@ -0,0 +1,226 @@ +/* + * File hash.c - generate hash tables for iso9660 filesystem. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: hash.c,v 1.2 1997/02/23 16:11:15 eric Rel $"; + +#include +#include "mkisofs.h" + +#define NR_HASH 1024 + +#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH) + +static struct file_hash * hash_table[NR_HASH] = {0,}; + +void FDECL1(add_hash, struct directory_entry *, spnt){ + struct file_hash * s_hash; + unsigned int hash_number; + + if(spnt->size == 0 || spnt->starting_block == 0) + if(spnt->size != 0 || spnt->starting_block != 0) { + fprintf(stderr,"Non zero-length file assigned zero extent.\n"); + exit(1); + }; + + if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return; + hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode); + +#if 0 + if (verbose) fprintf(stderr,"%s ",spnt->name); +#endif + s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); + s_hash->next = hash_table[hash_number]; + s_hash->inode = spnt->inode; + s_hash->dev = spnt->dev; + s_hash->starting_block = spnt->starting_block; + s_hash->size = spnt->size; + hash_table[hash_number] = s_hash; +} + +struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){ + unsigned int hash_number; + struct file_hash * spnt; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; + + spnt = hash_table[hash_number]; + while(spnt){ + if(spnt->inode == inode && spnt->dev == dev) return spnt; + spnt = spnt->next; + }; + return NULL; +} + + +static struct file_hash * directory_hash_table[NR_HASH] = {0,}; + +void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){ + struct file_hash * s_hash; + unsigned int hash_number; + + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + + s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); + s_hash->next = directory_hash_table[hash_number]; + s_hash->inode = inode; + s_hash->dev = dev; + directory_hash_table[hash_number] = s_hash; +} + +struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){ + unsigned int hash_number; + struct file_hash * spnt; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; + + spnt = directory_hash_table[hash_number]; + while(spnt){ + if(spnt->inode == inode && spnt->dev == dev) return spnt; + spnt = spnt->next; + }; + return NULL; +} + +struct name_hash +{ + struct name_hash * next; + struct directory_entry * de; +}; + +#define NR_NAME_HASH 128 + +static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,}; + +/* + * Find the hash bucket for this name. + */ +static unsigned int FDECL1(name_hash, const char *, name) +{ + unsigned int hash = 0; + const char * p; + + p = name; + + while (*p) + { + /* + * Don't hash the iso9660 version number. This way + * we can detect duplicates in cases where we have + * directories (i.e. foo) and non-directories + * (i.e. foo;1). + */ + if( *p == ';' ) + { + break; + } + hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++; + } + return hash % NR_NAME_HASH; +} + +void FDECL1(add_file_hash, struct directory_entry *, de){ + struct name_hash * new; + int hash; + + new = (struct name_hash *) e_malloc(sizeof(struct name_hash)); + new->de = de; + new->next = NULL; + hash = name_hash(de->isorec.name); + + /* Now insert into the hash table */ + new->next = name_hash_table[hash]; + name_hash_table[hash] = new; +} + +struct directory_entry * FDECL1(find_file_hash, char *, name) +{ + struct name_hash * nh; + char * p1; + char * p2; + + for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) + { + p1 = name; + p2 = nh->de->isorec.name; + + /* + * Look for end of string, or a mismatch. + */ + while(1==1) + { + if( (*p1 == '\0' || *p1 == ';') + || (*p2 == '\0' || *p2 == ';') + || (*p1 != *p2) ) + { + break; + } + p1++; + p2++; + } + + /* + * If we are at the end of both strings, then + * we have a match. + */ + if( (*p1 == '\0' || *p1 == ';') + && (*p2 == '\0' || *p2 == ';') ) + { + return nh->de; + } + } + return NULL; +} + +int FDECL1(delete_file_hash, struct directory_entry *, de){ + struct name_hash * nh, *prev; + int hash; + + prev = NULL; + hash = name_hash(de->isorec.name); + for(nh = name_hash_table[hash]; nh; nh = nh->next) { + if(nh->de == de) break; + prev = nh; + } + if(!nh) return 1; + if(!prev) + name_hash_table[hash] = nh->next; + else + prev->next = nh->next; + free(nh); + return 0; +} + +void flush_file_hash(){ + struct name_hash * nh, *nh1; + int i; + + for(i=0; inext; + free(nh); + nh = nh1; + } + name_hash_table[i] = NULL; + + } +} diff --git a/util/mkisofs/iso9660.h b/util/mkisofs/iso9660.h new file mode 100644 index 000000000..a58f96f0d --- /dev/null +++ b/util/mkisofs/iso9660.h @@ -0,0 +1,157 @@ +/* + * Header file iso9660.h - assorted structure definitions and typecasts. + * specific to iso9660 filesystem. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: iso9660.h,v 1.1 1997/02/23 15:55:25 eric Rel $ + */ + +#ifndef _ISOFS_FS_H +#define _ISOFS_FS_H + +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +#define EL_TORITO_ID "EL TORITO SPECIFICATION" +#define EL_TORITO_ARCH_x86 0 +#define EL_TORITO_ARCH_PPC 1 +#define EL_TORITO_ARCH_MAC 2 +#define EL_TORITO_BOOTABLE 0x88 +#define EL_TORITO_MEDIA_NOEMUL 0 +#define EL_TORITO_MEDIA_12FLOP 1 +#define EL_TORITO_MEDIA_144FLOP 2 +#define EL_TORITO_MEDIA_288FLOP 3 +#define EL_TORITO_MEDIA_HD 4 + +struct iso_primary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char unused1 [ISODCL ( 8, 8)]; + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char unused3 [ISODCL ( 89, 120)]; + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +/* El Torito Boot Record Volume Descriptor */ +struct eltorito_boot_descriptor { + char id [ISODCL ( 1, 1)]; /* 711 */ + char id2 [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char system_id [ISODCL ( 8, 39)]; + char unused2 [ISODCL ( 40, 71)]; + char bootcat_ptr [ISODCL ( 72 , 75)]; + char unused5 [ISODCL ( 76, 2048)]; +}; + +/* Validation entry for El Torito */ +struct eltorito_validation_entry { + char headerid [ISODCL ( 1, 1)]; /* 711 */ + char arch [ISODCL ( 2, 2)]; + char pad1 [ISODCL ( 3, 4)]; /* 711 */ + char id [ISODCL ( 5, 28)]; + char cksum [ISODCL ( 29, 30)]; + char key1 [ISODCL ( 31, 31)]; + char key2 [ISODCL ( 32, 32)]; +}; + +/* El Torito initial/default entry in boot catalog */ +struct eltorito_defaultboot_entry { + char boot_id [ISODCL ( 1, 1)]; /* 711 */ + char boot_media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; /* 711 */ + char arch [ISODCL ( 5, 5)]; + char pad1 [ISODCL ( 6, 6)]; + char nsect [ISODCL ( 7, 8)]; + char bootoff [ISODCL ( 9, 12)]; + char pad2 [ISODCL ( 13, 32)]; +}; + + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ + unsigned char name_len[2]; /* 721 */ + char extent[4]; /* 731 */ + char parent[2]; /* 721 */ + char name[1]; +}; + +struct iso_directory_record { + unsigned char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + char name [34]; /* Not really, but we need something here */ +}; +#endif + + + diff --git a/util/mkisofs/match.c b/util/mkisofs/match.c new file mode 100644 index 000000000..0f5c7d8a7 --- /dev/null +++ b/util/mkisofs/match.c @@ -0,0 +1,56 @@ +/* + * 27-Mar-96: Jan-Piet Mens + * added 'match' option (-m) to specify regular expressions NOT to be included + * in the CD image. + */ + +static char rcsid[] ="$Id: match.c,v 1.2 1997/02/23 16:10:42 eric Rel $"; + +#include +#ifndef VMS +#ifdef HAVE_MALLOC_H +#include +#else +#include +#endif +#endif +#include +#include "match.h" + +#define MAXMATCH 1000 +static char *mat[MAXMATCH]; + +void add_match(fn) +char * fn; +{ + register int i; + + for (i=0; mat[i] && i excluded filenmae */ + } + } + return 0; /* not found -> not excluded */ +} diff --git a/util/mkisofs/match.h b/util/mkisofs/match.h new file mode 100644 index 000000000..90def7c2d --- /dev/null +++ b/util/mkisofs/match.h @@ -0,0 +1,14 @@ +/* + * 27th March 1996. Added by Jan-Piet Mens for matching regular expressions + * in paths. + * + */ + +/* + * $Id: match.h,v 1.1 1997/02/23 15:56:12 eric Rel $ + */ + +#include "fnmatch.h" + +void add_match(); +int matches(); diff --git a/util/mkisofs/mkisofs.c b/util/mkisofs/mkisofs.c new file mode 100644 index 000000000..a2e2d1874 --- /dev/null +++ b/util/mkisofs/mkisofs.c @@ -0,0 +1,660 @@ +/* + * Program mkisofs.c - generate iso9660 filesystem based upon directory + * tree on hard disk. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: mkisofs.c,v 1.10.1.3 1998/06/02 03:36:16 eric Exp $"; + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include +#include "mkisofs.h" +#include "config.h" + +#ifdef linux +#include +#endif + +#include "iso9660.h" +#include + +#ifndef VMS +#include +#else +#include +#include "vms.h" +#endif + +#include +#include + +#ifndef VMS +#ifdef HAVE_UNISTD_H +#include +#endif +#endif + +#include "exclude.h" + +#ifdef __NetBSD__ +#include +#include +#endif + +struct directory * root = NULL; + +static char version_string[] = "mkisofs v1.11.3"; + +FILE * discimage; +unsigned int next_extent = 0; +unsigned int last_extent = 0; +unsigned int session_start = 0; +unsigned int path_table_size = 0; +unsigned int path_table[4] = {0,}; +unsigned int path_blocks = 0; +struct iso_directory_record root_record; +char * extension_record = NULL; +int extension_record_extent = 0; +static int extension_record_size = 0; + +/* These variables are associated with command line options */ +int use_eltorito = 0; +int use_RockRidge = 0; +int verbose = 0; +int all_files = 0; +int follow_links = 0; +int rationalize = 0; +int generate_tables = 0; +char * preparer = PREPARER_DEFAULT; +char * publisher = PUBLISHER_DEFAULT; +char * appid = APPID_DEFAULT; +char * copyright = COPYRIGHT_DEFAULT; +char * biblio = BIBLIO_DEFAULT; +char * abstract = ABSTRACT_DEFAULT; +char * volset_id = VOLSET_ID_DEFAULT; +char * volume_id = VOLUME_ID_DEFAULT; +char * system_id = SYSTEM_ID_DEFAULT; +char * boot_catalog = BOOT_CATALOG_DEFAULT; +char * boot_image = BOOT_IMAGE_DEFAULT; + +int omit_period = 0; /* Violates iso9660, but these are a pain */ +int transparent_compression = 0; /* So far only works with linux */ +int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/ +int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ +int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with + DOS */ +int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ + +struct rcopts{ + char * tag; + char ** variable; +}; + +struct rcopts rcopt[] = { + {"PREP", &preparer}, + {"PUBL", &publisher}, + {"APPI", &appid}, + {"COPY", ©right}, + {"BIBL", &biblio}, + {"ABST", &abstract}, + {"VOLS", &volset_id}, + {"VOLI", &volume_id}, + {"SYSI", &system_id}, + {NULL, NULL} +}; + +#if defined(ultrix) || defined(_AUX_SOURCE) +char *strdup(s) +char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} +#endif + +void FDECL1(read_rcfile, char *, appname) +{ + FILE * rcfile; + struct rcopts * rco; + char * pnt, *pnt1; + char linebuffer[256]; + static char rcfn[] = ".mkisofsrc"; + char filename[1000]; + int linum; + + strcpy(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + + if (!rcfile) + { + pnt = getenv("MKISOFSRC"); + if (pnt && strlen(pnt) <= sizeof(filename)) + { + strcpy(filename, pnt); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + + if (!rcfile) + { + pnt = getenv("HOME"); + if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) + { + strcpy(filename, pnt); + strcat(filename, "/"); + strcat(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) + { + strcpy(filename, appname); + pnt = strrchr(filename, '/'); + if (pnt) + { + strcpy(pnt + 1, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile) + return; + fprintf(stderr, "Using \"%s\"\n", filename); + /* OK, we got it. Now read in the lines and parse them */ + linum = 0; + while (fgets(linebuffer, sizeof(linebuffer), rcfile)) + { + char *name; + char *name_end; + ++linum; + /* skip any leading white space */ + pnt = linebuffer; + while (*pnt == ' ' || *pnt == '\t') + ++pnt; + /* If we are looking at a # character, this line is a comment. */ + if (*pnt == '#') + continue; + /* The name should begin in the left margin. Make sure it is in + upper case. Stop when we see white space or a comment. */ + name = pnt; + while (*pnt && isalpha(*pnt)) + { + if(islower(*pnt)) + *pnt = toupper(*pnt); + pnt++; + } + if (name == pnt) + { + fprintf(stderr, "%s:%d: name required\n", filename, linum); + continue; + } + name_end = pnt; + /* Skip past white space after the name */ + while (*pnt == ' ' || *pnt == '\t') + pnt++; + /* silently ignore errors in the rc file. */ + if (*pnt != '=') + { + fprintf(stderr, "%s:%d: equals sign required\n", filename, linum); + continue; + } + /* Skip pas the = sign, and any white space following it */ + pnt++; /* Skip past '=' sign */ + while (*pnt == ' ' || *pnt == '\t') + pnt++; + + /* now it is safe to NUL terminate the name */ + + *name_end = 0; + + /* Now get rid of trailing newline */ + + pnt1 = pnt; + while (*pnt1) + { + if (*pnt1 == '\n') + { + *pnt1 = 0; + break; + } + pnt1++; + }; + /* OK, now figure out which option we have */ + for(rco = rcopt; rco->tag; rco++) { + if(strcmp(rco->tag, name) == 0) + { + *rco->variable = strdup(pnt); + break; + }; + } + if (rco->tag == NULL) + { + fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum, + name); + } + } + if (ferror(rcfile)) + perror(filename); + fclose(rcfile); +} + +char * path_table_l = NULL; +char * path_table_m = NULL; +int goof = 0; + +void usage(){ + fprintf(stderr,"Usage:\n"); + fprintf(stderr, +"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ +[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" +#ifdef ADD_FILES +"[-i file] \n" +#endif +"[-P publisher] [ -A app_id ] [-z] \n \ +[-b boot_image_name] [-c boot_catalog-name] \ +[-x path -x path ...] path\n"); + exit(1); +} + + +/* + * Fill in date in the iso9660 format + * + * The standards state that the timezone offset is in multiples of 15 + * minutes, and is what you add to GMT to get the localtime. The U.S. + * is always at a negative offset, from -5h to -8h (can vary a little + * with DST, I guess). The Linux iso9660 filesystem has had the sign + * of this wrong for ages (mkisofs had it wrong too for the longest time). + */ +int FDECL2(iso9660_date,char *, result, time_t, ctime){ + struct tm *local; + local = localtime(&ctime); + result[0] = local->tm_year; + result[1] = local->tm_mon + 1; + result[2] = local->tm_mday; + result[3] = local->tm_hour; + result[4] = local->tm_min; + result[5] = local->tm_sec; + + /* + * Must recalculate proper timezone offset each time, + * as some files use daylight savings time and some don't... + */ + result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ + local = gmtime(&ctime); + local->tm_year -= result[0]; + local->tm_yday -= result[6]; + local->tm_hour -= result[3]; + local->tm_min -= result[4]; + if (local->tm_year < 0) + { + local->tm_yday = -1; + } + else + { + if (local->tm_year > 0) local->tm_yday = 1; + } + + result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; + + return 0; +} + + +extern char * cdwrite_data; + +int FDECL2(main, int, argc, char **, argv){ + char * outfile; + struct directory_entry de; + unsigned long mem_start; + struct stat statbuf; + char * scan_tree; + char * merge_image = NULL; + struct iso_directory_record * mrootp = NULL; + int c; +#ifdef ADD_FILES + char *add_file_file = NULL; +#endif + + if (argc < 2) + usage(); + + /* Get the defaults from the .mkisofsrc file */ + read_rcfile(argv[0]); + + outfile = NULL; + while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF) + switch (c) + { + case 'C': + /* + * This is a temporary hack until cdwrite gets the proper hooks in + * it. + */ + cdwrite_data = optarg; + break; + case 'a': + all_files++; + break; + case 'b': + use_eltorito++; + boot_image = optarg; /* pathname of the boot image on cd */ + if (boot_image == NULL) { + fprintf(stderr,"Required boot image pathname missing\n"); + exit(1); + } + break; + case 'c': + use_eltorito++; + boot_catalog = optarg; /* pathname of the boot image on cd */ + if (boot_catalog == NULL) { + fprintf(stderr,"Required boot catalog pathname missing\n"); + exit(1); + } + break; + case 'A': + appid = optarg; + if(strlen(appid) > 128) { + fprintf(stderr,"Application-id string too long\n"); + exit(1); + }; + break; + case 'd': + omit_period++; + break; + case 'D': + RR_relocation_depth = 32767; + break; + case 'f': + follow_links++; + break; + case 'i': +#ifdef ADD_FILES + add_file_file = optarg; + break; +#else + usage(); + exit(1); +#endif + case 'l': + full_iso9660_filenames++; + break; + case 'L': + allow_leading_dots++; + break; + case 'M': + merge_image = optarg; + break; + case 'N': + omit_version_number++; + break; + case 'o': + outfile = optarg; + break; + case 'p': + preparer = optarg; + if(strlen(preparer) > 128) { + fprintf(stderr,"Preparer string too long\n"); + exit(1); + }; + break; + case 'P': + publisher = optarg; + if(strlen(publisher) > 128) { + fprintf(stderr,"Publisher string too long\n"); + exit(1); + }; + break; + case 'R': + use_RockRidge++; + break; + case 'r': + rationalize++; + use_RockRidge++; + break; + case 'T': + generate_tables++; + break; + case 'V': + volume_id = optarg; + break; + case 'v': + verbose++; + break; + case 'z': +#ifdef VMS + fprintf(stderr,"Transparent compression not supported with VMS\n"); + exit(1); +#else + transparent_compression++; +#endif + break; + case 'm': + add_match(optarg); + break; + case 'x': + exclude(optarg); + break; + default: + usage(); + exit(1); + } +#ifdef __NetBSD__ + { + int resource; + struct rlimit rlp; + if (getrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: getrlimit"); + else { + rlp.rlim_cur=33554432; + if (setrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: setrlimit"); + } + } +#endif +#ifdef HAVE_SBRK + mem_start = (unsigned long) sbrk(0); +#endif + + if(verbose) fprintf(stderr,"%s\n", version_string); + + if( (cdwrite_data != NULL && merge_image == NULL) + || (cdwrite_data == NULL && merge_image != NULL) ) + { + fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n"); + exit(0); + } + + /* The first step is to scan the directory tree, and take some notes */ + + scan_tree = argv[optind]; + +#ifdef ADD_FILES + if (add_file_file) { + add_file(add_file_file); + } + add_file_list (argc, argv, optind+1); +#endif + + if(!scan_tree){ + usage(); + exit(1); + }; + +#ifndef VMS + if(scan_tree[strlen(scan_tree)-1] != '/') { + scan_tree = (char *) e_malloc(strlen(argv[optind])+2); + strcpy(scan_tree, argv[optind]); + strcat(scan_tree, "/"); + }; +#endif + + if(use_RockRidge){ +#if 1 + extension_record = generate_rr_extension_record("RRIP_1991A", + "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", + "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); +#else + extension_record = generate_rr_extension_record("IEEE_P1282", + "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", + "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); +#endif + } + + /* + * See if boot catalog file exists in root directory, if not + * we will create it. + */ + if (use_eltorito) + init_boot_catalog(argv[optind]); + + /* + * Find the device and inode number of the root directory. + * Record this in the hash table so we don't scan it more than + * once. + */ + stat_filter(argv[optind], &statbuf); + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + + memset(&de, 0, sizeof(de)); + + de.filedir = root; /* We need this to bootstrap */ + + if( merge_image != NULL ) + { + mrootp = merge_isofs(merge_image); + if( mrootp == NULL ) + { + /* + * Complain and die. + */ + fprintf(stderr,"Unable to open previous session image %s\n", + merge_image); + exit(1); + } + + memcpy(&de.isorec.extent, mrootp->extent, 8); + } + + /* + * Scan the actual directory (and any we find below it) + * for files to write out to the output image. + */ + if (!scan_directory_tree(argv[optind], &de, mrootp)) + { + exit(1); + } + + /* + * Fix a couple of things in the root directory so that everything + * is self consistent. + */ + root->self = root->contents; /* Fix this up so that the path tables get done right */ + + if(reloc_dir) sort_n_finish(reloc_dir); + + if (goof) exit(1); + + /* + * OK, ready to write the file. Open it up, and generate the thing. + */ + if (outfile){ + discimage = fopen(outfile, "w"); + if (!discimage){ + fprintf(stderr,"Unable to open disc image file\n"); + exit(1); + + }; + } else + discimage = stdout; + + /* Now assign addresses on the disc for the path table. */ + + path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; + if (path_blocks & 1) path_blocks++; + + path_table[0] = session_start + 0x10 + 2 + (use_eltorito ? 1 : 0); + path_table[1] = 0; + path_table[2] = path_table[0] + path_blocks; + path_table[3] = 0; + + last_extent += path_table[2] - session_start + path_blocks; + /* The next free block */ + + /* The next step is to go through the directory tree and assign extent + numbers for all of the directories */ + + assign_directory_addresses(root); + + if(extension_record) { + struct directory_entry * s_entry; + extension_record_extent = last_extent++; + s_entry = root->contents; + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24, + extension_record_extent); + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8, + extension_record_size); + }; + + if (use_RockRidge && reloc_dir) + finish_cl_pl_entries(); + + /* Now we generate the path tables that are used by DOS to improve directory + access times. */ + generate_path_tables(); + + /* Generate root record for volume descriptor. */ + generate_root_record(); + + if (verbose) + dump_tree(root); + + if( in_image != NULL ) + { + fclose(in_image); + } + + iso_write(discimage); + +#ifdef HAVE_SBRK + fprintf(stderr,"Max brk space used %x\n", + (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); +#endif + fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9); +#ifdef VMS + return 1; +#else + return 0; +#endif +} + +void * +FDECL1(e_malloc, size_t, size) +{ +void* pt = 0; + if( (size > 0) && ((pt=malloc(size))==NULL) ) { + fprintf(stderr, "Not enough memory\n"); + exit (1); + } +return pt; +} diff --git a/util/mkisofs/mkisofs.h b/util/mkisofs/mkisofs.h new file mode 100644 index 000000000..bc264d99a --- /dev/null +++ b/util/mkisofs/mkisofs.h @@ -0,0 +1,339 @@ +/* + * Header file mkisofs.h - assorted structure definitions and typecasts. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: mkisofs.h,v 1.5 1997/05/17 15:50:28 eric Exp $ + */ + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include + +/* This symbol is used to indicate that we do not have things like + symlinks, devices, and so forth available. Just files and dirs */ + +#ifdef VMS +#define NON_UNIXFS +#endif + +#ifdef DJGPP +#define NON_UNIXFS +#endif + +#ifdef VMS +#include +#define dirent direct +#else +#include +#endif + +#include +#include +#include + +#ifdef linux +#include +#endif + +#ifdef ultrix +extern char *strdup(); +#endif + +#ifdef __STDC__ +#define DECL(NAME,ARGS) NAME ARGS +#define FDECL1(NAME,TYPE0, ARG0) \ + NAME(TYPE0 ARG0) +#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \ + NAME(TYPE0 ARG0, TYPE1 ARG1) +#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2) +#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3) +#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4) +#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5) +#else +#define DECL(NAME,ARGS) NAME() +#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0; +#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1; +#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ + NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; +#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; +#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; +#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5; +#define const +#endif + + +#ifdef __svr4__ +#include +#else +extern int optind; +extern char *optarg; +/* extern int getopt (int __argc, char **__argv, char *__optstring); */ +#endif + +#include "iso9660.h" +#include "defaults.h" + +struct directory_entry{ + struct directory_entry * next; + struct iso_directory_record isorec; + unsigned int starting_block; + unsigned int size; + unsigned int priority; + char * name; + char * table; + char * whole_name; + struct directory * filedir; + struct directory_entry * parent_rec; + unsigned int de_flags; + ino_t inode; /* Used in the hash table */ + dev_t dev; /* Used in the hash table */ + unsigned char * rr_attributes; + unsigned int rr_attr_size; + unsigned int total_rr_attr_size; +}; + +struct file_hash{ + struct file_hash * next; + ino_t inode; /* Used in the hash table */ + dev_t dev; /* Used in the hash table */ + unsigned int starting_block; + unsigned int size; +}; + +/* + * This structure describes one complete directory. It has pointers + * to other directories in the overall tree so that it is clear where + * this directory lives in the tree, and it also must contain pointers + * to the contents of the directory. Note that subdirectories of this + * directory exist twice in this stucture. Once in the subdir chain, + * and again in the contents chain. + */ +struct directory{ + struct directory * next; /* Next directory at same level as this one */ + struct directory * subdir; /* First subdirectory in this directory */ + struct directory * parent; + struct directory_entry * contents; + struct directory_entry * self; + char * whole_name; /* Entire path */ + char * de_name; /* Entire path */ + unsigned int ce_bytes; /* Number of bytes of CE entries reqd for this dir */ + unsigned int depth; + unsigned int size; + unsigned int extent; + unsigned short path_index; +}; + +struct deferred{ + struct deferred * next; + unsigned int starting_block; + char * name; + struct directory * filedir; + unsigned int flags; +}; + +extern int goof; +extern struct directory * root; +extern struct directory * reloc_dir; +extern unsigned int next_extent; +extern unsigned int last_extent; +extern unsigned int last_extent_written; +extern unsigned int session_start; +extern unsigned int path_table_size; +extern unsigned int path_table[4]; +extern unsigned int path_blocks; +extern char * path_table_l; +extern char * path_table_m; +extern struct iso_directory_record root_record; + +extern int use_eltorito; +extern int use_RockRidge; +extern int rationalize; +extern int follow_links; +extern int verbose; +extern int all_files; +extern int generate_tables; +extern int omit_period; +extern int omit_version_number; +extern int transparent_compression; +extern int RR_relocation_depth; +extern int full_iso9660_filenames; + +/* tree.c */ +extern int DECL(stat_filter, (char *, struct stat *)); +extern void DECL(sort_n_finish,(struct directory *)); +extern void finish_cl_pl_entries(); +extern int DECL(scan_directory_tree,(char * path, + struct directory_entry * self, + struct iso_directory_record *)); +extern void DECL(generate_iso9660_directories,(struct directory *, FILE*)); +extern void DECL(dump_tree,(struct directory * node)); +extern struct directory_entry * DECL(search_tree_file, (struct + directory * node,char * filename)); + +/* eltorito.c */ +extern void DECL(init_boot_catalog, (const char * path )); +extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path )); + +/* write.c */ +extern void DECL(assign_directory_addresses,(struct directory * root)); +extern int DECL(get_733,(char *)); +extern int DECL(isonum_733,(unsigned char *)); +extern void DECL(set_723,(char *, unsigned int)); +extern void DECL(set_731,(char *, unsigned int)); +extern void DECL(set_721,(char *, unsigned int)); +extern void DECL(set_733,(char *, unsigned int)); +extern void DECL(sort_directory,(struct directory_entry **)); +extern void generate_root_record(); +extern void DECL(generate_one_directory,(struct directory *, FILE*)); +extern void generate_path_tables(); +extern int DECL(iso_write,(FILE * outfile)); +extern void DECL(memcpy_max, (char *, char *, int)); + + +/* multi.c */ + +extern FILE * in_image; +extern struct iso_directory_record * + DECL(merge_isofs,(char * path)); + +extern int DECL(free_mdinfo, (struct directory_entry **, int len)); + +extern struct directory_entry ** + DECL(read_merging_directory,(struct iso_directory_record *, int*)); +extern void + DECL(merge_remaining_entries, (struct directory *, + struct directory_entry **, int)); + +/* match.c */ +extern int DECL(matches, (char *)); +extern void DECL(add_match, (char *)); + +/* files.c */ +struct dirent * DECL(readdir_add_files, (char **, char *, DIR *)); + +/* */ + +extern int DECL(iso9660_file_length,(const char* name, + struct directory_entry * sresult, int flag)); +extern int DECL(iso9660_date,(char *, time_t)); +extern void DECL(add_hash,(struct directory_entry *)); +extern struct file_hash * DECL(find_hash,(dev_t, ino_t)); +extern void DECL(add_directory_hash,(dev_t, ino_t)); +extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t)); +extern void flush_file_hash(); +extern int DECL(delete_file_hash,(struct directory_entry *)); +extern struct directory_entry * DECL(find_file_hash,(char *)); +extern void DECL(add_file_hash,(struct directory_entry *)); +extern int DECL(generate_rock_ridge_attributes,(char *, char *, + struct directory_entry *, + struct stat *, struct stat *, + int deep_flag)); +extern char * DECL(generate_rr_extension_record,(char * id, char * descriptor, + char * source, int * size)); + +extern int DECL(check_prev_session, (struct directory_entry **, int len, + struct directory_entry *, + struct stat *, + struct stat *, + struct directory_entry **)); + +#ifdef USE_SCG +/* scsi.c */ +extern int readsecs(int startsecno, void *buffer, int sectorcount); +extern int scsidev_open(char *path); +#endif + +extern char * extension_record; +extern int extension_record_extent; +extern int n_data_extents; + +/* These are a few goodies that can be specified on the command line, and are + filled into the root record */ + +extern char * preparer; +extern char * publisher; +extern char * copyright; +extern char * biblio; +extern char * abstract; +extern char * appid; +extern char * volset_id; +extern char * system_id; +extern char * volume_id; +extern char * boot_catalog; +extern char * boot_image; + +extern void * DECL(e_malloc,(size_t)); + + +#define SECTOR_SIZE (2048) +#define ROUND_UP(X) ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1)) + +#define NEED_RE 1 +#define NEED_PL 2 +#define NEED_CL 4 +#define NEED_CE 8 +#define NEED_SP 16 + +#define PREV_SESS_DEV (sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd) +#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe) +#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff) +#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff) + +#ifdef VMS +#define STAT_INODE(X) (X.st_ino[0]) +#define PATH_SEPARATOR ']' +#define SPATH_SEPARATOR "" +#else +#define STAT_INODE(X) (X.st_ino) +#define PATH_SEPARATOR '/' +#define SPATH_SEPARATOR "/" +#endif + +/* + * When using multi-session, indicates that we can reuse the + * TRANS.TBL information for this directory entry. If this flag + * is set for all entries in a directory, it means we can just + * reuse the TRANS.TBL and not generate a new one. + */ +#define SAFE_TO_REUSE_TABLE_ENTRY 1 +/* + * Volume sequence number to use in all of the iso directory records. + */ +#define DEF_VSN 1 + +/* + * Make sure we have a definition for this. If not, take a very conservative + * guess. From what I can tell SunOS is the only one with this trouble. + */ +#ifndef NAME_MAX +#ifdef FILENAME_MAX +#define NAME_MAX FILENAME_MAX +#else +#define NAME_MAX 128 +#endif +#endif diff --git a/util/mkisofs/multi.c b/util/mkisofs/multi.c new file mode 100644 index 000000000..13ba6f6d1 --- /dev/null +++ b/util/mkisofs/multi.c @@ -0,0 +1,1018 @@ +/* + * File multi.c - scan existing iso9660 image and merge into + * iso9660 filesystem. Used for multisession support. + * + * Written by Eric Youngdale (1996). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +static char rcsid[] ="$Id: multi.c,v 1.6.1.3 1998/06/02 03:00:25 eric Exp $"; + +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifndef VMS + +#ifdef HAVE_UNISTD_H +#include +#endif + +#else +#include +#include +#include "vms.h" +extern char * strdup(const char *); +#endif + +#include "mkisofs.h" +#include "iso9660.h" + +#define TF_CREATE 1 +#define TF_MODIFY 2 +#define TF_ACCESS 4 +#define TF_ATTRIBUTES 8 + +static int DECL(get_session_start, (int *)); +static int DECL(merge_old_directory_into_tree, (struct directory_entry *, + struct directory *)); + +static int +isonum_711 (unsigned char * p) +{ + return (*p & 0xff); +} + +int +isonum_721 (unsigned char * p) +{ + return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); +} + +static int +isonum_723 (unsigned char * p) +{ +#if 0 + if (p[0] != p[3] || p[1] != p[2]) { + fprintf (stderr, "invalid format 7.2.3 number\n"); + exit (1); + } +#endif + return (isonum_721 (p)); +} + +int +isonum_731 (unsigned char * p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + +int +isonum_733 (unsigned char * p) +{ + return (isonum_731 (p)); +} + +FILE * in_image = NULL; + +#ifndef USE_SCG +/* + * Don't define readsecs if mkisofs is linked with + * the SCSI library. + * readsecs() will be implemented as SCSI command in this case. + * + * Use global var in_image directly in readsecs() + * the SCSI equivalent will not use a FILE* for I/O. + * + * The main point of this pointless abstraction is that Solaris won't let + * you read 2K sectors from the cdrom driver. The fact that 99.9% of the + * discs out there have a 2K sectorsize doesn't seem to matter that much. + * Anyways, this allows the use of a scsi-generics type of interface on + * Solaris. + */ +static int +readsecs(int startsecno, void *buffer, int sectorcount) +{ + int f = fileno(in_image); + + if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) { + fprintf(stderr," Seek error on old image\n"); + exit(10); + } + return (read(f, buffer, sectorcount * SECTOR_SIZE)); +} +#endif + +/* + * Parse the RR attributes so we can find the file name. + */ +static int +FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) +{ + int cont_extent, cont_offset, cont_size; + char name_buf[256]; + + cont_extent = cont_offset = cont_size = 0; + + while(len >= 4){ + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return -1; + }; + if(strncmp((char *) pnt, "NM", 2) == 0) { + strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); + name_buf[pnt[2] - 5] = 0; + dpnt->name = strdup(name_buf); + return 0; + } + + if(strncmp((char *) pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[SECTOR_SIZE]; + readsecs(cont_extent, sector, 1); + parse_rr(§or[cont_offset], cont_size, dpnt); + }; + }; + return 0; +} + + +static int +FDECL4(check_rr_dates, struct directory_entry *, dpnt, + struct directory_entry *, current, + struct stat *, statbuf, + struct stat *,lstatbuf) +{ + int cont_extent, cont_offset, cont_size; + int offset; + unsigned char * pnt; + int len; + int same_file; + int same_file_type; + mode_t mode; + char time_buf[7]; + + + cont_extent = cont_offset = cont_size = 0; + same_file = 1; + same_file_type = 1; + + pnt = dpnt->rr_attributes; + len = dpnt->rr_attr_size; + /* + * We basically need to parse the rr attributes again, and + * dig out the dates and file types. + */ + while(len >= 4){ + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return -1; + }; + + /* + * If we have POSIX file modes, make sure that the file type + * is the same. If it isn't, then we must always + * write the new file. + */ + if(strncmp((char *) pnt, "PX", 2) == 0) { + mode = isonum_733(pnt + 4); + if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) ) + { + same_file_type = 0; + same_file = 0; + } + } + + if(strncmp((char *) pnt, "TF", 2) == 0) { + offset = 5; + if( pnt[4] & TF_CREATE ) + { + iso9660_date((char *) time_buf, lstatbuf->st_ctime); + if(memcmp(time_buf, pnt+offset, 7) == 0) + same_file = 0; + offset += 7; + } + if( pnt[4] & TF_MODIFY ) + { + iso9660_date((char *) time_buf, lstatbuf->st_mtime); + if(memcmp(time_buf, pnt+offset, 7) == 0) + same_file = 0; + offset += 7; + } + } + + if(strncmp((char *) pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[SECTOR_SIZE]; + + readsecs(cont_extent, sector, 1); + parse_rr(§or[cont_offset], cont_size, dpnt); + }; + }; + + /* + * If we have the same fundamental file type, then it is clearly + * safe to reuse the TRANS.TBL entry. + */ + if( same_file_type ) + { + current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + } + + return same_file; +} + +struct directory_entry ** +FDECL2(read_merging_directory, struct iso_directory_record *, mrootp, + int *, nent) +{ + unsigned char * cpnt; + unsigned char * cpnt1; + char * dirbuff; + int i; + struct iso_directory_record * idr; + int len; + struct directory_entry **pnt; + int rlen; + struct directory_entry **rtn; + int seen_rockridge; + unsigned char * tt_buf; + int tt_extent; + int tt_size; + + /* + * First, allocate a buffer large enough to read in the entire + * directory. + */ + dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size)); + + readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff, + isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE); + + /* + * Next look over the directory, and count up how many entries we + * have. + */ + len = isonum_733((unsigned char *)mrootp->size); + i = 0; + *nent = 0; + while(i < len ) + { + idr = (struct iso_directory_record *) &dirbuff[i]; + if(idr->length[0] == 0) + { + i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + continue; + } + (*nent)++; + i += idr->length[0]; + } + + /* + * Now allocate the buffer which will hold the array we are + * about to return. + */ + rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); + + /* + * Finally, scan the directory one last time, and pick out the + * relevant bits of information, and store it in the relevant + * bits of the structure. + */ + i = 0; + pnt = rtn; + tt_extent = 0; + seen_rockridge = 0; + tt_size = 0; + while(i < len ) + { + idr = (struct iso_directory_record *) &dirbuff[i]; + if(idr->length[0] == 0) + { + i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + continue; + } + *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); + (*pnt)->next = NULL; + (*pnt)->isorec = *idr; + (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent); + (*pnt)->size = isonum_733((unsigned char *)idr->size); + (*pnt)->priority = 0; + (*pnt)->name = NULL; + (*pnt)->table = NULL; + (*pnt)->whole_name = NULL; + (*pnt)->filedir = NULL; + (*pnt)->parent_rec = NULL; + /* + * Set this information so that we correctly cache previous + * session bits of information. + */ + (*pnt)->inode = (*pnt)->starting_block; + (*pnt)->dev = PREV_SESS_DEV; + (*pnt)->rr_attributes = NULL; + (*pnt)->rr_attr_size = 0; + (*pnt)->total_rr_attr_size = 0; + (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY; + + /* + * Check for and parse any RR attributes for the file. + * All we are really looking for here is the original name + * of the file. + */ + rlen = idr->length[0] & 0xff; + cpnt = (unsigned char *) idr; + + rlen -= sizeof(struct iso_directory_record); + cpnt += sizeof(struct iso_directory_record); + + rlen += sizeof(idr->name); + cpnt -= sizeof(idr->name); + + rlen -= idr->name_len[0]; + cpnt += idr->name_len[0]; + + if((idr->name_len[0] & 1) == 0){ + cpnt++; + rlen--; + }; + + if( rlen != 0 ) + { + (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; + (*pnt)->rr_attributes = e_malloc(rlen); + memcpy((*pnt)->rr_attributes, cpnt, rlen); + seen_rockridge = 1; + } + + /* + * Now zero out the remainder of the name field. + */ + cpnt = (unsigned char *) &(*pnt)->isorec.name; + cpnt += idr->name_len[0]; + memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); + + parse_rr((*pnt)->rr_attributes, rlen, *pnt); + + if( ((*pnt)->isorec.name_len[0] == 1) + && ( ((*pnt)->isorec.name[0] == 0) + || ((*pnt)->isorec.name[0] == 1)) ) + { + if( (*pnt)->name != NULL ) + { + free((*pnt)->name); + } + if( (*pnt)->whole_name != NULL ) + { + free((*pnt)->whole_name); + } + if( (*pnt)->isorec.name[0] == 0 ) + { + (*pnt)->name = strdup("."); + } + else + { + (*pnt)->name = strdup(".."); + } + } + + if( strncmp(idr->name, "TRANS.TBL", 9) == 0) + { + if( (*pnt)->name != NULL ) + { + free((*pnt)->name); + } + if( (*pnt)->whole_name != NULL ) + { + free((*pnt)->whole_name); + } + (*pnt)->name = strdup(""); + tt_extent = isonum_733((unsigned char *)idr->extent); + tt_size = isonum_733((unsigned char *)idr->size); + } + + pnt++; + i += idr->length[0]; + } + + /* + * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it + * to get the filenames of the files. Also, save the table info, just + * in case we need to use it. + */ + if( tt_extent != 0 && tt_size != 0 ) + { + tt_buf = (unsigned char *) e_malloc(tt_size); + readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE); + + /* + * Loop through the file, examine each entry, and attempt to + * attach it to the correct entry. + */ + cpnt = tt_buf; + cpnt1 = tt_buf; + while( cpnt - tt_buf < tt_size ) + { + while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; + *cpnt1 = '\0'; + + for(pnt = rtn, i = 0; i <*nent; i++, pnt++) + { + rlen = isonum_711((*pnt)->isorec.name_len); + if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, + rlen) == 0 + && cpnt[2+rlen] == ' ') + { + (*pnt)->table = e_malloc(strlen((char*)cpnt) - 34); + sprintf((*pnt)->table, "%c\t%s\n", + *cpnt, cpnt+37); + if( (*pnt)->name == NULL ) + { + (*pnt)->name = strdup((char *) cpnt+37); + } + break; + } + } + cpnt = cpnt1 + 1; + cpnt1 = cpnt; + } + + free(tt_buf); + } + else if( !seen_rockridge ) + { + /* + * This is a fatal error right now because we must have some mechanism + * for taking the 8.3 names back to the original unix names. + * In principle we could do this the hard way, and try and translate + * the unix names that we have seen forwards, but this would be + * a real pain in the butt. + */ + fprintf(stderr,"Previous session must have either Rock Ridge (-R) or\n"); + fprintf(stderr,"TRANS.TBL (-T) for mkisofs to be able to correctly\n"); + fprintf(stderr,"generate additional sessions.\n"); + exit(3); + } + + if( dirbuff != NULL ) + { + free(dirbuff); + } + + return rtn; +} + +/* + * Free any associated data related to the structures. + */ +int +FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len ) +{ + int i; + struct directory_entry **p; + + p = ptr; + for(i=0; iname != NULL ) + { + free((*p)->name); + } + + if( (*p)->whole_name != NULL ) + { + free((*p)->whole_name); + } + + if( (*p)->rr_attributes != NULL ) + { + free((*p)->rr_attributes); + } + + if( (*p)->table != NULL ) + { + free((*p)->table); + } + + free(*p); + + } + + free(ptr); + return 0; +} + +/* + * Search the list to see if we have any entries from the previous + * session that match this entry. If so, copy the extent number + * over so we don't bother to write it out to the new session. + */ + +int +FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len, + struct directory_entry *, curr_entry, + struct stat *, statbuf, struct stat *, lstatbuf, + struct directory_entry **, odpnt) +{ + int i; + + for( i=0; i < len; i++ ) + { + if( ptr[i] == NULL ) + { + continue; + } + +#if 0 + if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 + && ptr[i]->name[0] == '\0' ) + { + continue; + } + if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 + && ptr[i]->name[0] == 1) + { + continue; + } +#else + if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 ) + { + continue; + } + if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 ) + { + continue; + } +#endif + + if( ptr[i]->name != NULL + && strcmp(ptr[i]->name, curr_entry->name) != 0 ) + { + continue; + } + + /* + * We know that the files have the same name. If they also have + * the same file type (i.e. file, dir, block, etc), then we + * can safely reuse the TRANS.TBL entry for this file. + * The check_rr_dates function will do this for us. + * + * Verify that the file type and dates are consistent. + * If not, we probably have a different file, and we need + * to write it out again. + */ + if( (ptr[i]->rr_attributes != NULL) + && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) + { + goto found_it; + } + + + /* + * Verify size and timestamp. If rock ridge is in use, we need + * to compare dates from RR too. Directories are special, we + * calculate their size later. + */ + if( (curr_entry->isorec.flags[0] & 2) == 0 + && ptr[i]->size != curr_entry->size ) + { + goto found_it; + } + + if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) + { + goto found_it; + } + + /* + * Never ever reuse directory extents. See comments in + * tree.c for an explaination of why this must be the case. + */ + if( (curr_entry->isorec.flags[0] & 2) != 0 ) + { + goto found_it; + } + + memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); + curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + goto found_it; + } + return 0; + +found_it: + if( odpnt != NULL ) + { + *odpnt = ptr[i]; + } + else + { + free(ptr[i]); + } + ptr[i] = NULL; + return 0; +} + +/* + * merge_isofs: Scan an existing image, and return a pointer + * to the root directory for this image. + */ +struct iso_directory_record * FDECL1(merge_isofs, char *, path) +{ + char buffer[SECTOR_SIZE]; + int file_addr; + int i; + struct iso_primary_descriptor * pri = NULL; + struct iso_directory_record * rootp; + struct iso_volume_descriptor * vdp; + + /* + * Start by opening up the image and searching for the volume header. + * Ultimately, we need to search for volume headers in multiple places + * because we might be starting with a multisession image. + * FIXME(eric). + */ + +#ifndef USE_SCG + in_image = fopen(path, "rb"); + if( in_image == NULL ) + { + return NULL; + } +#else + if (strchr(path, '/')) { + in_image = fopen(path, "rb"); + if( in_image == NULL ) { + return NULL; + } + } else { + if (scsidev_open(path) < 0) + return NULL; + } +#endif + + get_session_start(&file_addr); + + for(i = 0; i< 100; i++) + { + if (readsecs(file_addr/SECTOR_SIZE, &buffer, + sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer)) + { + fprintf(stderr," Read error on old image %s\n", path); + exit(10); + } + + vdp = (struct iso_volume_descriptor *)buffer; + + if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) + && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) ) + { + break; + } + file_addr += SECTOR_SIZE; + } + + if( i == 100 ) + { + return NULL; + } + + pri = (struct iso_primary_descriptor *)vdp; + + /* + * Check the blocksize of the image to make sure it is compatible. + */ + if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE) + || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) ) + { + return NULL; + } + + /* + * Get the location and size of the root directory. + */ + rootp = (struct iso_directory_record *) + malloc(sizeof(struct iso_directory_record)); + + memcpy(rootp, pri->root_directory_record, sizeof(*rootp)); + + return rootp; +} + +void FDECL3(merge_remaining_entries, struct directory *, this_dir, + struct directory_entry **, pnt, + int, n_orig) +{ + int i; + struct directory_entry * s_entry; + unsigned int ttbl_extent = 0; + unsigned int ttbl_index = 0; + + /* + * Whatever is leftover in the list needs to get merged back + * into the directory. + */ + for( i=0; i < n_orig; i++ ) + { + if( pnt[i] == NULL ) + { + continue; + } + + if( pnt[i]->name != NULL + && strcmp(pnt[i]->name, "") == 0 ) + { + ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent); + ttbl_index = i; + continue; + } + /* + * Skip directories for now - these need to be treated + * differently. + */ + if( (pnt[i]->isorec.flags[0] & 2) != 0 ) + { + /* + * FIXME - we need to insert this directory into the + * tree, so that the path tables we generate will + * be correct. + */ + if( (strcmp(pnt[i]->name, ".") == 0) + || (strcmp(pnt[i]->name, "..") == 0) ) + { + free(pnt[i]); + pnt[i] = NULL; + continue; + } + else + { + merge_old_directory_into_tree(pnt[i], this_dir); + } + } + pnt[i]->next = this_dir->contents; + pnt[i]->filedir = this_dir; + this_dir->contents = pnt[i]; + pnt[i] = NULL; + } + + + /* + * If we don't have an entry for the translation table, then + * don't bother trying to copy the starting extent over. + * Note that it is possible that if we are copying the entire + * directory, the entry for the translation table will have already + * been inserted into the linked list and removed from the old + * entries list, in which case we want to leave the extent number + * as it was before. + */ + if( ttbl_extent == 0 ) + { + return; + } + + /* + * Finally, check the directory we are creating to see whether + * there are any new entries in it. If there are not, we can + * reuse the same translation table. + */ + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + /* + * Don't care about '.' or '..'. They are never in the table + * anyways. + */ + if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 ) + { + continue; + } + if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 ) + { + continue; + } + if( strcmp(s_entry->name, "") == 0) + { + continue; + } + if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 ) + { + return; + } + } + + /* + * Locate the translation table, and re-use the same extent. + * It isn't clear that there should ever be one in there already + * so for now we try and muddle through the best we can. + */ + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + if( strcmp(s_entry->name, "") == 0) + { + fprintf(stderr,"Should never get here\n"); + set_733(s_entry->isorec.extent, ttbl_extent); + return; + } + } + + pnt[ttbl_index]->next = this_dir->contents; + pnt[ttbl_index]->filedir = this_dir; + this_dir->contents = pnt[ttbl_index]; + pnt[ttbl_index] = NULL; +} + + +/* + * Here we have a case of a directory that has completely disappeared from + * the face of the earth on the tree we are mastering from. Go through and + * merge it into the tree, as well as everything beneath it. + * + * Note that if a directory has been moved for some reason, this will + * incorrectly pick it up and attempt to merge it back into the old + * location. FIXME(eric). + */ +static int +FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, + struct directory *, parent) +{ + struct directory_entry **contents = NULL; + int i; + int n_orig; + struct directory * this_dir, *next_brother; + char whole_path[1024]; + + this_dir = (struct directory *) e_malloc(sizeof(struct directory)); + this_dir->next = NULL; + this_dir->subdir = NULL; + this_dir->self = dpnt; + this_dir->contents = NULL; + this_dir->size = 0; + this_dir->extent = 0; + this_dir->depth = parent->depth + 1; + this_dir->parent = parent; + if(!parent->subdir) + parent->subdir = this_dir; + else { + next_brother = parent->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + } + + /* + * Set the name for this directory. + */ + strcpy(whole_path, parent->de_name); + strcat(whole_path, SPATH_SEPARATOR); + strcat(whole_path, dpnt->name); + this_dir->de_name = strdup(whole_path); + this_dir->whole_name = strdup(whole_path); + + /* + * Now fill this directory using information from the previous + * session. + */ + contents = read_merging_directory(&dpnt->isorec, &n_orig); + /* + * Start by simply copying the '.', '..' and non-directory + * entries to this directory. Technically we could let + * merge_remaining_entries handle this, but it gets rather confused + * by the '.' and '..' entries. + */ + for(i=0; i < n_orig; i ++ ) + { + /* + * We can always reuse the TRANS.TBL in this particular case. + */ + contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + + if( ((contents[i]->isorec.flags[0] & 2) != 0) + && (i >= 2) ) + { + continue; + } + + /* + * If we have a directory, don't reuse the extent number. + */ + if( (contents[i]->isorec.flags[0] & 2) != 0 ) + { + memset(contents[i]->isorec.extent, 0, 8); + } + + contents[i]->next = this_dir->contents; + contents[i]->filedir = this_dir; + this_dir->contents = contents[i]; + contents[i] = NULL; + } + + /* + * Zero the extent number for ourselves. + */ + memset(dpnt->isorec.extent, 0, 8); + + /* + * Anything that is left are other subdirectories that need to be merged. + */ + merge_remaining_entries(this_dir, contents, n_orig); + free_mdinfo(contents, n_orig); + sort_n_finish(this_dir); + + return 0; +} + + +char * cdwrite_data = NULL; + +static int +FDECL1(get_session_start, int *, file_addr) +{ + char * pnt; + +#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS + /* + * FIXME(eric). We need to coordinate with cdwrite to obtain + * the parameters. For now, we assume we are writing the 2nd session, + * so we start from the session that starts at 0. + */ + + *file_addr = (16 << 11); + + /* + * We need to coordinate with cdwrite to get the next writable address + * from the device. Here is where we use it. + */ + session_start = last_extent = last_extent_written = cdwrite_result(); + +#else + + if( cdwrite_data == NULL ) + { + fprintf(stderr,"Special parameters for cdwrite not specified with -C\n"); + exit(1); + } + + /* + * Next try and find the ',' in there which delimits the two numbers. + */ + pnt = strchr(cdwrite_data, ','); + if( pnt == NULL ) + { + fprintf(stderr, "Malformed cdwrite parameters\n"); + exit(1); + } + + *pnt = '\0'; + *file_addr = atol(cdwrite_data) * SECTOR_SIZE; + pnt++; + + session_start = last_extent = last_extent_written = atol(pnt); + + pnt--; + *pnt = ','; + +#endif + return 0; +} + diff --git a/util/mkisofs/name.c b/util/mkisofs/name.c new file mode 100644 index 000000000..10475d43e --- /dev/null +++ b/util/mkisofs/name.c @@ -0,0 +1,390 @@ +/* + * File name.c - map full Unix file names to unique 8.3 names that + * would be valid on DOS. + * + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: name.c,v 1.7 1997/11/09 16:42:51 eric Exp $"; + +#include "mkisofs.h" + +#include + +extern int allow_leading_dots; + +/* + * Function: iso9660_file_length + * + * Purpose: Map file name to 8.3 format, return length + * of result. + * + * Arguments: name file name we need to map. + * sresult directory entry structure to contain mapped name. + * dirflag flag indicating whether this is a directory or not. + * + * Notes: This procedure probably needs to be rationalized somehow. + * New options to affect the behavior of this function + * would also be nice to have. + */ +int FDECL3(iso9660_file_length, + const char*, name, + struct directory_entry *, sresult, + int, dirflag) +{ + char * c; + int chars_after_dot = 0; + int chars_before_dot = 0; + int current_length = 0; + int extra = 0; + int ignore = 0; + char * last_dot; + const char * pnt; + int priority = 32767; + char * result; + int seen_dot = 0; + int seen_semic = 0; + int tildes = 0; + + result = sresult->isorec.name; + + /* + * For the '.' entry, generate the correct record, and return + * 1 for the length. + */ + if(strcmp(name,".") == 0) + { + if(result) + { + *result = 0; + } + return 1; + } + + /* + * For the '..' entry, generate the correct record, and return + * 1 for the length. + */ + if(strcmp(name,"..") == 0) + { + if(result) + { + *result++ = 1; + *result++ = 0; + } + return 1; + } + + /* + * Now scan the directory one character at a time, and figure out + * what to do. + */ + pnt = name; + + /* + * Find the '.' that we intend to use for the extension. Usually this + * is the last dot, but if we have . followed by nothing or a ~, we + * would consider this to be unsatisfactory, and we keep searching. + */ + last_dot = strrchr (pnt,'.'); + if( (last_dot != NULL) + && ( (last_dot[1] == '~') + || (last_dot[1] == '\0') + || (last_dot[1] == '\0')) ) + { + c = last_dot; + *c = '\0'; + last_dot = strrchr (pnt,'.'); + *c = '.'; + } + + while(*pnt) + { +#ifdef VMS + if( strcmp(pnt,".DIR;1") == 0 ) + { + break; + } +#endif + + /* + * This character indicates a Unix style of backup file + * generated by some editors. Lower the priority of + * the file. + */ + if(*pnt == '#') + { + priority = 1; + pnt++; + continue; + } + + /* + * This character indicates a Unix style of backup file + * generated by some editors. Lower the priority of + * the file. + */ + if(*pnt == '~') + { + priority = 1; + tildes++; + pnt++; + continue; + } + + /* + * This might come up if we had some joker already try and put + * iso9660 version numbers into the file names. This would be + * a silly thing to do on a Unix box, but we check for it + * anyways. If we see this, then we don't have to add our + * own version number at the end. + */ + if(*pnt == ';') + { + seen_semic = 1; + *result++ = *pnt++; + continue; + } + + /* + * If we have a name with multiple '.' characters, we ignore everything + * after we have gotten the extension. + */ + if(ignore) + { + pnt++; + continue; + } + + /* + * Spin past any iso9660 version number we might have. + */ + if(seen_semic) + { + if(*pnt >= '0' && *pnt <= '9') + { + *result++ = *pnt; + } + extra++; + pnt++; + continue; + } + + /* + * If we have full names, the names we generate will not + * work on a DOS machine, since they are not guaranteed + * to be 8.3. Nonetheless, in many cases this is a useful + * option. We still only allow one '.' character in the + * name, however. + */ + if(full_iso9660_filenames) + { + /* Here we allow a more relaxed syntax. */ + if(*pnt == '.') + { + if (seen_dot) + { + ignore++; + continue; + } + seen_dot++; + } + if(current_length < 30) + { + if( *pnt < 0 ) + { + *result++ = '_'; + } + else + { + *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt); + } + } + } + else + { + /* + * Dos style filenames. We really restrict the + * names here. + */ + /* It would be nice to have .tar.gz transform to .tgz, + * .ps.gz to .psz, ... + */ + if(*pnt == '.') + { + if (!chars_before_dot && !allow_leading_dots) + { + /* DOS can't read files with dot first */ + chars_before_dot++; + if (result) + { + *result++ = '_'; /* Substitute underscore */ + } + } + else if( pnt != last_dot ) + { + /* + * If this isn't the dot that we use for the extension, + * then change the character into a '_' instead. + */ + if(chars_before_dot < 8) + { + chars_before_dot++; + if(result) + { + *result++ = '_'; + } + } + } + else + { + if (seen_dot) + { + ignore++; continue; + } + if(result) + { + *result++ = '.'; + } + seen_dot++; + } + } + else + { + if( (seen_dot && (chars_after_dot < 3) && ++chars_after_dot) + || (!seen_dot && (chars_before_dot < 8) && ++chars_before_dot) ) + { + if(result) + { + switch (*pnt) + { + default: + if( *pnt < 0 ) + { + *result++ = '_'; + } + else + { + *result++ = islower(*pnt) ? toupper(*pnt) : *pnt; + } + break; + + /* + * Descriptions of DOS's 'Parse Filename' + * (function 29H) describes V1 and V2.0+ + * separator and terminator characters. + * These characters in a DOS name make + * the file visible but un-manipulable + * (all useful operations error off. + */ + /* separators */ + case '+': + case '=': + case '%': /* not legal DOS filename */ + case ':': + case ';': /* already handled */ + case '.': /* already handled */ + case ',': /* already handled */ + case '\t': + case ' ': + /* V1 only separators */ + case '/': + case '"': + case '[': + case ']': + /* terminators */ + case '>': + case '<': + case '|': + /* Hmm - what to do here? Skip? + * Win95 looks like it substitutes '_' + */ + *result++ = '_'; + break; + } /* switch (*pnt) */ + } /* if (result) */ + } /* if (chars_{after,before}_dot) ... */ + } /* else *pnt == '.' */ + } /* else DOS file names */ + current_length++; + pnt++; + } /* while (*pnt) */ + + /* + * OK, that wraps up the scan of the name. Now tidy up a few other + * things. + */ + + /* + * Look for emacs style of numbered backups, like foo.c.~3~. If + * we see this, convert the version number into the priority + * number. In case of name conflicts, this is what would end + * up being used as the 'extension'. + */ + if(tildes == 2) + { + int prio1 = 0; + pnt = name; + while (*pnt && *pnt != '~') + { + pnt++; + } + if (*pnt) + { + pnt++; + } + while(*pnt && *pnt != '~') + { + prio1 = 10*prio1 + *pnt - '0'; + pnt++; + } + priority = prio1; + } + + /* + * If this is not a directory, force a '.' in case we haven't + * seen one, and add a version number if we haven't seen one + * of those either. + */ + if (!dirflag) + { + if (!seen_dot && !omit_period) + { + if (result) *result++ = '.'; + extra++; + } + if(!omit_version_number && !seen_semic) + { + if(result) + { + *result++ = ';'; + *result++ = '1'; + }; + extra += 2; + } + } + + if(result) + { + *result++ = 0; + } + sresult->priority = priority; + + return (chars_before_dot + chars_after_dot + seen_dot + extra); +} diff --git a/util/mkisofs/rock.c b/util/mkisofs/rock.c new file mode 100644 index 000000000..47cba5527 --- /dev/null +++ b/util/mkisofs/rock.c @@ -0,0 +1,556 @@ +/* + * File rock.c - generate RRIP records for iso9660 filesystems. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: rock.c,v 1.3 1997/05/17 15:45:26 eric Exp $"; + +#include + +#include "config.h" + +#ifndef VMS +#if defined(MAJOR_IN_SYSMACROS) +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#endif +#if defined(MAJOR_IN_MKDEV) +#include +#include +#endif + +#include "mkisofs.h" +#include "iso9660.h" +#include + +#ifdef NON_UNIXFS +#define S_ISLNK(m) (0) +#else +#ifndef S_ISLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#endif + +#define SU_VERSION 1 + +#define SL_ROOT 8 +#define SL_PARENT 4 +#define SL_CURRENT 2 +#define SL_CONTINUE 1 + +#define CE_SIZE 28 +#define CL_SIZE 12 +#define ER_SIZE 8 +#define NM_SIZE 5 +#define PL_SIZE 12 +#define PN_SIZE 20 +#define PX_SIZE 36 +#define RE_SIZE 4 +#define SL_SIZE 20 +#define ZZ_SIZE 15 +#ifdef __QNX__ +#define TF_SIZE (5 + 4 * 7) +#else +#define TF_SIZE (5 + 3 * 7) +#endif + +/* If we need to store this number of bytes, make sure we + do not box ourselves in so that we do not have room for + a CE entry for the continuation record */ + +#define MAYBE_ADD_CE_ENTRY(BYTES) \ + (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0) + +/* + * Buffer to build RR attributes + */ + +static unsigned char Rock[16384]; +static unsigned char symlink_buff[256]; +static int ipnt = 0; +static int recstart = 0; +static int currlen = 0; +static int mainrec = 0; +static int reclimit; + +static void add_CE_entry(){ + if(recstart) + set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart); + Rock[ipnt++] ='C'; + Rock[ipnt++] ='E'; + Rock[ipnt++] = CE_SIZE; + Rock[ipnt++] = SU_VERSION; + set_733((char*)Rock + ipnt, 0); + ipnt += 8; + set_733((char*)Rock + ipnt, 0); + ipnt += 8; + set_733((char*)Rock + ipnt, 0); + ipnt += 8; + recstart = ipnt; + currlen = 0; + if(!mainrec) mainrec = ipnt; + reclimit = SECTOR_SIZE - 8; /* Limit to one sector */ +} + +#ifdef __STDC__ +int generate_rock_ridge_attributes (char * whole_name, char * name, + struct directory_entry * s_entry, + struct stat * statbuf, + struct stat * lstatbuf, + int deep_opt) +#else +int generate_rock_ridge_attributes (whole_name, name, + s_entry, + statbuf, + lstatbuf, + deep_opt) +char * whole_name; char * name; struct directory_entry * s_entry; +struct stat * statbuf, *lstatbuf; +int deep_opt; +#endif +{ + int flagpos, flagval; + int need_ce; + + statbuf = statbuf; /* this shuts up unreferenced compiler warnings */ + mainrec = recstart = ipnt = 0; + reclimit = 0xf8; + + /* Obtain the amount of space that is currently used for the directory + record. Assume max for name, since name conflicts may cause us + to rename the file later on */ + currlen = sizeof(s_entry->isorec); + + /* Identify that we are using the SUSP protocol */ + if(deep_opt & NEED_SP){ + Rock[ipnt++] ='S'; + Rock[ipnt++] ='P'; + Rock[ipnt++] = 7; + Rock[ipnt++] = SU_VERSION; + Rock[ipnt++] = 0xbe; + Rock[ipnt++] = 0xef; + Rock[ipnt++] = 0; + }; + + /* First build the posix name field */ + Rock[ipnt++] ='R'; + Rock[ipnt++] ='R'; + Rock[ipnt++] = 5; + Rock[ipnt++] = SU_VERSION; + flagpos = ipnt; + flagval = 0; + Rock[ipnt++] = 0; /* We go back and fix this later */ + + if(strcmp(name,".") && strcmp(name,"..")){ + char * npnt; + int remain, use; + + remain = strlen(name); + npnt = name; + + while(remain){ + use = remain; + need_ce = 0; + /* Can we fit this SUSP and a CE entry? */ + if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) { + use = reclimit - currlen - CE_SIZE - (ipnt - recstart); + need_ce++; + } + + /* Only room for 256 per SUSP field */ + if(use > 0xf8) use = 0xf8; + + /* First build the posix name field */ + Rock[ipnt++] ='N'; + Rock[ipnt++] ='M'; + Rock[ipnt++] = NM_SIZE + use; + Rock[ipnt++] = SU_VERSION; + Rock[ipnt++] = (remain != use ? 1 : 0); + flagval |= (1<<3); + strncpy((char *)&Rock[ipnt], npnt, use); + npnt += use; + ipnt += use; + remain -= use; + if(remain && need_ce) add_CE_entry(); + }; + }; + + /* + * Add the posix modes + */ + if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry(); + Rock[ipnt++] ='P'; + Rock[ipnt++] ='X'; + Rock[ipnt++] = PX_SIZE; + Rock[ipnt++] = SU_VERSION; + flagval |= (1<<0); + set_733((char*)Rock + ipnt, lstatbuf->st_mode); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_nlink); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_uid); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_gid); + ipnt += 8; + + /* + * Check for special devices + */ +#ifndef NON_UNIXFS + if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) { + if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry(); + Rock[ipnt++] ='P'; + Rock[ipnt++] ='N'; + Rock[ipnt++] = PN_SIZE; + Rock[ipnt++] = SU_VERSION; + flagval |= (1<<1); +#if !defined(MAJOR_IN_SYSMACROS) && !defined(MAJOR_IN_MKDEV) + set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev )); + ipnt += 8; + set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev)); + ipnt += 8; +#else + /* + * If we don't have sysmacros.h, then we have to guess as to how + * best to pick apart the device number for major/minor. + * Note: this may very well be wrong for many systems, so + * it is always best to use the major/minor macros if the + * system supports it. + */ + if(sizeof(dev_t) <= 2) { + set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8)); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff); + ipnt += 8; + } + else if(sizeof(dev_t) <= 4) { + set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff); + ipnt += 8; + } + else { + set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16); + ipnt += 8; + set_733((char*)Rock + ipnt, lstatbuf->st_rdev); + ipnt += 8; + } +#endif + }; +#endif + /* + * Check for and symbolic links. VMS does not have these. + */ + if (S_ISLNK(lstatbuf->st_mode)){ + int lenpos, lenval, j0, j1; + int nchar; + unsigned char * cpnt, *cpnt1; + nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff)); + symlink_buff[nchar < 0 ? 0 : nchar] = 0; + set_733(s_entry->isorec.size, 0); + cpnt = &symlink_buff[0]; + flagval |= (1<<2); + + while(nchar){ + if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry(); + Rock[ipnt++] ='S'; + Rock[ipnt++] ='L'; + lenpos = ipnt; + Rock[ipnt++] = SL_SIZE; + Rock[ipnt++] = SU_VERSION; + Rock[ipnt++] = 0; /* Flags */ + lenval = 5; + while(*cpnt){ + cpnt1 = (unsigned char *) strchr((char *) cpnt, '/'); + if(cpnt1) { + nchar--; + *cpnt1 = 0; + }; + + /* We treat certain components in a special way. */ + if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){ + if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); + Rock[ipnt++] = SL_PARENT; + Rock[ipnt++] = 0; /* length is zero */ + lenval += 2; + nchar -= 2; + } else if(cpnt[0] == '.' && cpnt[1] == 0){ + if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); + Rock[ipnt++] = SL_CURRENT; + Rock[ipnt++] = 0; /* length is zero */ + lenval += 2; + nchar -= 1; + } else if(cpnt[0] == 0){ + if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); + Rock[ipnt++] = SL_ROOT; + Rock[ipnt++] = 0; /* length is zero */ + lenval += 2; + } else { + /* If we do not have enough room for a component, start + a new continuations segment now */ + if(MAYBE_ADD_CE_ENTRY(6)) { + add_CE_entry(); + if(cpnt1){ + *cpnt1 = '/'; + nchar++; + cpnt1 = NULL; /* A kluge so that we can restart properly */ + } + break; + } + j0 = strlen((char *) cpnt); + while(j0) { + j1 = j0; + if(j1 > 0xf8) j1 = 0xf8; + need_ce = 0; + if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) { + j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart); + need_ce++; + } + Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0); + Rock[ipnt++] = j1; + strncpy((char *) Rock + ipnt, (char *) cpnt, j1); + ipnt += j1; + lenval += j1 + 2; + cpnt += j1; + nchar -= j1; /* Number we processed this time */ + j0 -= j1; + if(need_ce) { + add_CE_entry(); + if(cpnt1) { + *cpnt1 = '/'; + nchar++; + cpnt1 = NULL; /* A kluge so that we can restart properly */ + } + break; + } + } + }; + if(cpnt1) { + cpnt = cpnt1 + 1; + } else + break; + } + Rock[lenpos] = lenval; + if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */ + } /* while nchar */ + } /* Is a symbolic link */ + /* + * Add in the Rock Ridge TF time field + */ + if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry(); + Rock[ipnt++] ='T'; + Rock[ipnt++] ='F'; + Rock[ipnt++] = TF_SIZE; + Rock[ipnt++] = SU_VERSION; +#ifdef __QNX__ + Rock[ipnt++] = 0x0f; +#else + Rock[ipnt++] = 0x0e; +#endif + flagval |= (1<<7); +#ifdef __QNX__ + iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime); + ipnt += 7; +#endif + iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime); + ipnt += 7; + iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime); + ipnt += 7; + iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime); + ipnt += 7; + + /* + * Add in the Rock Ridge RE time field + */ + if(deep_opt & NEED_RE){ + if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry(); + Rock[ipnt++] ='R'; + Rock[ipnt++] ='E'; + Rock[ipnt++] = RE_SIZE; + Rock[ipnt++] = SU_VERSION; + flagval |= (1<<6); + }; + /* + * Add in the Rock Ridge PL record, if required. + */ + if(deep_opt & NEED_PL){ + if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry(); + Rock[ipnt++] ='P'; + Rock[ipnt++] ='L'; + Rock[ipnt++] = PL_SIZE; + Rock[ipnt++] = SU_VERSION; + set_733((char*)Rock + ipnt, 0); + ipnt += 8; + flagval |= (1<<5); + }; + + /* + * Add in the Rock Ridge CL field, if required. + */ + if(deep_opt & NEED_CL){ + if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry(); + Rock[ipnt++] ='C'; + Rock[ipnt++] ='L'; + Rock[ipnt++] = CL_SIZE; + Rock[ipnt++] = SU_VERSION; + set_733((char*)Rock + ipnt, 0); + ipnt += 8; + flagval |= (1<<4); + }; + +#ifndef VMS + /* If transparent compression was requested, fill in the correct + field for this file */ + if(transparent_compression && + S_ISREG(lstatbuf->st_mode) && + strlen(name) > 3 && + strcmp(name + strlen(name) - 3,".gZ") == 0){ + FILE * zipfile; + char * checkname; + unsigned int file_size; + unsigned char header[8]; + int OK_flag; + + /* First open file and verify that the correct algorithm was used */ + file_size = 0; + OK_flag = 1; + + zipfile = fopen(whole_name, "r"); + fread(header, 1, sizeof(header), zipfile); + + /* Check some magic numbers from gzip. */ + if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0; + /* Make sure file was blocksized. */ + if(((header[3] & 0x40) == 0)) OK_flag = 0; + /* OK, now go to the end of the file and get some more info */ + if(OK_flag){ + int status; + status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END); + if(status == -1) OK_flag = 0; + } + if(OK_flag){ + if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header)) + OK_flag = 0; + else { + int blocksize; + blocksize = (header[3] << 8) | header[2]; + file_size = ((unsigned int)header[7] << 24) | + ((unsigned int)header[6] << 16) | + ((unsigned int)header[5] << 8) | header[4]; +#if 0 + fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size); +#endif + if(blocksize != SECTOR_SIZE) OK_flag = 0; + } + } + fclose(zipfile); + + checkname = strdup(whole_name); + checkname[strlen(whole_name)-3] = 0; + zipfile = fopen(checkname, "r"); + if(zipfile) { + OK_flag = 0; + fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n"); + fclose(zipfile); + } + + free(checkname); + + if(OK_flag){ + if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry(); + Rock[ipnt++] ='Z'; + Rock[ipnt++] ='Z'; + Rock[ipnt++] = ZZ_SIZE; + Rock[ipnt++] = SU_VERSION; + Rock[ipnt++] = 'g'; /* Identify compression technique used */ + Rock[ipnt++] = 'z'; + Rock[ipnt++] = 3; + set_733((char*)Rock + ipnt, file_size); /* Real file size */ + ipnt += 8; + }; + } +#endif + /* + * Add in the Rock Ridge CE field, if required. We use this for the + * extension record that is stored in the root directory. + */ + if(deep_opt & NEED_CE) add_CE_entry(); + /* + * Done filling in all of the fields. Now copy it back to a buffer for the + * file in question. + */ + + /* Now copy this back to the buffer for the file */ + Rock[flagpos] = flagval; + + /* If there was a CE, fill in the size field */ + if(recstart) + set_733((char*)Rock + recstart - 8, ipnt - recstart); + + s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt); + s_entry->total_rr_attr_size = ipnt; + s_entry->rr_attr_size = (mainrec ? mainrec : ipnt); + memcpy(s_entry->rr_attributes, Rock, ipnt); + return ipnt; +} + +/* Guaranteed to return a single sector with the relevant info */ + +char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor, + char *, source, int *, size){ + int ipnt = 0; + char * pnt; + int len_id, len_des, len_src; + + len_id = strlen(id); + len_des = strlen(descriptor); + len_src = strlen(source); + Rock[ipnt++] ='E'; + Rock[ipnt++] ='R'; + Rock[ipnt++] = ER_SIZE + len_id + len_des + len_src; + Rock[ipnt++] = 1; + Rock[ipnt++] = len_id; + Rock[ipnt++] = len_des; + Rock[ipnt++] = len_src; + Rock[ipnt++] = 1; + + memcpy(Rock + ipnt, id, len_id); + ipnt += len_id; + + memcpy(Rock + ipnt, descriptor, len_des); + ipnt += len_des; + + memcpy(Rock + ipnt, source, len_src); + ipnt += len_src; + + if(ipnt > SECTOR_SIZE) { + fprintf(stderr,"Extension record too long\n"); + exit(1); + }; + pnt = (char *) e_malloc(SECTOR_SIZE); + memset(pnt, 0, SECTOR_SIZE); + memcpy(pnt, Rock, ipnt); + *size = ipnt; + return pnt; +} diff --git a/util/mkisofs/tree.c b/util/mkisofs/tree.c new file mode 100644 index 000000000..7180905df --- /dev/null +++ b/util/mkisofs/tree.c @@ -0,0 +1,1292 @@ +/* + * File tree.c - scan directory tree and build memory structures for iso9660 + * filesystem + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: tree.c,v 1.9.1.2 1998/06/02 03:17:31 eric Exp $"; + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include +#include +#include +#include + +#include "config.h" + +#ifndef VMS +#if defined(MAJOR_IN_SYSMACROS) +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#if defined(MAJOR_IN_MKDEV) +#include +#include +#endif +#else +#include +#include +#include "vms.h" +extern char * strdup(const char *); +#endif + +/* + * Autoconf should be able to figure this one out for us and let us know + * whether the system has memmove or not. + */ +# ifndef HAVE_MEMMOVE +# define memmove(d, s, n) bcopy ((s), (d), (n)) +# endif + +#include "mkisofs.h" +#include "iso9660.h" + +#include + +#include "exclude.h" + +#ifdef NON_UNIXFS +#define S_ISLNK(m) (0) +#define S_ISSOCK(m) (0) +#define S_ISFIFO(m) (0) +#else +#ifndef S_ISLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) (0) +# endif +#endif +#endif + +#ifdef __svr4__ +extern char * strdup(const char *); +#endif + +static unsigned char symlink_buff[256]; + +extern int verbose; + +struct stat fstatbuf = {0,}; /* We use this for the artificial entries we create */ + +struct stat root_statbuf = {0, }; /* Stat buffer for root directory */ + +struct directory * reloc_dir = NULL; + +void +FDECL1(stat_fix, struct stat *, st) +{ + /* Remove the uid and gid, they will only be useful on the author's + system. */ + st->st_uid = 0; + st->st_gid = 0; + + /* + * Make sure the file modes make sense. Turn on all read bits. Turn + * on all exec/search bits if any exec/search bit is set. Turn off + * all write bits, and all special mode bits (on a r/o fs lock bits + * are useless, and with uid+gid 0 don't want set-id bits, either). + */ + st->st_mode |= 0444; + if (st->st_mode & 0111) + st->st_mode |= 0111; + st->st_mode &= ~07222; +} + +int +FDECL2(stat_filter, char *, path, struct stat *, st) +{ + int result = stat(path, st); + if (result >= 0 && rationalize) + stat_fix(st); + return result; +} + +int +FDECL2(lstat_filter, char *, path, struct stat *, st) +{ + int result = lstat(path, st); + if (result >= 0 && rationalize) + stat_fix(st); + return result; +} + +void FDECL1(sort_n_finish, struct directory *, this_dir) +{ + struct directory_entry * s_entry; + struct directory_entry * s_entry1; + time_t current_time; + struct directory_entry * table; + int count; + int d1; + int d2; + int d3; + int new_reclen; + char * c; + int tablesize = 0; + char newname[34]; + char rootname[34]; + + /* Here we can take the opportunity to toss duplicate entries from the + directory. */ + + table = NULL; + + if(fstatbuf.st_ctime == 0) + { + time (¤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; + } + + flush_file_hash(); + s_entry = this_dir->contents; + while(s_entry) + { + + /* + * First assume no conflict, and handle this case + */ + if(!(s_entry1 = find_file_hash(s_entry->isorec.name))) + { + add_file_hash(s_entry); + s_entry = s_entry->next; + continue; + } + + if(s_entry1 == s_entry) + { + fprintf(stderr,"Fatal goof\n"); + exit(1); + } + + /* + * OK, handle the conflicts. Try substitute names until we come + * up with a winner + */ + strcpy(rootname, s_entry->isorec.name); + if(full_iso9660_filenames) + { + if(strlen(rootname) > 27) rootname[27] = 0; + } + + /* + * Strip off the non-significant part of the name so that we are left + * with a sensible root filename. If we don't find a '.', then try + * a ';'. + */ + c = strchr(rootname, '.'); + if (c) + *c = 0; + else + { + c = strchr(rootname, ';'); + if (c) *c = 0; + } + for(d1 = 0; d1 < 36; d1++) + { + for(d2 = 0; d2 < 36; d2++) + { + for(d3 = 0; d3 < 36; d3++) + { + sprintf(newname,"%s.%c%c%c%s", rootname, + (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10), + (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10), + (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10), + (s_entry->isorec.flags[0] == 2 || + omit_version_number ? "" : ";1")); + +#ifdef VMS + /* Sigh. VAXCRTL seems to be broken here */ + { + int ijk = 0; + while(newname[ijk]) + { + if(newname[ijk] == ' ') newname[ijk] = '0'; + ijk++; + } + } +#endif + + if(!find_file_hash(newname)) goto got_valid_name; + } + } + } + + /* + * If we fell off the bottom here, we were in real trouble. + */ + fprintf(stderr,"Unable to generate unique name for file %s\n", s_entry->name); + exit(1); + +got_valid_name: + /* + * OK, now we have a good replacement name. Now decide which one + * of these two beasts should get the name changed + */ + if(s_entry->priority < s_entry1->priority) + { + fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry->name, s_entry1->name); + s_entry->isorec.name_len[0] = strlen(newname); + new_reclen = sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name) + + strlen(newname); + if(use_RockRidge) + { + if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ + new_reclen += s_entry->rr_attr_size; + } + if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ + s_entry->isorec.length[0] = new_reclen; + strcpy(s_entry->isorec.name, newname); + } + else + { + delete_file_hash(s_entry1); + fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry1->name, s_entry->name); + s_entry1->isorec.name_len[0] = strlen(newname); + new_reclen = sizeof(struct iso_directory_record) - + sizeof(s_entry1->isorec.name) + + strlen(newname); + if(use_RockRidge) + { + if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ + new_reclen += s_entry1->rr_attr_size; + } + if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ + s_entry1->isorec.length[0] = new_reclen; + strcpy(s_entry1->isorec.name, newname); + add_file_hash(s_entry1); + } + add_file_hash(s_entry); + s_entry = s_entry->next; + } + + if(generate_tables + && !find_file_hash("TRANS.TBL") + && (reloc_dir != this_dir) + && (this_dir->extent == 0) ) + { + /* + * First we need to figure out how big this table is + */ + for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + if(strcmp(s_entry->name, ".") == 0 || + strcmp(s_entry->name, "..") == 0) continue; + if(s_entry->table) tablesize += 35 + strlen(s_entry->table); + } + } + + if( tablesize > 0 ) + { + table = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memset(table, 0, sizeof(struct directory_entry)); + table->table = NULL; + table->next = this_dir->contents; + this_dir->contents = table; + + table->filedir = root; + table->isorec.flags[0] = 0; + table->priority = 32768; + iso9660_date(table->isorec.date, fstatbuf.st_mtime); + table->inode = TABLE_INODE; + table->dev = (dev_t) UNCACHED_DEVICE; + set_723(table->isorec.volume_sequence_number, DEF_VSN); + set_733((char *) table->isorec.size, tablesize); + table->size = tablesize; + table->filedir = this_dir; + table->name = strdup(""); + table->table = (char *) e_malloc(ROUND_UP(tablesize)); + memset(table->table, 0, ROUND_UP(tablesize)); + iso9660_file_length ("TRANS.TBL", table, 0); + + if(use_RockRidge) + { + fstatbuf.st_mode = 0444 | S_IFREG; + fstatbuf.st_nlink = 1; + generate_rock_ridge_attributes("", + "TRANS.TBL", table, + &fstatbuf, &fstatbuf, 0); + } + } + + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + new_reclen = strlen(s_entry->isorec.name); + + if(s_entry->isorec.flags[0] == 2) + { + if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) + { + path_table_size += new_reclen + sizeof(struct iso_path_table) - 1; + if (new_reclen & 1) path_table_size++; + } + else + { + new_reclen = 1; + if (this_dir == root && strlen(s_entry->name) == 1) + path_table_size += sizeof(struct iso_path_table); + } + } + if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */ + s_entry->isorec.name_len[0] = new_reclen; + + new_reclen += + sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name); + + if (new_reclen & 1) + new_reclen++; + + new_reclen += s_entry->rr_attr_size; + + if (new_reclen & 1) new_reclen++; + + if(new_reclen > 0xff) + { + fprintf(stderr,"Fatal error - RR overflow for file %s\n", + s_entry->name); + exit(1); + } + s_entry->isorec.length[0] = new_reclen; + } + + sort_directory(&this_dir->contents); + + if(table) + { + count = 0; + for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){ + if(s_entry == table) continue; + if(!s_entry->table) continue; + if(strcmp(s_entry->name, ".") == 0 || + strcmp(s_entry->name, "..") == 0) continue; + + count += sprintf(table->table + count, "%c %-34s%s", + s_entry->table[0], + s_entry->isorec.name, s_entry->table+1); + free(s_entry->table); + s_entry->table = NULL; + } + + if(count != tablesize) + { + fprintf(stderr,"Translation table size mismatch %d %d\n", + count, tablesize); + exit(1); + } + } + + /* + * Now go through the directory and figure out how large this one will be. + * Do not split a directory entry across a sector boundary + */ + s_entry = this_dir->contents; + this_dir->ce_bytes = 0; + while(s_entry) + { + new_reclen = s_entry->isorec.length[0]; + if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) + this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & + ~(SECTOR_SIZE - 1); + this_dir->size += new_reclen; + + /* See if continuation entries were used on disc */ + if(use_RockRidge && + s_entry->rr_attr_size != s_entry->total_rr_attr_size) + { + unsigned char * pnt; + int len; + int nbytes; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + + /* + * We make sure that each continuation entry record is not + * split across sectors, but each file could in theory have more + * than one CE, so we scan through and figure out what we need. + */ + while(len > 3) + { + if(pnt[0] == 'C' && pnt[1] == 'E') + { + nbytes = get_733((char *) pnt+20); + + if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >= + SECTOR_SIZE) this_dir->ce_bytes = + ROUND_UP(this_dir->ce_bytes); + /* Now store the block in the ce buffer */ + this_dir->ce_bytes += nbytes; + if(this_dir->ce_bytes & 1) this_dir->ce_bytes++; + } + len -= pnt[2]; + pnt += pnt[2]; + } + } + s_entry = s_entry->next; + } +} + +static void generate_reloc_directory() +{ + int new_reclen; + time_t current_time; + struct directory_entry *s_entry; + + /* Create an entry for our internal tree */ + time (¤t_time); + reloc_dir = (struct directory *) + e_malloc(sizeof(struct directory)); + memset(reloc_dir, 0, sizeof(struct directory)); + reloc_dir->parent = root; + reloc_dir->next = root->subdir; + root->subdir = reloc_dir; + reloc_dir->depth = 1; + reloc_dir->whole_name = strdup("./rr_moved"); + reloc_dir->de_name = strdup("rr_moved"); + reloc_dir->extent = 0; + + new_reclen = strlen(reloc_dir->de_name); + + /* Now create an actual directory entry */ + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memset(s_entry, 0, sizeof(struct directory_entry)); + s_entry->next = root->contents; + reloc_dir->self = s_entry; + + root->contents = s_entry; + root->contents->name = strdup(reloc_dir->de_name); + root->contents->filedir = root; + root->contents->isorec.flags[0] = 2; + root->contents->priority = 32768; + iso9660_date(root->contents->isorec.date, current_time); + root->contents->inode = UNCACHED_INODE; + root->contents->dev = (dev_t) UNCACHED_DEVICE; + set_723(root->contents->isorec.volume_sequence_number, DEF_VSN); + iso9660_file_length (reloc_dir->de_name, root->contents, 1); + + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + "rr_moved", s_entry, + &fstatbuf, &fstatbuf, 0); + }; + + /* Now create the . and .. entries in rr_moved */ + /* Now create an actual directory entry */ + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry, root->contents, + sizeof(struct directory_entry)); + s_entry->name = strdup("."); + iso9660_file_length (".", s_entry, 1); + + s_entry->filedir = reloc_dir; + reloc_dir->contents = s_entry; + + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + ".", s_entry, + &fstatbuf, &fstatbuf, 0); + }; + + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry, root->contents, + sizeof(struct directory_entry)); + s_entry->name = strdup(".."); + iso9660_file_length ("..", s_entry, 1); + s_entry->filedir = root; + reloc_dir->contents->next = s_entry; + reloc_dir->contents->next->next = NULL; + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + "..", s_entry, + &root_statbuf, &root_statbuf, 0); + }; +} + +static void FDECL1(increment_nlink, struct directory_entry *, s_entry){ + unsigned char * pnt; + int len, nlink; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len){ + if(pnt[0] == 'P' && pnt[1] == 'X') { + nlink = get_733((char *) pnt+12); + set_733((char *) pnt+12, nlink+1); + break; + }; + len -= pnt[2]; + pnt += pnt[2]; + }; +} + +void finish_cl_pl_entries(){ + struct directory_entry *s_entry, *s_entry1; + struct directory * d_entry; + + s_entry = reloc_dir->contents; + s_entry = s_entry->next->next; /* Skip past . and .. */ + for(; s_entry; s_entry = s_entry->next){ + d_entry = reloc_dir->subdir; + while(d_entry){ + if(d_entry->self == s_entry) break; + d_entry = d_entry->next; + }; + if(!d_entry){ + fprintf(stderr,"Unable to locate directory parent\n"); + exit(1); + }; + + /* First fix the PL pointer in the directory in the rr_reloc dir */ + s_entry1 = d_entry->contents->next; + set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, + s_entry->filedir->extent); + + /* Now fix the CL pointer */ + s_entry1 = s_entry->parent_rec; + + set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, + d_entry->extent); + + s_entry->filedir = reloc_dir; /* Now we can fix this */ + } + /* Next we need to modify the NLINK terms in the assorted root directory records + to account for the presence of the RR_MOVED directory */ + + increment_nlink(root->self); + increment_nlink(root->self->next); + d_entry = root->subdir; + while(d_entry){ + increment_nlink(d_entry->contents->next); + d_entry = d_entry->next; + }; +} + +/* + * This function scans the directory tree, looking for files, and it makes + * note of everything that is found. We also begin to construct the ISO9660 + * directory entries, so that we can determine how large each directory is. + */ + +int +FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, + struct iso_directory_record *, mrootp){ + DIR * current_dir; + char whole_path[1024]; + struct dirent * d_entry; + struct directory_entry * s_entry, *s_entry1; + struct directory * this_dir, *next_brother, *parent; + struct stat statbuf, lstatbuf; + int status, dflag; + int lstatus; + int n_orig; + struct directory_entry **orig_contents = NULL; + struct directory_entry * odpnt = NULL; + char * cpnt; + int new_reclen; + int deep_flag; + char * old_path; + + current_dir = opendir(path); + d_entry = NULL; + + /* Apparently NFS sometimes allows you to open the directory, but + then refuses to allow you to read the contents. Allow for this */ + + old_path = path; + + if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir); + + if(!current_dir || !d_entry) { + fprintf(stderr,"Unable to open directory %s\n", path); + de->isorec.flags[0] &= ~2; /* Mark as not a directory */ + if(current_dir) closedir(current_dir); + return 0; + }; + + parent = de->filedir; + /* Set up the struct for the current directory, and insert it into the + tree */ + +#ifdef VMS + vms_path_fixup(path); +#endif + + this_dir = (struct directory *) e_malloc(sizeof(struct directory)); + this_dir->next = NULL; + new_reclen = 0; + this_dir->subdir = NULL; + this_dir->self = de; + this_dir->contents = NULL; + this_dir->whole_name = strdup(path); + cpnt = strrchr(path, PATH_SEPARATOR); + if(cpnt) + cpnt++; + else + cpnt = path; + this_dir->de_name = strdup(cpnt); + this_dir->size = 0; + this_dir->extent = 0; + + if(!parent || parent == root){ + if (!root) { + root = this_dir; /* First time through for root directory only */ + root->depth = 0; + root->parent = root; + } else { + this_dir->depth = 1; + if(!root->subdir) + root->subdir = this_dir; + else { + next_brother = root->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + }; + this_dir->parent = parent; + }; + } else { + /* Come through here for normal traversal of tree */ +#ifdef DEBUG + fprintf(stderr,"%s(%d) ", path, this_dir->depth); +#endif + if(parent->depth > RR_relocation_depth) { + fprintf(stderr,"Directories too deep %s\n", path); + exit(1); + }; + + this_dir->parent = parent; + this_dir->depth = parent->depth + 1; + + if(!parent->subdir) + parent->subdir = this_dir; + else { + next_brother = parent->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + } + } + + /* + * Parse the same directory in the image that we are merging + * for multisession stuff. + */ + if( mrootp != NULL ) + { + orig_contents = read_merging_directory(mrootp, &n_orig); + } + +/* Now we scan the directory itself, and look at what is inside of it. */ + + dflag = 0; + while(1==1){ + + /* The first time through, skip this, since we already asked for + the first entry when we opened the directory. */ + if(dflag) d_entry = readdir_add_files(&path, old_path, current_dir); + dflag++; + + if(!d_entry) break; + + /* OK, got a valid entry */ + + /* If we do not want all files, then pitch the backups. */ + if(!all_files){ + if(strchr(d_entry->d_name,'~')) continue; + if(strchr(d_entry->d_name,'#')) continue; + }; + + if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){ + fprintf(stderr, "Overflow of stat buffer\n"); + exit(1); + }; + + /* Generate the complete ASCII path for this file */ + strcpy(whole_path, path); +#ifndef VMS + if(whole_path[strlen(whole_path)-1] != '/') + strcat(whole_path, "/"); +#endif + strcat(whole_path, d_entry->d_name); + + /* Should we exclude this file? */ + if (is_excluded(whole_path)) { + if (verbose) { + fprintf(stderr, "Excluded: %s\n",whole_path); + } + continue; + } + /** Should we exclude this file ? */ + if (matches(d_entry->d_name)) { + if (verbose) { + fprintf(stderr, "Excluded by match: %s\n", whole_path); + } + continue; + } + + if( generate_tables + && strcmp(d_entry->d_name, "TRANS.TBL") == 0 ) + { + /* + * Ignore this entry. We are going to be generating new + * versions of these files, and we need to ignore any + * originals that we might have found. + */ + if (verbose) + { + fprintf(stderr, "Excluded: %s\n",whole_path); + } + continue; + } + +#if 0 + if (verbose) fprintf(stderr, "%s\n",whole_path); +#endif + status = stat_filter(whole_path, &statbuf); + + lstatus = lstat_filter(whole_path, &lstatbuf); + + if( (status == -1) && (lstatus == -1) ) + { + /* + * This means that the file doesn't exist, or isn't accessible. + * Sometimes this is because of NFS permissions problems + * or it could mean that the user has attempted to 'add' something + * with the -i option and the directory being added doesn't exist. + */ + fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path); + continue; + } + + if(this_dir == root && strcmp(d_entry->d_name, ".") == 0) + root_statbuf = statbuf; /* Save this for later on */ + + /* We do this to make sure that the root entries are consistent */ + if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) { + statbuf = root_statbuf; + lstatbuf = root_statbuf; + }; + + if(S_ISLNK(lstatbuf.st_mode)){ + + /* Here we decide how to handle the symbolic links. Here + we handle the general case - if we are not following + links or there is an error, then we must change + something. If RR is in use, it is easy, we let RR + describe the file. If not, then we punt the file. */ + + if((status || !follow_links)){ + if(use_RockRidge){ + status = 0; + statbuf.st_size = 0; + STAT_INODE(statbuf) = UNCACHED_INODE; + statbuf.st_dev = (dev_t) UNCACHED_DEVICE; + statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; + } else { + if(follow_links) fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); + else fprintf(stderr, + "Symlink %s ignored - continuing.\n", + whole_path); + continue; /* Non Rock Ridge discs - ignore all symlinks */ + }; + } + + /* Here we handle a different kind of case. Here we have + a symlink, but we want to follow symlinks. If we run + across a directory loop, then we need to pretend that + we are not following symlinks for this file. If this + is the first time we have seen this, then make this + seem as if there was no symlink there in the first + place */ + + if( follow_links + && S_ISDIR(statbuf.st_mode) ) + { + if( strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") ) + { + if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) + { + if(!use_RockRidge) + { + fprintf(stderr, "Already cached directory seen (%s)\n", + whole_path); + continue; + } + statbuf.st_size = 0; + STAT_INODE(statbuf) = UNCACHED_INODE; + statbuf.st_dev = (dev_t) UNCACHED_DEVICE; + statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; + } else { + lstatbuf = statbuf; + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + } + } + } + + /* + * For non-directories, we just copy the stat information over + * so we correctly include this file. + */ + if( follow_links + && !S_ISDIR(statbuf.st_mode) ) + { + lstatbuf = statbuf; + } + } + + /* + * Add directories to the cache so that we don't waste space even + * if we are supposed to be following symlinks. + */ + if( follow_links + && strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") + && S_ISDIR(statbuf.st_mode) ) + { + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + } +#ifdef VMS + if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && + statbuf.st_fab_rfm != FAB$C_STMLF)) { + fprintf(stderr,"Warning - file %s has an unsupported VMS record" + " format (%d)\n", + whole_path, statbuf.st_fab_rfm); + } +#endif + + if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){ + fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", + whole_path, errno); + continue; + } + + /* Add this so that we can detect directory loops with hard links. + If we are set up to follow symlinks, then we skip this checking. */ + if( !follow_links + && S_ISDIR(lstatbuf.st_mode) + && strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") ) + { + if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) { + fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).\n", + whole_path, (unsigned long) statbuf.st_dev, + (unsigned long) STAT_INODE(statbuf)); + exit(1); + }; + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + }; + + if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) && + !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) + && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) && + !S_ISDIR(lstatbuf.st_mode)) { + fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n", + whole_path); + continue; + }; + + /* Who knows what trash this is - ignore and continue */ + + if(status) { + fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); + continue; + }; + + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + s_entry->next = this_dir->contents; + memset(s_entry->isorec.extent, 0, 8); + this_dir->contents = s_entry; + deep_flag = 0; + s_entry->table = NULL; + + s_entry->name = strdup(d_entry->d_name); + s_entry->whole_name = strdup (whole_path); + + s_entry->de_flags = 0; + s_entry->filedir = this_dir; + s_entry->isorec.flags[0] = 0; + s_entry->isorec.ext_attr_length[0] = 0; + iso9660_date(s_entry->isorec.date, statbuf.st_mtime); + s_entry->isorec.file_unit_size[0] = 0; + s_entry->isorec.interleave[0] = 0; + if(parent && parent == reloc_dir && strcmp(d_entry->d_name, "..") == 0){ + s_entry->inode = UNCACHED_INODE; + s_entry->dev = (dev_t) UNCACHED_DEVICE; + deep_flag = NEED_PL; + } else { + s_entry->inode = STAT_INODE(statbuf); + s_entry->dev = statbuf.st_dev; + }; + set_723(s_entry->isorec.volume_sequence_number, DEF_VSN); + iso9660_file_length(d_entry->d_name, s_entry, S_ISDIR(statbuf.st_mode)); + s_entry->rr_attr_size = 0; + s_entry->total_rr_attr_size = 0; + s_entry->rr_attributes = NULL; + + /* Directories are assigned sizes later on */ + if (!S_ISDIR(statbuf.st_mode)) { + set_733((char *) s_entry->isorec.size, statbuf.st_size); + + if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || + S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode) + || S_ISLNK(lstatbuf.st_mode)) + s_entry->size = 0; + else + s_entry->size = statbuf.st_size; + } else + s_entry->isorec.flags[0] = 2; + + /* + * We always should create an entirely new directory tree whenever + * we generate a new session, unless there were *no* changes whatsoever + * to any of the directories, in which case it would be kind of pointless + * to generate a new session. + * + * I believe it is possible to rigorously prove that any change anywhere + * in the filesystem will force the entire tree to be regenerated + * because the modified directory will get a new extent number. Since + * each subdirectory of the changed directory has a '..' entry, all of + * them will need to be rewritten too, and since the parent directory + * of the modified directory will have an extent pointer to the directory + * it too will need to be rewritten. Thus we will never be able to reuse + * any directory information when writing new sessions. + * + * We still check the previous session so we can mark off the equivalent + * entry in the list we got from the original disc, however. + */ + if(S_ISDIR(statbuf.st_mode) && orig_contents != NULL){ + check_prev_session(orig_contents, n_orig, s_entry, + &statbuf, &lstatbuf, &odpnt); + } + + if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") && + S_ISDIR(statbuf.st_mode) && this_dir->depth > RR_relocation_depth){ + if(!reloc_dir) generate_reloc_directory(); + + s_entry1 = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry1, this_dir->contents, + sizeof(struct directory_entry)); + s_entry1->table = NULL; + s_entry1->name = strdup(this_dir->contents->name); + s_entry1->whole_name = strdup(this_dir->contents->whole_name); + s_entry1->next = reloc_dir->contents; + reloc_dir->contents = s_entry1; + s_entry1->priority = 32768; + s_entry1->parent_rec = this_dir->contents; + + deep_flag = NEED_RE; + + if(use_RockRidge) { + generate_rock_ridge_attributes(whole_path, + d_entry->d_name, s_entry1, + &statbuf, &lstatbuf, deep_flag); + } + + deep_flag = 0; + + /* We need to set this temporarily so that the parent to this is correctly + determined. */ + s_entry1->filedir = reloc_dir; + if( odpnt != NULL ) + { + scan_directory_tree(whole_path, s_entry1, &odpnt->isorec); + } + else + { + scan_directory_tree(whole_path, s_entry1, NULL); + } + if( odpnt != NULL ) + { + free(odpnt); + odpnt = NULL; + } + s_entry1->filedir = this_dir; + + statbuf.st_size = 0; + statbuf.st_mode &= 0777; + set_733((char *) s_entry->isorec.size, 0); + s_entry->size = 0; + s_entry->isorec.flags[0] = 0; + s_entry->inode = UNCACHED_INODE; + deep_flag = NEED_CL; + }; + + if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) { + char buffer[2048]; + int nchar; + switch(lstatbuf.st_mode & S_IFMT){ + case S_IFDIR: + sprintf(buffer,"D\t%s\n", + s_entry->name); + break; +#ifndef NON_UNIXFS + case S_IFBLK: + sprintf(buffer,"B\t%s\t%lu %lu\n", + s_entry->name, + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev)); + break; + case S_IFIFO: + sprintf(buffer,"P\t%s\n", + s_entry->name); + break; + case S_IFCHR: + sprintf(buffer,"C\t%s\t%lu %lu\n", + s_entry->name, + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev)); + break; + case S_IFLNK: + nchar = readlink(whole_path, + symlink_buff, + sizeof(symlink_buff)); + symlink_buff[nchar < 0 ? 0 : nchar] = 0; + sprintf(buffer,"L\t%s\t%s\n", + s_entry->name, symlink_buff); + break; +#ifdef S_IFSOCK + case S_IFSOCK: + sprintf(buffer,"S\t%s\n", + s_entry->name); + break; +#endif +#endif /* NON_UNIXFS */ + case S_IFREG: + default: + sprintf(buffer,"F\t%s\n", + s_entry->name); + break; + }; + s_entry->table = strdup(buffer); + }; + + /* + * See if we have an entry for this guy in the previous session. + */ + if( orig_contents != NULL && !S_ISDIR(statbuf.st_mode)) + { + check_prev_session(orig_contents, n_orig, s_entry, + &statbuf, &lstatbuf, NULL); + } + + if(S_ISDIR(statbuf.st_mode)){ + int dflag; + if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) { + if( odpnt != NULL ) + { + dflag = scan_directory_tree(whole_path, s_entry, + &odpnt->isorec); + } + else + { + dflag = scan_directory_tree(whole_path, s_entry, NULL); + } + /* If unable to scan directory, mark this as a non-directory */ + if(!dflag) + lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; + if( odpnt != NULL ) + { + free(odpnt); + odpnt = NULL; + } + } + } + + if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".") == 0) + deep_flag |= NEED_CE | NEED_SP; /* For extension record */ + + /* Now figure out how much room this file will take in the directory */ + + if(use_RockRidge) { + generate_rock_ridge_attributes(whole_path, + d_entry->d_name, s_entry, + &statbuf, &lstatbuf, deep_flag); + + } + } + closedir(current_dir); + + if( orig_contents != NULL ) + { + merge_remaining_entries(this_dir, orig_contents, n_orig); + free_mdinfo(orig_contents, n_orig); + } + + if( this_dir->contents == NULL ) + { + /* + * This directory must have been inaccessible. + */ + return 0; + } + sort_n_finish(this_dir); + + return 1; +} + + +void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){ + struct directory * dpnt; + + dpnt = node; + + while (dpnt){ + if( dpnt->extent > session_start ) + { + generate_one_directory(dpnt, outfile); + } + if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile); + dpnt = dpnt->next; + } +} + +void FDECL1(dump_tree, struct directory *, node){ + struct directory * dpnt; + + dpnt = node; + + while (dpnt){ + fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name); + if(dpnt->subdir) dump_tree(dpnt->subdir); + dpnt = dpnt->next; + } +} + +/* + * something quick and dirty to locate a file given a path + * recursively walks down path in filename until it finds the + * directory entry for the desired file + */ +struct directory_entry * FDECL2(search_tree_file, struct directory *, + node,char *, filename) +{ + struct directory_entry * depnt; + struct directory * dpnt; + char * p1; + char * rest; + char * subdir; + + /* + * strip off next directory name from filename + */ + subdir = strdup(filename); + + if( (p1=strchr(subdir, '/')) == subdir ) + { + fprintf(stderr,"call to search_tree_file with an absolute path, stripping\n"); + fprintf(stderr,"initial path separator. Hope this was intended...\n"); + memmove(subdir, subdir+1, strlen(subdir)-1); + p1 = strchr(subdir, '/'); + } + + /* + * do we need to find a subdirectory + */ + if (p1) + { + *p1 = '\0'; + +#ifdef DEBUG_TORITO + printf("Looking for subdir called %s\n",p1); +#endif + + rest = p1+1; + +#ifdef DEBUG_TORITO + printf("Remainder of path name is now %s\n", rest); +#endif + + dpnt = node->subdir; + while( dpnt ) + { +#ifdef DEBUG_TORITO + fprintf(stderr,"%4d %5d %s\n", dpnt->extent, dpnt->size, + dpnt->de_name); +#endif + if (!strcmp(subdir, dpnt->de_name)) + { +#ifdef DEBUG_TORITO + printf("Calling next level with filename = %s", rest); +#endif + return(search_tree_file( dpnt, rest )); + } + dpnt = dpnt->next; + } + + /* if we got here means we couldnt find the subdir */ + return (NULL); + } + else + { + /* + * look for a normal file now + */ + depnt = node->contents; + while (depnt) + { +#ifdef DEBUG_TORITO + fprintf(stderr,"%4d %5d %s\n",depnt->isorec.extent, + depnt->size, depnt->name); +#endif + if (!strcmp(filename, depnt->name)) + { +#ifdef DEBUG_TORITO + printf("Found our file %s", filename); +#endif + return(depnt); + } + depnt = depnt->next; + } + /* + * if we got here means we couldnt find the subdir + */ + return (NULL); + } + fprintf(stderr,"We cant get here in search_tree_file :-/ \n"); +} + diff --git a/util/mkisofs/write.c b/util/mkisofs/write.c new file mode 100644 index 000000000..cfc9b763c --- /dev/null +++ b/util/mkisofs/write.c @@ -0,0 +1,1142 @@ +/* + * Program write.c - dump memory structures to file for iso9660 filesystem. + + Written by Eric Youngdale (1993). + + Copyright 1993 Yggdrasil Computing, Incorporated + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$Id: write.c,v 1.6.1.3 1997/11/13 05:07:13 eric Exp $"; + +#include +#include +#include "mkisofs.h" +#include "iso9660.h" +#include +#include + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef __svr4__ +extern char * strdup(const char *); +#endif + +#ifdef VMS +extern char * strdup(const char *); +#endif + + +/* Max number of sectors we will write at one time */ +#define NSECT 16 + +/* Counters for statistics */ + +static int table_size = 0; +static int total_dir_size = 0; +static int rockridge_size = 0; +static struct directory ** pathlist; +static next_path_index = 1; + +/* Used to fill in some of the information in the volume descriptor. */ +static struct tm local; +static struct tm gmt; + +/* Routines to actually write the disc. We write sequentially so that + we could write a tape, or write the disc directly */ + + +#define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof(vol_desc.X)) + +void FDECL2(set_721, char *, pnt, unsigned int, i) +{ + pnt[0] = i & 0xff; + pnt[1] = (i >> 8) & 0xff; +} + +void FDECL2(set_722, char *, pnt, unsigned int, i) +{ + pnt[0] = (i >> 8) & 0xff; + pnt[1] = i & 0xff; +} + +void FDECL2(set_723, char *, pnt, unsigned int, i) +{ + pnt[3] = pnt[0] = i & 0xff; + pnt[2] = pnt[1] = (i >> 8) & 0xff; +} + +void FDECL2(set_731, char *, pnt, unsigned int, i) +{ + pnt[0] = i & 0xff; + pnt[1] = (i >> 8) & 0xff; + pnt[2] = (i >> 16) & 0xff; + pnt[3] = (i >> 24) & 0xff; +} + +void FDECL2(set_732, char *, pnt, unsigned int, i) +{ + pnt[3] = i & 0xff; + pnt[2] = (i >> 8) & 0xff; + pnt[1] = (i >> 16) & 0xff; + pnt[0] = (i >> 24) & 0xff; +} + +int FDECL1(get_733, char *, p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + +void FDECL2(set_733, char *, pnt, unsigned int, i) +{ + pnt[7] = pnt[0] = i & 0xff; + pnt[6] = pnt[1] = (i >> 8) & 0xff; + pnt[5] = pnt[2] = (i >> 16) & 0xff; + pnt[4] = pnt[3] = (i >> 24) & 0xff; +} + +void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file) +{ + while(count) + { + int got = fwrite(buffer,size,count,file); + + if(got<=0) + { + fprintf(stderr,"cannot fwrite %d*%d\n",size,count); + exit(1); + } + count-=got,*(char**)&buffer+=size*got; + } +} + +struct deferred_write +{ + struct deferred_write * next; + char * table; + unsigned int extent; + unsigned int size; + char * name; +}; + +static struct deferred_write * dw_head = NULL, * dw_tail = NULL; + +static struct directory_entry * sort_dir; +static struct eltorito_boot_descriptor boot_desc; + +unsigned int last_extent_written =0; +static struct iso_primary_descriptor vol_desc; +static path_table_index; +static time_t begun; + +/* We recursively walk through all of the directories and assign extent + numbers to them. We have already assigned extent numbers to everything that + goes in front of them */ + +void FDECL1(assign_directory_addresses, struct directory *, node) +{ + int dir_size; + struct directory * dpnt; + + dpnt = node; + + while (dpnt) + { + /* + * If we already have an extent for this (i.e. it came from + * a multisession disc), then don't reassign a new extent. + */ + dpnt->path_index = next_path_index++; + if( dpnt->extent == 0 ) + { + dpnt->extent = last_extent; + dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11; + + last_extent += dir_size; + + /* + * Leave room for the CE entries for this directory. Keep them + * close to the reference directory so that access will be + * quick. + */ + if(dpnt->ce_bytes) + { + last_extent += ROUND_UP(dpnt->ce_bytes) >> 11; + } + } + + if(dpnt->subdir) + { + assign_directory_addresses(dpnt->subdir); + } + + dpnt = dpnt->next; + } +} + +static void FDECL3(write_one_file, char *, filename, + unsigned int, size, FILE *, outfile) +{ + char buffer[SECTOR_SIZE * NSECT]; + FILE * infile; + int remain; + int use; + + + if ((infile = fopen(filename, "rb")) == NULL) + { +#if defined(sun) || defined(_AUX_SOURCE) + fprintf(stderr, "cannot open %s: (%d)\n", filename, errno); +#else + fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno)); +#endif + exit(1); + } + remain = size; + + while(remain > 0) + { + use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain); + use = ROUND_UP(use); /* Round up to nearest sector boundary */ + memset(buffer, 0, use); + if (fread(buffer, 1, use, infile) == 0) + { + fprintf(stderr,"cannot read from %s\n",filename); + exit(1); + } + xfwrite(buffer, 1, use, outfile); + last_extent_written += use/SECTOR_SIZE; +#if 0 + if((last_extent_written % 1000) < use/SECTOR_SIZE) + { + fprintf(stderr,"%d..", last_extent_written); + } +#else + if((last_extent_written % 5000) < use/SECTOR_SIZE) + { + time_t now; + time_t the_end; + double frac; + + time(&now); + frac = last_extent_written / (double)last_extent; + the_end = begun + (now - begun) / frac; + fprintf(stderr, "%6.2f%% done, estimate finish %s", + frac * 100., ctime(&the_end)); + } +#endif + remain -= use; + } + fclose(infile); +} /* write_one_file(... */ + +static void FDECL1(write_files, FILE *, outfile) +{ + struct deferred_write * dwpnt, *dwnext; + dwpnt = dw_head; + while(dwpnt) + { + if(dwpnt->table) + { + xfwrite(dwpnt->table, 1, ROUND_UP(dwpnt->size), outfile); + last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE; + table_size += dwpnt->size; +/* fprintf(stderr,"Size %d ", dwpnt->size); */ + free(dwpnt->table); + } + else + { + +#ifdef VMS + vms_write_one_file(dwpnt->name, dwpnt->size, outfile); +#else + write_one_file(dwpnt->name, dwpnt->size, outfile); +#endif + free(dwpnt->name); + } + + dwnext = dwpnt; + dwpnt = dwpnt->next; + free(dwnext); + } +} /* write_files(... */ + +#if 0 +static void dump_filelist() +{ + struct deferred_write * dwpnt; + dwpnt = dw_head; + while(dwpnt) + { + fprintf(stderr, "File %s\n",dwpnt->name); + dwpnt = dwpnt->next; + } + fprintf(stderr,"\n"); +} +#endif + +int FDECL2(compare_dirs, const void *, rr, const void *, ll) +{ + char * rpnt, *lpnt; + struct directory_entry ** r, **l; + + r = (struct directory_entry **) rr; + l = (struct directory_entry **) ll; + rpnt = (*r)->isorec.name; + lpnt = (*l)->isorec.name; + + /* + * Put the '.' and '..' entries on the head of the sorted list. + * For normal ASCII, this always happens to be the case, but out of + * band characters cause this not to be the case sometimes. + */ + if( strcmp(rpnt, ".") == 0 ) return -1; + if( strcmp(lpnt, ".") == 0 ) return 1; + + if( strcmp(rpnt, "..") == 0 ) return -1; + if( strcmp(lpnt, "..") == 0 ) return 1; + + while(*rpnt && *lpnt) + { + if(*rpnt == ';' && *lpnt != ';') return -1; + if(*rpnt != ';' && *lpnt == ';') return 1; + + if(*rpnt == ';' && *lpnt == ';') return 0; + + if(*rpnt == '.' && *lpnt != '.') return -1; + if(*rpnt != '.' && *lpnt == '.') return 1; + + if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1; + if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1; + rpnt++; lpnt++; + } + if(*rpnt) return 1; + if(*lpnt) return -1; + return 0; +} + +void FDECL1(sort_directory, struct directory_entry **, sort_dir) +{ + int dcount = 0; + int i, len; + struct directory_entry * s_entry; + struct directory_entry ** sortlist; + + s_entry = *sort_dir; + while(s_entry) + { + dcount++; + s_entry = s_entry->next; + } + + /* + * OK, now we know how many there are. Build a vector for sorting. + */ + sortlist = (struct directory_entry **) + e_malloc(sizeof(struct directory_entry *) * dcount); + + dcount = 0; + s_entry = *sort_dir; + while(s_entry) + { + sortlist[dcount] = s_entry; + len = s_entry->isorec.name_len[0]; + s_entry->isorec.name[len] = 0; + dcount++; + s_entry = s_entry->next; + } + + qsort(sortlist, dcount, sizeof(struct directory_entry *), + (int (*)(const void *, const void *))compare_dirs); + + /* + * Now reassemble the linked list in the proper sorted order + */ + for(i=0; inext = sortlist[i+1]; + } + + sortlist[dcount-1]->next = NULL; + *sort_dir = sortlist[0]; + + free(sortlist); + +} + +void generate_root_record() +{ + time_t ctime; + + time (&ctime); + + local = *localtime(&ctime); + gmt = *gmtime(&ctime); + + root_record.length[0] = 1 + sizeof(struct iso_directory_record) + - sizeof(root_record.name); + root_record.ext_attr_length[0] = 0; + set_733((char *) root_record.extent, root->extent); + set_733((char *) root_record.size, ROUND_UP(root->size)); + iso9660_date(root_record.date, ctime); + root_record.flags[0] = 2; + root_record.file_unit_size[0] = 0; + root_record.interleave[0] = 0; + set_723(root_record.volume_sequence_number, DEF_VSN); + root_record.name_len[0] = 1; +} + +static void FDECL1(assign_file_addresses, struct directory *, dpnt) +{ + struct directory * finddir; + struct directory_entry * s_entry; + struct file_hash *s_hash; + struct deferred_write * dwpnt; + char whole_path[1024]; + + while (dpnt) + { + s_entry = dpnt->contents; + for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) + { + + /* + * If we already have an extent for this entry, + * then don't assign a new one. It must have come + * from a previous session on the disc. Note that + * we don't end up scheduling the thing for writing + * either. + */ + if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 ) + { + continue; + } + + /* + * This saves some space if there are symlinks present + */ + s_hash = find_hash(s_entry->dev, s_entry->inode); + if(s_hash) + { + if(verbose) + { + fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, + SPATH_SEPARATOR, s_entry->name); + } + set_733((char *) s_entry->isorec.extent, s_hash->starting_block); + set_733((char *) s_entry->isorec.size, s_hash->size); + continue; + } + + /* + * If this is for a directory that is not a . or a .. entry, + * then look up the information for the entry. We have already + * assigned extents for directories, so we just need to + * fill in the blanks here. + */ + if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && + s_entry->isorec.flags[0] == 2) + { + finddir = dpnt->subdir; + while(1==1) + { + if(finddir->self == s_entry) break; + finddir = finddir->next; + if(!finddir) + { + fprintf(stderr,"Fatal goof\n"); exit(1); + } + } + set_733((char *) s_entry->isorec.extent, finddir->extent); + s_entry->starting_block = finddir->extent; + s_entry->size = ROUND_UP(finddir->size); + total_dir_size += s_entry->size; + add_hash(s_entry); + set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size)); + continue; + } + + + /* + * If this is . or .., then look up the relevant info from the + * tables. + */ + if(strcmp(s_entry->name,".") == 0) + { + set_733((char *) s_entry->isorec.extent, dpnt->extent); + + /* + * Set these so that the hash table has the + * correct information + */ + s_entry->starting_block = dpnt->extent; + s_entry->size = ROUND_UP(dpnt->size); + + add_hash(s_entry); + s_entry->starting_block = dpnt->extent; + set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size)); + continue; + } + + if(strcmp(s_entry->name,"..") == 0) + { + if(dpnt == root) + { + total_dir_size += root->size; + } + set_733((char *) s_entry->isorec.extent, dpnt->parent->extent); + + /* + * Set these so that the hash table has the + * correct information + */ + s_entry->starting_block = dpnt->parent->extent; + s_entry->size = ROUND_UP(dpnt->parent->size); + + add_hash(s_entry); + s_entry->starting_block = dpnt->parent->extent; + set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size)); + continue; + } + + /* + * Some ordinary non-directory file. Just schedule the + * file to be written. This is all quite + * straightforward, just make a list and assign extents + * as we go. Once we get through writing all of the + * directories, we should be ready write out these + * files + */ + if(s_entry->size) + { + dwpnt = (struct deferred_write *) + e_malloc(sizeof(struct deferred_write)); + if(dw_tail) + { + dw_tail->next = dwpnt; + dw_tail = dwpnt; + } + else + { + dw_head = dwpnt; + dw_tail = dwpnt; + } + if(s_entry->inode == TABLE_INODE) + { + dwpnt->table = s_entry->table; + dwpnt->name = NULL; + sprintf(whole_path,"%s%sTRANS.TBL", + s_entry->filedir->whole_name, SPATH_SEPARATOR); + } + else + { + dwpnt->table = NULL; + strcpy(whole_path, s_entry->whole_name); + dwpnt->name = strdup(whole_path); + } + dwpnt->next = NULL; + dwpnt->size = s_entry->size; + dwpnt->extent = last_extent; + set_733((char *) s_entry->isorec.extent, last_extent); + s_entry->starting_block = last_extent; + add_hash(s_entry); + last_extent += ROUND_UP(s_entry->size) >> 11; + if(verbose) + { + fprintf(stderr,"%d %d %s\n", s_entry->starting_block, + last_extent-1, whole_path); + } +#ifdef DBG_ISO + if((ROUND_UP(s_entry->size) >> 11) > 500) + { + fprintf(stderr,"Warning: large file %s\n", whole_path); + fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); + fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); + + } +#endif + if(last_extent > (800000000 >> 11)) + { + /* + * More than 800Mb? Punt + */ + fprintf(stderr,"Extent overflow processing file %s\n", whole_path); + fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); + fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); + exit(1); + } + continue; + } + + /* + * This is for zero-length files. If we leave the extent 0, + * then we get screwed, because many readers simply drop files + * that have an extent of zero. Thus we leave the size 0, + * and just assign the extent number. + */ + set_733((char *) s_entry->isorec.extent, last_extent); + } + if(dpnt->subdir) + { + assign_file_addresses(dpnt->subdir); + } + dpnt = dpnt->next; + } +} /* assign_file_addresses(... */ + +void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile) +{ + unsigned int ce_address = 0; + char * ce_buffer; + unsigned int ce_index = 0; + unsigned int ce_size; + unsigned int dir_index; + char * directory_buffer; + int new_reclen; + struct directory_entry * s_entry; + struct directory_entry * s_entry_d; + unsigned int total_size; + + total_size = (dpnt->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); + directory_buffer = (char *) e_malloc(total_size); + memset(directory_buffer, 0, total_size); + dir_index = 0; + + ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); + ce_buffer = NULL; + + if(ce_size) + { + ce_buffer = (char *) e_malloc(ce_size); + memset(ce_buffer, 0, ce_size); + + ce_index = 0; + + /* + * Absolute byte address of CE entries for this directory + */ + ce_address = last_extent_written + (total_size >> 11); + ce_address = ce_address << 11; + } + + s_entry = dpnt->contents; + while(s_entry) + { + + /* + * We do not allow directory entries to cross sector boundaries. + * Simply pad, and then start the next entry at the next sector + */ + new_reclen = s_entry->isorec.length[0]; + if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE ) + { + dir_index = (dir_index + (SECTOR_SIZE - 1)) & + ~(SECTOR_SIZE - 1); + } + + memcpy(directory_buffer + dir_index, &s_entry->isorec, + sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]); + dir_index += sizeof(struct iso_directory_record) - + sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0]; + + /* + * Add the Rock Ridge attributes, if present + */ + if(s_entry->rr_attr_size) + { + if(dir_index & 1) + { + directory_buffer[dir_index++] = 0; + } + + /* + * If the RR attributes were too long, then write the + * CE records, as required. + */ + if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) + { + unsigned char * pnt; + int len, nbytes; + + /* + * Go through the entire record and fix up the CE entries + * so that the extent and offset are correct + */ + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len > 3) + { +#ifdef DEBUG + if (!ce_size) + { + fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n", + ce_index, ce_address); + } +#endif + + if(pnt[0] == 'C' && pnt[1] == 'E') + { + nbytes = get_733( (char *) pnt+20); + + if((ce_index & (SECTOR_SIZE - 1)) + nbytes >= + SECTOR_SIZE) + { + ce_index = ROUND_UP(ce_index); + } + + set_733( (char *) pnt+4, + (ce_address + ce_index) >> 11); + set_733( (char *) pnt+12, + (ce_address + ce_index) & (SECTOR_SIZE - 1)); + + + /* + * Now store the block in the ce buffer + */ + memcpy(ce_buffer + ce_index, + pnt + pnt[2], nbytes); + ce_index += nbytes; + if(ce_index & 1) + { + ce_index++; + } + } + len -= pnt[2]; + pnt += pnt[2]; + } + + } + + rockridge_size += s_entry->total_rr_attr_size; + memcpy(directory_buffer + dir_index, s_entry->rr_attributes, + s_entry->rr_attr_size); + dir_index += s_entry->rr_attr_size; + } + if(dir_index & 1) + { + directory_buffer[dir_index++] = 0; + } + + s_entry_d = s_entry; + s_entry = s_entry->next; + + if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes); + if( s_entry_d->name != NULL ) + { + free (s_entry_d->name); + } + if( s_entry_d->whole_name != NULL ) + { + free (s_entry_d->whole_name); + } + free (s_entry_d); + } + sort_dir = NULL; + + if(dpnt->size != dir_index) + { + fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, + dir_index, dpnt->de_name); + } + + xfwrite(directory_buffer, 1, total_size, outfile); + last_extent_written += total_size >> 11; + free(directory_buffer); + + if(ce_size) + { + if(ce_index != dpnt->ce_bytes) + { + fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n", + ce_index, dpnt->ce_bytes); + } + xfwrite(ce_buffer, 1, ce_size, outfile); + last_extent_written += ce_size >> 11; + free(ce_buffer); + } + +} /* generate_one_directory(... */ + +static +void FDECL1(build_pathlist, struct directory *, node) +{ + struct directory * dpnt; + + dpnt = node; + + while (dpnt) + { + pathlist[dpnt->path_index] = dpnt; + if(dpnt->subdir) build_pathlist(dpnt->subdir); + dpnt = dpnt->next; + } +} /* build_pathlist(... */ + +int FDECL2(compare_paths, void const *, r, void const *, l) +{ + struct directory const *ll = *(struct directory * const *)l; + struct directory const *rr = *(struct directory * const *)r; + + if (rr->parent->path_index < ll->parent->path_index) + { + return -1; + } + + if (rr->parent->path_index > ll->parent->path_index) + { + return 1; + } + + return strcmp(rr->self->isorec.name, ll->self->isorec.name); + +} /* compare_paths(... */ + +void generate_path_tables() +{ + struct directory_entry * de; + struct directory * dpnt; + int fix; + int i; + int j; + int namelen; + char * npnt; + char * npnt1; + int tablesize; + + /* + * First allocate memory for the tables and initialize the memory + */ + tablesize = path_blocks << 11; + path_table_m = (char *) e_malloc(tablesize); + path_table_l = (char *) e_malloc(tablesize); + memset(path_table_l, 0, tablesize); + memset(path_table_m, 0, tablesize); + + /* + * Now start filling in the path tables. Start with root directory + */ + path_table_index = 0; + pathlist = (struct directory **) e_malloc(sizeof(struct directory *) + * next_path_index); + memset(pathlist, 0, sizeof(struct directory *) * next_path_index); + build_pathlist(root); + + do + { + fix = 0; + qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), + (int (*)(const void *, const void *))compare_paths); + + for(j=1; jpath_index != j) + { + pathlist[j]->path_index = j; + fix++; + } + } + } while(fix); + + for(j=1; jde_name; + + /* + * So the root comes out OK + */ + if( (*npnt == 0) || (dpnt == root) ) + { + npnt = "."; + } + npnt1 = strrchr(npnt, PATH_SEPARATOR); + if(npnt1) + { + npnt = npnt1 + 1; + } + + de = dpnt->self; + if(!de) + { + fprintf(stderr,"Fatal goof\n"); + exit(1); + } + + + namelen = de->isorec.name_len[0]; + + path_table_l[path_table_index] = namelen; + path_table_m[path_table_index] = namelen; + path_table_index += 2; + + set_731(path_table_l + path_table_index, dpnt->extent); + set_732(path_table_m + path_table_index, dpnt->extent); + path_table_index += 4; + + set_721(path_table_l + path_table_index, + dpnt->parent->path_index); + set_722(path_table_m + path_table_index, + dpnt->parent->path_index); + path_table_index += 2; + + for(i =0; iisorec.name[i]; + path_table_m[path_table_index] = de->isorec.name[i]; + path_table_index++; + } + if(path_table_index & 1) + { + path_table_index++; /* For odd lengths we pad */ + } + } + + free(pathlist); + if(path_table_index != path_table_size) + { + fprintf(stderr,"Path table lengths do not match %d %d\n", + path_table_index, + path_table_size); + } +} /* generate_path_tables(... */ + +void +FDECL3(memcpy_max, char *, to, char *, from, int, max) +{ + int n = strlen(from); + if (n > max) + { + n = max; + } + memcpy(to, from, n); + +} /* memcpy_max(... */ + +int FDECL1(iso_write, FILE *, outfile) +{ + char buffer[2048]; + int i; + char iso_time[17]; + int should_write; + + time(&begun); + assign_file_addresses(root); + + memset(buffer, 0, sizeof(buffer)); + + /* + * This will break in the year 2000, I supose, but there is no good way + * to get the top two digits of the year. + */ + sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local.tm_year, + local.tm_mon+1, local.tm_mday, + local.tm_hour, local.tm_min, local.tm_sec); + + local.tm_min -= gmt.tm_min; + local.tm_hour -= gmt.tm_hour; + local.tm_yday -= gmt.tm_yday; + iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15; + + /* + * First, we output 16 sectors of all zero + */ + + for(i=0; i<16; i++) + { + xfwrite(buffer, 1, sizeof(buffer), outfile); + } + + last_extent_written += 16; + + /* + * Next we write out the primary descriptor for the disc + */ + memset(&vol_desc, 0, sizeof(vol_desc)); + vol_desc.type[0] = ISO_VD_PRIMARY; + memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + vol_desc.version[0] = 1; + + memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id)); + memcpy_max(vol_desc.system_id, system_id, strlen(system_id)); + + memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id)); + memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id)); + + should_write = last_extent - session_start; + set_733((char *) vol_desc.volume_space_size, should_write); + set_723(vol_desc.volume_set_size, 1); + set_723(vol_desc.volume_sequence_number, DEF_VSN); + set_723(vol_desc.logical_block_size, 2048); + + /* + * The path tables are used by DOS based machines to cache directory + * locations + */ + + set_733((char *) vol_desc.path_table_size, path_table_size); + set_731(vol_desc.type_l_path_table, path_table[0]); + set_731(vol_desc.opt_type_l_path_table, path_table[1]); + set_732(vol_desc.type_m_path_table, path_table[2]); + set_732(vol_desc.opt_type_m_path_table, path_table[3]); + + /* + * Now we copy the actual root directory record + */ + memcpy(vol_desc.root_directory_record, &root_record, + sizeof(struct iso_directory_record) + 1); + + /* + * The rest is just fluff. It looks nice to fill in many of these fields, + * though. + */ + FILL_SPACE(volume_set_id); + if(volset_id) memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id)); + + FILL_SPACE(publisher_id); + if(publisher) memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher)); + + FILL_SPACE(preparer_id); + if(preparer) memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer)); + + FILL_SPACE(application_id); + if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid)); + + FILL_SPACE(copyright_file_id); + if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, + strlen(copyright)); + + FILL_SPACE(abstract_file_id); + if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, + strlen(abstract)); + + FILL_SPACE(bibliographic_file_id); + if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, + strlen(biblio)); + + FILL_SPACE(creation_date); + FILL_SPACE(modification_date); + FILL_SPACE(expiration_date); + FILL_SPACE(effective_date); + vol_desc.file_structure_version[0] = 1; + FILL_SPACE(application_data); + + memcpy(vol_desc.creation_date, iso_time, 17); + memcpy(vol_desc.modification_date, iso_time, 17); + memcpy(vol_desc.expiration_date, "0000000000000000", 17); + memcpy(vol_desc.effective_date, iso_time, 17); + + /* + * if not a bootable cd do it the old way + */ + xfwrite(&vol_desc, 1, 2048, outfile); + last_extent_written++; + if (use_eltorito) + { + /* + * Next we write out the boot volume descriptor for the disc + */ + get_torito_desc(&boot_desc); + xfwrite(&boot_desc, 1, 2048, outfile); + last_extent_written ++; + } + + /* + * Now write the end volume descriptor. Much simpler than the other one + */ + memset(&vol_desc, 0, sizeof(vol_desc)); + vol_desc.type[0] = ISO_VD_END; + memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + vol_desc.version[0] = 1; + xfwrite(&vol_desc, 1, 2048, outfile); + last_extent_written += 1; + + /* + * Next we write the path tables + */ + xfwrite(path_table_l, 1, path_blocks << 11, outfile); + xfwrite(path_table_m, 1, path_blocks << 11, outfile); + last_extent_written += 2*path_blocks; + free(path_table_l); + free(path_table_m); + path_table_l = NULL; + path_table_m = NULL; + + /* + * OK, all done with that crap. Now write out the directories. + * This is where the fur starts to fly, because we need to keep track of + * each file as we find it and keep track of where we put it. + */ + +#ifdef DBG_ISO + fprintf(stderr,"Total directory extents being written = %d\n", last_extent); +#endif +#if 0 + generate_one_directory(root, outfile); +#endif + generate_iso9660_directories(root, outfile); + + if(extension_record) + { + xfwrite(extension_record, 1, SECTOR_SIZE, outfile); + last_extent_written++; + } + + /* + * Now write all of the files that we need. + */ + fprintf(stderr,"Total extents scheduled to be written = %d\n", + last_extent - session_start); + write_files(outfile); + + fprintf(stderr,"Total extents actually written = %d\n", + last_extent_written - session_start); + /* + * Hard links throw us off here + */ + if(should_write != last_extent - session_start) + { + fprintf(stderr,"Number of extents written not what was predicted. Please fix.\n"); + fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent); + } + + fprintf(stderr,"Total translation table size: %d\n", table_size); + fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size); + fprintf(stderr,"Total directory bytes: %d\n", total_dir_size); + fprintf(stderr,"Path table size(bytes): %d\n", path_table_size); + +#ifdef DEBUG + fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n", + next_extent, last_extent, last_extent_written); +#endif + + return 0; + +} /* iso_write(... */ From 63eb2d63b134cc5877bab10a6c4cacc2ae738be4 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 22:51:41 +0000 Subject: [PATCH 062/146] Import http://www.tux.org/pub/people/eric-youngdale/mkisofs/mkisofs-1.12b4.tar.gz --- util/mkisofs/defaults.h | 12 +- util/mkisofs/eltorito.c | 42 +- util/mkisofs/getopt.c | 760 +++++++++++++++++++ util/mkisofs/getopt1.c | 190 +++++ util/mkisofs/hash.c | 5 +- util/mkisofs/iso9660.h | 9 +- util/mkisofs/joliet.c | 972 ++++++++++++++++++++++++ util/mkisofs/mkisofs.c | 652 ++++++++++++++-- util/mkisofs/mkisofs.h | 154 +++- util/mkisofs/multi.c | 137 +++- util/mkisofs/name.c | 24 +- util/mkisofs/rock.c | 51 +- util/mkisofs/tree.c | 1571 +++++++++++++++++++++++++-------------- util/mkisofs/write.c | 503 +++++++++---- 14 files changed, 4270 insertions(+), 812 deletions(-) create mode 100644 util/mkisofs/getopt.c create mode 100644 util/mkisofs/getopt1.c create mode 100644 util/mkisofs/joliet.c 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}; From 11e9a11511909eb94fbde8451552e1a8143bbe6b Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sun, 8 Nov 2009 22:52:08 +0000 Subject: [PATCH 063/146] Import http://www.tux.org/pub/people/eric-youngdale/mkisofs/mkisofs-1.12b5.tar.gz --- util/mkisofs/defaults.h | 8 +- util/mkisofs/eltorito.c | 11 +- util/mkisofs/exclude.h | 6 +- util/mkisofs/fnmatch.c | 26 ++-- util/mkisofs/include/fctldefs.h | 57 +++++++ util/mkisofs/include/mconfig.h | 268 ++++++++++++++++++++++++++++++++ util/mkisofs/include/prototyp.h | 74 +++++++++ util/mkisofs/include/statdefs.h | 139 +++++++++++++++++ util/mkisofs/joliet.c | 138 ++++++++++------ util/mkisofs/match.c | 93 ++++++++++- util/mkisofs/match.h | 14 +- util/mkisofs/mkisofs.c | 205 +++++++++++++++++++++--- util/mkisofs/mkisofs.h | 22 ++- util/mkisofs/multi.c | 108 ++++++++++--- util/mkisofs/name.c | 6 +- util/mkisofs/rock.c | 56 ++++--- util/mkisofs/tree.c | 173 +++++++++++++++++---- util/mkisofs/write.c | 178 ++++++++++++++------- 18 files changed, 1364 insertions(+), 218 deletions(-) create mode 100644 util/mkisofs/include/fctldefs.h create mode 100644 util/mkisofs/include/mconfig.h create mode 100644 util/mkisofs/include/prototyp.h create mode 100644 util/mkisofs/include/statdefs.h diff --git a/util/mkisofs/defaults.h b/util/mkisofs/defaults.h index 9e8f3331a..dc9ad380c 100644 --- a/util/mkisofs/defaults.h +++ b/util/mkisofs/defaults.h @@ -2,12 +2,14 @@ * Header file defaults.h - assorted default values for character strings in * the volume descriptor. * - * $Id: defaults.h,v 1.6 1998/06/02 02:40:37 eric Exp $ + * $Id: defaults.h,v 1.8 1999/03/02 03:41:25 eric Exp $ */ #define PREPARER_DEFAULT NULL #define PUBLISHER_DEFAULT NULL -#define APPID_DEFAULT NULL +#ifndef APPID_DEFAULT +#define APPID_DEFAULT "MKISOFS ISO 9660 FILESYSTEM BUILDER" +#endif #define COPYRIGHT_DEFAULT NULL #define BIBLIO_DEFAULT NULL #define ABSTRACT_DEFAULT NULL @@ -24,7 +26,7 @@ #endif #ifdef __sun -#ifdef __svr4__ +#ifdef __SVR4 #define SYSTEM_ID_DEFAULT "Solaris" #else #define SYSTEM_ID_DEFAULT "SunOS" diff --git a/util/mkisofs/eltorito.c b/util/mkisofs/eltorito.c index 3ff50e92e..b577c731d 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.12 1998/06/02 02:40:37 eric Exp $"; +static char rcsid[] ="$Id: eltorito.c,v 1.13 1999/03/02 03:41:25 eric Exp $"; #include #include @@ -44,8 +44,9 @@ static char rcsid[] ="$Id: eltorito.c,v 1.12 1998/06/02 02:40:37 eric Exp $"; static struct eltorito_validation_entry valid_desc; static struct eltorito_defaultboot_entry default_desc; -static struct eltorito_boot_descriptor boot_desc; +static struct eltorito_boot_descriptor gboot_desc; +static int tvd_write __PR((FILE * outfile)); /* * Check for presence of boot catalog. If it does not exist then make it @@ -275,13 +276,13 @@ void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) /* * Function to write the EVD for the disc. */ -int FDECL1(tvd_write, FILE *, outfile) +static 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); + get_torito_desc(&gboot_desc); + xfwrite(&gboot_desc, 1, 2048, outfile); last_extent_written ++; return 0; } diff --git a/util/mkisofs/exclude.h b/util/mkisofs/exclude.h index b9581a9e9..87cd6948a 100644 --- a/util/mkisofs/exclude.h +++ b/util/mkisofs/exclude.h @@ -3,8 +3,8 @@ * added 'exclude' option (-x) to specify pathnames NOT to be included in * CD image. * - * $Id: exclude.h,v 1.1 1997/02/23 15:53:19 eric Rel $ + * $Id: exclude.h,v 1.2 1999/03/02 03:41:25 eric Exp $ */ -void exclude(); -int is_excluded(); +void exclude __PR((char * fn)); +int is_excluded __PR((char * fn)); diff --git a/util/mkisofs/fnmatch.c b/util/mkisofs/fnmatch.c index cd5c0b27c..44de92e07 100644 --- a/util/mkisofs/fnmatch.c +++ b/util/mkisofs/fnmatch.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -static char rcsid[] ="$Id: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $"; +static char rcsid[] ="$Id: fnmatch.c,v 1.4 1999/03/02 03:41:25 eric Exp $"; #ifdef HAVE_CONFIG_H #include @@ -26,6 +26,10 @@ static char rcsid[] ="$Id: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $"; #include #include +#ifndef __STDC__ +#define const +#endif + #ifndef FNM_FILE_NAME #define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ #endif @@ -81,7 +85,7 @@ fnmatch (pattern, string, flags) while ((c = *p++) != '\0') { - c = FOLD (c); + c = FOLD ((unsigned char)c); switch (c) { @@ -99,9 +103,9 @@ fnmatch (pattern, string, flags) if (!(flags & FNM_NOESCAPE)) { c = *p++; - c = FOLD (c); + c = FOLD ((unsigned char )c); } - if (FOLD (*n) != c) + if (FOLD ((unsigned char )*n) != c) return FNM_NOMATCH; break; @@ -120,9 +124,9 @@ fnmatch (pattern, string, flags) { char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - c1 = FOLD (c1); + c1 = FOLD ((unsigned char )c1); for (--p; *n != '\0'; ++n) - if ((c == '[' || FOLD (*n) == c1) && + if ((c == '[' || FOLD ((unsigned char )*n) == c1) && fnmatch (p, n, flags & ~FNM_PERIOD) == 0) return 0; return FNM_NOMATCH; @@ -152,14 +156,14 @@ fnmatch (pattern, string, flags) if (!(flags & FNM_NOESCAPE) && c == '\\') cstart = cend = *p++; - cstart = cend = FOLD (cstart); + cstart = cend = FOLD ((unsigned char)cstart); if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; c = *p++; - c = FOLD (c); + c = FOLD ((unsigned char)c); if ((flags & FNM_FILE_NAME) && c == '/') /* [/] can never match. */ @@ -172,12 +176,12 @@ fnmatch (pattern, string, flags) cend = *p++; if (cend == '\0') return FNM_NOMATCH; - cend = FOLD (cend); + cend = FOLD ((unsigned char)cend); c = *p++; } - if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + if (FOLD ((unsigned char)*n) >= cstart && FOLD ((unsigned char)*n) <= cend) goto matched; if (c == ']') @@ -206,7 +210,7 @@ fnmatch (pattern, string, flags) break; default: - if (c != FOLD (*n)) + if (c != FOLD ((unsigned char)*n)) return FNM_NOMATCH; } diff --git a/util/mkisofs/include/fctldefs.h b/util/mkisofs/include/fctldefs.h new file mode 100644 index 000000000..de6b6a394 --- /dev/null +++ b/util/mkisofs/include/fctldefs.h @@ -0,0 +1,57 @@ +/* @(#)fctldefs.h 1.2 98/10/08 Copyright 1996 J. Schilling */ +/* + * Generic header for users of open(), creat() and chmod() + * + * Copyright (c) 1996 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _FCTLDEFS_H +#define _FCTLDEFS_H + +#ifndef _MCONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_FCNTL_H + +# include + +#else /* HAVE_FCNTL_H */ + +# include + +#endif /* HAVE_FCNTL_H */ + +/* + * Do not define more than O_RDONLY / O_WRONLY / O_RDWR + * The values may differ. + */ +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_WRONLY +#define O_WRONLY 1 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#endif /* _FCTLDEFS_H */ diff --git a/util/mkisofs/include/mconfig.h b/util/mkisofs/include/mconfig.h new file mode 100644 index 000000000..1725217d3 --- /dev/null +++ b/util/mkisofs/include/mconfig.h @@ -0,0 +1,268 @@ +/* @(#)mconfig.h 1.24 98/12/14 Copyright 1995 J. Schilling */ +/* + * definitions for machine configuration + * + * Copyright (c) 1995 J. Schilling + * + * This file must be included before any other file. + * Use only cpp instructions. + * + * NOTE: SING: (Schily Is Not Gnu) + */ +/* + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MCONFIG_H +#define _MCONFIG_H + +/* + * This hack that is needed as long as VMS has no POSIX shell. + */ +#ifdef VMS +# define USE_STATIC_CONF +#endif + +#ifdef VANILLA_AUTOCONF +#include +#else +#ifdef USE_STATIC_CONF +#include /* This is the current static autoconf stuff */ +#else +#include /* This is the current dynamic autoconf stuff */ +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(unix) || defined(__unix) || defined(__unix__) +# define IS_UNIX +#endif + +#ifdef __MSDOS__ +# define IS_MSDOS +#endif + +#if defined(tos) || defined(__tos) +# define IS_TOS +#endif + +#ifdef THINK_C +# define IS_MAC +#endif + +#if defined(sun) || defined(__sun) || defined(__sun__) +# define IS_SUN +#endif + +#if defined(__CYGWIN32__) +# define IS_GCC_WIN32 +#endif + +/*--------------------------------------------------------------------------*/ +/* + * Some magic that cannot (yet) be figured out with autoconf. + */ + +#ifdef sparc +# ifndef HAVE_LDSTUB +# define HAVE_LDSTUB +# endif +# ifndef HAVE_SCANSTACK +# define HAVE_SCANSTACK +# endif +#endif +#if defined(__i386_) || defined(i386) +# ifndef HAVE_XCHG +# define HAVE_XCHG +# endif +# ifndef HAVE_SCANSTACK +# define HAVE_SCANSTACK +# endif +#endif + +#if defined(SOL2) || defined(SOL2) || defined(S5R4) || defined(__S5R4) \ + || defined(SVR4) +# ifndef __SVR4 +# define __SVR4 +# endif +#endif + +#ifdef __SVR4 +# ifndef SVR4 +# define SVR4 +# endif +#endif + +/* + * SunOS 4.x / SunOS 5.x + */ +#if defined(IS_SUN) +# define HAVE_GETAV0 +#endif + +/* + * AIX + */ +#if defined(_IBMR2) || defined(_AIX) +# define IS_UNIX /* ??? really ??? */ +#endif + +/* + * Silicon Graphics (must be before SVR4) + */ +#if defined(sgi) || defined(__sgi) +# define __NOT_SVR4__ /* Not a real SVR4 implementation */ +#endif + +/* + * Data General + */ +#if defined(__DGUX__) +#ifdef XXXXXXX +# undef HAVE_MTGET_DSREG +# undef HAVE_MTGET_RESID +# undef HAVE_MTGET_FILENO +# undef HAVE_MTGET_BLKNO +#endif +# define mt_type mt_model +# define mt_dsreg mt_status1 +# define mt_erreg mt_status2 + /* + * DGUX hides its flock as dg_flock. + */ +# define HAVE_FLOCK +# define flock dg_flock + /* + * Use the BSD style wait on DGUX to get the resource usages of child + * processes. + */ +# define _BSD_WAIT_FLAVOR +#endif + +/* + * Apple Rhapsody + */ +#if defined(__NeXT__) && defined(__TARGET_OSNAME) && __TARGET_OSNAME == rhapsody +# define HAVE_OSDEF /* prevent later definitions to overwrite current */ +#endif + +/* + * NextStep + */ +#if defined(__NeXT__) && !defined(HAVE_OSDEF) +#define NO_PRINT_OVR +#undef HAVE_USG_STDIO /* + * NeXT Step 3.x uses __flsbuf(unsigned char , FILE *) + * instead of __flsbuf(int, FILE *) + */ +#endif + +/* + * NextStep 3.x has a broken linker that does not allow us to override + * these functions. + */ +#ifndef __OPRINTF__ + +#ifdef NO_PRINT_OVR +# define printf Xprintf +# define fprintf Xfprintf +# define sprintf Xsprintf +#endif + +#endif /* __OPRINTF__ */ + +/*--------------------------------------------------------------------------*/ +/* + * If there is no flock defined by the system, use emulation + * through fcntl record locking. + */ +#ifndef HAVE_FLOCK +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* don't block when locking */ +#define LOCK_UN 8 /* unlock */ +#endif + +#include + +/* + * gcc 2.x generally implements the long long type. + */ +#ifdef __GNUC__ +# if __GNUC__ > 1 +# ifndef HAVE_LONGLONG +# define HAVE_LONGLONG +# endif +# endif +#endif + +/* + * Convert to GNU name + */ +#ifdef HAVE_STDC_HEADERS +# ifndef STDC_HEADERS +# define STDC_HEADERS +# endif +#endif +/* + * Convert to SCHILY name + */ +#ifdef STDC_HEADERS +# ifndef HAVE_STDC_HEADERS +# define HAVE_STDC_HEADERS +# endif +#endif + +#ifdef IS_UNIX +# define PATH_DELIM '/' +# define PATH_DELIM_STR "/" +# define far +# define near +#endif + +#ifdef IS_GCC_WIN32 +# define PATH_DELIM '/' +# define PATH_DELIM_STR "/" +# define far +# define near +#endif + +#ifdef IS_MSDOS +# define PATH_DELIM '\\' +# define PATH_DELIM_STR "\\" +#endif + +#ifdef IS_TOS +# define PATH_DELIM '\\' +# define PATH_DELIM_STR "\\" +# define far +# define near +#endif + +#ifdef IS_MAC +# define PATH_DELIM ':' +# define PATH_DELIM_STR ":" +# define far +# define near +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _MCONFIG_H */ diff --git a/util/mkisofs/include/prototyp.h b/util/mkisofs/include/prototyp.h new file mode 100644 index 000000000..c74ae0af8 --- /dev/null +++ b/util/mkisofs/include/prototyp.h @@ -0,0 +1,74 @@ +/* @(#)prototyp.h 1.7 98/10/08 Copyright 1995 J. Schilling */ +/* + * Definitions for dealing with ANSI / KR C-Compilers + * + * Copyright (c) 1995 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PROTOTYP_H +#define _PROTOTYP_H + +#ifndef PROTOTYPES + /* + * If this has already been defined, + * someone else knows better than us... + */ +# ifdef __STDC__ +# if __STDC__ /* ANSI C */ +# define PROTOTYPES +# endif +# if defined(sun) && __STDC__ - 0 == 0 /* Sun C */ +# define PROTOTYPES +# endif +# endif +#endif /* PROTOTYPES */ + +/* + * If we have prototypes, we should have stdlib.h string.h stdarg.h + */ +#ifdef PROTOTYPES +#if !(defined(SABER) && defined(sun)) +# ifndef HAVE_STDARG_H +# define HAVE_STDARG_H +# endif +#endif +# ifndef HAVE_STDLIB_H +# define HAVE_STDLIB_H +# endif +# ifndef HAVE_STRING_H +# define HAVE_STRING_H +# endif +# ifndef HAVE_STDC_HEADERS +# define HAVE_STDC_HEADERS +# endif +# ifndef STDC_HEADERS +# define STDC_HEADERS /* GNU name */ +# endif +#endif + +#ifdef NO_PROTOTYPES /* Force not to use prototypes */ +# undef PROTOTYPES +#endif + +#ifdef PROTOTYPES +# define __PR(a) a +#else +# define __PR(a) () +#endif + +#endif /* _PROTOTYP_H */ diff --git a/util/mkisofs/include/statdefs.h b/util/mkisofs/include/statdefs.h new file mode 100644 index 000000000..0e34805ce --- /dev/null +++ b/util/mkisofs/include/statdefs.h @@ -0,0 +1,139 @@ +/* @(#)statdefs.h 1.1 98/11/22 Copyright 1998 J. Schilling */ +/* + * Definitions for stat() file mode + * + * Copyright (c) 1998 J. Schilling + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _STATDEFS_H +#define _STATDEFS_H + +#ifndef _MCONFIG_H +#include +#endif + +#ifdef STAT_MACROS_BROKEN +#undef S_ISFIFO /* Named pipe */ +#undef S_ISCHR /* Character special */ +#undef S_ISMPC /* UNUSED multiplexed c */ +#undef S_ISDIR /* Directory */ +#undef S_ISNAM /* Named file (XENIX) */ +#undef S_ISBLK /* Block special */ +#undef S_ISMPB /* UNUSED multiplexed b */ +#undef S_ISREG /* Regular file */ +#undef S_ISCNT /* Contiguous file */ +#undef S_ISLNK /* Symbolic link */ +#undef S_ISSHAD /* Solaris shadow inode */ +#undef S_ISSOCK /* UNIX domain socket */ +#undef S_ISDOOR /* Solaris DOOR */ +#endif + +#ifndef S_ISFIFO /* Named pipe */ +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) (0) +# endif +#endif +#ifndef S_ISCHR /* Character special */ +# ifdef S_IFCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) (0) +# endif +#endif +#ifndef S_ISMPC /* UNUSED multiplexed c */ +# ifdef S_IFMPC +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +# else +# define S_ISMPC(m) (0) +# endif +#endif +#ifndef S_ISDIR /* Directory */ +# ifdef S_IFDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# else +# define S_ISDIR(m) (0) +# endif +#endif +#ifndef S_ISNAM /* Named file (XENIX) */ +# ifdef S_IFNAM +# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) +# else +# define S_ISNAM(m) (0) +# endif +#endif +#ifndef S_ISBLK /* Block special */ +# ifdef S_IFBLK +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(m) (0) +# endif +#endif +#ifndef S_ISMPB /* UNUSED multiplexed b */ +# ifdef S_IFMPB +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# else +# define S_ISMPB(m) (0) +# endif +#endif +#ifndef S_ISREG /* Regular file */ +# ifdef S_IFREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# else +# define S_ISREG(m) (0) +# endif +#endif +#ifndef S_ISCNT /* Contiguous file */ +# ifdef S_IFCNT +# define S_ISCNT(m) (((m) & S_IFMT) == S_IFCNT) +# else +# define S_ISCNT(m) (0) +# endif +#endif +#ifndef S_ISLNK /* Symbolic link */ +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# else +# define S_ISLNK(m) (0) +# endif +#endif +#ifndef S_ISSHAD /* Solaris shadow inode */ +# ifdef S_IFSHAD +# define S_ISSHAD(m) (((m) & S_IFMT) == S_IFSHAD) +# else +# define S_ISSHAD(m) (0) +# endif +#endif +#ifndef S_ISSOCK /* UNIX domain socket */ +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) (0) +# endif +#endif +#ifndef S_ISDOOR /* Solaris DOOR */ +# ifdef S_IFDOOR +# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR) +# else +# define S_ISDOOR(m) (0) +# endif +#endif + +#endif /* _STATDEFS_H */ + diff --git a/util/mkisofs/joliet.c b/util/mkisofs/joliet.c index d3e8cb0e3..0aa866854 100644 --- a/util/mkisofs/joliet.c +++ b/util/mkisofs/joliet.c @@ -17,7 +17,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: joliet.c,v 1.12 1998/06/02 02:40:37 eric Exp $"; +static char rcsid[] ="$Id: joliet.c,v 1.14 1999/03/07 17:41:19 eric Exp $"; /* @@ -77,13 +77,15 @@ static char rcsid[] ="$Id: joliet.c,v 1.12 1998/06/02 02:40:37 eric Exp $"; #include #include -static jpath_table_index; +static int jpath_table_index; static struct directory ** jpathlist; -static next_jpath_index = 1; +static int next_jpath_index = 1; static int sort_goof; +static int generate_joliet_path_tables __PR((void)); static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir)); static void DECL(assign_joliet_directory_addresses, (struct directory * node)); +static int jroot_gen __PR((void)); /* * Function: convert_to_unicode @@ -121,7 +123,14 @@ static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char for(i=0; i < size ; i += 2, j++) { buffer[i] = 0; - if( tmpbuf[j] < 0x1f && tmpbuf[j] != 0 ) + /* + * JS integrated from: Achim_Kaiser@t-online.de + * + * Let all valid unicode characters pass through (assuming ISO-8859-1). + * Others are set to '_' . + */ + if( tmpbuf[j] != 0 && + (tmpbuf[j] <= 0x1f || (tmpbuf[j] >= 0x7F && tmpbuf[j] <= 0xA0)) ) { buffer[i+1] = '_'; } @@ -166,7 +175,6 @@ static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char static int FDECL1(joliet_strlen, const char *, string) { int rtn; - struct iso_directory_record foobar; rtn = strlen(string) << 1; @@ -192,32 +200,36 @@ static int FDECL1(joliet_strlen, const char *, string) * already present in the buffer. Just modifiy the * appropriate fields. */ -static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, vol_desc) +static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, jvol_desc) { - vol_desc->type[0] = ISO_VD_SUPPLEMENTARY; + jvol_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? + * FIXME(eric) - how does Romeo fit in here? As mkisofs just + * "expands" 8 bit character codes to 16 bits and does nothing + * special with the Unicode characters, therefore shouldn't mkisofs + * really be stating that it's using UCS-2 Level 1, not Level 3 for + * the Joliet directory tree. */ - strcpy(vol_desc->escape_sequences, "%/E"); + strcpy(jvol_desc->escape_sequences, "%/@"); /* * 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_733((char *) jvol_desc->path_table_size, jpath_table_size); + set_731(jvol_desc->type_l_path_table, jpath_table[0]); + set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]); + set_732(jvol_desc->type_m_path_table, jpath_table[2]); + set_732(jvol_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); + memcpy(jvol_desc->root_directory_record, &jroot_record, + sizeof(struct iso_directory_record)); /* * Finally, we have a bunch of strings to convert to Unicode. @@ -225,15 +237,15 @@ static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, vol_des * 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); + convert_to_unicode((u_char *)jvol_desc->system_id, sizeof(jvol_desc->system_id), NULL); + convert_to_unicode((u_char *)jvol_desc->volume_id, sizeof(jvol_desc->volume_id), NULL); + convert_to_unicode((u_char *)jvol_desc->volume_set_id, sizeof(jvol_desc->volume_set_id), NULL); + convert_to_unicode((u_char *)jvol_desc->publisher_id, sizeof(jvol_desc->publisher_id), NULL); + convert_to_unicode((u_char *)jvol_desc->preparer_id, sizeof(jvol_desc->preparer_id), NULL); + convert_to_unicode((u_char *)jvol_desc->application_id, sizeof(jvol_desc->application_id), NULL); + convert_to_unicode((u_char *)jvol_desc->copyright_file_id, sizeof(jvol_desc->copyright_file_id), NULL); + convert_to_unicode((u_char *)jvol_desc->abstract_file_id, sizeof(jvol_desc->abstract_file_id), NULL); + convert_to_unicode((u_char *)jvol_desc->bibliographic_file_id, sizeof(jvol_desc->bibliographic_file_id), NULL); } @@ -261,8 +273,9 @@ static void FDECL1(assign_joliet_directory_addresses, struct directory *, node) last_extent += dir_size; } } - - if(dpnt->subdir) + + /* skip if hidden - but not for the rr_moved dir */ + if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) { assign_joliet_directory_addresses(dpnt->subdir); } @@ -341,6 +354,12 @@ static int generate_joliet_path_tables() memset(jpath_table_l, 0, tablesize); memset(jpath_table_m, 0, tablesize); + if( next_jpath_index > 0xffff ) + { + fprintf(stderr, "Unable to generate sane path tables - too many directories (%d)\n", + next_jpath_index); + exit(1); + } /* * Now start filling in the path tables. Start with root directory */ @@ -353,8 +372,13 @@ static int generate_joliet_path_tables() do { fix = 0; +#ifdef __STDC__ qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), (int (*)(const void *, const void *))joliet_compare_paths); +#else + qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), + joliet_compare_paths); +#endif for(j=1; jjcontents; while(s_entry) { - if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) == 0 ) - { + if(s_entry->de_flags & INHIBIT_JOLIET_ENTRY) { + s_entry = s_entry->jnext; + continue; + } + /* * 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 @@ -617,8 +644,8 @@ static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE { directory_buffer[dir_index++] = 0; } - } - s_entry = s_entry->jnext; + + s_entry = s_entry->jnext; } if(dpnt->jsize != dir_index) @@ -637,8 +664,15 @@ static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir) struct directory_entry * s_entry; int status = 0; + /* don't want to skip this directory if it's the reloc_dir at the moment */ + if(this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) + { + return 0; + } + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) { + /* skip hidden entries */ if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 ) { continue; @@ -707,6 +741,10 @@ static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir) * Do not split a directory entry across a sector boundary */ s_entry = this_dir->jcontents; +/* + * XXX Is it ok to comment this out? + */ +/*XXX JS this_dir->ce_bytes = 0;*/ for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext) { int jreclen; @@ -798,14 +836,16 @@ static int FDECL2(joliet_compare_dirs, const void *, rr, const void *, ll) static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir) { int dcount = 0; - int i, len; + int i; struct directory_entry * s_entry; struct directory_entry ** sortlist; s_entry = *sort_dir; while(s_entry) { - dcount++; + /* skip hidden entries */ + if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) + dcount++; s_entry = s_entry->next; } @@ -819,14 +859,22 @@ static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir) s_entry = *sort_dir; while(s_entry) { - sortlist[dcount] = s_entry; - dcount++; + /* skip hidden entries */ + if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) { + sortlist[dcount] = s_entry; + dcount++; + } s_entry = s_entry->next; } sort_goof = 0; +#ifdef __STDC__ qsort(sortlist, dcount, sizeof(struct directory_entry *), (int (*)(const void *, const void *))joliet_compare_dirs); +#else + qsort(sortlist, dcount, sizeof(struct directory_entry *), + joliet_compare_dirs); +#endif /* * Now reassemble the linked list in the proper sorted order @@ -846,24 +894,24 @@ static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir) int FDECL1(joliet_sort_tree, struct directory *, node) { struct directory * dpnt; - int goof = 0; + int ret = 0; dpnt = node; while (dpnt){ - goof = joliet_sort_n_finish(dpnt); - if( goof ) + ret = joliet_sort_n_finish(dpnt); + if( ret ) { break; } - if(dpnt->subdir) goof = joliet_sort_tree(dpnt->subdir); - if( goof ) + if(dpnt->subdir) ret = joliet_sort_tree(dpnt->subdir); + if( ret ) { break; } dpnt = dpnt->next; } - return goof; + return ret; } static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){ @@ -879,12 +927,14 @@ static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, * In theory we should never reuse a directory, so this doesn't * make much sense. */ - if( dpnt->extent > session_start ) + if( dpnt->jextent > session_start ) { generate_one_joliet_directory(dpnt, outfile); } } - if(dpnt->subdir) generate_joliet_directories(dpnt->subdir, outfile); + /* skip if hidden - but not for the rr_moved dir */ + if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) + generate_joliet_directories(dpnt->subdir, outfile); dpnt = dpnt->next; } } @@ -925,7 +975,7 @@ static int jroot_gen() 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); + set_723(jroot_record.volume_sequence_number, volume_sequence_number); jroot_record.name_len[0] = 1; return 0; } diff --git a/util/mkisofs/match.c b/util/mkisofs/match.c index 0f5c7d8a7..e01314b0b 100644 --- a/util/mkisofs/match.c +++ b/util/mkisofs/match.c @@ -4,8 +4,10 @@ * in the CD image. */ -static char rcsid[] ="$Id: match.c,v 1.2 1997/02/23 16:10:42 eric Rel $"; +static char rcsid[] ="$Id: match.c,v 1.3 1999/03/02 03:41:25 eric Exp $"; +#include "config.h" +#include #include #ifndef VMS #ifdef HAVE_MALLOC_H @@ -54,3 +56,92 @@ char * fn; } return 0; /* not found -> not excluded */ } + +/* ISO9660/RR hide */ + +static char *i_mat[MAXMATCH]; + +void i_add_match(fn) +char * fn; +{ + register int i; + + for (i=0; i_mat[i] && i excluded filenmae */ + } + } + return 0; /* not found -> not excluded */ +} + +int i_ishidden() +{ + return((int)i_mat[0]); +} + +/* Joliet hide */ + +static char *j_mat[MAXMATCH]; + +void j_add_match(fn) +char * fn; +{ + register int i; + + for (i=0; j_mat[i] && i excluded filenmae */ + } + } + return 0; /* not found -> not excluded */ +} + +int j_ishidden() +{ + return((int)j_mat[0]); +} + diff --git a/util/mkisofs/match.h b/util/mkisofs/match.h index 90def7c2d..7367dd211 100644 --- a/util/mkisofs/match.h +++ b/util/mkisofs/match.h @@ -5,10 +5,18 @@ */ /* - * $Id: match.h,v 1.1 1997/02/23 15:56:12 eric Rel $ + * $Id: match.h,v 1.2 1999/03/02 03:41:25 eric Exp $ */ #include "fnmatch.h" -void add_match(); -int matches(); +void add_match __PR((char *fn)); +int matches __PR((char *fn)); + +void i_add_match __PR((char *fn)); +int i_matches __PR((char *fn)); +int i_ishidden __PR((void)); + +void j_add_match __PR((char *fn)); +int j_matches __PR((char *fn)); +int j_ishidden __PR((void)); diff --git a/util/mkisofs/mkisofs.c b/util/mkisofs/mkisofs.c index 3344a921a..11959c0ca 100644 --- a/util/mkisofs/mkisofs.c +++ b/util/mkisofs/mkisofs.c @@ -20,11 +20,12 @@ 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.29 1998/06/02 03:43:45 eric Exp $"; +static char rcsid[] ="$Id: mkisofs.c,v 1.32 1999/03/07 21:48:49 eric Exp $"; #include #include "config.h" #include "mkisofs.h" +#include "match.h" #ifdef linux #include @@ -50,6 +51,7 @@ static char rcsid[] ="$Id: mkisofs.c,v 1.29 1998/06/02 03:43:45 eric Exp $"; #include #endif #endif +#include #include "exclude.h" @@ -60,8 +62,9 @@ static char rcsid[] ="$Id: mkisofs.c,v 1.29 1998/06/02 03:43:45 eric Exp $"; struct directory * root = NULL; -static char version_string[] = "mkisofs 1.12b4"; +static char version_string[] = "mkisofs 1.12b5"; +char * outfile; FILE * discimage; unsigned int next_extent = 0; unsigned int last_extent = 0; @@ -104,6 +107,8 @@ char * volume_id = VOLUME_ID_DEFAULT; char * system_id = SYSTEM_ID_DEFAULT; char * boot_catalog = BOOT_CATALOG_DEFAULT; char * boot_image = BOOT_IMAGE_DEFAULT; +int volume_set_size = 1; +int volume_sequence_number = 1; int omit_period = 0; /* Violates iso9660, but these are a pain */ int transparent_compression = 0; /* So far only works with linux */ @@ -166,19 +171,35 @@ struct ld_option #define OPTION_NOSPLIT_SL_FIELD 153 #define OPTION_PRINT_SIZE 154 #define OPTION_SPLIT_OUTPUT 155 +#define OPTION_ABSTRACT 156 +#define OPTION_BIBLIO 157 +#define OPTION_COPYRIGHT 158 +#define OPTION_SYSID 159 +#define OPTION_VOLSET 160 +#define OPTION_VOLSET_SIZE 161 +#define OPTION_VOLSET_SEQ_NUM 162 +#define OPTION_I_HIDE 163 +#define OPTION_J_HIDE 164 +#define OPTION_LOG_FILE 165 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 }, + { {"abstract", required_argument, NULL, OPTION_ABSTRACT}, + '\0', "FILE", "Set Abstract filename" , ONE_DASH }, { {"appid", required_argument, NULL, 'A'}, 'A', "ID", "Set Application ID" , ONE_DASH }, + { {"biblio", required_argument, NULL, OPTION_BIBLIO}, + '\0', "FILE", "Set Bibliographic filename" , ONE_DASH }, + { {"copyright", required_argument, NULL, OPTION_COPYRIGHT}, + '\0', "FILE", "Set Copyright filename" , 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 }, + 'C', "PARAMS", "Magic paramters from cdrecord" , ONE_DASH }, { {"omit-period", no_argument, NULL, 'd'}, 'd', NULL, "Omit trailing periods from filenames", ONE_DASH }, { {"disable-deep-relocation", no_argument, NULL, 'D'}, @@ -187,6 +208,10 @@ static const struct ld_option ld_options[] = 'f', NULL, "Follow symbolic links", ONE_DASH }, { {"help", no_argument, NULL, OPTION_HELP}, '\0', NULL, "Print option help", ONE_DASH }, + { {"hide", required_argument, NULL, OPTION_I_HIDE}, + '\0', "GLOBFILE", "Hide ISO9660/RR file" , ONE_DASH }, + { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE}, + '\0', "GLOBFILE", "Hide Joliet file" , ONE_DASH }, { {NULL, required_argument, NULL, 'i'}, 'i', "ADD_FILES", "No longer supported" , TWO_DASHES }, { {"joliet", no_argument, NULL, 'J'}, @@ -195,6 +220,8 @@ static const struct ld_option ld_options[] = '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 }, + { {"log-file", required_argument, NULL, OPTION_LOG_FILE}, + '\0', "LOG_FILE", "Re-direct messages to LOG_FILE", ONE_DASH }, { {"exclude", required_argument, NULL, 'm'}, 'm', "GLOBFILE", "Exclude file name" , ONE_DASH }, { {"prev-session", required_argument, NULL, 'M'}, @@ -221,12 +248,20 @@ static const struct ld_option ld_options[] = '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 }, + { {"sysid", required_argument, NULL, OPTION_SYSID}, + '\0', "ID", "Set System ID" , 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 }, + { {"volset", required_argument, NULL, OPTION_VOLSET}, + '\0', "ID", "Set Volume set ID" , ONE_DASH }, + { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE}, + '\0', "#", "Set Volume set size" , ONE_DASH }, + { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM}, + '\0', "#", "Set Volume set sequence number" , ONE_DASH }, { {"old-exclude", required_argument, NULL, 'x'}, 'x', "FILE", "Exclude file name(depreciated)" , ONE_DASH } #ifdef ERIC_neverdef @@ -242,6 +277,10 @@ char *strdup(s) char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} #endif + void read_rcfile __PR((char * appname)); + void usage __PR((void)); +static void hide_reloc_dir __PR((void)); + void FDECL1(read_rcfile, char *, appname) { FILE * rcfile; @@ -318,10 +357,10 @@ void FDECL1(read_rcfile, char *, appname) /* The name should begin in the left margin. Make sure it is in upper case. Stop when we see white space or a comment. */ name = pnt; - while (*pnt && isalpha(*pnt)) + while (*pnt && isalpha((unsigned char)*pnt)) { - if(islower(*pnt)) - *pnt = toupper(*pnt); + if(islower((unsigned char)*pnt)) + *pnt = toupper((unsigned char)*pnt); pnt++; } if (name == pnt) @@ -408,7 +447,7 @@ void usage(){ #endif int i; - const char **targets, **pp; +/* const char **targets, **pp;*/ fprintf (stderr, "Usage: %s [options] file...\n", program_name); @@ -500,9 +539,9 @@ void usage(){ * with DST, I guess). The Linux iso9660 filesystem has had the sign * of this wrong for ages (mkisofs had it wrong too for the longest time). */ -int FDECL2(iso9660_date,char *, result, time_t, ctime){ +int FDECL2(iso9660_date,char *, result, time_t, crtime){ struct tm *local; - local = localtime(&ctime); + local = localtime(&crtime); result[0] = local->tm_year; result[1] = local->tm_mon + 1; result[2] = local->tm_mday; @@ -515,7 +554,7 @@ int FDECL2(iso9660_date,char *, result, time_t, ctime){ * as some files use daylight savings time and some don't... */ result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ - local = gmtime(&ctime); + local = gmtime(&crtime); local->tm_year -= result[0]; local->tm_yday -= result[6]; local->tm_hour -= result[3]; @@ -534,11 +573,28 @@ int FDECL2(iso9660_date,char *, result, time_t, ctime){ return 0; } +/* hide "./rr_moved" if all its contents are hidden */ +static void +hide_reloc_dir() +{ + struct directory_entry * s_entry; + + for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) { + if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0) + continue; + + if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) + return; + } + + /* all entries are hidden, so hide this directory */ + reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; + reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY; +} extern char * cdwrite_data; int FDECL2(main, int, argc, char **, argv){ - char * outfile; struct directory_entry de; #ifdef HAVE_SBRK unsigned long mem_start; @@ -552,6 +608,7 @@ int FDECL2(main, int, argc, char **, argv){ char shortopts[OPTION_COUNT * 3 + 2]; struct option longopts[OPTION_COUNT + 1]; int c; + char *log_file = 0; if (argc < 2) usage(); @@ -643,6 +700,13 @@ int FDECL2(main, int, argc, char **, argv){ exit(1); } break; + case OPTION_ABSTRACT: + abstract = optarg; + if(strlen(abstract) > 37) { + fprintf(stderr,"Abstract filename string too long\n"); + exit(1); + }; + break; case 'A': appid = optarg; if(strlen(appid) > 128) { @@ -650,6 +714,20 @@ int FDECL2(main, int, argc, char **, argv){ exit(1); }; break; + case OPTION_BIBLIO: + biblio = optarg; + if(strlen(biblio) > 37) { + fprintf(stderr,"Bibliographic filename string too long\n"); + exit(1); + }; + break; + case OPTION_COPYRIGHT: + copyright = optarg; + if(strlen(copyright) > 37) { + fprintf(stderr,"Copyright filename string too long\n"); + exit(1); + }; + break; case 'd': omit_period++; break; @@ -665,6 +743,9 @@ int FDECL2(main, int, argc, char **, argv){ case 'L': allow_leading_dots++; break; + case OPTION_LOG_FILE: + log_file = optarg; + break; case 'M': merge_image = optarg; break; @@ -704,11 +785,39 @@ int FDECL2(main, int, argc, char **, argv){ case OPTION_SPLIT_OUTPUT: split_output++; break; + case OPTION_SYSID: + system_id = optarg; + if(strlen(system_id) > 32) { + fprintf(stderr,"System ID string too long\n"); + exit(1); + }; + break; case 'T': generate_tables++; break; case 'V': volume_id = optarg; + if(strlen(volume_id) > 32) { + fprintf(stderr,"Volume ID string too long\n"); + exit(1); + }; + break; + case OPTION_VOLSET: + volset_id = optarg; + if(strlen(volset_id) > 128) { + fprintf(stderr,"Volume set ID string too long\n"); + exit(1); + }; + break; + case OPTION_VOLSET_SIZE: + volume_set_size = atoi(optarg); + break; + case OPTION_VOLSET_SEQ_NUM: + volume_sequence_number = atoi(optarg); + if (volume_sequence_number > volume_set_size) { + fprintf(stderr,"Volume set sequence number too big\n"); + exit(1); + } break; case 'v': verbose++; @@ -730,6 +839,12 @@ int FDECL2(main, int, argc, char **, argv){ */ add_match(optarg); break; + case OPTION_I_HIDE: + i_add_match(optarg); + break; + case OPTION_J_HIDE: + j_add_match(optarg); + break; case OPTION_HELP: usage (); exit (0); @@ -764,15 +879,23 @@ parse_input_files: mem_start = (unsigned long) sbrk(0); #endif + /* if the -hide-joliet option has been given, set the Joliet option */ + if (!use_Joliet && j_ishidden()) + use_Joliet++; + if(verbose > 1) fprintf(stderr,"%s\n", version_string); - if( (cdwrite_data != NULL && merge_image == NULL) - || (cdwrite_data == NULL && merge_image != NULL) ) + if(cdwrite_data == NULL && merge_image != NULL) { - fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n"); + fprintf(stderr,"Multisession usage bug: Must specify -C if -M is used.\n"); exit(0); } + if(cdwrite_data != NULL && merge_image == NULL) + { + fprintf(stderr,"Warning: -C specified without -M: old session data will not be merged.\n"); + } + /* The first step is to scan the directory tree, and take some notes */ scan_tree = argv[optind]; @@ -803,6 +926,34 @@ parse_input_files: #endif } + if (log_file) { + FILE *lfp; + int i; + + /* open log file - test that we can open OK */ + if ((lfp = fopen(log_file, "w")) == NULL) { + fprintf(stderr,"can't open logfile: %s\n", log_file); + exit (1); + } + fclose(lfp); + + /* redirect all stderr message to log_file */ + fprintf(stderr, "re-directing all messages to %s\n", log_file); + fflush(stderr); + + /* associate stderr with the log file */ + if (freopen(log_file, "w", stderr) == NULL) { + fprintf(stderr,"can't open logfile: %s\n", log_file); + exit (1); + } + if(verbose > 1) { + for (i=0;i