--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * Program eltorito.c - Handle El Torito specific extensions to iso9660.
+ *
+
+ Written by Michael Fulbright <msf@redhat.com> (1996).
+
+ Copyright 1996 RedHat Software, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+static char rcsid[] ="$Id: eltorito.c,v 1.7 1997/05/17 15:44:31 eric Exp $";
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#undef MIN
+#define MIN(a, b) (((a) < (b))? (a): (b))
+
+static struct eltorito_validation_entry valid_desc;
+static struct eltorito_defaultboot_entry default_desc;
+
+/*
+ * Check for presence of boot catalog. If it does not exist then make it
+ */
+void FDECL1(init_boot_catalog, const char *, path)
+{
+
+ int bcat;
+ char * bootpath; /* filename of boot catalog */
+ char * buf;
+ struct stat statbuf;
+
+ bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2);
+ strcpy(bootpath, path);
+ if (bootpath[strlen(bootpath)-1] != '/')
+ {
+ strcat(bootpath,"/");
+ }
+
+ strcat(bootpath, boot_catalog);
+
+ /*
+ * check for the file existing
+ */
+#ifdef DEBUG_TORITO
+ printf("Looking for boot catalog file %s\n",bootpath);
+#endif
+
+ if (!stat_filter(bootpath, &statbuf))
+ {
+ /*
+ * make sure its big enough to hold what we want
+ */
+ if (statbuf.st_size == 2048)
+ {
+ /*
+ * printf("Boot catalog exists, so we do nothing\n");
+ */
+ free(bootpath);
+ return;
+ }
+ else
+ {
+ fprintf(stderr, "A boot catalog exists and appears corrupted.\n");
+ fprintf(stderr, "Please check the following file: %s.\n",bootpath);
+ fprintf(stderr, "This file must be removed before a bootable CD can be done.\n");
+ free(bootpath);
+ exit(1);
+ }
+ }
+
+ /*
+ * file does not exist, so we create it
+ * make it one CD sector long
+ */
+ bcat = open(bootpath, O_WRONLY | O_CREAT, S_IROTH | S_IRGRP | S_IRWXU );
+ if (bcat == -1)
+ {
+ fprintf(stderr, "Error creating boot catalog, exiting...\n");
+ perror("");
+ exit(1);
+ }
+
+ buf = (char *) e_malloc( 2048 );
+ write(bcat, buf, 2048);
+ close(bcat);
+ free(bootpath);
+} /* init_boot_catalog(... */
+
+void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc)
+{
+ int bootcat;
+ int checksum;
+ unsigned char * checksum_ptr;
+ struct directory_entry * de;
+ struct directory_entry * de2;
+ int i;
+ int nsectors;
+
+ memset(boot_desc, 0, sizeof(*boot_desc));
+ boot_desc->id[0] = 0;
+ memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+ boot_desc->version[0] = 1;
+
+ memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID));
+
+ /*
+ * search from root of iso fs to find boot catalog
+ */
+ de2 = search_tree_file(root, boot_catalog);
+ if (!de2)
+ {
+ fprintf(stderr,"Uh oh, I cant find the boot catalog!\n");
+ exit(1);
+ }
+
+ set_731(boot_desc->bootcat_ptr,
+ (unsigned int) get_733(de2->isorec.extent));
+
+ /*
+ * now adjust boot catalog
+ * lets find boot image first
+ */
+ de=search_tree_file(root, boot_image);
+ if (!de)
+ {
+ fprintf(stderr,"Uh oh, I cant find the boot image!\n");
+ exit(1);
+ }
+
+ /*
+ * we have the boot image, so write boot catalog information
+ * Next we write out the primary descriptor for the disc
+ */
+ memset(&valid_desc, 0, sizeof(valid_desc));
+ valid_desc.headerid[0] = 1;
+ valid_desc.arch[0] = EL_TORITO_ARCH_x86;
+
+ /*
+ * we'll shove start of publisher id into id field, may get truncated
+ * but who really reads this stuff!
+ */
+ if (publisher)
+ memcpy_max(valid_desc.id, publisher, MIN(23, strlen(publisher)));
+
+ valid_desc.key1[0] = 0x55;
+ valid_desc.key2[0] = 0xAA;
+
+ /*
+ * compute the checksum
+ */
+ checksum=0;
+ checksum_ptr = (unsigned char *) &valid_desc;
+ for (i=0; i<sizeof(valid_desc); i+=2)
+ {
+ /*
+ * skip adding in ckecksum word, since we dont have it yet!
+ */
+ if (i == 28)
+ {
+ continue;
+ }
+ checksum += (unsigned int)checksum_ptr[i];
+ checksum += ((unsigned int)checksum_ptr[i+1])*256;
+ }
+
+ /*
+ * now find out the real checksum
+ */
+ checksum = -checksum;
+ set_721(valid_desc.cksum, (unsigned int) checksum);
+
+ /*
+ * now make the initial/default entry for boot catalog
+ */
+ memset(&default_desc, 0, sizeof(default_desc));
+ default_desc.boot_id[0] = EL_TORITO_BOOTABLE;
+
+ /*
+ * use default BIOS loadpnt
+ */
+ set_721(default_desc.loadseg, 0);
+ default_desc.arch[0] = EL_TORITO_ARCH_x86;
+
+ /*
+ * figure out size of boot image in sectors, for now hard code to
+ * assume 512 bytes/sector on a bootable floppy
+ */
+ nsectors = ((de->size + 511) & ~(511))/512;
+ printf("\nSize of boot image is %d sectors -> ", nsectors);
+
+ /*
+ * choose size of emulated floppy based on boot image size
+ */
+ if (nsectors == 2880 )
+ {
+ default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP;
+ printf("Emulating a 1.44 meg floppy\n");
+ }
+ else if (nsectors == 5760 )
+ {
+ default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP;
+ printf("Emulating a 2.88 meg floppy\n");
+ }
+ else if (nsectors == 2400 )
+ {
+ default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP;
+ printf("Emulating a 1.2 meg floppy\n");
+ }
+ else
+ {
+ fprintf(stderr,"\nError - boot image is not the an allowable size.\n");
+ exit(1);
+ }
+
+
+ /*
+ * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!!
+ */
+ nsectors = 1;
+ set_721(default_desc.nsect, (unsigned int) nsectors );
+#ifdef DEBUG_TORITO
+ printf("Extent of boot images is %d\n",get_733(de->isorec.extent));
+#endif
+ set_731(default_desc.bootoff,
+ (unsigned int) get_733(de->isorec.extent));
+
+ /*
+ * now write it to disk
+ */
+ bootcat = open(de2->whole_name, O_RDWR);
+ if (bootcat == -1)
+ {
+ fprintf(stderr,"Error opening boot catalog for update.\n");
+ perror("");
+ exit(1);
+ }
+
+ /*
+ * write out
+ */
+ write(bootcat, &valid_desc, 32);
+ write(bootcat, &default_desc, 32);
+ close(bootcat);
+} /* get_torito_desc(... */
--- /dev/null
+/*
+ * 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();
--- /dev/null
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $";
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+
+#ifndef FNM_FILE_NAME
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#endif
+
+#ifndef FNM_LEADING_DIR
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#endif
+
+#ifndef FNM_CASEFOLD
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+
+#include <ctype.h>
+
+#if defined (STDC_HEADERS) || !defined (isascii)
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int
+fnmatch (pattern, string, flags)
+ const char *pattern;
+ const char *string;
+ int flags;
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+/* Note that this evalutes C many times. */
+#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+
+ while ((c = *p++) != '\0')
+ {
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_FILE_NAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ c = FOLD (c);
+ }
+ if (FOLD (*n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+ if (((flags & FNM_FILE_NAME) && *n == '/') ||
+ (c == '?' && *n == '\0'))
+ return FNM_NOMATCH;
+
+ if (c == '\0')
+ return 0;
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+ c1 = FOLD (c1);
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || FOLD (*n) == c1) &&
+ fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ return 0;
+ return FNM_NOMATCH;
+ }
+
+ case '[':
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+
+ if (*n == '\0')
+ return FNM_NOMATCH;
+
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ not = (*p == '!' || *p == '^');
+ if (not)
+ ++p;
+
+ c = *p++;
+ for (;;)
+ {
+ register char cstart = c, cend = c;
+
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ cstart = cend = *p++;
+
+ cstart = cend = FOLD (cstart);
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ c = FOLD (c);
+
+ if ((flags & FNM_FILE_NAME) && c == '/')
+ /* [/] can never match. */
+ return FNM_NOMATCH;
+
+ if (c == '-' && *p != ']')
+ {
+ cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+
+ c = *p++;
+ }
+
+ if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+ goto matched;
+
+ if (c == ']')
+ break;
+ }
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:;
+ /* Skip the rest of the [...] that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != FOLD (*n))
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && *n == '/')
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
--- /dev/null
+/*
+ * File hash.c - generate hash tables for iso9660 filesystem.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: hash.c,v 1.2 1997/02/23 16:11:15 eric Rel $";
+
+#include <stdlib.h>
+#include "mkisofs.h"
+
+#define NR_HASH 1024
+
+#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH)
+
+static struct file_hash * hash_table[NR_HASH] = {0,};
+
+void FDECL1(add_hash, struct directory_entry *, spnt){
+ struct file_hash * s_hash;
+ unsigned int hash_number;
+
+ if(spnt->size == 0 || spnt->starting_block == 0)
+ if(spnt->size != 0 || spnt->starting_block != 0) {
+ fprintf(stderr,"Non zero-length file assigned zero extent.\n");
+ exit(1);
+ };
+
+ if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return;
+ hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
+
+#if 0
+ if (verbose) fprintf(stderr,"%s ",spnt->name);
+#endif
+ s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+ s_hash->next = hash_table[hash_number];
+ s_hash->inode = spnt->inode;
+ s_hash->dev = spnt->dev;
+ s_hash->starting_block = spnt->starting_block;
+ s_hash->size = spnt->size;
+ hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){
+ unsigned int hash_number;
+ struct file_hash * spnt;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+ spnt = hash_table[hash_number];
+ while(spnt){
+ if(spnt->inode == inode && spnt->dev == dev) return spnt;
+ spnt = spnt->next;
+ };
+ return NULL;
+}
+
+
+static struct file_hash * directory_hash_table[NR_HASH] = {0,};
+
+void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){
+ struct file_hash * s_hash;
+ unsigned int hash_number;
+
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+
+ s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
+ s_hash->next = directory_hash_table[hash_number];
+ s_hash->inode = inode;
+ s_hash->dev = dev;
+ directory_hash_table[hash_number] = s_hash;
+}
+
+struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){
+ unsigned int hash_number;
+ struct file_hash * spnt;
+ hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
+ if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
+
+ spnt = directory_hash_table[hash_number];
+ while(spnt){
+ if(spnt->inode == inode && spnt->dev == dev) return spnt;
+ spnt = spnt->next;
+ };
+ return NULL;
+}
+
+struct name_hash
+{
+ struct name_hash * next;
+ struct directory_entry * de;
+};
+
+#define NR_NAME_HASH 128
+
+static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
+
+/*
+ * Find the hash bucket for this name.
+ */
+static unsigned int FDECL1(name_hash, const char *, name)
+{
+ unsigned int hash = 0;
+ const char * p;
+
+ p = name;
+
+ while (*p)
+ {
+ /*
+ * Don't hash the iso9660 version number. This way
+ * we can detect duplicates in cases where we have
+ * directories (i.e. foo) and non-directories
+ * (i.e. foo;1).
+ */
+ if( *p == ';' )
+ {
+ break;
+ }
+ hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
+ }
+ return hash % NR_NAME_HASH;
+}
+
+void FDECL1(add_file_hash, struct directory_entry *, de){
+ struct name_hash * new;
+ int hash;
+
+ new = (struct name_hash *) e_malloc(sizeof(struct name_hash));
+ new->de = de;
+ new->next = NULL;
+ hash = name_hash(de->isorec.name);
+
+ /* Now insert into the hash table */
+ new->next = name_hash_table[hash];
+ name_hash_table[hash] = new;
+}
+
+struct directory_entry * FDECL1(find_file_hash, char *, name)
+{
+ struct name_hash * nh;
+ char * p1;
+ char * p2;
+
+ for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
+ {
+ p1 = name;
+ p2 = nh->de->isorec.name;
+
+ /*
+ * Look for end of string, or a mismatch.
+ */
+ while(1==1)
+ {
+ if( (*p1 == '\0' || *p1 == ';')
+ || (*p2 == '\0' || *p2 == ';')
+ || (*p1 != *p2) )
+ {
+ break;
+ }
+ p1++;
+ p2++;
+ }
+
+ /*
+ * If we are at the end of both strings, then
+ * we have a match.
+ */
+ if( (*p1 == '\0' || *p1 == ';')
+ && (*p2 == '\0' || *p2 == ';') )
+ {
+ return nh->de;
+ }
+ }
+ return NULL;
+}
+
+int FDECL1(delete_file_hash, struct directory_entry *, de){
+ struct name_hash * nh, *prev;
+ int hash;
+
+ prev = NULL;
+ hash = name_hash(de->isorec.name);
+ for(nh = name_hash_table[hash]; nh; nh = nh->next) {
+ if(nh->de == de) break;
+ prev = nh;
+ }
+ if(!nh) return 1;
+ if(!prev)
+ name_hash_table[hash] = nh->next;
+ else
+ prev->next = nh->next;
+ free(nh);
+ return 0;
+}
+
+void flush_file_hash(){
+ struct name_hash * nh, *nh1;
+ int i;
+
+ for(i=0; i<NR_NAME_HASH; i++) {
+ nh = name_hash_table[i];
+ while(nh) {
+ nh1 = nh->next;
+ free(nh);
+ nh = nh1;
+ }
+ name_hash_table[i] = NULL;
+
+ }
+}
--- /dev/null
+/*
+ * 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
+
+
+
--- /dev/null
+/*
+ * 27-Mar-96: Jan-Piet Mens <jpm@mens.de>
+ * added 'match' option (-m) to specify regular expressions NOT to be included
+ * in the CD image.
+ */
+
+static char rcsid[] ="$Id: match.c,v 1.2 1997/02/23 16:10:42 eric Rel $";
+
+#include <stdio.h>
+#ifndef VMS
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+#include <string.h>
+#include "match.h"
+
+#define MAXMATCH 1000
+static char *mat[MAXMATCH];
+
+void add_match(fn)
+char * fn;
+{
+ register int i;
+
+ for (i=0; mat[i] && i<MAXMATCH; i++);
+ if (i == MAXMATCH) {
+ fprintf(stderr,"Can't exclude RE '%s' - too many entries in table\n",fn);
+ return;
+ }
+
+
+ mat[i] = (char *) malloc(strlen(fn)+1);
+ if (! mat[i]) {
+ fprintf(stderr,"Can't allocate memory for excluded filename\n");
+ return;
+ }
+
+ strcpy(mat[i],fn);
+}
+
+int matches(fn)
+char * fn;
+{
+ /* very dumb search method ... */
+ register int i;
+
+ for (i=0; mat[i] && i<MAXMATCH; i++) {
+ if (fnmatch(mat[i], fn, FNM_FILE_NAME) != FNM_NOMATCH) {
+ return 1; /* found -> excluded filenmae */
+ }
+ }
+ return 0; /* not found -> not excluded */
+}
--- /dev/null
+/*
+ * 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();
--- /dev/null
+/*
+ * Program mkisofs.c - generate iso9660 filesystem based upon directory
+ * tree on hard disk.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: mkisofs.c,v 1.10.1.3 1998/06/02 03:36:16 eric Exp $";
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <errno.h>
+#include "mkisofs.h"
+#include "config.h"
+
+#ifdef linux
+#include <getopt.h>
+#endif
+
+#include "iso9660.h"
+#include <ctype.h>
+
+#ifndef VMS
+#include <time.h>
+#else
+#include <sys/time.h>
+#include "vms.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifndef VMS
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#include "exclude.h"
+
+#ifdef __NetBSD__
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+struct directory * root = NULL;
+
+static char version_string[] = "mkisofs v1.11.3";
+
+FILE * discimage;
+unsigned int next_extent = 0;
+unsigned int last_extent = 0;
+unsigned int session_start = 0;
+unsigned int path_table_size = 0;
+unsigned int path_table[4] = {0,};
+unsigned int path_blocks = 0;
+struct iso_directory_record root_record;
+char * extension_record = NULL;
+int extension_record_extent = 0;
+static int extension_record_size = 0;
+
+/* These variables are associated with command line options */
+int use_eltorito = 0;
+int use_RockRidge = 0;
+int verbose = 0;
+int all_files = 0;
+int follow_links = 0;
+int rationalize = 0;
+int generate_tables = 0;
+char * preparer = PREPARER_DEFAULT;
+char * publisher = PUBLISHER_DEFAULT;
+char * appid = APPID_DEFAULT;
+char * copyright = COPYRIGHT_DEFAULT;
+char * biblio = BIBLIO_DEFAULT;
+char * abstract = ABSTRACT_DEFAULT;
+char * volset_id = VOLSET_ID_DEFAULT;
+char * volume_id = VOLUME_ID_DEFAULT;
+char * system_id = SYSTEM_ID_DEFAULT;
+char * boot_catalog = BOOT_CATALOG_DEFAULT;
+char * boot_image = BOOT_IMAGE_DEFAULT;
+
+int omit_period = 0; /* Violates iso9660, but these are a pain */
+int transparent_compression = 0; /* So far only works with linux */
+int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/
+int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */
+int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with
+ DOS */
+int allow_leading_dots = 0; /* DOS cannot read names with leading dots */
+
+struct rcopts{
+ char * tag;
+ char ** variable;
+};
+
+struct rcopts rcopt[] = {
+ {"PREP", &preparer},
+ {"PUBL", &publisher},
+ {"APPI", &appid},
+ {"COPY", ©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;
+}
--- /dev/null
+/*
+ * Header file mkisofs.h - assorted structure definitions and typecasts.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * $Id: mkisofs.h,v 1.5 1997/05/17 15:50:28 eric Exp $
+ */
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdio.h>
+
+/* This symbol is used to indicate that we do not have things like
+ symlinks, devices, and so forth available. Just files and dirs */
+
+#ifdef VMS
+#define NON_UNIXFS
+#endif
+
+#ifdef DJGPP
+#define NON_UNIXFS
+#endif
+
+#ifdef VMS
+#include <sys/dir.h>
+#define dirent direct
+#else
+#include <dirent.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef linux
+#include <sys/dir.h>
+#endif
+
+#ifdef ultrix
+extern char *strdup();
+#endif
+
+#ifdef __STDC__
+#define DECL(NAME,ARGS) NAME ARGS
+#define FDECL1(NAME,TYPE0, ARG0) \
+ NAME(TYPE0 ARG0)
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1)
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2)
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3)
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4)
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+ NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5)
+#else
+#define DECL(NAME,ARGS) NAME()
+#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0;
+#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1;
+#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \
+ NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2;
+#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3;
+#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4;
+#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \
+ NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5;
+#define const
+#endif
+
+
+#ifdef __svr4__
+#include <stdlib.h>
+#else
+extern int optind;
+extern char *optarg;
+/* extern int getopt (int __argc, char **__argv, char *__optstring); */
+#endif
+
+#include "iso9660.h"
+#include "defaults.h"
+
+struct directory_entry{
+ struct directory_entry * next;
+ struct iso_directory_record isorec;
+ unsigned int starting_block;
+ unsigned int size;
+ unsigned int priority;
+ char * name;
+ char * table;
+ char * whole_name;
+ struct directory * filedir;
+ struct directory_entry * parent_rec;
+ unsigned int de_flags;
+ ino_t inode; /* Used in the hash table */
+ dev_t dev; /* Used in the hash table */
+ unsigned char * rr_attributes;
+ unsigned int rr_attr_size;
+ unsigned int total_rr_attr_size;
+};
+
+struct file_hash{
+ struct file_hash * next;
+ ino_t inode; /* Used in the hash table */
+ dev_t dev; /* Used in the hash table */
+ unsigned int starting_block;
+ unsigned int size;
+};
+
+/*
+ * This structure describes one complete directory. It has pointers
+ * to other directories in the overall tree so that it is clear where
+ * this directory lives in the tree, and it also must contain pointers
+ * to the contents of the directory. Note that subdirectories of this
+ * directory exist twice in this stucture. Once in the subdir chain,
+ * and again in the contents chain.
+ */
+struct directory{
+ struct directory * next; /* Next directory at same level as this one */
+ struct directory * subdir; /* First subdirectory in this directory */
+ struct directory * parent;
+ struct directory_entry * contents;
+ struct directory_entry * self;
+ char * whole_name; /* Entire path */
+ char * de_name; /* Entire path */
+ unsigned int ce_bytes; /* Number of bytes of CE entries reqd for this dir */
+ unsigned int depth;
+ unsigned int size;
+ unsigned int extent;
+ unsigned short path_index;
+};
+
+struct deferred{
+ struct deferred * next;
+ unsigned int starting_block;
+ char * name;
+ struct directory * filedir;
+ unsigned int flags;
+};
+
+extern int goof;
+extern struct directory * root;
+extern struct directory * reloc_dir;
+extern unsigned int next_extent;
+extern unsigned int last_extent;
+extern unsigned int last_extent_written;
+extern unsigned int session_start;
+extern unsigned int path_table_size;
+extern unsigned int path_table[4];
+extern unsigned int path_blocks;
+extern char * path_table_l;
+extern char * path_table_m;
+extern struct iso_directory_record root_record;
+
+extern int use_eltorito;
+extern int use_RockRidge;
+extern int rationalize;
+extern int follow_links;
+extern int verbose;
+extern int all_files;
+extern int generate_tables;
+extern int omit_period;
+extern int omit_version_number;
+extern int transparent_compression;
+extern int RR_relocation_depth;
+extern int full_iso9660_filenames;
+
+/* tree.c */
+extern int DECL(stat_filter, (char *, struct stat *));
+extern void DECL(sort_n_finish,(struct directory *));
+extern void finish_cl_pl_entries();
+extern int DECL(scan_directory_tree,(char * path,
+ struct directory_entry * self,
+ struct iso_directory_record *));
+extern void DECL(generate_iso9660_directories,(struct directory *, FILE*));
+extern void DECL(dump_tree,(struct directory * node));
+extern struct directory_entry * DECL(search_tree_file, (struct
+ directory * node,char * filename));
+
+/* eltorito.c */
+extern void DECL(init_boot_catalog, (const char * path ));
+extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path ));
+
+/* write.c */
+extern void DECL(assign_directory_addresses,(struct directory * root));
+extern int DECL(get_733,(char *));
+extern int DECL(isonum_733,(unsigned char *));
+extern void DECL(set_723,(char *, unsigned int));
+extern void DECL(set_731,(char *, unsigned int));
+extern void DECL(set_721,(char *, unsigned int));
+extern void DECL(set_733,(char *, unsigned int));
+extern void DECL(sort_directory,(struct directory_entry **));
+extern void generate_root_record();
+extern void DECL(generate_one_directory,(struct directory *, FILE*));
+extern void generate_path_tables();
+extern int DECL(iso_write,(FILE * outfile));
+extern void DECL(memcpy_max, (char *, char *, int));
+
+
+/* multi.c */
+
+extern FILE * in_image;
+extern struct iso_directory_record *
+ DECL(merge_isofs,(char * path));
+
+extern int DECL(free_mdinfo, (struct directory_entry **, int len));
+
+extern struct directory_entry **
+ DECL(read_merging_directory,(struct iso_directory_record *, int*));
+extern void
+ DECL(merge_remaining_entries, (struct directory *,
+ struct directory_entry **, int));
+
+/* match.c */
+extern int DECL(matches, (char *));
+extern void DECL(add_match, (char *));
+
+/* files.c */
+struct dirent * DECL(readdir_add_files, (char **, char *, DIR *));
+
+/* */
+
+extern int DECL(iso9660_file_length,(const char* name,
+ struct directory_entry * sresult, int flag));
+extern int DECL(iso9660_date,(char *, time_t));
+extern void DECL(add_hash,(struct directory_entry *));
+extern struct file_hash * DECL(find_hash,(dev_t, ino_t));
+extern void DECL(add_directory_hash,(dev_t, ino_t));
+extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t));
+extern void flush_file_hash();
+extern int DECL(delete_file_hash,(struct directory_entry *));
+extern struct directory_entry * DECL(find_file_hash,(char *));
+extern void DECL(add_file_hash,(struct directory_entry *));
+extern int DECL(generate_rock_ridge_attributes,(char *, char *,
+ struct directory_entry *,
+ struct stat *, struct stat *,
+ int deep_flag));
+extern char * DECL(generate_rr_extension_record,(char * id, char * descriptor,
+ char * source, int * size));
+
+extern int DECL(check_prev_session, (struct directory_entry **, int len,
+ struct directory_entry *,
+ struct stat *,
+ struct stat *,
+ struct directory_entry **));
+
+#ifdef USE_SCG
+/* scsi.c */
+extern int readsecs(int startsecno, void *buffer, int sectorcount);
+extern int scsidev_open(char *path);
+#endif
+
+extern char * extension_record;
+extern int extension_record_extent;
+extern int n_data_extents;
+
+/* These are a few goodies that can be specified on the command line, and are
+ filled into the root record */
+
+extern char * preparer;
+extern char * publisher;
+extern char * copyright;
+extern char * biblio;
+extern char * abstract;
+extern char * appid;
+extern char * volset_id;
+extern char * system_id;
+extern char * volume_id;
+extern char * boot_catalog;
+extern char * boot_image;
+
+extern void * DECL(e_malloc,(size_t));
+
+
+#define SECTOR_SIZE (2048)
+#define ROUND_UP(X) ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
+
+#define NEED_RE 1
+#define NEED_PL 2
+#define NEED_CL 4
+#define NEED_CE 8
+#define NEED_SP 16
+
+#define PREV_SESS_DEV (sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd)
+#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe)
+#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff)
+#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff)
+
+#ifdef VMS
+#define STAT_INODE(X) (X.st_ino[0])
+#define PATH_SEPARATOR ']'
+#define SPATH_SEPARATOR ""
+#else
+#define STAT_INODE(X) (X.st_ino)
+#define PATH_SEPARATOR '/'
+#define SPATH_SEPARATOR "/"
+#endif
+
+/*
+ * When using multi-session, indicates that we can reuse the
+ * TRANS.TBL information for this directory entry. If this flag
+ * is set for all entries in a directory, it means we can just
+ * reuse the TRANS.TBL and not generate a new one.
+ */
+#define SAFE_TO_REUSE_TABLE_ENTRY 1
+/*
+ * Volume sequence number to use in all of the iso directory records.
+ */
+#define DEF_VSN 1
+
+/*
+ * Make sure we have a definition for this. If not, take a very conservative
+ * guess. From what I can tell SunOS is the only one with this trouble.
+ */
+#ifndef NAME_MAX
+#ifdef FILENAME_MAX
+#define NAME_MAX FILENAME_MAX
+#else
+#define NAME_MAX 128
+#endif
+#endif
--- /dev/null
+/*
+ * File multi.c - scan existing iso9660 image and merge into
+ * iso9660 filesystem. Used for multisession support.
+ *
+ * Written by Eric Youngdale (1996).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static char rcsid[] ="$Id: multi.c,v 1.6.1.3 1998/06/02 03:00:25 eric Exp $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifndef VMS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#define TF_CREATE 1
+#define TF_MODIFY 2
+#define TF_ACCESS 4
+#define TF_ATTRIBUTES 8
+
+static int DECL(get_session_start, (int *));
+static int DECL(merge_old_directory_into_tree, (struct directory_entry *,
+ struct directory *));
+
+static int
+isonum_711 (unsigned char * p)
+{
+ return (*p & 0xff);
+}
+
+int
+isonum_721 (unsigned char * p)
+{
+ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
+}
+
+static int
+isonum_723 (unsigned char * p)
+{
+#if 0
+ if (p[0] != p[3] || p[1] != p[2]) {
+ fprintf (stderr, "invalid format 7.2.3 number\n");
+ exit (1);
+ }
+#endif
+ return (isonum_721 (p));
+}
+
+int
+isonum_731 (unsigned char * p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+int
+isonum_733 (unsigned char * p)
+{
+ return (isonum_731 (p));
+}
+
+FILE * in_image = NULL;
+
+#ifndef USE_SCG
+/*
+ * Don't define readsecs if mkisofs is linked with
+ * the SCSI library.
+ * readsecs() will be implemented as SCSI command in this case.
+ *
+ * Use global var in_image directly in readsecs()
+ * the SCSI equivalent will not use a FILE* for I/O.
+ *
+ * The main point of this pointless abstraction is that Solaris won't let
+ * you read 2K sectors from the cdrom driver. The fact that 99.9% of the
+ * discs out there have a 2K sectorsize doesn't seem to matter that much.
+ * Anyways, this allows the use of a scsi-generics type of interface on
+ * Solaris.
+ */
+static int
+readsecs(int startsecno, void *buffer, int sectorcount)
+{
+ int f = fileno(in_image);
+
+ if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) {
+ fprintf(stderr," Seek error on old image\n");
+ exit(10);
+ }
+ return (read(f, buffer, sectorcount * SECTOR_SIZE));
+}
+#endif
+
+/*
+ * Parse the RR attributes so we can find the file name.
+ */
+static int
+FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt)
+{
+ int cont_extent, cont_offset, cont_size;
+ char name_buf[256];
+
+ cont_extent = cont_offset = cont_size = 0;
+
+ while(len >= 4){
+ if(pnt[3] != 1) {
+ printf("**BAD RRVERSION");
+ return -1;
+ };
+ if(strncmp((char *) pnt, "NM", 2) == 0) {
+ strncpy(name_buf, (char *) pnt+5, pnt[2] - 5);
+ name_buf[pnt[2] - 5] = 0;
+ dpnt->name = strdup(name_buf);
+ return 0;
+ }
+
+ if(strncmp((char *) pnt, "CE", 2) == 0) {
+ cont_extent = isonum_733(pnt+4);
+ cont_offset = isonum_733(pnt+12);
+ cont_size = isonum_733(pnt+20);
+ };
+
+ len -= pnt[2];
+ pnt += pnt[2];
+ if(len <= 3 && cont_extent) {
+ unsigned char sector[SECTOR_SIZE];
+ readsecs(cont_extent, sector, 1);
+ parse_rr(§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("<translation table>");
+ tt_extent = isonum_733((unsigned char *)idr->extent);
+ tt_size = isonum_733((unsigned char *)idr->size);
+ }
+
+ pnt++;
+ i += idr->length[0];
+ }
+
+ /*
+ * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it
+ * to get the filenames of the files. Also, save the table info, just
+ * in case we need to use it.
+ */
+ if( tt_extent != 0 && tt_size != 0 )
+ {
+ tt_buf = (unsigned char *) e_malloc(tt_size);
+ readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE);
+
+ /*
+ * Loop through the file, examine each entry, and attempt to
+ * attach it to the correct entry.
+ */
+ cpnt = tt_buf;
+ cpnt1 = tt_buf;
+ while( cpnt - tt_buf < tt_size )
+ {
+ while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++;
+ *cpnt1 = '\0';
+
+ for(pnt = rtn, i = 0; i <*nent; i++, pnt++)
+ {
+ rlen = isonum_711((*pnt)->isorec.name_len);
+ if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name,
+ rlen) == 0
+ && cpnt[2+rlen] == ' ')
+ {
+ (*pnt)->table = e_malloc(strlen((char*)cpnt) - 34);
+ sprintf((*pnt)->table, "%c\t%s\n",
+ *cpnt, cpnt+37);
+ if( (*pnt)->name == NULL )
+ {
+ (*pnt)->name = strdup((char *) cpnt+37);
+ }
+ break;
+ }
+ }
+ cpnt = cpnt1 + 1;
+ cpnt1 = cpnt;
+ }
+
+ free(tt_buf);
+ }
+ else if( !seen_rockridge )
+ {
+ /*
+ * This is a fatal error right now because we must have some mechanism
+ * for taking the 8.3 names back to the original unix names.
+ * In principle we could do this the hard way, and try and translate
+ * the unix names that we have seen forwards, but this would be
+ * a real pain in the butt.
+ */
+ fprintf(stderr,"Previous session must have either Rock Ridge (-R) or\n");
+ fprintf(stderr,"TRANS.TBL (-T) for mkisofs to be able to correctly\n");
+ fprintf(stderr,"generate additional sessions.\n");
+ exit(3);
+ }
+
+ if( dirbuff != NULL )
+ {
+ free(dirbuff);
+ }
+
+ return rtn;
+}
+
+/*
+ * Free any associated data related to the structures.
+ */
+int
+FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len )
+{
+ int i;
+ struct directory_entry **p;
+
+ p = ptr;
+ for(i=0; i<len; i++, p++)
+ {
+ /*
+ * If the tree-handling code decided that it needed an entry,
+ * it will have removed it from the list. Thus we must allow
+ * for null pointers here.
+ */
+ if( *p == NULL )
+ {
+ continue;
+ }
+
+ if( (*p)->name != NULL )
+ {
+ free((*p)->name);
+ }
+
+ if( (*p)->whole_name != NULL )
+ {
+ free((*p)->whole_name);
+ }
+
+ if( (*p)->rr_attributes != NULL )
+ {
+ free((*p)->rr_attributes);
+ }
+
+ if( (*p)->table != NULL )
+ {
+ free((*p)->table);
+ }
+
+ free(*p);
+
+ }
+
+ free(ptr);
+ return 0;
+}
+
+/*
+ * Search the list to see if we have any entries from the previous
+ * session that match this entry. If so, copy the extent number
+ * over so we don't bother to write it out to the new session.
+ */
+
+int
+FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len,
+ struct directory_entry *, curr_entry,
+ struct stat *, statbuf, struct stat *, lstatbuf,
+ struct directory_entry **, odpnt)
+{
+ int i;
+
+ for( i=0; i < len; i++ )
+ {
+ if( ptr[i] == NULL )
+ {
+ continue;
+ }
+
+#if 0
+ if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+ && ptr[i]->name[0] == '\0' )
+ {
+ continue;
+ }
+ if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1
+ && ptr[i]->name[0] == 1)
+ {
+ continue;
+ }
+#else
+ if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 )
+ {
+ continue;
+ }
+ if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 )
+ {
+ continue;
+ }
+#endif
+
+ if( ptr[i]->name != NULL
+ && strcmp(ptr[i]->name, curr_entry->name) != 0 )
+ {
+ continue;
+ }
+
+ /*
+ * We know that the files have the same name. If they also have
+ * the same file type (i.e. file, dir, block, etc), then we
+ * can safely reuse the TRANS.TBL entry for this file.
+ * The check_rr_dates function will do this for us.
+ *
+ * Verify that the file type and dates are consistent.
+ * If not, we probably have a different file, and we need
+ * to write it out again.
+ */
+ if( (ptr[i]->rr_attributes != NULL)
+ && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) )
+ {
+ goto found_it;
+ }
+
+
+ /*
+ * Verify size and timestamp. If rock ridge is in use, we need
+ * to compare dates from RR too. Directories are special, we
+ * calculate their size later.
+ */
+ if( (curr_entry->isorec.flags[0] & 2) == 0
+ && ptr[i]->size != curr_entry->size )
+ {
+ goto found_it;
+ }
+
+ if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 )
+ {
+ goto found_it;
+ }
+
+ /*
+ * Never ever reuse directory extents. See comments in
+ * tree.c for an explaination of why this must be the case.
+ */
+ if( (curr_entry->isorec.flags[0] & 2) != 0 )
+ {
+ goto found_it;
+ }
+
+ memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
+ curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+ goto found_it;
+ }
+ return 0;
+
+found_it:
+ if( odpnt != NULL )
+ {
+ *odpnt = ptr[i];
+ }
+ else
+ {
+ free(ptr[i]);
+ }
+ ptr[i] = NULL;
+ return 0;
+}
+
+/*
+ * merge_isofs: Scan an existing image, and return a pointer
+ * to the root directory for this image.
+ */
+struct iso_directory_record * FDECL1(merge_isofs, char *, path)
+{
+ char buffer[SECTOR_SIZE];
+ int file_addr;
+ int i;
+ struct iso_primary_descriptor * pri = NULL;
+ struct iso_directory_record * rootp;
+ struct iso_volume_descriptor * vdp;
+
+ /*
+ * Start by opening up the image and searching for the volume header.
+ * Ultimately, we need to search for volume headers in multiple places
+ * because we might be starting with a multisession image.
+ * FIXME(eric).
+ */
+
+#ifndef USE_SCG
+ in_image = fopen(path, "rb");
+ if( in_image == NULL )
+ {
+ return NULL;
+ }
+#else
+ if (strchr(path, '/')) {
+ in_image = fopen(path, "rb");
+ if( in_image == NULL ) {
+ return NULL;
+ }
+ } else {
+ if (scsidev_open(path) < 0)
+ return NULL;
+ }
+#endif
+
+ get_session_start(&file_addr);
+
+ for(i = 0; i< 100; i++)
+ {
+ if (readsecs(file_addr/SECTOR_SIZE, &buffer,
+ sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer))
+ {
+ fprintf(stderr," Read error on old image %s\n", path);
+ exit(10);
+ }
+
+ vdp = (struct iso_volume_descriptor *)buffer;
+
+ if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0)
+ && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) )
+ {
+ break;
+ }
+ file_addr += SECTOR_SIZE;
+ }
+
+ if( i == 100 )
+ {
+ return NULL;
+ }
+
+ pri = (struct iso_primary_descriptor *)vdp;
+
+ /*
+ * Check the blocksize of the image to make sure it is compatible.
+ */
+ if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE)
+ || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) )
+ {
+ return NULL;
+ }
+
+ /*
+ * Get the location and size of the root directory.
+ */
+ rootp = (struct iso_directory_record *)
+ malloc(sizeof(struct iso_directory_record));
+
+ memcpy(rootp, pri->root_directory_record, sizeof(*rootp));
+
+ return rootp;
+}
+
+void FDECL3(merge_remaining_entries, struct directory *, this_dir,
+ struct directory_entry **, pnt,
+ int, n_orig)
+{
+ int i;
+ struct directory_entry * s_entry;
+ unsigned int ttbl_extent = 0;
+ unsigned int ttbl_index = 0;
+
+ /*
+ * Whatever is leftover in the list needs to get merged back
+ * into the directory.
+ */
+ for( i=0; i < n_orig; i++ )
+ {
+ if( pnt[i] == NULL )
+ {
+ continue;
+ }
+
+ if( pnt[i]->name != NULL
+ && strcmp(pnt[i]->name, "<translation table>") == 0 )
+ {
+ ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent);
+ ttbl_index = i;
+ continue;
+ }
+ /*
+ * Skip directories for now - these need to be treated
+ * differently.
+ */
+ if( (pnt[i]->isorec.flags[0] & 2) != 0 )
+ {
+ /*
+ * FIXME - we need to insert this directory into the
+ * tree, so that the path tables we generate will
+ * be correct.
+ */
+ if( (strcmp(pnt[i]->name, ".") == 0)
+ || (strcmp(pnt[i]->name, "..") == 0) )
+ {
+ free(pnt[i]);
+ pnt[i] = NULL;
+ continue;
+ }
+ else
+ {
+ merge_old_directory_into_tree(pnt[i], this_dir);
+ }
+ }
+ pnt[i]->next = this_dir->contents;
+ pnt[i]->filedir = this_dir;
+ this_dir->contents = pnt[i];
+ pnt[i] = NULL;
+ }
+
+
+ /*
+ * If we don't have an entry for the translation table, then
+ * don't bother trying to copy the starting extent over.
+ * Note that it is possible that if we are copying the entire
+ * directory, the entry for the translation table will have already
+ * been inserted into the linked list and removed from the old
+ * entries list, in which case we want to leave the extent number
+ * as it was before.
+ */
+ if( ttbl_extent == 0 )
+ {
+ return;
+ }
+
+ /*
+ * Finally, check the directory we are creating to see whether
+ * there are any new entries in it. If there are not, we can
+ * reuse the same translation table.
+ */
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+ {
+ /*
+ * Don't care about '.' or '..'. They are never in the table
+ * anyways.
+ */
+ if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 )
+ {
+ continue;
+ }
+ if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 )
+ {
+ continue;
+ }
+ if( strcmp(s_entry->name, "<translation table>") == 0)
+ {
+ continue;
+ }
+ if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 )
+ {
+ return;
+ }
+ }
+
+ /*
+ * Locate the translation table, and re-use the same extent.
+ * It isn't clear that there should ever be one in there already
+ * so for now we try and muddle through the best we can.
+ */
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+ {
+ if( strcmp(s_entry->name, "<translation table>") == 0)
+ {
+ fprintf(stderr,"Should never get here\n");
+ set_733(s_entry->isorec.extent, ttbl_extent);
+ return;
+ }
+ }
+
+ pnt[ttbl_index]->next = this_dir->contents;
+ pnt[ttbl_index]->filedir = this_dir;
+ this_dir->contents = pnt[ttbl_index];
+ pnt[ttbl_index] = NULL;
+}
+
+
+/*
+ * Here we have a case of a directory that has completely disappeared from
+ * the face of the earth on the tree we are mastering from. Go through and
+ * merge it into the tree, as well as everything beneath it.
+ *
+ * Note that if a directory has been moved for some reason, this will
+ * incorrectly pick it up and attempt to merge it back into the old
+ * location. FIXME(eric).
+ */
+static int
+FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt,
+ struct directory *, parent)
+{
+ struct directory_entry **contents = NULL;
+ int i;
+ int n_orig;
+ struct directory * this_dir, *next_brother;
+ char whole_path[1024];
+
+ this_dir = (struct directory *) e_malloc(sizeof(struct directory));
+ this_dir->next = NULL;
+ this_dir->subdir = NULL;
+ this_dir->self = dpnt;
+ this_dir->contents = NULL;
+ this_dir->size = 0;
+ this_dir->extent = 0;
+ this_dir->depth = parent->depth + 1;
+ this_dir->parent = parent;
+ if(!parent->subdir)
+ parent->subdir = this_dir;
+ else {
+ next_brother = parent->subdir;
+ while(next_brother->next) next_brother = next_brother->next;
+ next_brother->next = this_dir;
+ }
+
+ /*
+ * Set the name for this directory.
+ */
+ strcpy(whole_path, parent->de_name);
+ strcat(whole_path, SPATH_SEPARATOR);
+ strcat(whole_path, dpnt->name);
+ this_dir->de_name = strdup(whole_path);
+ this_dir->whole_name = strdup(whole_path);
+
+ /*
+ * Now fill this directory using information from the previous
+ * session.
+ */
+ contents = read_merging_directory(&dpnt->isorec, &n_orig);
+ /*
+ * Start by simply copying the '.', '..' and non-directory
+ * entries to this directory. Technically we could let
+ * merge_remaining_entries handle this, but it gets rather confused
+ * by the '.' and '..' entries.
+ */
+ for(i=0; i < n_orig; i ++ )
+ {
+ /*
+ * We can always reuse the TRANS.TBL in this particular case.
+ */
+ contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+
+ if( ((contents[i]->isorec.flags[0] & 2) != 0)
+ && (i >= 2) )
+ {
+ continue;
+ }
+
+ /*
+ * If we have a directory, don't reuse the extent number.
+ */
+ if( (contents[i]->isorec.flags[0] & 2) != 0 )
+ {
+ memset(contents[i]->isorec.extent, 0, 8);
+ }
+
+ contents[i]->next = this_dir->contents;
+ contents[i]->filedir = this_dir;
+ this_dir->contents = contents[i];
+ contents[i] = NULL;
+ }
+
+ /*
+ * Zero the extent number for ourselves.
+ */
+ memset(dpnt->isorec.extent, 0, 8);
+
+ /*
+ * Anything that is left are other subdirectories that need to be merged.
+ */
+ merge_remaining_entries(this_dir, contents, n_orig);
+ free_mdinfo(contents, n_orig);
+ sort_n_finish(this_dir);
+
+ return 0;
+}
+
+
+char * cdwrite_data = NULL;
+
+static int
+FDECL1(get_session_start, int *, file_addr)
+{
+ char * pnt;
+
+#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS
+ /*
+ * FIXME(eric). We need to coordinate with cdwrite to obtain
+ * the parameters. For now, we assume we are writing the 2nd session,
+ * so we start from the session that starts at 0.
+ */
+
+ *file_addr = (16 << 11);
+
+ /*
+ * We need to coordinate with cdwrite to get the next writable address
+ * from the device. Here is where we use it.
+ */
+ session_start = last_extent = last_extent_written = cdwrite_result();
+
+#else
+
+ if( cdwrite_data == NULL )
+ {
+ fprintf(stderr,"Special parameters for cdwrite not specified with -C\n");
+ exit(1);
+ }
+
+ /*
+ * Next try and find the ',' in there which delimits the two numbers.
+ */
+ pnt = strchr(cdwrite_data, ',');
+ if( pnt == NULL )
+ {
+ fprintf(stderr, "Malformed cdwrite parameters\n");
+ exit(1);
+ }
+
+ *pnt = '\0';
+ *file_addr = atol(cdwrite_data) * SECTOR_SIZE;
+ pnt++;
+
+ session_start = last_extent = last_extent_written = atol(pnt);
+
+ pnt--;
+ *pnt = ',';
+
+#endif
+ return 0;
+}
+
--- /dev/null
+/*
+ * File name.c - map full Unix file names to unique 8.3 names that
+ * would be valid on DOS.
+ *
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: name.c,v 1.7 1997/11/09 16:42:51 eric Exp $";
+
+#include "mkisofs.h"
+
+#include <ctype.h>
+
+extern int allow_leading_dots;
+
+/*
+ * Function: iso9660_file_length
+ *
+ * Purpose: Map file name to 8.3 format, return length
+ * of result.
+ *
+ * Arguments: name file name we need to map.
+ * sresult directory entry structure to contain mapped name.
+ * dirflag flag indicating whether this is a directory or not.
+ *
+ * Notes: This procedure probably needs to be rationalized somehow.
+ * New options to affect the behavior of this function
+ * would also be nice to have.
+ */
+int FDECL3(iso9660_file_length,
+ const char*, name,
+ struct directory_entry *, sresult,
+ int, dirflag)
+{
+ char * c;
+ int chars_after_dot = 0;
+ int chars_before_dot = 0;
+ int current_length = 0;
+ int extra = 0;
+ int ignore = 0;
+ char * last_dot;
+ const char * pnt;
+ int priority = 32767;
+ char * result;
+ int seen_dot = 0;
+ int seen_semic = 0;
+ int tildes = 0;
+
+ result = sresult->isorec.name;
+
+ /*
+ * For the '.' entry, generate the correct record, and return
+ * 1 for the length.
+ */
+ if(strcmp(name,".") == 0)
+ {
+ if(result)
+ {
+ *result = 0;
+ }
+ return 1;
+ }
+
+ /*
+ * For the '..' entry, generate the correct record, and return
+ * 1 for the length.
+ */
+ if(strcmp(name,"..") == 0)
+ {
+ if(result)
+ {
+ *result++ = 1;
+ *result++ = 0;
+ }
+ return 1;
+ }
+
+ /*
+ * Now scan the directory one character at a time, and figure out
+ * what to do.
+ */
+ pnt = name;
+
+ /*
+ * Find the '.' that we intend to use for the extension. Usually this
+ * is the last dot, but if we have . followed by nothing or a ~, we
+ * would consider this to be unsatisfactory, and we keep searching.
+ */
+ last_dot = strrchr (pnt,'.');
+ if( (last_dot != NULL)
+ && ( (last_dot[1] == '~')
+ || (last_dot[1] == '\0')
+ || (last_dot[1] == '\0')) )
+ {
+ c = last_dot;
+ *c = '\0';
+ last_dot = strrchr (pnt,'.');
+ *c = '.';
+ }
+
+ while(*pnt)
+ {
+#ifdef VMS
+ if( strcmp(pnt,".DIR;1") == 0 )
+ {
+ break;
+ }
+#endif
+
+ /*
+ * This character indicates a Unix style of backup file
+ * generated by some editors. Lower the priority of
+ * the file.
+ */
+ if(*pnt == '#')
+ {
+ priority = 1;
+ pnt++;
+ continue;
+ }
+
+ /*
+ * This character indicates a Unix style of backup file
+ * generated by some editors. Lower the priority of
+ * the file.
+ */
+ if(*pnt == '~')
+ {
+ priority = 1;
+ tildes++;
+ pnt++;
+ continue;
+ }
+
+ /*
+ * This might come up if we had some joker already try and put
+ * iso9660 version numbers into the file names. This would be
+ * a silly thing to do on a Unix box, but we check for it
+ * anyways. If we see this, then we don't have to add our
+ * own version number at the end.
+ */
+ if(*pnt == ';')
+ {
+ seen_semic = 1;
+ *result++ = *pnt++;
+ continue;
+ }
+
+ /*
+ * If we have a name with multiple '.' characters, we ignore everything
+ * after we have gotten the extension.
+ */
+ if(ignore)
+ {
+ pnt++;
+ continue;
+ }
+
+ /*
+ * Spin past any iso9660 version number we might have.
+ */
+ if(seen_semic)
+ {
+ if(*pnt >= '0' && *pnt <= '9')
+ {
+ *result++ = *pnt;
+ }
+ extra++;
+ pnt++;
+ continue;
+ }
+
+ /*
+ * If we have full names, the names we generate will not
+ * work on a DOS machine, since they are not guaranteed
+ * to be 8.3. Nonetheless, in many cases this is a useful
+ * option. We still only allow one '.' character in the
+ * name, however.
+ */
+ if(full_iso9660_filenames)
+ {
+ /* Here we allow a more relaxed syntax. */
+ if(*pnt == '.')
+ {
+ if (seen_dot)
+ {
+ ignore++;
+ continue;
+ }
+ seen_dot++;
+ }
+ if(current_length < 30)
+ {
+ if( *pnt < 0 )
+ {
+ *result++ = '_';
+ }
+ else
+ {
+ *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Dos style filenames. We really restrict the
+ * names here.
+ */
+ /* It would be nice to have .tar.gz transform to .tgz,
+ * .ps.gz to .psz, ...
+ */
+ if(*pnt == '.')
+ {
+ if (!chars_before_dot && !allow_leading_dots)
+ {
+ /* DOS can't read files with dot first */
+ chars_before_dot++;
+ if (result)
+ {
+ *result++ = '_'; /* Substitute underscore */
+ }
+ }
+ else if( pnt != last_dot )
+ {
+ /*
+ * If this isn't the dot that we use for the extension,
+ * then change the character into a '_' instead.
+ */
+ if(chars_before_dot < 8)
+ {
+ chars_before_dot++;
+ if(result)
+ {
+ *result++ = '_';
+ }
+ }
+ }
+ else
+ {
+ if (seen_dot)
+ {
+ ignore++; continue;
+ }
+ if(result)
+ {
+ *result++ = '.';
+ }
+ seen_dot++;
+ }
+ }
+ else
+ {
+ if( (seen_dot && (chars_after_dot < 3) && ++chars_after_dot)
+ || (!seen_dot && (chars_before_dot < 8) && ++chars_before_dot) )
+ {
+ if(result)
+ {
+ switch (*pnt)
+ {
+ default:
+ if( *pnt < 0 )
+ {
+ *result++ = '_';
+ }
+ else
+ {
+ *result++ = islower(*pnt) ? toupper(*pnt) : *pnt;
+ }
+ break;
+
+ /*
+ * Descriptions of DOS's 'Parse Filename'
+ * (function 29H) describes V1 and V2.0+
+ * separator and terminator characters.
+ * These characters in a DOS name make
+ * the file visible but un-manipulable
+ * (all useful operations error off.
+ */
+ /* separators */
+ case '+':
+ case '=':
+ case '%': /* not legal DOS filename */
+ case ':':
+ case ';': /* already handled */
+ case '.': /* already handled */
+ case ',': /* already handled */
+ case '\t':
+ case ' ':
+ /* V1 only separators */
+ case '/':
+ case '"':
+ case '[':
+ case ']':
+ /* terminators */
+ case '>':
+ case '<':
+ case '|':
+ /* Hmm - what to do here? Skip?
+ * Win95 looks like it substitutes '_'
+ */
+ *result++ = '_';
+ break;
+ } /* switch (*pnt) */
+ } /* if (result) */
+ } /* if (chars_{after,before}_dot) ... */
+ } /* else *pnt == '.' */
+ } /* else DOS file names */
+ current_length++;
+ pnt++;
+ } /* while (*pnt) */
+
+ /*
+ * OK, that wraps up the scan of the name. Now tidy up a few other
+ * things.
+ */
+
+ /*
+ * Look for emacs style of numbered backups, like foo.c.~3~. If
+ * we see this, convert the version number into the priority
+ * number. In case of name conflicts, this is what would end
+ * up being used as the 'extension'.
+ */
+ if(tildes == 2)
+ {
+ int prio1 = 0;
+ pnt = name;
+ while (*pnt && *pnt != '~')
+ {
+ pnt++;
+ }
+ if (*pnt)
+ {
+ pnt++;
+ }
+ while(*pnt && *pnt != '~')
+ {
+ prio1 = 10*prio1 + *pnt - '0';
+ pnt++;
+ }
+ priority = prio1;
+ }
+
+ /*
+ * If this is not a directory, force a '.' in case we haven't
+ * seen one, and add a version number if we haven't seen one
+ * of those either.
+ */
+ if (!dirflag)
+ {
+ if (!seen_dot && !omit_period)
+ {
+ if (result) *result++ = '.';
+ extra++;
+ }
+ if(!omit_version_number && !seen_semic)
+ {
+ if(result)
+ {
+ *result++ = ';';
+ *result++ = '1';
+ };
+ extra += 2;
+ }
+ }
+
+ if(result)
+ {
+ *result++ = 0;
+ }
+ sresult->priority = priority;
+
+ return (chars_before_dot + chars_after_dot + seen_dot + extra);
+}
--- /dev/null
+/*
+ * File rock.c - generate RRIP records for iso9660 filesystems.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: rock.c,v 1.3 1997/05/17 15:45:26 eric Exp $";
+
+#include <stdlib.h>
+
+#include "config.h"
+
+#ifndef VMS
+#if defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <string.h>
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m) (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#define SU_VERSION 1
+
+#define SL_ROOT 8
+#define SL_PARENT 4
+#define SL_CURRENT 2
+#define SL_CONTINUE 1
+
+#define CE_SIZE 28
+#define CL_SIZE 12
+#define ER_SIZE 8
+#define NM_SIZE 5
+#define PL_SIZE 12
+#define PN_SIZE 20
+#define PX_SIZE 36
+#define RE_SIZE 4
+#define SL_SIZE 20
+#define ZZ_SIZE 15
+#ifdef __QNX__
+#define TF_SIZE (5 + 4 * 7)
+#else
+#define TF_SIZE (5 + 3 * 7)
+#endif
+
+/* If we need to store this number of bytes, make sure we
+ do not box ourselves in so that we do not have room for
+ a CE entry for the continuation record */
+
+#define MAYBE_ADD_CE_ENTRY(BYTES) \
+ (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
+
+/*
+ * Buffer to build RR attributes
+ */
+
+static unsigned char Rock[16384];
+static unsigned char symlink_buff[256];
+static int ipnt = 0;
+static int recstart = 0;
+static int currlen = 0;
+static int mainrec = 0;
+static int reclimit;
+
+static void add_CE_entry(){
+ if(recstart)
+ set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
+ Rock[ipnt++] ='C';
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] = CE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ recstart = ipnt;
+ currlen = 0;
+ if(!mainrec) mainrec = ipnt;
+ reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
+}
+
+#ifdef __STDC__
+int generate_rock_ridge_attributes (char * whole_name, char * name,
+ struct directory_entry * s_entry,
+ struct stat * statbuf,
+ struct stat * lstatbuf,
+ int deep_opt)
+#else
+int generate_rock_ridge_attributes (whole_name, name,
+ s_entry,
+ statbuf,
+ lstatbuf,
+ deep_opt)
+char * whole_name; char * name; struct directory_entry * s_entry;
+struct stat * statbuf, *lstatbuf;
+int deep_opt;
+#endif
+{
+ int flagpos, flagval;
+ int need_ce;
+
+ statbuf = statbuf; /* this shuts up unreferenced compiler warnings */
+ mainrec = recstart = ipnt = 0;
+ reclimit = 0xf8;
+
+ /* Obtain the amount of space that is currently used for the directory
+ record. Assume max for name, since name conflicts may cause us
+ to rename the file later on */
+ currlen = sizeof(s_entry->isorec);
+
+ /* Identify that we are using the SUSP protocol */
+ if(deep_opt & NEED_SP){
+ Rock[ipnt++] ='S';
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] = 7;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0xbe;
+ Rock[ipnt++] = 0xef;
+ Rock[ipnt++] = 0;
+ };
+
+ /* First build the posix name field */
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] = 5;
+ Rock[ipnt++] = SU_VERSION;
+ flagpos = ipnt;
+ flagval = 0;
+ Rock[ipnt++] = 0; /* We go back and fix this later */
+
+ if(strcmp(name,".") && strcmp(name,"..")){
+ char * npnt;
+ int remain, use;
+
+ remain = strlen(name);
+ npnt = name;
+
+ while(remain){
+ use = remain;
+ need_ce = 0;
+ /* Can we fit this SUSP and a CE entry? */
+ if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+ use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+ need_ce++;
+ }
+
+ /* Only room for 256 per SUSP field */
+ if(use > 0xf8) use = 0xf8;
+
+ /* First build the posix name field */
+ Rock[ipnt++] ='N';
+ Rock[ipnt++] ='M';
+ Rock[ipnt++] = NM_SIZE + use;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = (remain != use ? 1 : 0);
+ flagval |= (1<<3);
+ strncpy((char *)&Rock[ipnt], npnt, use);
+ npnt += use;
+ ipnt += use;
+ remain -= use;
+ if(remain && need_ce) add_CE_entry();
+ };
+ };
+
+ /*
+ * Add the posix modes
+ */
+ if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='X';
+ Rock[ipnt++] = PX_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<0);
+ set_733((char*)Rock + ipnt, lstatbuf->st_mode);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_uid);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_gid);
+ ipnt += 8;
+
+ /*
+ * Check for special devices
+ */
+#ifndef NON_UNIXFS
+ if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
+ if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='N';
+ Rock[ipnt++] = PN_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<1);
+#if !defined(MAJOR_IN_SYSMACROS) && !defined(MAJOR_IN_MKDEV)
+ set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
+ ipnt += 8;
+#else
+ /*
+ * If we don't have sysmacros.h, then we have to guess as to how
+ * best to pick apart the device number for major/minor.
+ * Note: this may very well be wrong for many systems, so
+ * it is always best to use the major/minor macros if the
+ * system supports it.
+ */
+ if(sizeof(dev_t) <= 2) {
+ set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
+ ipnt += 8;
+ }
+ else if(sizeof(dev_t) <= 4) {
+ set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
+ ipnt += 8;
+ }
+ else {
+ set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
+ ipnt += 8;
+ set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
+ ipnt += 8;
+ }
+#endif
+ };
+#endif
+ /*
+ * Check for and symbolic links. VMS does not have these.
+ */
+ if (S_ISLNK(lstatbuf->st_mode)){
+ int lenpos, lenval, j0, j1;
+ int nchar;
+ unsigned char * cpnt, *cpnt1;
+ nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff));
+ symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+ set_733(s_entry->isorec.size, 0);
+ cpnt = &symlink_buff[0];
+ flagval |= (1<<2);
+
+ while(nchar){
+ if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='S';
+ Rock[ipnt++] ='L';
+ lenpos = ipnt;
+ Rock[ipnt++] = SL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0; /* Flags */
+ lenval = 5;
+ while(*cpnt){
+ cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
+ if(cpnt1) {
+ nchar--;
+ *cpnt1 = 0;
+ };
+
+ /* We treat certain components in a special way. */
+ if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = SL_PARENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 2;
+ } else if(cpnt[0] == '.' && cpnt[1] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = SL_CURRENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 1;
+ } else if(cpnt[0] == 0){
+ if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
+ Rock[ipnt++] = SL_ROOT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ } else {
+ /* If we do not have enough room for a component, start
+ a new continuations segment now */
+ if(MAYBE_ADD_CE_ENTRY(6)) {
+ add_CE_entry();
+ if(cpnt1){
+ *cpnt1 = '/';
+ nchar++;
+ cpnt1 = NULL; /* A kluge so that we can restart properly */
+ }
+ break;
+ }
+ j0 = strlen((char *) cpnt);
+ while(j0) {
+ j1 = j0;
+ if(j1 > 0xf8) j1 = 0xf8;
+ need_ce = 0;
+ if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
+ j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
+ need_ce++;
+ }
+ Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
+ Rock[ipnt++] = j1;
+ strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
+ ipnt += j1;
+ lenval += j1 + 2;
+ cpnt += j1;
+ nchar -= j1; /* Number we processed this time */
+ j0 -= j1;
+ if(need_ce) {
+ add_CE_entry();
+ if(cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ cpnt1 = NULL; /* A kluge so that we can restart properly */
+ }
+ break;
+ }
+ }
+ };
+ if(cpnt1) {
+ cpnt = cpnt1 + 1;
+ } else
+ break;
+ }
+ Rock[lenpos] = lenval;
+ if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
+ } /* while nchar */
+ } /* Is a symbolic link */
+ /*
+ * Add in the Rock Ridge TF time field
+ */
+ if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='T';
+ Rock[ipnt++] ='F';
+ Rock[ipnt++] = TF_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+#ifdef __QNX__
+ Rock[ipnt++] = 0x0f;
+#else
+ Rock[ipnt++] = 0x0e;
+#endif
+ flagval |= (1<<7);
+#ifdef __QNX__
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
+ ipnt += 7;
+#endif
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
+ ipnt += 7;
+
+ /*
+ * Add in the Rock Ridge RE time field
+ */
+ if(deep_opt & NEED_RE){
+ if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] = RE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1<<6);
+ };
+ /*
+ * Add in the Rock Ridge PL record, if required.
+ */
+ if(deep_opt & NEED_PL){
+ if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='P';
+ Rock[ipnt++] ='L';
+ Rock[ipnt++] = PL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1<<5);
+ };
+
+ /*
+ * Add in the Rock Ridge CL field, if required.
+ */
+ if(deep_opt & NEED_CL){
+ if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='C';
+ Rock[ipnt++] ='L';
+ Rock[ipnt++] = CL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char*)Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1<<4);
+ };
+
+#ifndef VMS
+ /* If transparent compression was requested, fill in the correct
+ field for this file */
+ if(transparent_compression &&
+ S_ISREG(lstatbuf->st_mode) &&
+ strlen(name) > 3 &&
+ strcmp(name + strlen(name) - 3,".gZ") == 0){
+ FILE * zipfile;
+ char * checkname;
+ unsigned int file_size;
+ unsigned char header[8];
+ int OK_flag;
+
+ /* First open file and verify that the correct algorithm was used */
+ file_size = 0;
+ OK_flag = 1;
+
+ zipfile = fopen(whole_name, "r");
+ fread(header, 1, sizeof(header), zipfile);
+
+ /* Check some magic numbers from gzip. */
+ if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
+ /* Make sure file was blocksized. */
+ if(((header[3] & 0x40) == 0)) OK_flag = 0;
+ /* OK, now go to the end of the file and get some more info */
+ if(OK_flag){
+ int status;
+ status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
+ if(status == -1) OK_flag = 0;
+ }
+ if(OK_flag){
+ if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
+ OK_flag = 0;
+ else {
+ int blocksize;
+ blocksize = (header[3] << 8) | header[2];
+ file_size = ((unsigned int)header[7] << 24) |
+ ((unsigned int)header[6] << 16) |
+ ((unsigned int)header[5] << 8) | header[4];
+#if 0
+ fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
+#endif
+ if(blocksize != SECTOR_SIZE) OK_flag = 0;
+ }
+ }
+ fclose(zipfile);
+
+ checkname = strdup(whole_name);
+ checkname[strlen(whole_name)-3] = 0;
+ zipfile = fopen(checkname, "r");
+ if(zipfile) {
+ OK_flag = 0;
+ fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n");
+ fclose(zipfile);
+ }
+
+ free(checkname);
+
+ if(OK_flag){
+ if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
+ Rock[ipnt++] ='Z';
+ Rock[ipnt++] ='Z';
+ Rock[ipnt++] = ZZ_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 'g'; /* Identify compression technique used */
+ Rock[ipnt++] = 'z';
+ Rock[ipnt++] = 3;
+ set_733((char*)Rock + ipnt, file_size); /* Real file size */
+ ipnt += 8;
+ };
+ }
+#endif
+ /*
+ * Add in the Rock Ridge CE field, if required. We use this for the
+ * extension record that is stored in the root directory.
+ */
+ if(deep_opt & NEED_CE) add_CE_entry();
+ /*
+ * Done filling in all of the fields. Now copy it back to a buffer for the
+ * file in question.
+ */
+
+ /* Now copy this back to the buffer for the file */
+ Rock[flagpos] = flagval;
+
+ /* If there was a CE, fill in the size field */
+ if(recstart)
+ set_733((char*)Rock + recstart - 8, ipnt - recstart);
+
+ s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
+ s_entry->total_rr_attr_size = ipnt;
+ s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
+ memcpy(s_entry->rr_attributes, Rock, ipnt);
+ return ipnt;
+}
+
+/* Guaranteed to return a single sector with the relevant info */
+
+char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor,
+ char *, source, int *, size){
+ int ipnt = 0;
+ char * pnt;
+ int len_id, len_des, len_src;
+
+ len_id = strlen(id);
+ len_des = strlen(descriptor);
+ len_src = strlen(source);
+ Rock[ipnt++] ='E';
+ Rock[ipnt++] ='R';
+ Rock[ipnt++] = ER_SIZE + len_id + len_des + len_src;
+ Rock[ipnt++] = 1;
+ Rock[ipnt++] = len_id;
+ Rock[ipnt++] = len_des;
+ Rock[ipnt++] = len_src;
+ Rock[ipnt++] = 1;
+
+ memcpy(Rock + ipnt, id, len_id);
+ ipnt += len_id;
+
+ memcpy(Rock + ipnt, descriptor, len_des);
+ ipnt += len_des;
+
+ memcpy(Rock + ipnt, source, len_src);
+ ipnt += len_src;
+
+ if(ipnt > SECTOR_SIZE) {
+ fprintf(stderr,"Extension record too long\n");
+ exit(1);
+ };
+ pnt = (char *) e_malloc(SECTOR_SIZE);
+ memset(pnt, 0, SECTOR_SIZE);
+ memcpy(pnt, Rock, ipnt);
+ *size = ipnt;
+ return pnt;
+}
--- /dev/null
+/*
+ * File tree.c - scan directory tree and build memory structures for iso9660
+ * filesystem
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: tree.c,v 1.9.1.2 1998/06/02 03:17:31 eric Exp $";
+
+/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "config.h"
+
+#ifndef VMS
+#if defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#endif
+#else
+#include <sys/file.h>
+#include <vms/fabdef.h>
+#include "vms.h"
+extern char * strdup(const char *);
+#endif
+
+/*
+ * Autoconf should be able to figure this one out for us and let us know
+ * whether the system has memmove or not.
+ */
+# ifndef HAVE_MEMMOVE
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+
+#include "mkisofs.h"
+#include "iso9660.h"
+
+#include <sys/stat.h>
+
+#include "exclude.h"
+
+#ifdef NON_UNIXFS
+#define S_ISLNK(m) (0)
+#define S_ISSOCK(m) (0)
+#define S_ISFIFO(m) (0)
+#else
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) (0)
+# endif
+#endif
+#endif
+
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+static unsigned char symlink_buff[256];
+
+extern int verbose;
+
+struct stat fstatbuf = {0,}; /* We use this for the artificial entries we create */
+
+struct stat root_statbuf = {0, }; /* Stat buffer for root directory */
+
+struct directory * reloc_dir = NULL;
+
+void
+FDECL1(stat_fix, struct stat *, st)
+{
+ /* Remove the uid and gid, they will only be useful on the author's
+ system. */
+ st->st_uid = 0;
+ st->st_gid = 0;
+
+ /*
+ * Make sure the file modes make sense. Turn on all read bits. Turn
+ * on all exec/search bits if any exec/search bit is set. Turn off
+ * all write bits, and all special mode bits (on a r/o fs lock bits
+ * are useless, and with uid+gid 0 don't want set-id bits, either).
+ */
+ st->st_mode |= 0444;
+ if (st->st_mode & 0111)
+ st->st_mode |= 0111;
+ st->st_mode &= ~07222;
+}
+
+int
+FDECL2(stat_filter, char *, path, struct stat *, st)
+{
+ int result = stat(path, st);
+ if (result >= 0 && rationalize)
+ stat_fix(st);
+ return result;
+}
+
+int
+FDECL2(lstat_filter, char *, path, struct stat *, st)
+{
+ int result = lstat(path, st);
+ if (result >= 0 && rationalize)
+ stat_fix(st);
+ return result;
+}
+
+void FDECL1(sort_n_finish, struct directory *, this_dir)
+{
+ struct directory_entry * s_entry;
+ struct directory_entry * s_entry1;
+ time_t current_time;
+ struct directory_entry * table;
+ int count;
+ int d1;
+ int d2;
+ int d3;
+ int new_reclen;
+ char * c;
+ int tablesize = 0;
+ char newname[34];
+ char rootname[34];
+
+ /* Here we can take the opportunity to toss duplicate entries from the
+ directory. */
+
+ table = NULL;
+
+ if(fstatbuf.st_ctime == 0)
+ {
+ time (¤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("<translation table>");
+ table->table = (char *) e_malloc(ROUND_UP(tablesize));
+ memset(table->table, 0, ROUND_UP(tablesize));
+ iso9660_file_length ("TRANS.TBL", table, 0);
+
+ if(use_RockRidge)
+ {
+ fstatbuf.st_mode = 0444 | S_IFREG;
+ fstatbuf.st_nlink = 1;
+ generate_rock_ridge_attributes("",
+ "TRANS.TBL", table,
+ &fstatbuf, &fstatbuf, 0);
+ }
+ }
+
+ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next)
+ {
+ new_reclen = strlen(s_entry->isorec.name);
+
+ if(s_entry->isorec.flags[0] == 2)
+ {
+ if (strcmp(s_entry->name,".") && strcmp(s_entry->name,".."))
+ {
+ path_table_size += new_reclen + sizeof(struct iso_path_table) - 1;
+ if (new_reclen & 1) path_table_size++;
+ }
+ else
+ {
+ new_reclen = 1;
+ if (this_dir == root && strlen(s_entry->name) == 1)
+ path_table_size += sizeof(struct iso_path_table);
+ }
+ }
+ if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */
+ s_entry->isorec.name_len[0] = new_reclen;
+
+ new_reclen +=
+ sizeof(struct iso_directory_record) -
+ sizeof(s_entry->isorec.name);
+
+ if (new_reclen & 1)
+ new_reclen++;
+
+ new_reclen += s_entry->rr_attr_size;
+
+ if (new_reclen & 1) new_reclen++;
+
+ if(new_reclen > 0xff)
+ {
+ fprintf(stderr,"Fatal error - RR overflow for file %s\n",
+ s_entry->name);
+ exit(1);
+ }
+ s_entry->isorec.length[0] = new_reclen;
+ }
+
+ sort_directory(&this_dir->contents);
+
+ if(table)
+ {
+ count = 0;
+ for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){
+ if(s_entry == table) continue;
+ if(!s_entry->table) continue;
+ if(strcmp(s_entry->name, ".") == 0 ||
+ strcmp(s_entry->name, "..") == 0) continue;
+
+ count += sprintf(table->table + count, "%c %-34s%s",
+ s_entry->table[0],
+ s_entry->isorec.name, s_entry->table+1);
+ free(s_entry->table);
+ s_entry->table = NULL;
+ }
+
+ if(count != tablesize)
+ {
+ fprintf(stderr,"Translation table size mismatch %d %d\n",
+ count, tablesize);
+ exit(1);
+ }
+ }
+
+ /*
+ * Now go through the directory and figure out how large this one will be.
+ * Do not split a directory entry across a sector boundary
+ */
+ s_entry = this_dir->contents;
+ this_dir->ce_bytes = 0;
+ while(s_entry)
+ {
+ new_reclen = s_entry->isorec.length[0];
+ if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE)
+ this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
+ ~(SECTOR_SIZE - 1);
+ this_dir->size += new_reclen;
+
+ /* See if continuation entries were used on disc */
+ if(use_RockRidge &&
+ s_entry->rr_attr_size != s_entry->total_rr_attr_size)
+ {
+ unsigned char * pnt;
+ int len;
+ int nbytes;
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+
+ /*
+ * We make sure that each continuation entry record is not
+ * split across sectors, but each file could in theory have more
+ * than one CE, so we scan through and figure out what we need.
+ */
+ while(len > 3)
+ {
+ if(pnt[0] == 'C' && pnt[1] == 'E')
+ {
+ nbytes = get_733((char *) pnt+20);
+
+ if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
+ SECTOR_SIZE) this_dir->ce_bytes =
+ ROUND_UP(this_dir->ce_bytes);
+ /* Now store the block in the ce buffer */
+ this_dir->ce_bytes += nbytes;
+ if(this_dir->ce_bytes & 1) this_dir->ce_bytes++;
+ }
+ len -= pnt[2];
+ pnt += pnt[2];
+ }
+ }
+ s_entry = s_entry->next;
+ }
+}
+
+static void generate_reloc_directory()
+{
+ int new_reclen;
+ time_t current_time;
+ struct directory_entry *s_entry;
+
+ /* Create an entry for our internal tree */
+ time (¤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");
+}
+
--- /dev/null
+/*
+ * Program write.c - dump memory structures to file for iso9660 filesystem.
+
+ Written by Eric Youngdale (1993).
+
+ Copyright 1993 Yggdrasil Computing, Incorporated
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+static char rcsid[] ="$Id: write.c,v 1.6.1.3 1997/11/13 05:07:13 eric Exp $";
+
+#include <string.h>
+#include <stdlib.h>
+#include "mkisofs.h"
+#include "iso9660.h"
+#include <time.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __svr4__
+extern char * strdup(const char *);
+#endif
+
+#ifdef VMS
+extern char * strdup(const char *);
+#endif
+
+
+/* Max number of sectors we will write at one time */
+#define NSECT 16
+
+/* Counters for statistics */
+
+static int table_size = 0;
+static int total_dir_size = 0;
+static int rockridge_size = 0;
+static struct directory ** pathlist;
+static next_path_index = 1;
+
+/* Used to fill in some of the information in the volume descriptor. */
+static struct tm local;
+static struct tm gmt;
+
+/* Routines to actually write the disc. We write sequentially so that
+ we could write a tape, or write the disc directly */
+
+
+#define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof(vol_desc.X))
+
+void FDECL2(set_721, char *, pnt, unsigned int, i)
+{
+ pnt[0] = i & 0xff;
+ pnt[1] = (i >> 8) & 0xff;
+}
+
+void FDECL2(set_722, char *, pnt, unsigned int, i)
+{
+ pnt[0] = (i >> 8) & 0xff;
+ pnt[1] = i & 0xff;
+}
+
+void FDECL2(set_723, char *, pnt, unsigned int, i)
+{
+ pnt[3] = pnt[0] = i & 0xff;
+ pnt[2] = pnt[1] = (i >> 8) & 0xff;
+}
+
+void FDECL2(set_731, char *, pnt, unsigned int, i)
+{
+ pnt[0] = i & 0xff;
+ pnt[1] = (i >> 8) & 0xff;
+ pnt[2] = (i >> 16) & 0xff;
+ pnt[3] = (i >> 24) & 0xff;
+}
+
+void FDECL2(set_732, char *, pnt, unsigned int, i)
+{
+ pnt[3] = i & 0xff;
+ pnt[2] = (i >> 8) & 0xff;
+ pnt[1] = (i >> 16) & 0xff;
+ pnt[0] = (i >> 24) & 0xff;
+}
+
+int FDECL1(get_733, char *, p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+void FDECL2(set_733, char *, pnt, unsigned int, i)
+{
+ pnt[7] = pnt[0] = i & 0xff;
+ pnt[6] = pnt[1] = (i >> 8) & 0xff;
+ pnt[5] = pnt[2] = (i >> 16) & 0xff;
+ pnt[4] = pnt[3] = (i >> 24) & 0xff;
+}
+
+void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
+{
+ while(count)
+ {
+ int got = fwrite(buffer,size,count,file);
+
+ if(got<=0)
+ {
+ fprintf(stderr,"cannot fwrite %d*%d\n",size,count);
+ exit(1);
+ }
+ count-=got,*(char**)&buffer+=size*got;
+ }
+}
+
+struct deferred_write
+{
+ struct deferred_write * next;
+ char * table;
+ unsigned int extent;
+ unsigned int size;
+ char * name;
+};
+
+static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
+
+static struct directory_entry * sort_dir;
+static struct eltorito_boot_descriptor boot_desc;
+
+unsigned int last_extent_written =0;
+static struct iso_primary_descriptor vol_desc;
+static path_table_index;
+static time_t begun;
+
+/* We recursively walk through all of the directories and assign extent
+ numbers to them. We have already assigned extent numbers to everything that
+ goes in front of them */
+
+void FDECL1(assign_directory_addresses, struct directory *, node)
+{
+ int dir_size;
+ struct directory * dpnt;
+
+ dpnt = node;
+
+ while (dpnt)
+ {
+ /*
+ * If we already have an extent for this (i.e. it came from
+ * a multisession disc), then don't reassign a new extent.
+ */
+ dpnt->path_index = next_path_index++;
+ if( dpnt->extent == 0 )
+ {
+ dpnt->extent = last_extent;
+ dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
+
+ last_extent += dir_size;
+
+ /*
+ * Leave room for the CE entries for this directory. Keep them
+ * close to the reference directory so that access will be
+ * quick.
+ */
+ if(dpnt->ce_bytes)
+ {
+ last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
+ }
+ }
+
+ if(dpnt->subdir)
+ {
+ assign_directory_addresses(dpnt->subdir);
+ }
+
+ dpnt = dpnt->next;
+ }
+}
+
+static void FDECL3(write_one_file, char *, filename,
+ unsigned int, size, FILE *, outfile)
+{
+ char buffer[SECTOR_SIZE * NSECT];
+ FILE * infile;
+ int remain;
+ int use;
+
+
+ if ((infile = fopen(filename, "rb")) == NULL)
+ {
+#if defined(sun) || defined(_AUX_SOURCE)
+ fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
+#else
+ fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
+#endif
+ exit(1);
+ }
+ remain = size;
+
+ while(remain > 0)
+ {
+ use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
+ use = ROUND_UP(use); /* Round up to nearest sector boundary */
+ memset(buffer, 0, use);
+ if (fread(buffer, 1, use, infile) == 0)
+ {
+ fprintf(stderr,"cannot read from %s\n",filename);
+ exit(1);
+ }
+ xfwrite(buffer, 1, use, outfile);
+ last_extent_written += use/SECTOR_SIZE;
+#if 0
+ if((last_extent_written % 1000) < use/SECTOR_SIZE)
+ {
+ fprintf(stderr,"%d..", last_extent_written);
+ }
+#else
+ if((last_extent_written % 5000) < use/SECTOR_SIZE)
+ {
+ time_t now;
+ time_t the_end;
+ double frac;
+
+ time(&now);
+ frac = last_extent_written / (double)last_extent;
+ the_end = begun + (now - begun) / frac;
+ fprintf(stderr, "%6.2f%% done, estimate finish %s",
+ frac * 100., ctime(&the_end));
+ }
+#endif
+ remain -= use;
+ }
+ fclose(infile);
+} /* write_one_file(... */
+
+static void FDECL1(write_files, FILE *, outfile)
+{
+ struct deferred_write * dwpnt, *dwnext;
+ dwpnt = dw_head;
+ while(dwpnt)
+ {
+ if(dwpnt->table)
+ {
+ xfwrite(dwpnt->table, 1, ROUND_UP(dwpnt->size), outfile);
+ last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
+ table_size += dwpnt->size;
+/* fprintf(stderr,"Size %d ", dwpnt->size); */
+ free(dwpnt->table);
+ }
+ else
+ {
+
+#ifdef VMS
+ vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
+#else
+ write_one_file(dwpnt->name, dwpnt->size, outfile);
+#endif
+ free(dwpnt->name);
+ }
+
+ dwnext = dwpnt;
+ dwpnt = dwpnt->next;
+ free(dwnext);
+ }
+} /* write_files(... */
+
+#if 0
+static void dump_filelist()
+{
+ struct deferred_write * dwpnt;
+ dwpnt = dw_head;
+ while(dwpnt)
+ {
+ fprintf(stderr, "File %s\n",dwpnt->name);
+ dwpnt = dwpnt->next;
+ }
+ fprintf(stderr,"\n");
+}
+#endif
+
+int FDECL2(compare_dirs, const void *, rr, const void *, ll)
+{
+ char * rpnt, *lpnt;
+ struct directory_entry ** r, **l;
+
+ r = (struct directory_entry **) rr;
+ l = (struct directory_entry **) ll;
+ rpnt = (*r)->isorec.name;
+ lpnt = (*l)->isorec.name;
+
+ /*
+ * Put the '.' and '..' entries on the head of the sorted list.
+ * For normal ASCII, this always happens to be the case, but out of
+ * band characters cause this not to be the case sometimes.
+ */
+ if( strcmp(rpnt, ".") == 0 ) return -1;
+ if( strcmp(lpnt, ".") == 0 ) return 1;
+
+ if( strcmp(rpnt, "..") == 0 ) return -1;
+ if( strcmp(lpnt, "..") == 0 ) return 1;
+
+ while(*rpnt && *lpnt)
+ {
+ if(*rpnt == ';' && *lpnt != ';') return -1;
+ if(*rpnt != ';' && *lpnt == ';') return 1;
+
+ if(*rpnt == ';' && *lpnt == ';') return 0;
+
+ if(*rpnt == '.' && *lpnt != '.') return -1;
+ if(*rpnt != '.' && *lpnt == '.') return 1;
+
+ if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1;
+ if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1;
+ rpnt++; lpnt++;
+ }
+ if(*rpnt) return 1;
+ if(*lpnt) return -1;
+ return 0;
+}
+
+void FDECL1(sort_directory, struct directory_entry **, sort_dir)
+{
+ int dcount = 0;
+ int i, len;
+ struct directory_entry * s_entry;
+ struct directory_entry ** sortlist;
+
+ s_entry = *sort_dir;
+ while(s_entry)
+ {
+ dcount++;
+ s_entry = s_entry->next;
+ }
+
+ /*
+ * OK, now we know how many there are. Build a vector for sorting.
+ */
+ sortlist = (struct directory_entry **)
+ e_malloc(sizeof(struct directory_entry *) * dcount);
+
+ dcount = 0;
+ s_entry = *sort_dir;
+ while(s_entry)
+ {
+ sortlist[dcount] = s_entry;
+ len = s_entry->isorec.name_len[0];
+ s_entry->isorec.name[len] = 0;
+ dcount++;
+ s_entry = s_entry->next;
+ }
+
+ qsort(sortlist, dcount, sizeof(struct directory_entry *),
+ (int (*)(const void *, const void *))compare_dirs);
+
+ /*
+ * Now reassemble the linked list in the proper sorted order
+ */
+ for(i=0; i<dcount-1; i++)
+ {
+ sortlist[i]->next = sortlist[i+1];
+ }
+
+ sortlist[dcount-1]->next = NULL;
+ *sort_dir = sortlist[0];
+
+ free(sortlist);
+
+}
+
+void generate_root_record()
+{
+ time_t ctime;
+
+ time (&ctime);
+
+ local = *localtime(&ctime);
+ gmt = *gmtime(&ctime);
+
+ root_record.length[0] = 1 + sizeof(struct iso_directory_record)
+ - sizeof(root_record.name);
+ root_record.ext_attr_length[0] = 0;
+ set_733((char *) root_record.extent, root->extent);
+ set_733((char *) root_record.size, ROUND_UP(root->size));
+ iso9660_date(root_record.date, ctime);
+ root_record.flags[0] = 2;
+ root_record.file_unit_size[0] = 0;
+ root_record.interleave[0] = 0;
+ set_723(root_record.volume_sequence_number, DEF_VSN);
+ root_record.name_len[0] = 1;
+}
+
+static void FDECL1(assign_file_addresses, struct directory *, dpnt)
+{
+ struct directory * finddir;
+ struct directory_entry * s_entry;
+ struct file_hash *s_hash;
+ struct deferred_write * dwpnt;
+ char whole_path[1024];
+
+ while (dpnt)
+ {
+ s_entry = dpnt->contents;
+ for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
+ {
+
+ /*
+ * If we already have an extent for this entry,
+ * then don't assign a new one. It must have come
+ * from a previous session on the disc. Note that
+ * we don't end up scheduling the thing for writing
+ * either.
+ */
+ if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 )
+ {
+ continue;
+ }
+
+ /*
+ * This saves some space if there are symlinks present
+ */
+ s_hash = find_hash(s_entry->dev, s_entry->inode);
+ if(s_hash)
+ {
+ if(verbose)
+ {
+ fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name,
+ SPATH_SEPARATOR, s_entry->name);
+ }
+ set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
+ set_733((char *) s_entry->isorec.size, s_hash->size);
+ continue;
+ }
+
+ /*
+ * If this is for a directory that is not a . or a .. entry,
+ * then look up the information for the entry. We have already
+ * assigned extents for directories, so we just need to
+ * fill in the blanks here.
+ */
+ if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") &&
+ s_entry->isorec.flags[0] == 2)
+ {
+ finddir = dpnt->subdir;
+ while(1==1)
+ {
+ if(finddir->self == s_entry) break;
+ finddir = finddir->next;
+ if(!finddir)
+ {
+ fprintf(stderr,"Fatal goof\n"); exit(1);
+ }
+ }
+ set_733((char *) s_entry->isorec.extent, finddir->extent);
+ s_entry->starting_block = finddir->extent;
+ s_entry->size = ROUND_UP(finddir->size);
+ total_dir_size += s_entry->size;
+ add_hash(s_entry);
+ set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size));
+ continue;
+ }
+
+
+ /*
+ * If this is . or .., then look up the relevant info from the
+ * tables.
+ */
+ if(strcmp(s_entry->name,".") == 0)
+ {
+ set_733((char *) s_entry->isorec.extent, dpnt->extent);
+
+ /*
+ * Set these so that the hash table has the
+ * correct information
+ */
+ s_entry->starting_block = dpnt->extent;
+ s_entry->size = ROUND_UP(dpnt->size);
+
+ add_hash(s_entry);
+ s_entry->starting_block = dpnt->extent;
+ set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size));
+ continue;
+ }
+
+ if(strcmp(s_entry->name,"..") == 0)
+ {
+ if(dpnt == root)
+ {
+ total_dir_size += root->size;
+ }
+ set_733((char *) s_entry->isorec.extent, dpnt->parent->extent);
+
+ /*
+ * Set these so that the hash table has the
+ * correct information
+ */
+ s_entry->starting_block = dpnt->parent->extent;
+ s_entry->size = ROUND_UP(dpnt->parent->size);
+
+ add_hash(s_entry);
+ s_entry->starting_block = dpnt->parent->extent;
+ set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
+ continue;
+ }
+
+ /*
+ * Some ordinary non-directory file. Just schedule the
+ * file to be written. This is all quite
+ * straightforward, just make a list and assign extents
+ * as we go. Once we get through writing all of the
+ * directories, we should be ready write out these
+ * files
+ */
+ if(s_entry->size)
+ {
+ dwpnt = (struct deferred_write *)
+ e_malloc(sizeof(struct deferred_write));
+ if(dw_tail)
+ {
+ dw_tail->next = dwpnt;
+ dw_tail = dwpnt;
+ }
+ else
+ {
+ dw_head = dwpnt;
+ dw_tail = dwpnt;
+ }
+ if(s_entry->inode == TABLE_INODE)
+ {
+ dwpnt->table = s_entry->table;
+ dwpnt->name = NULL;
+ sprintf(whole_path,"%s%sTRANS.TBL",
+ s_entry->filedir->whole_name, SPATH_SEPARATOR);
+ }
+ else
+ {
+ dwpnt->table = NULL;
+ strcpy(whole_path, s_entry->whole_name);
+ dwpnt->name = strdup(whole_path);
+ }
+ dwpnt->next = NULL;
+ dwpnt->size = s_entry->size;
+ dwpnt->extent = last_extent;
+ set_733((char *) s_entry->isorec.extent, last_extent);
+ s_entry->starting_block = last_extent;
+ add_hash(s_entry);
+ last_extent += ROUND_UP(s_entry->size) >> 11;
+ if(verbose)
+ {
+ fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
+ last_extent-1, whole_path);
+ }
+#ifdef DBG_ISO
+ if((ROUND_UP(s_entry->size) >> 11) > 500)
+ {
+ fprintf(stderr,"Warning: large file %s\n", whole_path);
+ fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+ fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+
+ }
+#endif
+ if(last_extent > (800000000 >> 11))
+ {
+ /*
+ * More than 800Mb? Punt
+ */
+ fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
+ fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
+ fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
+ exit(1);
+ }
+ continue;
+ }
+
+ /*
+ * This is for zero-length files. If we leave the extent 0,
+ * then we get screwed, because many readers simply drop files
+ * that have an extent of zero. Thus we leave the size 0,
+ * and just assign the extent number.
+ */
+ set_733((char *) s_entry->isorec.extent, last_extent);
+ }
+ if(dpnt->subdir)
+ {
+ assign_file_addresses(dpnt->subdir);
+ }
+ dpnt = dpnt->next;
+ }
+} /* assign_file_addresses(... */
+
+void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
+{
+ unsigned int ce_address = 0;
+ char * ce_buffer;
+ unsigned int ce_index = 0;
+ unsigned int ce_size;
+ unsigned int dir_index;
+ char * directory_buffer;
+ int new_reclen;
+ struct directory_entry * s_entry;
+ struct directory_entry * s_entry_d;
+ unsigned int total_size;
+
+ total_size = (dpnt->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
+ directory_buffer = (char *) e_malloc(total_size);
+ memset(directory_buffer, 0, total_size);
+ dir_index = 0;
+
+ ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1);
+ ce_buffer = NULL;
+
+ if(ce_size)
+ {
+ ce_buffer = (char *) e_malloc(ce_size);
+ memset(ce_buffer, 0, ce_size);
+
+ ce_index = 0;
+
+ /*
+ * Absolute byte address of CE entries for this directory
+ */
+ ce_address = last_extent_written + (total_size >> 11);
+ ce_address = ce_address << 11;
+ }
+
+ s_entry = dpnt->contents;
+ while(s_entry)
+ {
+
+ /*
+ * We do not allow directory entries to cross sector boundaries.
+ * Simply pad, and then start the next entry at the next sector
+ */
+ new_reclen = s_entry->isorec.length[0];
+ if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
+ {
+ dir_index = (dir_index + (SECTOR_SIZE - 1)) &
+ ~(SECTOR_SIZE - 1);
+ }
+
+ memcpy(directory_buffer + dir_index, &s_entry->isorec,
+ sizeof(struct iso_directory_record) -
+ sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
+ dir_index += sizeof(struct iso_directory_record) -
+ sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
+
+ /*
+ * Add the Rock Ridge attributes, if present
+ */
+ if(s_entry->rr_attr_size)
+ {
+ if(dir_index & 1)
+ {
+ directory_buffer[dir_index++] = 0;
+ }
+
+ /*
+ * If the RR attributes were too long, then write the
+ * CE records, as required.
+ */
+ if(s_entry->rr_attr_size != s_entry->total_rr_attr_size)
+ {
+ unsigned char * pnt;
+ int len, nbytes;
+
+ /*
+ * Go through the entire record and fix up the CE entries
+ * so that the extent and offset are correct
+ */
+
+ pnt = s_entry->rr_attributes;
+ len = s_entry->total_rr_attr_size;
+ while(len > 3)
+ {
+#ifdef DEBUG
+ if (!ce_size)
+ {
+ fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n",
+ ce_index, ce_address);
+ }
+#endif
+
+ if(pnt[0] == 'C' && pnt[1] == 'E')
+ {
+ nbytes = get_733( (char *) pnt+20);
+
+ if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
+ SECTOR_SIZE)
+ {
+ ce_index = ROUND_UP(ce_index);
+ }
+
+ set_733( (char *) pnt+4,
+ (ce_address + ce_index) >> 11);
+ set_733( (char *) pnt+12,
+ (ce_address + ce_index) & (SECTOR_SIZE - 1));
+
+
+ /*
+ * Now store the block in the ce buffer
+ */
+ memcpy(ce_buffer + ce_index,
+ pnt + pnt[2], nbytes);
+ ce_index += nbytes;
+ if(ce_index & 1)
+ {
+ ce_index++;
+ }
+ }
+ len -= pnt[2];
+ pnt += pnt[2];
+ }
+
+ }
+
+ rockridge_size += s_entry->total_rr_attr_size;
+ memcpy(directory_buffer + dir_index, s_entry->rr_attributes,
+ s_entry->rr_attr_size);
+ dir_index += s_entry->rr_attr_size;
+ }
+ if(dir_index & 1)
+ {
+ directory_buffer[dir_index++] = 0;
+ }
+
+ s_entry_d = s_entry;
+ s_entry = s_entry->next;
+
+ if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes);
+ if( s_entry_d->name != NULL )
+ {
+ free (s_entry_d->name);
+ }
+ if( s_entry_d->whole_name != NULL )
+ {
+ free (s_entry_d->whole_name);
+ }
+ free (s_entry_d);
+ }
+ sort_dir = NULL;
+
+ if(dpnt->size != dir_index)
+ {
+ fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size,
+ dir_index, dpnt->de_name);
+ }
+
+ xfwrite(directory_buffer, 1, total_size, outfile);
+ last_extent_written += total_size >> 11;
+ free(directory_buffer);
+
+ if(ce_size)
+ {
+ if(ce_index != dpnt->ce_bytes)
+ {
+ fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
+ ce_index, dpnt->ce_bytes);
+ }
+ xfwrite(ce_buffer, 1, ce_size, outfile);
+ last_extent_written += ce_size >> 11;
+ free(ce_buffer);
+ }
+
+} /* generate_one_directory(... */
+
+static
+void FDECL1(build_pathlist, struct directory *, node)
+{
+ struct directory * dpnt;
+
+ dpnt = node;
+
+ while (dpnt)
+ {
+ pathlist[dpnt->path_index] = dpnt;
+ if(dpnt->subdir) build_pathlist(dpnt->subdir);
+ dpnt = dpnt->next;
+ }
+} /* build_pathlist(... */
+
+int FDECL2(compare_paths, void const *, r, void const *, l)
+{
+ struct directory const *ll = *(struct directory * const *)l;
+ struct directory const *rr = *(struct directory * const *)r;
+
+ if (rr->parent->path_index < ll->parent->path_index)
+ {
+ return -1;
+ }
+
+ if (rr->parent->path_index > ll->parent->path_index)
+ {
+ return 1;
+ }
+
+ return strcmp(rr->self->isorec.name, ll->self->isorec.name);
+
+} /* compare_paths(... */
+
+void generate_path_tables()
+{
+ struct directory_entry * de;
+ struct directory * dpnt;
+ int fix;
+ int i;
+ int j;
+ int namelen;
+ char * npnt;
+ char * npnt1;
+ int tablesize;
+
+ /*
+ * First allocate memory for the tables and initialize the memory
+ */
+ tablesize = path_blocks << 11;
+ path_table_m = (char *) e_malloc(tablesize);
+ path_table_l = (char *) e_malloc(tablesize);
+ memset(path_table_l, 0, tablesize);
+ memset(path_table_m, 0, tablesize);
+
+ /*
+ * Now start filling in the path tables. Start with root directory
+ */
+ path_table_index = 0;
+ pathlist = (struct directory **) e_malloc(sizeof(struct directory *)
+ * next_path_index);
+ memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
+ build_pathlist(root);
+
+ do
+ {
+ fix = 0;
+ qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
+ (int (*)(const void *, const void *))compare_paths);
+
+ for(j=1; j<next_path_index; j++)
+ {
+ if(pathlist[j]->path_index != j)
+ {
+ pathlist[j]->path_index = j;
+ fix++;
+ }
+ }
+ } while(fix);
+
+ for(j=1; j<next_path_index; j++)
+ {
+ dpnt = pathlist[j];
+ if(!dpnt)
+ {
+ fprintf(stderr,"Entry %d not in path tables\n", j);
+ exit(1);
+ }
+ npnt = dpnt->de_name;
+
+ /*
+ * So the root comes out OK
+ */
+ if( (*npnt == 0) || (dpnt == root) )
+ {
+ npnt = ".";
+ }
+ npnt1 = strrchr(npnt, PATH_SEPARATOR);
+ if(npnt1)
+ {
+ npnt = npnt1 + 1;
+ }
+
+ de = dpnt->self;
+ if(!de)
+ {
+ fprintf(stderr,"Fatal goof\n");
+ exit(1);
+ }
+
+
+ namelen = de->isorec.name_len[0];
+
+ path_table_l[path_table_index] = namelen;
+ path_table_m[path_table_index] = namelen;
+ path_table_index += 2;
+
+ set_731(path_table_l + path_table_index, dpnt->extent);
+ set_732(path_table_m + path_table_index, dpnt->extent);
+ path_table_index += 4;
+
+ set_721(path_table_l + path_table_index,
+ dpnt->parent->path_index);
+ set_722(path_table_m + path_table_index,
+ dpnt->parent->path_index);
+ path_table_index += 2;
+
+ for(i =0; i<namelen; i++)
+ {
+ path_table_l[path_table_index] = de->isorec.name[i];
+ path_table_m[path_table_index] = de->isorec.name[i];
+ path_table_index++;
+ }
+ if(path_table_index & 1)
+ {
+ path_table_index++; /* For odd lengths we pad */
+ }
+ }
+
+ free(pathlist);
+ if(path_table_index != path_table_size)
+ {
+ fprintf(stderr,"Path table lengths do not match %d %d\n",
+ path_table_index,
+ path_table_size);
+ }
+} /* generate_path_tables(... */
+
+void
+FDECL3(memcpy_max, char *, to, char *, from, int, max)
+{
+ int n = strlen(from);
+ if (n > max)
+ {
+ n = max;
+ }
+ memcpy(to, from, n);
+
+} /* memcpy_max(... */
+
+int FDECL1(iso_write, FILE *, outfile)
+{
+ char buffer[2048];
+ int i;
+ char iso_time[17];
+ int should_write;
+
+ time(&begun);
+ assign_file_addresses(root);
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /*
+ * This will break in the year 2000, I supose, but there is no good way
+ * to get the top two digits of the year.
+ */
+ sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local.tm_year,
+ local.tm_mon+1, local.tm_mday,
+ local.tm_hour, local.tm_min, local.tm_sec);
+
+ local.tm_min -= gmt.tm_min;
+ local.tm_hour -= gmt.tm_hour;
+ local.tm_yday -= gmt.tm_yday;
+ iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15;
+
+ /*
+ * First, we output 16 sectors of all zero
+ */
+
+ for(i=0; i<16; i++)
+ {
+ xfwrite(buffer, 1, sizeof(buffer), outfile);
+ }
+
+ last_extent_written += 16;
+
+ /*
+ * Next we write out the primary descriptor for the disc
+ */
+ memset(&vol_desc, 0, sizeof(vol_desc));
+ vol_desc.type[0] = ISO_VD_PRIMARY;
+ memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+ vol_desc.version[0] = 1;
+
+ memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
+ memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
+
+ memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
+ memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
+
+ should_write = last_extent - session_start;
+ set_733((char *) vol_desc.volume_space_size, should_write);
+ set_723(vol_desc.volume_set_size, 1);
+ set_723(vol_desc.volume_sequence_number, DEF_VSN);
+ set_723(vol_desc.logical_block_size, 2048);
+
+ /*
+ * The path tables are used by DOS based machines to cache directory
+ * locations
+ */
+
+ set_733((char *) vol_desc.path_table_size, path_table_size);
+ set_731(vol_desc.type_l_path_table, path_table[0]);
+ set_731(vol_desc.opt_type_l_path_table, path_table[1]);
+ set_732(vol_desc.type_m_path_table, path_table[2]);
+ set_732(vol_desc.opt_type_m_path_table, path_table[3]);
+
+ /*
+ * Now we copy the actual root directory record
+ */
+ memcpy(vol_desc.root_directory_record, &root_record,
+ sizeof(struct iso_directory_record) + 1);
+
+ /*
+ * The rest is just fluff. It looks nice to fill in many of these fields,
+ * though.
+ */
+ FILL_SPACE(volume_set_id);
+ if(volset_id) memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
+
+ FILL_SPACE(publisher_id);
+ if(publisher) memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
+
+ FILL_SPACE(preparer_id);
+ if(preparer) memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
+
+ FILL_SPACE(application_id);
+ if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
+
+ FILL_SPACE(copyright_file_id);
+ if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright,
+ strlen(copyright));
+
+ FILL_SPACE(abstract_file_id);
+ if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract,
+ strlen(abstract));
+
+ FILL_SPACE(bibliographic_file_id);
+ if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio,
+ strlen(biblio));
+
+ FILL_SPACE(creation_date);
+ FILL_SPACE(modification_date);
+ FILL_SPACE(expiration_date);
+ FILL_SPACE(effective_date);
+ vol_desc.file_structure_version[0] = 1;
+ FILL_SPACE(application_data);
+
+ memcpy(vol_desc.creation_date, iso_time, 17);
+ memcpy(vol_desc.modification_date, iso_time, 17);
+ memcpy(vol_desc.expiration_date, "0000000000000000", 17);
+ memcpy(vol_desc.effective_date, iso_time, 17);
+
+ /*
+ * if not a bootable cd do it the old way
+ */
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ last_extent_written++;
+ if (use_eltorito)
+ {
+ /*
+ * Next we write out the boot volume descriptor for the disc
+ */
+ get_torito_desc(&boot_desc);
+ xfwrite(&boot_desc, 1, 2048, outfile);
+ last_extent_written ++;
+ }
+
+ /*
+ * Now write the end volume descriptor. Much simpler than the other one
+ */
+ memset(&vol_desc, 0, sizeof(vol_desc));
+ vol_desc.type[0] = ISO_VD_END;
+ memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
+ vol_desc.version[0] = 1;
+ xfwrite(&vol_desc, 1, 2048, outfile);
+ last_extent_written += 1;
+
+ /*
+ * Next we write the path tables
+ */
+ xfwrite(path_table_l, 1, path_blocks << 11, outfile);
+ xfwrite(path_table_m, 1, path_blocks << 11, outfile);
+ last_extent_written += 2*path_blocks;
+ free(path_table_l);
+ free(path_table_m);
+ path_table_l = NULL;
+ path_table_m = NULL;
+
+ /*
+ * OK, all done with that crap. Now write out the directories.
+ * This is where the fur starts to fly, because we need to keep track of
+ * each file as we find it and keep track of where we put it.
+ */
+
+#ifdef DBG_ISO
+ fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
+#endif
+#if 0
+ generate_one_directory(root, outfile);
+#endif
+ generate_iso9660_directories(root, outfile);
+
+ if(extension_record)
+ {
+ xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
+ last_extent_written++;
+ }
+
+ /*
+ * Now write all of the files that we need.
+ */
+ fprintf(stderr,"Total extents scheduled to be written = %d\n",
+ last_extent - session_start);
+ write_files(outfile);
+
+ fprintf(stderr,"Total extents actually written = %d\n",
+ last_extent_written - session_start);
+ /*
+ * Hard links throw us off here
+ */
+ if(should_write != last_extent - session_start)
+ {
+ fprintf(stderr,"Number of extents written not what was predicted. Please fix.\n");
+ fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
+ }
+
+ fprintf(stderr,"Total translation table size: %d\n", table_size);
+ fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
+ fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
+ fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
+
+#ifdef DEBUG
+ fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
+ next_extent, last_extent, last_extent_written);
+#endif
+
+ return 0;
+
+} /* iso_write(... */