diff -uNr cdrtools-2.0+a27/mkisofs/Makefile cdrtools-2.0+a27.steve/mkisofs/Makefile
--- cdrtools-2.0+a27/mkisofs/Makefile	2004-02-22 15:13:43.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/Makefile	2004-06-04 05:00:43.000000000 +0100
@@ -33,9 +33,10 @@
 CPPOPTS +=	-DDVD_VIDEO
 CPPOPTS +=	-DSORTING
 CPPOPTS +=	-I../libhfs_iso/
-CPPOPTS	+=	-DHAVE_CONFIG_H -DUSE_LIBSCHILY -DUSE_SCG \
+CPPOPTS	+=	-DHAVE_CONFIG_H -DUSE_LIBSCHILY -DUSE_SCG -DJIGDO_TEMPLATE \
 		'-DAPPID_DEFAULT="MKISOFS ISO 9660/HFS FILESYSTEM BUILDER & CDRECORD CD-R/DVD CREATOR (C) 1993 E.YOUNGDALE (C) 1997 J.PEARSON/J.SCHILLING"' \
 		-I../cdrecord
+CFLAGS  +=  -Wall -Wno-unused -g -O2
 CFILES=		mkisofs.c tree.c write.c hash.c rock.c udf.c multi.c \
 		joliet.c match.c name.c fnmatch.c eltorito.c boot.c \
 		getopt.c getopt1.c \
@@ -44,14 +45,14 @@
 		modes.c \
 		apple.c volume.c desktop.c mac_label.c stream.c \
 		ifo_read.c dvd_file.c dvd_reader.c \
-		defaults.c getnum.c
+		defaults.c getnum.c md5.c jte.c
 HFILES=		apple.h bootinfo.h config.h defaults.h diskmbr.h exclude.h \
 		fnmatch.h getopt.h iso9660.h mac_label.h mactypes.h match.h \
 		mkisofs.h sunlabel.h udf.h udf_fs.h vms.h \
 		ifo_read.h dvd_file.h dvd_reader.h bswap.h ifo_types.h \
-		../cdrecord/defaults.h
+		../cdrecord/defaults.h md5.h jte.h
 
-LIBS=		-lhfs -lfile -lunls -lrscg -lscg $(LIB_VOLMGT) -ldeflt -lschily $(SCSILIB) $(LIB_SOCKET)
+LIBS=		-lz -lhfs -lfile -lunls -lrscg -lscg $(LIB_VOLMGT) -ldeflt -lschily $(SCSILIB) $(LIB_SOCKET)
 XMK_FILE=	Makefile.man hybridman.mk
 
 ###########################################################################
@@ -59,3 +60,5 @@
 ###########################################################################
 count:	$(CFILES) $(HFILES)
 	count $r1
+
+
Binary files cdrtools-2.0+a27/mkisofs/OBJ/i686-linux-cc/mkisofs and cdrtools-2.0+a27.steve/mkisofs/OBJ/i686-linux-cc/mkisofs differ
diff -uNr cdrtools-2.0+a27/mkisofs/boot.c cdrtools-2.0+a27.steve/mkisofs/boot.c
--- cdrtools-2.0+a27/mkisofs/boot.c	2004-02-22 15:25:09.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/boot.c	2004-05-28 16:35:00.000000000 +0100
@@ -49,11 +49,11 @@
 EXPORT	int	make_sun_label		__PR((void));
 EXPORT	int	make_sunx86_label	__PR((void));
 LOCAL	void	dup_sun_label		__PR((int part));
-LOCAL	int	sunboot_write		__PR((FILE *outfile));
+LOCAL	int	sunboot_write		__PR((FILE *outfile, FILE *jtfile));
 LOCAL	int	sunlabel_size		__PR((int starting_extent));
-LOCAL	int	sunlabel_write		__PR((FILE * outfile));
+LOCAL	int	sunlabel_write		__PR((FILE * outfile, FILE *jtfile));
 LOCAL	int	genboot_size		__PR((int starting_extent));
-LOCAL	int	genboot_write		__PR((FILE * outfile));
+LOCAL	int	genboot_write		__PR((FILE * outfile, FILE *jtfile));
 
 /*
  * Set the virtual geometry in the disk label.
@@ -354,8 +354,8 @@
  * Write out Sun boot partitions.
  */
 LOCAL int
-sunboot_write(outfile)
-	FILE	*outfile;
+sunboot_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	i;
@@ -373,6 +373,7 @@
 	 */
 	amt = roundup(last_extent_written, (CD_CYLSIZE/SECTOR_SIZE)) - last_extent_written;
 	for (n = 0; n < amt; n++) {
+        jtwrite(buffer, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
 		last_extent_written++;
 	}
@@ -403,6 +404,7 @@
 			memset(buffer, 0, sizeof (buffer));
 			if (read(f, buffer, SECTOR_SIZE) < 0)
 				comerr("Read error on '%s'.\n", boot_files[i]);
+            jtwrite(buffer, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 			xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
 			last_extent_written++;
 		}
@@ -435,8 +437,8 @@
  * Sun disk label on the firs 512 bytes of the generic boot code.
  */
 LOCAL int
-sunlabel_write(outfile)
-	FILE	*outfile;
+sunlabel_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 		char	buffer[SECTOR_SIZE];
 	register char	*p;
@@ -484,6 +486,7 @@
 		memcpy(buffer, &cd_label, 512);
 	}
 
+    jtwrite(buffer, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
@@ -507,8 +510,8 @@
  * If there is a Sun disk label, start writing at sector 1.
  */
 LOCAL int
-genboot_write(outfile)
-	FILE	*outfile;
+genboot_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	i;
@@ -523,7 +526,8 @@
 			comerr("Read error on '%s'.\n", genboot_image);
 
 		if (i != 0 || last_extent_written == session_start) {
-			xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
+			jtwrite(buffer, SECTOR_SIZE, 1, jtfile, 0, FALSE);
+            xfwrite(buffer, SECTOR_SIZE, 1, outfile, 0, FALSE);
 			last_extent_written++;
 		}
 	}
diff -uNr cdrtools-2.0+a27/mkisofs/defaults.h cdrtools-2.0+a27.steve/mkisofs/defaults.h
--- cdrtools-2.0+a27/mkisofs/defaults.h	2004-03-01 23:47:25.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/defaults.h	2004-05-28 16:35:57.000000000 +0100
@@ -108,3 +108,7 @@
 #ifndef SYSTEM_ID_DEFAULT
 #define	SYSTEM_ID_DEFAULT	"LINUX"
 #endif
+
+#define  SILO_BOOT_IMAGE_DEFAULT "boot/second.b"
+#define  SILO_BOOTBLOCK_DEFAULT        "boot/cd.b"
+#define  SILO_CONF_FILE_DEFAULT        "/etc/silo.conf"
Binary files cdrtools-2.0+a27/mkisofs/diag/OBJ/i686-linux-cc/devdump and cdrtools-2.0+a27.steve/mkisofs/diag/OBJ/i686-linux-cc/devdump differ
Binary files cdrtools-2.0+a27/mkisofs/diag/OBJ/i686-linux-cc/isodebug and cdrtools-2.0+a27.steve/mkisofs/diag/OBJ/i686-linux-cc/isodebug differ
Binary files cdrtools-2.0+a27/mkisofs/diag/OBJ/i686-linux-cc/isodump and cdrtools-2.0+a27.steve/mkisofs/diag/OBJ/i686-linux-cc/isodump differ
Binary files cdrtools-2.0+a27/mkisofs/diag/OBJ/i686-linux-cc/isoinfo and cdrtools-2.0+a27.steve/mkisofs/diag/OBJ/i686-linux-cc/isoinfo differ
Binary files cdrtools-2.0+a27/mkisofs/diag/OBJ/i686-linux-cc/isovfy and cdrtools-2.0+a27.steve/mkisofs/diag/OBJ/i686-linux-cc/isovfy differ
diff -uNr cdrtools-2.0+a27/mkisofs/eltorito.c cdrtools-2.0+a27.steve/mkisofs/eltorito.c
--- cdrtools-2.0+a27/mkisofs/eltorito.c	2004-03-04 22:39:29.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/eltorito.c	2004-05-28 16:30:21.000000000 +0100
@@ -52,7 +52,7 @@
 						struct eltorito_boot_entry_info *boot_entry));
 	void	get_boot_entry		__PR((void));
 	void	new_boot_entry		__PR((void));
-static	int	tvd_write		__PR((FILE * outfile));
+static	int	tvd_write		__PR((FILE * outfile, FILE * jtfile));
 
 
 LOCAL	char	*bootcat_path;		/* filename of boot catalog */
@@ -652,8 +652,8 @@
  * Function to write the EVD for the disc.
  */
 static int
-tvd_write(outfile)
-	FILE	*outfile;
+tvd_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	/* check the boot image is not NULL */
 	if (!boot_image) {
@@ -666,6 +666,7 @@
 	}
 	/* Next we write out the boot volume descriptor for the disc */
 	get_torito_desc(&gboot_desc);
+	jtwrite(&gboot_desc, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(&gboot_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
diff -uNr cdrtools-2.0+a27/mkisofs/joliet.c cdrtools-2.0+a27.steve/mkisofs/joliet.c
--- cdrtools-2.0+a27/mkisofs/joliet.c	2003-04-27 23:36:08.000000000 +0100
+++ cdrtools-2.0+a27.steve/mkisofs/joliet.c	2004-05-28 22:41:32.000000000 +0100
@@ -117,7 +117,7 @@
 static int	joliet_compare_paths	__PR((void const *r, void const *l));
 static int	generate_joliet_path_tables __PR((void));
 static void	generate_one_joliet_directory __PR((struct directory *dpnt,
-						FILE *outfile));
+						FILE *outfile, FILE *jtfile));
 static int	joliet_sort_n_finish	__PR((struct directory *this_dir));
 
 static int	joliet_compare_dirs	__PR((const void *rr, const void *ll));
@@ -125,12 +125,12 @@
 static int	joliet_sort_directory	__PR((struct directory_entry **sort_dir));
 	int	joliet_sort_tree	__PR((struct directory *node));
 static void	generate_joliet_directories __PR((struct directory *node,
-						FILE *outfile));
-static int	jpathtab_write		__PR((FILE *outfile));
+						FILE *outfile, FILE *jtfile));
+static int	jpathtab_write		__PR((FILE *outfile, FILE *jtfile));
 static int	jdirtree_size		__PR((int starting_extent));
 static int	jroot_gen		__PR((void));
-static int	jdirtree_write		__PR((FILE *outfile));
-static int	jvd_write		__PR((FILE *outfile));
+static int	jdirtree_write		__PR((FILE *outfile, FILE *jtfile));
+static int	jvd_write		__PR((FILE *outfile, FILE *jtfile));
 static int	jpathtab_size		__PR((int starting_extent));
 
 /*
@@ -674,9 +674,9 @@
 }/* generate_path_tables(... */
 
 static void
-generate_one_joliet_directory(dpnt, outfile)
+generate_one_joliet_directory(dpnt, outfile, jtfile)
 	struct directory	*dpnt;
-	FILE			*outfile;
+	FILE			*outfile, *jtfile;
 {
 	unsigned int		dir_index;
 	char			*directory_buffer;
@@ -849,6 +849,7 @@
 			dir_index, dpnt->de_name);
 #endif
 	}
+	jtwrite(directory_buffer, total_size, 1, jtfile, 0, FALSE);
 	xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
 	last_extent_written += total_size >> 11;
 	free(directory_buffer);
@@ -1197,9 +1198,9 @@
 }
 
 static void
-generate_joliet_directories(node, outfile)
+generate_joliet_directories(node, outfile, jtfile)
 	struct directory	*node;
-	FILE			*outfile;
+	FILE			*outfile, *jtfile;
 {
 	struct directory *dpnt;
 
@@ -1212,14 +1213,14 @@
 			 * doesn't make much sense.
 			 */
 			if (dpnt->jextent > session_start) {
-				generate_one_joliet_directory(dpnt, outfile);
+				generate_one_joliet_directory(dpnt, outfile, jtfile);
 			}
 		}
 		/* skip if hidden - but not for the rr_moved dir */
 		if (dpnt->subdir &&
 		    (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) ||
 		    dpnt == reloc_dir)) {
-			generate_joliet_directories(dpnt->subdir, outfile);
+			generate_joliet_directories(dpnt->subdir, outfile, jtfile);
 		}
 		dpnt = dpnt->next;
 	}
@@ -1230,13 +1231,16 @@
  * Function to write the EVD for the disc.
  */
 static int
-jpathtab_write(outfile)
-	FILE	*outfile;
+jpathtab_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	/* Next we write the path tables */
+	jtwrite(jpath_table_l, jpath_blocks << 11, 1, jtfile, 0, FALSE);
 	xfwrite(jpath_table_l, jpath_blocks << 11, 1, outfile, 0, FALSE);
+	last_extent_written += jpath_blocks;
+	jtwrite(jpath_table_m, jpath_blocks << 11, 1, jtfile, 0, FALSE);
 	xfwrite(jpath_table_m, jpath_blocks << 11, 1, outfile, 0, FALSE);
-	last_extent_written += 2 * jpath_blocks;
+	last_extent_written += jpath_blocks;
 	free(jpath_table_l);
 	free(jpath_table_m);
 	jpath_table_l = NULL;
@@ -1270,10 +1274,10 @@
 }
 
 static int
-jdirtree_write(outfile)
-	FILE	*outfile;
+jdirtree_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
-	generate_joliet_directories(root, outfile);
+	generate_joliet_directories(root, outfile, jtfile);
 	return (0);
 }
 
@@ -1281,14 +1285,15 @@
  * Function to write the EVD for the disc.
  */
 static int
-jvd_write(outfile)
-	FILE	*outfile;
+jvd_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	struct iso_primary_descriptor jvol_desc;
 
 	/* Next we write out the boot volume descriptor for the disc */
 	jvol_desc = vol_desc;
 	get_joliet_vol_desc(&jvol_desc);
+	jtwrite(&jvol_desc, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(&jvol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
diff -uNr cdrtools-2.0+a27/mkisofs/jte.c cdrtools-2.0+a27.steve/mkisofs/jte.c
--- cdrtools-2.0+a27/mkisofs/jte.c	1970-01-01 01:00:00.000000000 +0100
+++ cdrtools-2.0+a27.steve/mkisofs/jte.c	2004-06-04 05:18:31.000000000 +0100
@@ -0,0 +1,823 @@
+#include <mconfig.h>
+#include "mkisofs.h"
+#include <timedefs.h>
+#include <fctldefs.h>
+#include <zlib.h>
+#ifdef SORTING
+#include "match.h"
+#endif /* SORTING */
+#include <errno.h>
+#include <schily.h>
+#ifdef DVD_VIDEO
+#include "dvd_reader.h"
+#include "dvd_file.h"
+#include "ifo_read.h"
+#endif
+#ifdef APPLE_HYB
+#include <ctype.h>
+#endif
+
+#ifdef	VMS
+#include "vms.h"
+#endif
+
+/* Different types used in the extent_type below */
+#define JTET_HEADER     0
+#define JTET_FOOTER     1
+#define JTET_FILE_MATCH 2
+#define JTET_NOMATCH    3
+
+#define JTE_ID_STRING     "JTE"
+#define JTE_HEADER_STRING "MKJ IMAGE START"
+#define JTE_FOOTER_STRING "*MKJ IMAGE END*"
+#define JTE_VER_MAJOR     0x0001
+#define JTE_VER_MINOR     0x0000
+#define JTE_NAME          "JTE"
+#define JTE_COMMENT       "JTE at http://www.einval.com/~steve/software/CD/JTE/ ; jigdo at http://atterer.net/jigdo/"
+
+#define JIGDO_TEMPLATE_VERSION "1.1"
+
+struct jt_extent_data
+{
+    unsigned char id[4];                       /* "JTE" plus NULL terminator */
+    unsigned char extent_type;                 /* The type of this extent in the jigdo template file */
+    unsigned char extent_length[8];            /* The length in bytes of this extent, including all
+                                                  the metadata. 64-bit, big endian */
+    unsigned char start_sector[4];             /* The start sector of this extent within the output image;
+                                                  32-bit BE. Header and footer use 0xFFFFFFFF */
+    union
+    {
+        struct
+        {
+            unsigned char header_string[16];   /* Recognition string. Should contain "MKJ IMAGE START",
+                                                  including NULL terminator */
+            unsigned char version[4];          /* Version number, encoded MMmm */
+            unsigned char sector_size[4];      /* Sector size used in this image.
+                                                  _Always_ expected to be 2KB. Stored as 32-bit BE */
+            unsigned char pad[16];
+        } header;
+        struct
+        {
+            unsigned char footer_string[16];   /* Recognition string. Should contain "*MKJ IMAGE END*",
+                                                  including NULL terminator */
+            unsigned char image_size[8];       /* Size of image, in bytes. 64-bit BE. */
+            unsigned char md5[16];             /* MD5SUM of the entire image */
+        } footer;
+        struct
+        {
+            unsigned char file_length[8];      /* The actual length of the file stored in this extent.
+                                                  Will be <= extent_length; also 64-bit BE */
+            unsigned char filename_length[4];  /* The length of the following filename entry */
+            unsigned char md5[16];             /* MD5SUM of the _file_ data in this lump, without padding */
+            unsigned char pad[12];
+        } file_match;
+        struct
+        {
+            unsigned char unmatched_length[8]; /* The length of the data in this extent. Will be == 
+                                                  extent_length - sizeof(struct jt_extent_data) ; also 64-bit BE */
+            unsigned char md5[16];             /* MD5SUM of this lump of unmatched data */
+            unsigned char pad[16];
+        } nomatch;
+    } data;
+};
+
+FILE	*jthelper = NULL;
+FILE	*jtjigdo = NULL;
+FILE	*jttemplate = NULL;
+char    *jtemplate_out = NULL; /* Output name for jigdo template file; NULL means don't do it */
+char    *jjigdo_out = NULL; /* Output name for jigdo .jigdo file; NULL means don't do it */
+char    *jhelper_out = NULL; /* Output name for jigdo helper file; NULL means don't do it */
+int      jte_min_size = 8192; /* 8KB seems a reasonable minimum */
+
+static struct mk_MD5Context jtcontext;
+static struct mk_MD5Context template_context;
+
+typedef struct _file_entry
+{
+    unsigned char md5[16];
+    off_t file_length;
+    char *filename;
+} file_entry_t;
+
+typedef struct _unmatched_entry
+{
+    off_t uncompressed_length;
+} unmatched_entry_t;    
+
+typedef struct _entry
+{
+    int entry_type; /* JTET_TYPE as above */
+    struct _entry *next;
+    union
+    {
+        file_entry_t      file;
+        unmatched_entry_t chunk;
+    } data;
+} entry_t;
+
+typedef struct _jigdo_file_entry
+{
+    unsigned char type;
+    unsigned char fileLen[6];
+    unsigned char fileRsync[8];
+    unsigned char fileMD5[16];
+} jigdo_file_entry_t;
+
+typedef struct _jigdo_chunk_entry
+{
+    unsigned char type;
+    unsigned char skipLen[6];
+} jigdo_chunk_entry_t;
+
+typedef struct _jigdo_image_entry
+{
+    unsigned char type;
+    unsigned char imageLen[6];
+    unsigned char imageMD5[16];
+    unsigned char blockLen[4];
+} jigdo_image_entry_t;
+
+entry_t *entry_list = NULL;
+entry_t *last_entry = NULL;
+FILE    *t_file = NULL;
+FILE    *j_file = NULL;
+int      num_matches = 0;
+int      num_chunks = 0;
+
+static size_t template_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+    mk_MD5Update(&template_context, ptr, size * nmemb);
+    return fwrite(ptr, size, nmemb, stream);
+}
+
+static void write_template_header()
+{
+    char buf[2048];
+    int i = 0;
+    char *p = buf;
+
+    memset(buf, 0, sizeof(buf));
+
+    mk_MD5Init(&template_context);
+    i += sprintf(p, "JigsawDownload template %s %s/%d.%d \r\n",
+                 JIGDO_TEMPLATE_VERSION, JTE_NAME, JTE_VER_MAJOR, JTE_VER_MINOR);
+    p = &buf[i];
+
+    i += sprintf(p, "%s \r\n", JTE_COMMENT);
+    p = &buf[i];
+
+    i += sprintf(p, "\r\n");
+    template_fwrite(buf, i, 1, t_file);
+}
+
+/* Initialise state; for now:
+   
+   1. Start the JTE file
+   2. Start the jigdo template file, initialise state
+*/
+void write_jt_header(FILE *jtimage, FILE *template_file, FILE *jigdo_file)
+{
+    struct jt_extent_data extent;
+    unsigned long long tmp_size = 0;
+    
+    if (NULL == jtimage)
+        return;
+
+    t_file = template_file;
+    j_file = jigdo_file;
+
+    memset(&extent, 0, sizeof(extent));
+
+    sprintf(&extent.id[0], "%s", JTE_ID_STRING);
+    extent.extent_type = JTET_HEADER;
+
+    /* Fill in the length of this extent */
+    tmp_size = sizeof(extent);
+    extent.extent_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.extent_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.extent_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.extent_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.extent_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.extent_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.extent_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.extent_length[7] = tmp_size & 0xFF;
+
+    /* And now the offset from the start of the image */
+    extent.start_sector[0] = 0xFF;
+    extent.start_sector[1] = 0xFF;
+    extent.start_sector[2] = 0xFF;
+    extent.start_sector[3] = 0xFF;
+
+    sprintf(&extent.data.header.header_string[0], "%s", JTE_HEADER_STRING);
+    extent.data.header.version[0] = (JTE_VER_MAJOR >> 8) & 0xFF;
+    extent.data.header.version[1] = JTE_VER_MAJOR & 0xFF;
+    extent.data.header.version[2] = (JTE_VER_MINOR >> 8) & 0xFF;
+    extent.data.header.version[3] = JTE_VER_MINOR & 0xFF;
+    /* Write the sector size */
+    tmp_size = osecsize;
+    if (!osecsize)
+        tmp_size = 2048;
+    extent.data.header.sector_size[0] = (tmp_size >> 24) & 0xFF;
+    extent.data.header.sector_size[1] = (tmp_size >> 16) & 0xFF;
+    extent.data.header.sector_size[2] = (tmp_size >> 8) & 0xFF;
+    extent.data.header.sector_size[3] = tmp_size & 0xFF;
+
+    /* Write the extent header data */
+    fwrite(&extent, sizeof(extent), 1, jtimage);
+
+    /* Start MD5 work too */
+    mk_MD5Init(&jtcontext);
+
+    /* Start the template file */
+    write_template_header();
+}
+
+static void flush_compressed_chunk(void *buffer, off_t size)
+{
+    z_stream c_stream; /* compression stream */
+    unsigned char comp_size_out[6];
+    unsigned char uncomp_size_out[6];
+    off_t compressed_size_out = 0;
+    int err = 0;
+    unsigned char *comp_buf = NULL;
+
+    c_stream.zalloc = NULL;
+    c_stream.zfree = NULL;
+    c_stream.opaque = NULL;
+
+    err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+    comp_buf = malloc(2 * size); /* Worst case */
+    c_stream.next_out = comp_buf;
+    c_stream.avail_out = 2 * size;
+    c_stream.next_in = buffer;
+    c_stream.avail_in = size;
+    
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    err = deflate(&c_stream, Z_FINISH);
+    
+    compressed_size_out = c_stream.total_out + 16;
+    err = deflateEnd(&c_stream);
+
+    template_fwrite("DATA", 4, 1, t_file);
+
+    comp_size_out[0] = (unsigned char)(compressed_size_out & 0xFF);
+    comp_size_out[1] = (unsigned char)((compressed_size_out >> 8) & 0xFF);
+    comp_size_out[2] = (unsigned char)((compressed_size_out >> 16) & 0xFF);
+    comp_size_out[3] = (unsigned char)((compressed_size_out >> 24) & 0xFF);
+    comp_size_out[4] = (unsigned char)((compressed_size_out >> 32) & 0xFF);
+    comp_size_out[5] = (unsigned char)((compressed_size_out >> 40) & 0xFF);
+    template_fwrite(comp_size_out, sizeof(comp_size_out), 1, t_file);
+    
+    uncomp_size_out[0] = (unsigned char)(size & 0xFF);
+    uncomp_size_out[1] = (unsigned char)((size >> 8) & 0xFF);
+    uncomp_size_out[2] = (unsigned char)((size >> 16) & 0xFF);
+    uncomp_size_out[3] = (unsigned char)((size >> 24) & 0xFF);
+    uncomp_size_out[4] = (unsigned char)((size >> 32) & 0xFF);
+    uncomp_size_out[5] = (unsigned char)((size >> 40) & 0xFF);
+    template_fwrite(uncomp_size_out, sizeof(uncomp_size_out), 1, t_file);
+    
+    template_fwrite(comp_buf, c_stream.total_out, 1, t_file);
+    free(comp_buf);
+}
+
+static void write_compressed_chunk(unsigned char *buffer, size_t size)
+{
+    static unsigned char uncomp_buf[1024 * 1024];
+    static size_t uncomp_buf_used = 0;
+
+    if ((uncomp_buf_used + size) > sizeof(uncomp_buf))
+    {
+        flush_compressed_chunk(uncomp_buf, uncomp_buf_used);
+        uncomp_buf_used = 0;
+    }
+
+    if (!size) /* Signal a flush before we start writing the DESC entry */
+    {
+        flush_compressed_chunk(uncomp_buf, uncomp_buf_used);
+        return;
+    }
+    
+    if (!uncomp_buf_used)
+        memset(uncomp_buf, 0, sizeof(uncomp_buf));
+
+    while (size > sizeof(uncomp_buf))
+    {
+        flush_compressed_chunk(buffer, sizeof(uncomp_buf));
+        buffer += sizeof(uncomp_buf);
+        size -= sizeof(uncomp_buf);
+    }
+    memcpy(&uncomp_buf[uncomp_buf_used], buffer, size);
+    uncomp_buf_used += size;
+}
+
+static void write_template_desc_entries(off_t image_len, char *image_md5)
+{
+    entry_t *entry = entry_list;
+    off_t desc_len = 0;
+    unsigned char out_len[6];
+    jigdo_image_entry_t jimage;
+
+    desc_len = 16 /* DESC + length twice */
+        + (sizeof(jigdo_file_entry_t) * num_matches)
+        + (sizeof(jigdo_chunk_entry_t) * num_chunks)
+        + sizeof(jigdo_image_entry_t);
+    out_len[0] = (unsigned char)(desc_len & 0xFF);
+    out_len[1] = (unsigned char)((desc_len >> 8) & 0xFF);
+    out_len[2] = (unsigned char)((desc_len >> 16) & 0xFF);
+    out_len[3] = (unsigned char)((desc_len >> 24) & 0xFF);
+    out_len[4] = (unsigned char)((desc_len >> 32) & 0xFF);
+    out_len[5] = (unsigned char)((desc_len >> 40) & 0xFF);
+    
+    write_compressed_chunk(NULL, 0);
+    template_fwrite("DESC", 4, 1, t_file);
+    template_fwrite(out_len, sizeof(out_len), 1, t_file);
+    
+    while (entry)
+    {
+        switch (entry->entry_type)
+        {
+            case JTET_FILE_MATCH:
+            {
+                jigdo_file_entry_t jfile;
+                jfile.type = 6; /* Matched file */
+                jfile.fileLen[0] = (unsigned char)(entry->data.file.file_length & 0xFF);
+                jfile.fileLen[1] = (unsigned char)((entry->data.file.file_length >> 8) & 0xFF);
+                jfile.fileLen[2] = (unsigned char)((entry->data.file.file_length >> 16) & 0xFF);
+                jfile.fileLen[3] = (unsigned char)((entry->data.file.file_length >> 24) & 0xFF);
+                jfile.fileLen[4] = (unsigned char)((entry->data.file.file_length >> 32) & 0xFF);
+                jfile.fileLen[5] = (unsigned char)((entry->data.file.file_length >> 40) & 0xFF);
+                memset(jfile.fileRsync, 0, sizeof(jfile.fileRsync)); /* Will it work? */
+                memcpy(jfile.fileMD5, entry->data.file.md5, sizeof(jfile.fileMD5));
+                template_fwrite(&jfile, sizeof(jfile), 1, t_file);
+                break;
+            }
+            case JTET_NOMATCH:
+            {
+                jigdo_chunk_entry_t jchunk;
+                jchunk.type = 2; /* Raw data */
+                jchunk.skipLen[0] = (unsigned char)(entry->data.chunk.uncompressed_length & 0xFF);
+                jchunk.skipLen[1] = (unsigned char)((entry->data.chunk.uncompressed_length >> 8) & 0xFF);
+                jchunk.skipLen[2] = (unsigned char)((entry->data.chunk.uncompressed_length >> 16) & 0xFF);
+                jchunk.skipLen[3] = (unsigned char)((entry->data.chunk.uncompressed_length >> 24) & 0xFF);
+                jchunk.skipLen[4] = (unsigned char)((entry->data.chunk.uncompressed_length >> 32) & 0xFF);
+                jchunk.skipLen[5] = (unsigned char)((entry->data.chunk.uncompressed_length >> 40) & 0xFF);
+                template_fwrite(&jchunk, sizeof(jchunk), 1, t_file);
+                break;
+            }
+        }
+        entry = entry->next;
+    }
+
+    jimage.type = 5;
+    jimage.imageLen[0] = (unsigned char)(image_len & 0xFF);
+    jimage.imageLen[1] = (unsigned char)((image_len >> 8) & 0xFF);
+    jimage.imageLen[2] = (unsigned char)((image_len >> 16) & 0xFF);
+    jimage.imageLen[3] = (unsigned char)((image_len >> 24) & 0xFF);
+    jimage.imageLen[4] = (unsigned char)((image_len >> 32) & 0xFF);
+    jimage.imageLen[5] = (unsigned char)((image_len >> 40) & 0xFF);
+    memcpy(jimage.imageMD5, image_md5, sizeof(jimage.imageMD5));
+    memset(jimage.blockLen, 0, sizeof(jimage.blockLen)); /* Might work... */
+    template_fwrite(&jimage, sizeof(jimage), 1, t_file);    
+    template_fwrite(out_len, sizeof(out_len), 1, t_file);
+}
+
+static char *base64_dump(unsigned char *buf, size_t buf_size)
+{
+    const char *b64_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+    int value = 0;
+    unsigned int i;
+    int bits = 0;
+    static char output_buffer[2048];
+    char *p = output_buffer;
+
+    memset(output_buffer, 0, sizeof(output_buffer));
+    if (buf_size >= (sizeof(output_buffer) * 6/8))
+    {
+        fprintf(stderr, "base64_dump: Buffer too small!\n");
+        exit(1);
+    }
+
+    for (i = 0; i < buf_size ; i++)
+    {
+        value = (value << 8) | buf[i];
+        bits += 2;
+        p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
+        if (bits >= 8) {
+            bits -= 6;
+            p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
+        }
+    }
+    if (bits > 0)
+    {
+        value <<= 8 - bits;
+        p += sprintf(p, "%c", b64_enc[(value >> bits) & 63U]);
+    }
+    return output_buffer;
+}
+
+static char *hex_dump(unsigned char *buf, size_t buf_size)
+{
+    static char output_buffer[2048];
+    char *p = output_buffer;
+    unsigned int i;
+    
+    memset(output_buffer, 0, sizeof(output_buffer));
+    if (buf_size >= (sizeof(output_buffer) / 2))
+    {
+        fprintf(stderr, "hex_dump: Buffer too small!\n");
+        exit(1);
+    }
+
+    for (i = 0; i < buf_size; i++)
+        p += sprintf(p, "%2.2x", buf[i]);
+    
+    return output_buffer;
+}
+
+/* Write the .jigdo file to match the .template we've just finished. */
+static void write_jigdo_file(void)
+{
+    unsigned char template_md5sum[16];
+    entry_t *entry = entry_list;
+
+    mk_MD5Final(&template_md5sum[0], &template_context);
+
+    fprintf(j_file, "# JigsawDownload\n");
+    fprintf(j_file, "# See <http://atterer.net/jigdo/> for details about jigdo\n");
+    fprintf(j_file, "# See <http://www.einval.com/~steve/software/CD/JTE/> for details about JTE\n\n");
+    
+    fprintf(j_file, "[Jigdo]\n");
+    fprintf(j_file, "Version=%s\n", JIGDO_TEMPLATE_VERSION);
+    fprintf(j_file, "Generator=%s/%d.%d\n\n", JTE_NAME, JTE_VER_MAJOR, JTE_VER_MINOR);
+
+    fprintf(j_file, "[Image]\n");
+    fprintf(j_file, "Filename=%s\n", outfile);
+    fprintf(j_file, "Template=http://localhost/%s\n", jtemplate_out);
+    fprintf(j_file, "Template-MD5Sum=%s \n\n",
+            base64_dump(&template_md5sum[0], sizeof(template_md5sum)));
+    fprintf(j_file, "[Parts]\n");
+    while (entry)
+    {
+        if (JTET_FILE_MATCH == entry->entry_type)
+            fprintf(j_file, "%s=%s\n",
+                    base64_dump(&entry->data.file.md5[0], sizeof(entry->data.file.md5)),
+                    entry->data.file.filename);
+        entry = entry->next;
+    }
+    fflush(j_file);
+}
+
+/* Finish and flush state; for now:
+   
+   1. Finish up the JTE file
+   2. Dump the DESC blocks and the footer information in the jigdo template file
+   3. Write the jigdo .jigdo file containing file pointers
+*/
+void write_jt_footer(FILE *jtimage)
+{
+    struct jt_extent_data extent;
+    unsigned long long tmp_size = 0;
+    struct stat sb;
+    
+    if (NULL == jtimage)
+        return;
+
+    memset(&extent, 0, sizeof(extent));
+    memset(&sb, 0, sizeof(sb));
+
+    sprintf(&extent.id[0], "%s", JTE_ID_STRING);
+    extent.extent_type = JTET_FOOTER;
+
+    /* Fill in the length of this extent */
+    tmp_size = sizeof(extent);
+    extent.extent_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.extent_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.extent_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.extent_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.extent_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.extent_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.extent_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.extent_length[7] = tmp_size & 0xFF;
+
+    /* And now the offset from the start of the image */
+    extent.start_sector[0] = 0xFF;
+    extent.start_sector[1] = 0xFF;
+    extent.start_sector[2] = 0xFF;
+    extent.start_sector[3] = 0xFF;
+
+    sprintf(&extent.data.footer.footer_string[0], "%s", JTE_FOOTER_STRING);
+
+    tmp_size = (unsigned long long)SECTOR_SIZE * last_extent_written;
+    extent.data.footer.image_size[0] = (tmp_size >> 56) & 0xFF;
+    extent.data.footer.image_size[1] = (tmp_size >> 48) & 0xFF;
+    extent.data.footer.image_size[2] = (tmp_size >> 40) & 0xFF;
+    extent.data.footer.image_size[3] = (tmp_size >> 32) & 0xFF;
+    extent.data.footer.image_size[4] = (tmp_size >> 24) & 0xFF;
+    extent.data.footer.image_size[5] = (tmp_size >> 16) & 0xFF;
+    extent.data.footer.image_size[6] = (tmp_size >> 8) & 0xFF;
+    extent.data.footer.image_size[7] = tmp_size & 0xFF;
+
+    /* Finish calculating the image's checksum */
+    mk_MD5Final(&extent.data.footer.md5[0], &jtcontext);
+    
+    /* Write the extent data */
+    fwrite(&extent, sizeof(extent), 1, jtimage);
+
+    write_template_desc_entries(tmp_size, extent.data.footer.md5);
+
+    write_jigdo_file();
+}
+
+static void add_unmatched_entry(int uncompressed_length)
+{
+    entry_t *new_entry = NULL;
+
+    /* Can we extend a previous non-match entry? */
+    if (last_entry && (JTET_NOMATCH == last_entry->entry_type))
+    {
+        last_entry->data.chunk.uncompressed_length += uncompressed_length;
+        return;
+    }
+
+    new_entry = calloc(1, sizeof(entry_t));
+    new_entry->entry_type = JTET_NOMATCH;
+    new_entry->next = NULL;
+    new_entry->data.chunk.uncompressed_length = uncompressed_length;
+
+    /* Add to the end of the list */
+    if (NULL == last_entry)
+    {
+        last_entry = new_entry;
+        entry_list = new_entry;
+    }
+    else
+    {
+        last_entry->next = new_entry;
+        last_entry = new_entry;
+    }
+    num_chunks++;
+}
+
+static void add_file_entry(char *filename, off_t size, unsigned char *md5)
+{
+    entry_t *new_entry = NULL;
+
+    new_entry = calloc(1, sizeof(entry_t));
+    new_entry->entry_type = JTET_FILE_MATCH;
+    new_entry->next = NULL;
+    memcpy(new_entry->data.file.md5, md5, sizeof(new_entry->data.file.md5));
+    new_entry->data.file.file_length = size;
+    new_entry->data.file.filename = strdup(filename);
+
+    /* Add to the end of the list */
+    if (NULL == last_entry)
+    {
+        last_entry = new_entry;
+        entry_list = new_entry;
+    }
+    else
+    {
+        last_entry->next = new_entry;
+        last_entry = new_entry;
+    }
+    num_matches++;
+}    
+
+/* Cope with an unmatched block in the .iso file:
+
+   1. Write an unmatched entry in the JTE file
+   2. Write a compressed data chunk in the jigdo template file
+   3. Add an entry in our list of unmatched chunks for later */
+void jtwrite(buffer, size, count, file, submode, islast)
+	void	*buffer;
+	int	size;
+	int	count;
+	FILE	*file;
+	int	submode;
+	BOOL	islast;
+{
+    struct jt_extent_data extent;
+    unsigned long long tmp_size = 0;
+    struct mk_MD5Context chunk_context;
+    int compressed_size = 0;
+    char *ptr = buffer;
+
+    if (NULL == file)
+        return;
+
+    memset(&extent, 0, sizeof(extent));
+    mk_MD5Init(&chunk_context);
+
+#ifdef	JTWRITE_DEBUG
+	if (count != 1 || (size % 2048) != 0)
+		error("Count: %d, size: %d\n", count, size);
+#endif
+
+    sprintf(&extent.id[0], "%s", JTE_ID_STRING);
+
+    /* We should only ever be writing an "unmatched" chunk of data here */    
+    extent.extent_type = JTET_NOMATCH;
+
+    /* Fill in the length of this extent */
+    tmp_size = (unsigned long long)size * count;
+    tmp_size += sizeof(extent);
+    extent.extent_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.extent_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.extent_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.extent_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.extent_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.extent_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.extent_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.extent_length[7] = tmp_size & 0xFF;
+
+    /* And now the offset from the start of the image */
+    tmp_size = last_extent_written;
+    extent.start_sector[0] = (tmp_size >> 24) & 0xFF;
+    extent.start_sector[1] = (tmp_size >> 16) & 0xFF;
+    extent.start_sector[2] = (tmp_size >> 8) & 0xFF;
+    extent.start_sector[3] = tmp_size & 0xFF;
+
+    /* And now the size of the chunk of unmatched data following this
+       header */
+    tmp_size = (unsigned long long)size * count;
+    extent.data.nomatch.unmatched_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.data.nomatch.unmatched_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.data.nomatch.unmatched_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.data.nomatch.unmatched_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.data.nomatch.unmatched_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.data.nomatch.unmatched_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.data.nomatch.unmatched_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.data.nomatch.unmatched_length[7] = tmp_size & 0xFF;
+
+    /* Update the two checksums: the global image sum and the sum of
+       this extent */
+    mk_MD5Update(&jtcontext, buffer, size);
+    mk_MD5Update(&chunk_context, buffer, size);
+    mk_MD5Final(&extent.data.nomatch.md5[0], &chunk_context);
+
+    /* Write the extent header */
+    fwrite(&extent, sizeof(extent), 1, file);
+
+    /* Write a compressed version of the data to the template file,
+       and add a reference on the state list so we can write that
+       later. */
+    write_compressed_chunk(buffer, size);
+    add_unmatched_entry(size);
+
+    /* And now write out the data, in just the same way as we do in
+       the real image. */
+	while (count) {
+		int	got;
+
+        got = fwrite(ptr, size, count, file);
+
+		if (got <= 0) {
+#ifdef	USE_LIBSCHILY
+			comerr("cannot fwrite %d*%d to jtimage file\n", size, count);
+#else
+			fprintf(stderr, "cannot fwrite %d*%d to jtimage file\n", size, count);
+			exit(1);
+#endif
+		}
+		count -= got, ptr += size * got;
+	}
+}
+
+/* Cope with an file entry in the .iso file:
+
+   1. Write a match entry in the JTE file
+   2. Add an entry in our list of files for later */
+void write_jt_match_record(FILE *jtfile, char *filename, int sector_size, off_t size)
+{
+    struct jt_extent_data extent;
+    unsigned long long tmp_size = 0;
+    struct mk_MD5Context file_context;
+    char buf[32768];
+    off_t remain = size;
+	FILE		*infile = NULL;
+	int	use;
+
+    if (NULL == jtfile)
+        return;
+
+    memset(&extent, 0, sizeof(extent));
+    memset(buf, 0, sizeof(buf));
+    mk_MD5Init(&file_context);
+
+    if ((infile = fopen(filename, "rb")) == NULL) {
+#ifdef	USE_LIBSCHILY
+		comerr("cannot open '%s'\n", filename);
+#else
+#ifndef	HAVE_STRERROR
+		fprintf(stderr, "cannot open '%s': (%d)\n",
+				filename, errno);
+#else
+		fprintf(stderr, "cannot open '%s': %s\n",
+				filename, strerror(errno));
+#endif
+		exit(1);
+#endif
+	}
+
+    while (remain > 0)
+    {
+        use = remain;
+        if (remain > sizeof(buf))
+            use = sizeof(buf);
+		if (fread(buf, 1, use, infile) == 0) {
+#ifdef	USE_LIBSCHILY
+			comerr("cannot read from '%s'\n", filename);
+#else
+			fprintf(stderr, "cannot read from '%s'\n", filename);
+			exit(1);
+#endif
+		}
+        mk_MD5Update(&jtcontext, buf, use);
+        mk_MD5Update(&file_context, buf, use);
+        remain -= use;
+    }
+
+    fclose(infile);
+    
+    sprintf(&extent.id[0], "%s", JTE_ID_STRING);
+    extent.extent_type = JTET_FILE_MATCH;
+
+    /* Fill in the length of this extent */
+    tmp_size = sizeof(extent) + strlen(filename) + 1;
+    extent.extent_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.extent_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.extent_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.extent_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.extent_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.extent_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.extent_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.extent_length[7] = tmp_size & 0xFF;
+
+    /* And now the offset from the start of the image */
+    tmp_size = last_extent_written;
+    extent.start_sector[0] = (tmp_size >> 24) & 0xFF;
+    extent.start_sector[1] = (tmp_size >> 16) & 0xFF;
+    extent.start_sector[2] = (tmp_size >> 8) & 0xFF;
+    extent.start_sector[3] = tmp_size & 0xFF;
+
+    tmp_size = (unsigned long long)size;
+    extent.data.file_match.file_length[0] = (tmp_size >> 56) & 0xFF;
+    extent.data.file_match.file_length[1] = (tmp_size >> 48) & 0xFF;
+    extent.data.file_match.file_length[2] = (tmp_size >> 40) & 0xFF;
+    extent.data.file_match.file_length[3] = (tmp_size >> 32) & 0xFF;
+    extent.data.file_match.file_length[4] = (tmp_size >> 24) & 0xFF;
+    extent.data.file_match.file_length[5] = (tmp_size >> 16) & 0xFF;
+    extent.data.file_match.file_length[6] = (tmp_size >> 8) & 0xFF;
+    extent.data.file_match.file_length[7] = tmp_size & 0xFF;
+
+    tmp_size = strlen(filename) + 1;
+    extent.data.file_match.filename_length[0] = (tmp_size >> 24) & 0xFF;
+    extent.data.file_match.filename_length[1] = (tmp_size >> 16) & 0xFF;
+    extent.data.file_match.filename_length[2] = (tmp_size >> 8) & 0xFF;
+    extent.data.file_match.filename_length[3] = tmp_size & 0xFF;
+    
+    mk_MD5Final(&extent.data.file_match.md5[0], &file_context);
+
+    /* Write the extent header data */
+    fwrite(&extent, sizeof(extent), 1, jtfile);
+
+    /* And now the filename itself */
+    fwrite(filename, strlen(filename) + 1, 1, jtfile);
+
+    /* Update the image checksum with any necessary padding data */
+    if (size % sector_size)
+    {
+        int pad_size = sector_size - (size % sector_size);
+        memset(buf, 0, pad_size);
+        mk_MD5Update(&jtcontext, buf, pad_size);
+    }
+    
+    add_file_entry(filename, size, &extent.data.file_match.md5[0]);
+    if (size % sector_size)
+    {
+        int pad_size = sector_size - (size % sector_size);
+        write_compressed_chunk(buf, pad_size);
+        add_unmatched_entry(pad_size);
+    }        
+}
+
+/* Should we list a file separately in the jigdo output, or should we
+   just dump it into the template file as binary data? Two common
+   cases to look for here:
+
+   1. Small files are better simply folded in, as they take less space that way.
+
+   2. Files in /doc (for example) may change in the archive all the
+      time and it's better to not have to fetch snapshot copies if we
+      can avoid it.
+      
+   WARNING: exclude by filename pattern (2) is not (yet) supported...
+
+*/
+extern int  list_file_in_jigdo(char *filename, off_t size)
+{
+    if (size < jte_min_size)
+        return 0;
+    /* else */
+    return 1;
+}
diff -uNr cdrtools-2.0+a27/mkisofs/jte.h cdrtools-2.0+a27.steve/mkisofs/jte.h
--- cdrtools-2.0+a27/mkisofs/jte.h	1970-01-01 01:00:00.000000000 +0100
+++ cdrtools-2.0+a27.steve/mkisofs/jte.h	2004-06-04 05:07:06.000000000 +0100
@@ -0,0 +1,16 @@
+extern char *jtemplate_out;
+extern char *jhelper_out;
+extern char *jjigdo_out;
+extern FILE	*jthelper;
+extern FILE *jtjigdo;
+extern FILE *jttemplate;
+extern int  jte_min_size;
+
+extern void write_jt_header(FILE *jtimage, FILE *template_file, FILE *jigdo_file);
+extern void write_jt_footer(FILE *jtimage);
+extern void jtwrite(void *buffer, int size, int count,
+                    FILE *file, int submode, BOOL islast);
+extern void write_jt_match_record(FILE *jtfile, char *filename,
+                                  int sector_size, off_t size);
+extern int  list_file_in_jigdo(char *filename, off_t size);
+
diff -uNr cdrtools-2.0+a27/mkisofs/md5.c cdrtools-2.0+a27.steve/mkisofs/md5.c
--- cdrtools-2.0+a27/mkisofs/md5.c	1970-01-01 01:00:00.000000000 +0100
+++ cdrtools-2.0+a27.steve/mkisofs/md5.c	2004-05-31 15:14:23.000000000 +0100
@@ -0,0 +1,326 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+   not require an integer type which is exactly 32 bits.  This work
+   draws on the changes for the same purpose by Tatu Ylonen
+   <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
+   that code, there is no copyright issue.  I hereby disclaim
+   copyright in any changes I have made; this code remains in the
+   public domain.  */
+
+/* Note regarding cvs_* namespace: this avoids potential conflicts
+   with libraries such as some versions of Kerberos.  No particular
+   need to worry about whether the system supplies an MD5 library, as
+   this file is only about 3k of object code.  */
+
+/* Steve McIntyre, 2004/05/31: borrowed this code from the CVS
+   library. s/cvs_/mk_/ across the source */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>	/* for memcpy() and memset() */
+
+#include "md5.h"
+
+/* Little-endian byte-swapping routines.  Note that these do not
+   depend on the size of datatypes such as mk_uint32, nor do they require
+   us to detect the endianness of the machine we are running on.  It
+   is possible they should be macros for speed, but I would be
+   surprised if they were a performance bottleneck for MD5.  */
+
+static mk_uint32
+getu32 (addr)
+     const unsigned char *addr;
+{
+	return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+		| addr[1]) << 8 | addr[0];
+}
+
+static void
+putu32 (data, addr)
+     mk_uint32 data;
+     unsigned char *addr;
+{
+	addr[0] = (unsigned char)data;
+	addr[1] = (unsigned char)(data >> 8);
+	addr[2] = (unsigned char)(data >> 16);
+	addr[3] = (unsigned char)(data >> 24);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+mk_MD5Init (ctx)
+     struct mk_MD5Context *ctx;
+{
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bits[0] = 0;
+	ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+mk_MD5Update (ctx, buf, len)
+     struct mk_MD5Context *ctx;
+     unsigned char const *buf;
+     unsigned len;
+{
+	mk_uint32 t;
+
+	/* Update bitcount */
+
+	t = ctx->bits[0];
+	if ((ctx->bits[0] = (t + ((mk_uint32)len << 3)) & 0xffffffff) < t)
+		ctx->bits[1]++;	/* Carry from low to high */
+	ctx->bits[1] += len >> 29;
+
+	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+	/* Handle any leading odd-sized chunks */
+
+	if ( t ) {
+		unsigned char *p = ctx->in + t;
+
+		t = 64-t;
+		if (len < t) {
+			memcpy(p, buf, len);
+			return;
+		}
+		memcpy(p, buf, t);
+		mk_MD5Transform (ctx->buf, ctx->in);
+		buf += t;
+		len -= t;
+	}
+
+	/* Process data in 64-byte chunks */
+
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		mk_MD5Transform (ctx->buf, ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+mk_MD5Final (digest, ctx)
+     unsigned char digest[16];
+     struct mk_MD5Context *ctx;
+{
+	unsigned count;
+	unsigned char *p;
+
+	/* Compute number of bytes mod 64 */
+	count = (ctx->bits[0] >> 3) & 0x3F;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+	   always at least one byte free */
+	p = ctx->in + count;
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 64 bytes */
+	count = 64 - 1 - count;
+
+	/* Pad out to 56 mod 64 */
+	if (count < 8) {
+		/* Two lots of padding:  Pad the first block to 64 bytes */
+		memset(p, 0, count);
+		mk_MD5Transform (ctx->buf, ctx->in);
+
+		/* Now fill the next block with 56 bytes */
+		memset(ctx->in, 0, 56);
+	} else {
+		/* Pad block to 56 bytes */
+		memset(p, 0, count-8);
+	}
+
+	/* Append length in bits and transform */
+	putu32(ctx->bits[0], ctx->in + 56);
+	putu32(ctx->bits[1], ctx->in + 60);
+
+	mk_MD5Transform (ctx->buf, ctx->in);
+	putu32(ctx->buf[0], digest);
+	putu32(ctx->buf[1], digest + 4);
+	putu32(ctx->buf[2], digest + 8);
+	putu32(ctx->buf[3], digest + 12);
+	memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+mk_MD5Transform (buf, inraw)
+     mk_uint32 buf[4];
+     const unsigned char inraw[64];
+{
+	register mk_uint32 a, b, c, d;
+	mk_uint32 in[16];
+	int i;
+
+	for (i = 0; i < 16; ++i)
+		in[i] = getu32 (inraw + 4 * i);
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
+	MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
+	MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
+	MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
+	MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
+	MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
+	MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
+	MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
+	MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
+	MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
+	MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
+	MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
+	MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
+	MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
+	MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
+	MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
+	MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
+	MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
+	MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
+	MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
+	MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+#endif
+
+#ifdef TEST
+/* Simple test program.  Can use it to manually run the tests from
+   RFC1321 for example.  */
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+	struct mk_MD5Context context;
+	unsigned char checksum[16];
+	int i;
+	int j;
+
+	if (argc < 2)
+	{
+		fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
+		exit (1);
+	}
+	for (j = 1; j < argc; ++j)
+	{
+		printf ("MD5 (\"%s\") = ", argv[j]);
+		mk_MD5Init (&context);
+		mk_MD5Update (&context, argv[j], strlen (argv[j]));
+		mk_MD5Final (checksum, &context);
+		for (i = 0; i < 16; i++)
+		{
+			printf ("%02x", (unsigned int) checksum[i]);
+		}
+		printf ("\n");
+	}
+	return 0;
+}
+#endif /* TEST */
diff -uNr cdrtools-2.0+a27/mkisofs/md5.h cdrtools-2.0+a27.steve/mkisofs/md5.h
--- cdrtools-2.0+a27/mkisofs/md5.h	1970-01-01 01:00:00.000000000 +0100
+++ cdrtools-2.0+a27.steve/mkisofs/md5.h	2004-05-31 15:09:05.000000000 +0100
@@ -0,0 +1,26 @@
+/* See md5.c for explanation and copyright information.  */
+
+#ifndef MD5_H
+#define MD5_H
+
+/* Unlike previous versions of this code, uint32 need not be exactly
+   32 bits, merely 32 bits or more.  Choosing a data type which is 32
+   bits instead of 64 is not important; speed is considerably more
+   important.  ANSI guarantees that "unsigned long" will be big enough,
+   and always using it seems to have few disadvantages.  */
+typedef unsigned long mk_uint32;
+
+struct mk_MD5Context {
+	mk_uint32 buf[4];
+	mk_uint32 bits[2];
+	unsigned char in[64];
+};
+
+void mk_MD5Init (struct mk_MD5Context *context);
+void mk_MD5Update (struct mk_MD5Context *context,
+			   unsigned char const *buf, unsigned len);
+void mk_MD5Final (unsigned char digest[16],
+			  struct mk_MD5Context *context);
+void mk_MD5Transform (mk_uint32 buf[4], const unsigned char in[64]);
+
+#endif /* !MD5_H */
diff -uNr cdrtools-2.0+a27/mkisofs/mkisofs.c cdrtools-2.0+a27.steve/mkisofs/mkisofs.c
--- cdrtools-2.0+a27/mkisofs/mkisofs.c	2004-03-04 23:22:28.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/mkisofs.c	2004-06-04 05:14:05.000000000 +0100
@@ -364,6 +364,14 @@
 #define	OPTION_SUNX86BOOT		1068
 #define	OPTION_SUNX86LABEL		1069
 
+#ifdef JIGDO_TEMPLATE
+#define OPTION_JTH_OUTPUT    1100
+#define OPTION_JTT_OUTPUT    1101
+#define OPTION_JTJ_OUTPUT    1102
+#define OPTION_JT_MIN_SIZE   1103
+#define OPTION_JT_EXCLUDE    1104
+#endif
+
 #ifdef UDF
 #define	OPTION_UDF			1500
 #endif
@@ -575,6 +583,19 @@
 	{{"sectype", required_argument, NULL, 's'},
 	's', "TYPE", "Set output sector type to e.g. data/xa1/raw", ONE_DASH},
 
+#ifdef JIGDO_TEMPLATE
+    {{"jigdo-helper", required_argument, NULL, OPTION_JTH_OUTPUT},
+     '\0', NULL, "Produce a jigdo raw-template helper file as well as the .iso", ONE_DASH },
+    {{"jigdo-jigdo", required_argument, NULL, OPTION_JTJ_OUTPUT},
+     '\0', NULL, "Produce a jigdo .jigdo file as well as the .iso", ONE_DASH },
+    {{"jigdo-template", required_argument, NULL, OPTION_JTT_OUTPUT},
+     '\0', NULL, "Produce a jigdo .template file as well as the .iso", ONE_DASH },
+    {{"jigdo-min-file-size", required_argument, NULL, OPTION_JT_MIN_SIZE},
+     '\0', NULL, "Minimum size for a file to be listed in the jigdo file", ONE_DASH },
+    {{"jigdo-exclude", required_argument, NULL, OPTION_JT_EXCLUDE},
+     '\0', NULL, "Pattern(s) to exclude from the jigdo file", ONE_DASH },
+#endif
+
 #ifdef SORTING
 	{ {"sort", required_argument, NULL, OPTION_SORT},
 	'\0', "FILE", "Sort file content locations according to rules in FILE", ONE_DASH },
@@ -1337,6 +1358,22 @@
 		case OPTION_OUTPUT_CHARSET:
 			ocharset = optarg;
 			break;
+        case OPTION_JTH_OUTPUT:
+            jhelper_out = optarg;
+            break;
+        case OPTION_JTT_OUTPUT:
+            jtemplate_out = optarg;
+            break;
+        case OPTION_JTJ_OUTPUT:
+            jjigdo_out = optarg;
+            break;
+        case OPTION_JT_MIN_SIZE:
+            jte_min_size = atoi(optarg);
+            break;
+        case OPTION_JT_EXCLUDE:
+            /* Don't handle this yet! */
+            exit(1);
+            break;
 		case OPTION_NOBAK:
 			all_files = 0;
 			break;
@@ -3101,6 +3138,28 @@
 			exit(1);
 #endif
 		}
+        if (jtemplate_out || jjigdo_out || jhelper_out) {
+            if (!jtemplate_out || !jjigdo_out || !jhelper_out) {
+#ifdef        USE_LIBSCHILY
+                comerr("Bad options - need to specify all jigdo output names!\n");
+#else
+                fprintf(stderr, "Bad options - need to specify all jigdo output names!\n");
+                exit(1);
+#endif
+            }
+            jthelper = fopen(jhelper_out, "wb");
+            jtjigdo = fopen(jjigdo_out, "wb");
+            jttemplate = fopen(jtemplate_out, "wb");
+            if (!jthelper || !jtjigdo || !jttemplate) {
+#ifdef        USE_LIBSCHILY
+                comerr("Unable to open jigdo template image file\n");
+#else
+                fprintf(stderr, "Unable to open jigdo template image file\n");
+                exit(1);
+#endif
+            }
+            write_jt_header(jthelper, jttemplate, jtjigdo);
+        }
 	} else {
 		discimage = stdout;
 
@@ -3340,11 +3399,11 @@
 			"Implementation botch: %s should start at %u but starts at %u.\n",
 			opnt->of_name, opnt->of_start_extent, last_extent_written);
 		}
-		if (opnt->of_write != NULL) {
+		if (opnt->of_iso_write != NULL) {
 			if (verbose > 1)
 				fprintf(stderr, "Writing:   %-40sStart Block %u\n",
 					opnt->of_name, last_extent_written);
-			(*opnt->of_write) (discimage);
+			(*opnt->of_iso_write) (discimage, jthelper);
 			if (verbose > 1)
 				fprintf(stderr, "Done with: %-40sBlock(s)    %d\n",
 					opnt->of_name, last_extent_written-oext);
@@ -3356,6 +3415,17 @@
 				last_extent, last_extent_written);
 	}
 
+    if (jthelper)
+    {
+        write_jt_footer(jthelper);
+        fclose(jthelper);
+    }
+
+    if (jttemplate)
+        fclose(jttemplate);
+    if (jtjigdo)
+        fclose(jtjigdo);
+    
 	if (verbose > 0) {
 #ifdef HAVE_SBRK
 		fprintf(stderr, "Max brk space used %x\n",
diff -uNr cdrtools-2.0+a27/mkisofs/mkisofs.h cdrtools-2.0+a27.steve/mkisofs/mkisofs.h
--- cdrtools-2.0+a27/mkisofs/mkisofs.h	2004-03-04 21:47:39.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/mkisofs.h	2004-06-04 05:01:55.000000000 +0100
@@ -34,6 +34,10 @@
 #include <utypes.h>
 #include <standard.h>
 #include <libport.h>
+#ifdef JIGDO_TEMPLATE
+#include "md5.h"
+#include "jte.h"
+#endif
 
 #ifdef	DVD_VIDEO
 #ifndef	UDF
@@ -159,7 +163,7 @@
 	struct output_fragment *of_next;
 	int		(*of_size)	__PR((int));
 	int		(*of_generate)	__PR((void));
-	int		(*of_write)	__PR((FILE *));
+	int		(*of_iso_write)	__PR((FILE *, FILE *));
 	char		*of_name;			/* Textual description */
 	unsigned int	of_start_extent;		/* For consist check */
 };
@@ -194,6 +198,7 @@
 extern struct output_fragment hfs_desc;
 
 #endif	/* APPLE_HYB */
+
 #ifdef DVD_VIDEO
 /*
  * This structure holds the information necessary to create a valid
@@ -357,6 +362,7 @@
 extern int	split_SL_component;
 extern int	split_SL_field;
 extern char	*trans_tbl;
+char		*outfile;
 
 #define	JMAX		64	/* maximum Joliet file name length (spec) */
 #define	JLONGMAX	103	/* out of spec Joliet file name length */
@@ -431,7 +437,7 @@
 
 #endif	/* APPLE_HYB */
 
-extern void generate_iso9660_directories __PR((struct directory *, FILE *));
+extern void generate_iso9660_directories __PR((struct directory *, FILE *, FILE *));
 extern void dump_tree __PR((struct directory * node));
 extern struct directory_entry *search_tree_file __PR((struct
 				directory * node, char *filename));
@@ -464,7 +470,7 @@
 extern void set_721 __PR((char *, unsigned int));
 extern void set_733 __PR((char *, unsigned int));
 extern int sort_directory __PR((struct directory_entry **, int));
-extern void generate_one_directory __PR((struct directory *, FILE *));
+extern void generate_one_directory __PR((struct directory *, FILE *, FILE *));
 extern void memcpy_max __PR((char *, char *, int));
 extern int oneblock_size __PR((int starting_extent));
 extern struct iso_primary_descriptor vol_desc;
diff -uNr cdrtools-2.0+a27/mkisofs/stream.c cdrtools-2.0+a27.steve/mkisofs/stream.c
--- cdrtools-2.0+a27/mkisofs/stream.c	2004-03-04 22:56:57.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/stream.c	2004-05-28 16:30:21.000000000 +0100
@@ -35,9 +35,9 @@
 
 LOCAL int	gen_str_path	__PR((void));
 
-LOCAL int	write_str_file	__PR((FILE *outfile));
-LOCAL int	write_str_dir	__PR((FILE *outfile));
-LOCAL int	write_str_path	__PR((FILE *outfile));
+LOCAL int	write_str_file	__PR((FILE *outfile, FILE *jtfile));
+LOCAL int	write_str_dir	__PR((FILE *outfile, FILE *jtfile));
+LOCAL int	write_str_path	__PR((FILE *outfile, FILE *jtfile));
 
 extern struct directory *root;
 extern unsigned int	session_start;
@@ -139,8 +139,8 @@
  * Write the file content
  */
 LOCAL int
-write_str_file(outfile)
-	FILE	*outfile;
+write_str_file(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	unsigned int	idx = 0;
 	unsigned int	iso_blocks;
@@ -157,6 +157,7 @@
 			break;
 		}
 		idx += count;
+		jtwrite(buf, count, 1, jtfile, 0, FALSE);
 		xfwrite(buf, count, 1, outfile, 0, FALSE);
 	}
 
@@ -164,16 +165,24 @@
 	iso_blocks = ISO_BLOCKS(idx);
 	memset(buf, 0, SECTOR_SIZE);
 	if (SECTOR_SIZE * iso_blocks - idx)
+    {
+		jtwrite(buf, SECTOR_SIZE * iso_blocks - idx, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE * iso_blocks - idx, 1, outfile, 0, FALSE);
+    }
 	/*
 	 * If we didn't fill the available area, pad to directory block
 	 */
 	for (count = 0; count < (avail_extent - iso_blocks); count++)
+    {
+		jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
-
+    }
 	for (count = 0; count < stream_pad; count++)
+    {
+		jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
-
+    }
+    
 	last_extent_written += avail_extent + stream_pad;
 	return (0);
 }
@@ -182,8 +191,8 @@
  * Generate and write the directory record data
  */
 LOCAL int
-write_str_dir(outfile)
-	FILE	*outfile;
+write_str_dir(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	int	to_write;
 	char	*buf;
@@ -201,7 +210,9 @@
 	set_723((char *)s_dir.volume_sequence_number, volume_sequence_number);
 	s_dir.name_len[0] = 1;
 	s_dir.name[0] = 0;
+	jtwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, jtfile, 0, FALSE);
 	xfwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, outfile, 0, FALSE);
+	jtwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, jtfile, 0, FALSE);
 	xfwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, outfile, 0, FALSE);
 	memset(&s_dir, 0, sizeof (struct iso_directory_record));
 	s_dir.length[0] = 34 + strlen(stream_filename);
@@ -214,6 +225,8 @@
 	set_723((char *)s_dir.volume_sequence_number, volume_sequence_number);
 	s_dir.name_len[0] = strlen(stream_filename);
 	memcpy(s_dir.name, stream_filename, s_dir.name_len[0]);
+	jtwrite(&s_dir, offsetof(struct iso_directory_record, name[0])
+		+ s_dir.name_len[0], 1, jtfile, 0, FALSE);
 	xfwrite(&s_dir, offsetof(struct iso_directory_record, name[0])
 		+ s_dir.name_len[0], 1, outfile, 0, FALSE);
 
@@ -222,6 +235,8 @@
 	 * with filename length stream_filename + round up for even lenght count
 	 */
 	to_write = (s_dir.name_len[0] % 2) ? 0 : 1;
+	jtwrite(buf, SECTOR_SIZE - ((3 * 34) + s_dir.name_len[0]) +
+		to_write, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE - ((3 * 34) + s_dir.name_len[0]) +
 		to_write, 1, outfile, 0, FALSE);
 	free(buf);
@@ -233,10 +248,12 @@
  * Generate the path table data
  */
 LOCAL int
-write_str_path(outfile)
-	FILE	*outfile;
+write_str_path(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
+	jtwrite(l_path, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(l_path, SECTOR_SIZE, 1, outfile, 0, FALSE);
+	jtwrite(m_path, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(m_path, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written += 2;
 	free(l_path);
diff -uNr cdrtools-2.0+a27/mkisofs/tree.c cdrtools-2.0+a27.steve/mkisofs/tree.c
--- cdrtools-2.0+a27/mkisofs/tree.c	2004-01-06 21:37:56.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/tree.c	2004-05-28 16:30:21.000000000 +0100
@@ -89,7 +89,7 @@
 						char *short_name));
 #endif
 EXPORT	void	generate_iso9660_directories __PR((struct directory *node,
-						FILE *outfile));
+						FILE *outfile, FILE *jtfile));
 EXPORT	struct directory *
 		find_or_create_directory __PR((struct directory *parent,
 						const char *path,
@@ -2193,9 +2193,10 @@
 
 
 EXPORT void
-generate_iso9660_directories(node, outfile)
+generate_iso9660_directories(node, outfile, jtfile)
 	struct directory	*node;
 	FILE			*outfile;
+    FILE            *jtfile;
 {
 	struct directory *dpnt;
 
@@ -2203,10 +2204,10 @@
 
 	while (dpnt) {
 		if (dpnt->extent > session_start) {
-			generate_one_directory(dpnt, outfile);
+			generate_one_directory(dpnt, outfile, jtfile);
 		}
 		if (dpnt->subdir)
-			generate_iso9660_directories(dpnt->subdir, outfile);
+			generate_iso9660_directories(dpnt->subdir, outfile, jtfile);
 		dpnt = dpnt->next;
 	}
 }
diff -uNr cdrtools-2.0+a27/mkisofs/udf.c cdrtools-2.0+a27.steve/mkisofs/udf.c
--- cdrtools-2.0+a27/mkisofs/udf.c	2004-02-24 23:16:47.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/udf.c	2004-05-28 16:30:21.000000000 +0100
@@ -1014,11 +1014,11 @@
 
 static void
 #ifdef PROTOTYPES
-write_one_udf_directory(struct directory *dpnt, FILE *outfile)
+write_one_udf_directory(struct directory *dpnt, FILE *outfile, FILE *jtfile)
 #else
-write_one_udf_directory(dpnt, outfile)
+write_one_udf_directory(dpnt, outfile, jtfile)
 	struct directory	*dpnt;
-	FILE			*outfile;
+	FILE			*outfile, *jtfile;
 #endif
 {
 	unsigned size_in_bytes, padded_size_in_bytes;
@@ -1038,6 +1038,7 @@
 		1,	/* is_directory */
 		directory_link_count(dpnt),
 		(dpnt == root) ? 0 : dpnt->self->udf_file_entry_sector);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 
@@ -1055,6 +1056,7 @@
 		1,
 		parent->self->udf_file_entry_sector - lba_udf_partition_start,
 		(parent == root) ? 0 : parent->self->udf_file_entry_sector);
+	jtwrite(buf, ident_size, 1, jtfile, 0, FALSE);
 	xfwrite(buf, ident_size, 1, outfile, 0, FALSE);
 	size_in_bytes = ident_size;
 
@@ -1100,6 +1102,7 @@
 			!!(de1->isorec.flags[0] & ISO_DIRECTORY),
 			de1->udf_file_entry_sector - lba_udf_partition_start,
 			de1->udf_file_entry_sector);
+		jtwrite(buf, ident_size, 1, jtfile, 0, FALSE);
 		xfwrite(buf, ident_size, 1, outfile, 0, FALSE);
 		size_in_bytes += ident_size;
 	}
@@ -1107,6 +1110,7 @@
 	padded_size_in_bytes = PAD(size_in_bytes, SECTOR_SIZE);
 	if (size_in_bytes < padded_size_in_bytes) {
 		memset(buf, 0, padded_size_in_bytes - size_in_bytes);
+		jtwrite(buf, padded_size_in_bytes - size_in_bytes, 1, jtfile, 0, FALSE);
 		xfwrite(buf, padded_size_in_bytes - size_in_bytes, 1, outfile, 0, FALSE);
 	}
 
@@ -1115,30 +1119,30 @@
 
 static void
 #ifdef PROTOTYPES
-write_udf_directories(struct directory *dpnt, FILE *outfile)
+write_udf_directories(struct directory *dpnt, FILE *outfile, FILE *jtfile)
 #else
-write_udf_directories(dpnt, outfile)
+write_udf_directories(dpnt, outfile, jtfile)
 	struct directory	*dpnt;
-	FILE			*outfile;
+	FILE			*outfile, *jtfile;
 #endif
 {
 	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
-		write_one_udf_directory(dpnt, outfile);
+		write_one_udf_directory(dpnt, outfile, jtfile);
 	}
 	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
-			write_udf_directories(dpnt, outfile);
+			write_udf_directories(dpnt, outfile, jtfile);
 		}
 	}
 }
 
 static void
 #ifdef PROTOTYPES
-write_udf_file_entries(struct directory *dpnt, FILE *outfile)
+write_udf_file_entries(struct directory *dpnt, FILE *outfile, FILE *jtfile)
 #else
-write_udf_file_entries(dpnt, outfile)
+write_udf_file_entries(dpnt, outfile, jtfile)
 	struct directory	*dpnt;
-	FILE			*outfile;
+	FILE			*outfile, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE];
@@ -1161,13 +1165,14 @@
 					0,	/* is_directory */
 					1,	/* link_count */
 					de->udf_file_entry_sector);
+				jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 				xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
 			}
 		}
 	}
 	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
-			write_udf_file_entries(dpnt, outfile);
+			write_udf_file_entries(dpnt, outfile, jtfile);
 		}
 	}
 }
@@ -1176,10 +1181,10 @@
 
 static int
 #ifdef PROTOTYPES
-udf_vol_recognition_area_write(FILE *out)
+udf_vol_recognition_area_write(FILE *out, FILE *jtfile)
 #else
-udf_vol_recognition_area_write(out)
-	FILE	*out;
+udf_vol_recognition_area_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	static const char *identifiers[3] = { "BEA01", "NSR02", "TEA01" };
@@ -1192,6 +1197,7 @@
 	set8(&vsd->structure_version, 1);
 	for (i = 0; i < 3; ++i) {
 		memcpy(vsd->standard_identifier, identifiers[i], 5);
+		jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 	}
 	last_extent_written += 3;
@@ -1200,10 +1206,10 @@
 
 static int
 #ifdef PROTOTYPES
-udf_main_seq_write(FILE *out)
+udf_main_seq_write(FILE *out, FILE *jtfile)
 #else
-udf_main_seq_write(out)
-	FILE	*out;
+udf_main_seq_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE];
@@ -1218,30 +1224,37 @@
 
 	memset(buf, 0, sizeof (buf));
 	set_primary_vol_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	set_impl_use_vol_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	set_partition_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	set_logical_vol_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	set_unallocated_space_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	set_terminating_desc(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 
 	memset(buf, 0, sizeof (buf));
 	for (i = 6; i < UDF_MAIN_SEQ_LENGTH; ++i) {
+        jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 		last_extent_written++;
 	}
@@ -1251,10 +1264,10 @@
 
 static int
 #ifdef PROTOTYPES
-udf_integ_seq_write(FILE *out)
+udf_integ_seq_write(FILE *out, FILE *jtfile)
 #else
-udf_integ_seq_write(out)
-	FILE	*out;
+udf_integ_seq_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE*UDF_INTEG_SEQ_LENGTH];
@@ -1265,32 +1278,34 @@
 						last_extent_written++);
 	set_terminating_desc(buf+1*SECTOR_SIZE, last_extent_written++);
 
+	jtwrite(buf, SECTOR_SIZE, UDF_INTEG_SEQ_LENGTH, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, UDF_INTEG_SEQ_LENGTH, out, 0, FALSE);
 	return (0);
 }
 
 static int
 #ifdef PROTOTYPES
-udf_anchor_vol_desc_write(FILE *out)
+udf_anchor_vol_desc_write(FILE *out, FILE *jtfile)
 #else
-udf_anchor_vol_desc_write(out)
-	FILE	*out;
+udf_anchor_vol_desc_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE];
 
 	memset(buf, 0, sizeof (buf));
 	set_anchor_volume_desc_pointer(buf, last_extent_written++);
+	jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 	return (0);
 }
 
 static int
 #ifdef PROTOTYPES
-udf_file_set_desc_write(FILE *out)
+udf_file_set_desc_write(FILE *out, FILE *jtfile)
 #else
-udf_file_set_desc_write(out)
-	FILE	*out;
+udf_file_set_desc_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE*2];
@@ -1302,6 +1317,7 @@
 	set_terminating_desc(buf+1*SECTOR_SIZE,
 			(last_extent_written++) - lba_udf_partition_start);
 
+	jtwrite(buf, SECTOR_SIZE, 2, jtfile, 0, FALSE);
 	xfwrite(buf, SECTOR_SIZE, 2, out, 0, FALSE);
 
 	return (0);
@@ -1309,40 +1325,41 @@
 
 static int
 #ifdef PROTOTYPES
-udf_dirtree_write(FILE *out)
+udf_dirtree_write(FILE *out, FILE *jtfile)
 #else
-udf_dirtree_write(out)
-	FILE	*out;
+udf_dirtree_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
-	write_udf_directories(root, out);
+	write_udf_directories(root, out, jtfile);
 	return (0);
 }
 
 static int
 #ifdef PROTOTYPES
-udf_file_entries_write(FILE *out)
+udf_file_entries_write(FILE *out, FILE *jtfile)
 #else
-udf_file_entries_write(out)
-	FILE	*out;
+udf_file_entries_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
-	write_udf_file_entries(root, out);
+	write_udf_file_entries(root, out, jtfile);
 	return (0);
 }
 
 static int
 #ifdef PROTOTYPES
-pad_to(unsigned last_extent_to_write, FILE *out)
+pad_to(unsigned last_extent_to_write, FILE *out, FILE *jtfile)
 #else
-pad_to(last_extent_to_write, out)
+pad_to(last_extent_to_write, out, jtfile)
 	unsigned	last_extent_to_write;
-	FILE		*out;
+	FILE		*out, *jtfile;
 #endif
 {
 	char buf[SECTOR_SIZE];
 	memset(buf, 0, sizeof (buf));
 	while (last_extent_written < last_extent_to_write) {
+		jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 		++last_extent_written;
 	}
@@ -1351,32 +1368,32 @@
 
 static int
 #ifdef PROTOTYPES
-udf_pad_to_sector_32_write(FILE *out)
+udf_pad_to_sector_32_write(FILE *out, FILE *jtfile)
 #else
-udf_pad_to_sector_32_write(out)
-	FILE	*out;
+udf_pad_to_sector_32_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
-	return (pad_to(session_start+32, out));
+	return (pad_to(session_start+32, out, jtfile));
 }
 
 static int
 #ifdef PROTOTYPES
-udf_pad_to_sector_256_write(FILE *out)
+udf_pad_to_sector_256_write(FILE *out, FILE *jtfile)
 #else
-udf_pad_to_sector_256_write(out)
-	FILE	*out;
+udf_pad_to_sector_256_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
-	return (pad_to(session_start+256, out));
+	return (pad_to(session_start+256, out, jtfile));
 }
 
 static int
 #ifdef PROTOTYPES
-udf_padend_avdp_write(FILE *out)
+udf_padend_avdp_write(FILE *out, FILE *jtfile)
 #else
-udf_padend_avdp_write(out)
-	FILE	*out;
+udf_padend_avdp_write(out, jtfile)
+	FILE	*out, *jtfile;
 #endif
 {
 	Uchar buf[SECTOR_SIZE];
@@ -1388,6 +1405,7 @@
 	memset(buf, 0, sizeof (buf));
 	while (last_extent_written < last_extent_to_write) {
 		set_anchor_volume_desc_pointer(buf, last_extent_written++);
+		jtwrite(buf, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 		xfwrite(buf, SECTOR_SIZE, 1, out, 0, FALSE);
 	}
 	return (0);
diff -uNr cdrtools-2.0+a27/mkisofs/write.c cdrtools-2.0+a27.steve/mkisofs/write.c
--- cdrtools-2.0+a27/mkisofs/write.c	2004-02-29 16:20:27.000000000 +0000
+++ cdrtools-2.0+a27.steve/mkisofs/write.c	2004-06-04 05:21:33.000000000 +0100
@@ -85,12 +85,12 @@
 static	int	assign_directory_addresses __PR((struct directory *node));
 #ifdef APPLE_HYB
 static	void	write_one_file	__PR((char *filename, off_t size,
-					FILE *outfile, off_t off));
+					FILE *outfile, FILE *jtfile, off_t off));
 #else
 static	void	write_one_file	__PR((char *filename, off_t size,
-					FILE *outfile));
+					FILE *outfile, FILE *jtfile));
 #endif
-static	void	write_files	__PR((FILE *outfile));
+static	void	write_files	__PR((FILE *outfile, FILE *jtfile));
 #if 0
 static	void	dump_filelist	__PR((void));
 #endif
@@ -102,21 +102,21 @@
 static	void	free_one_directory  __PR((struct directory *dpnt));
 static	void	free_directories __PR((struct directory *dpnt));
 	void	generate_one_directory __PR((struct directory *dpnt,
-						FILE *outfile));
+						FILE *outfile, FILE *jtfile));
 static	void	build_pathlist	__PR((struct directory *node));
 static	int	compare_paths	__PR((void const *r, void const *l));
 static	int	generate_path_tables __PR((void));
 	void	memcpy_max	__PR((char *to, char *from, int max));
 	void	outputlist_insert __PR((struct output_fragment *frag));
-static	int	file_write	__PR((FILE *outfile));
-static	int	pvd_write	__PR((FILE *outfile));
-static	int	xpvd_write	__PR((FILE *outfile));
-static	int	evd_write	__PR((FILE *outfile));
-static	int	vers_write	__PR((FILE *outfile));
+static	int	file_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	pvd_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	xpvd_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	evd_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	vers_write	__PR((FILE *outfile, FILE *jtfile));
 static	int	graftcp		__PR((char *to, char *from, char *ep));
 static	int	pathcp		__PR((char *to, char *from, char *ep));
-static	int	pathtab_write	__PR((FILE *outfile));
-static	int	exten_write	__PR((FILE *outfile));
+static	int	pathtab_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	exten_write	__PR((FILE *outfile, FILE *jtfile));
 	int	oneblock_size	__PR((int starting_extent));
 static	int	pathtab_size	__PR((int starting_extent));
 static	int	startpad_size	__PR((int starting_extent));
@@ -127,11 +127,11 @@
 static	int	dirtree_fixup	__PR((int starting_extent));
 static	int	dirtree_size	__PR((int starting_extent));
 static	int	ext_size	__PR((int starting_extent));
-static	int	dirtree_write	__PR((FILE *outfile));
-static	int	dirtree_cleanup	__PR((FILE *outfile));
-static	int	startpad_write	__PR((FILE *outfile));
-static	int	interpad_write	__PR((FILE *outfile));
-static	int	endpad_write	__PR((FILE *outfile));
+static	int	dirtree_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	dirtree_cleanup	__PR((FILE *outfile, FILE *jtfile));
+static	int	startpad_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	interpad_write	__PR((FILE *outfile, FILE *jtfile));
+static	int	endpad_write	__PR((FILE *outfile, FILE *jtfile));
 #ifdef APPLE_HYB
 static	int	hfs_pad;
 static	int	hfs_get_parms	__PR((char * key));
@@ -140,7 +140,7 @@
 	Ulong	get_adj_size	__PR((int Csize));
 	int	adj_size	__PR((int Csize, int start_extent, int extra));
 	void	adj_size_other	__PR((struct directory *dpnt));
-static	int	hfs_hce_write	__PR((FILE * outfile));
+static	int	hfs_hce_write	__PR((FILE * outfile, FILE * jtfile));
 	int	insert_padding_file __PR((int size));
 #endif	/* APPLE_HYB */
 
@@ -289,6 +289,7 @@
 #endif
 		}
 	}
+
 	while (count) {
 		int	got;
 
@@ -427,17 +428,19 @@
 
 #ifdef APPLE_HYB
 static void
-write_one_file(filename, size, outfile, off)
+write_one_file(filename, size, outfile, jtfile, off)
 	char		*filename;
 	off_t		size;
 	FILE		*outfile;
+    FILE        *jtfile;
 	off_t		off;
 #else
 static void
-write_one_file(filename, size, outfile)
+write_one_file(filename, size, outfile, jtfile)
 	char		*filename;
 	off_t		size;
 	FILE		*outfile;
+    FILE        *jtfile;
 #endif	/* APPLE_HYB */
 {
 	/*
@@ -452,7 +455,7 @@
 	FILE		*infile;
 	off_t		remain;
 	int	use;
-
+    int include_in_jigdo = list_file_in_jigdo(filename, size);
 
 	if ((infile = fopen(filename, "rb")) == NULL) {
 #ifdef	USE_LIBSCHILY
@@ -473,6 +476,9 @@
 #endif	/* APPLE_HYB */
 	remain = size;
 
+    if (include_in_jigdo)
+        write_jt_match_record(jtfile, filename, SECTOR_SIZE, size);
+
 	while (remain > 0) {
 		use = (remain > SECTOR_SIZE * NSECT - 1 ?
 				NSECT * SECTOR_SIZE : remain);
@@ -487,6 +493,9 @@
 			exit(1);
 #endif
 		}
+        if (!include_in_jigdo)
+            jtwrite(buffer, use, 1, jtfile,
+                    XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
 		xfwrite(buffer, use, 1, outfile,
 				XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
 		last_extent_written += use / SECTOR_SIZE;
@@ -520,11 +529,12 @@
 		remain -= use;
 	}
 	fclose(infile);
+
 }/* write_one_file(... */
 
 static void
-write_files(outfile)
-	FILE	*outfile;
+write_files(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	struct deferred_write	*dwpnt,
 				*dwnext;
@@ -539,6 +549,9 @@
 				(Llong)dwpnt->size, dwpnt->extent);
 #endif
 		if (dwpnt->table) {
+			jtwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
+                            jtfile,
+							XA_SUBH_DATA, TRUE);
 			xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
 							outfile,
 							XA_SUBH_DATA, TRUE);
@@ -550,13 +563,13 @@
 		} else {
 
 #ifdef VMS
-			vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
+			vms_write_one_file(dwpnt->name, dwpnt->size, outfile, jtfile);
 #else
 #ifdef APPLE_HYB
-			write_one_file(dwpnt->name, dwpnt->size, outfile,
+			write_one_file(dwpnt->name, dwpnt->size, outfile, jtfile,
 								dwpnt->off);
 #else
-			write_one_file(dwpnt->name, dwpnt->size, outfile);
+			write_one_file(dwpnt->name, dwpnt->size, outfile, jtfile);
 #endif	/* APPLE_HYB */
 #endif
 			free(dwpnt->name);
@@ -583,9 +596,11 @@
 			Uint	i;
 
 			for (i = 0; i < dwpnt->pad; i++)
+            {
+				jtwrite(blk, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 				xfwrite(blk, SECTOR_SIZE, 1, outfile, 0, FALSE);
-
-			last_extent_written += dwpnt->pad;
+                last_extent_written++;
+            }
 		}
 #endif	/* APPLE_HYB || DVD_VIDEO */
 
@@ -797,10 +812,10 @@
 	if (dcount < 2) {
 #ifdef	USE_LIBSCHILY
 		errmsgno(EX_BAD,
-			"Directory size too small (. or .. missing ???)\n");
+			"Directory size too small (. or .. missing !)\n");
 #else
 		fprintf(stderr,
-			"Directory size too small (. or .. missing ???)\n");
+			"Directory size too small (. or .. missing !)\n");
 #endif
 		sort_goof = 1;
 
@@ -1338,9 +1353,10 @@
 }
 
 void
-generate_one_directory(dpnt, outfile)
+generate_one_directory(dpnt, outfile, jtfile)
 	struct directory	*dpnt;
 	FILE			*outfile;
+    FILE            *jtfile;
 {
 	unsigned int	ce_address = 0;
 	char		*ce_buffer;
@@ -1501,6 +1517,7 @@
 			dir_index, dpnt->de_name);
 #endif
 	}
+	jtwrite(directory_buffer, total_size, 1, jtfile, 0, FALSE);
 	xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
 	last_extent_written += total_size >> 11;
 	free(directory_buffer);
@@ -1518,6 +1535,7 @@
 				ce_index, dpnt->ce_bytes);
 #endif
 		}
+		jtwrite(ce_buffer, ce_size, 1, jtfile, 0, FALSE);
 		xfwrite(ce_buffer, ce_size, 1, outfile, 0, FALSE);
 		last_extent_written += ce_size >> 11;
 		free(ce_buffer);
@@ -1734,8 +1752,8 @@
 }
 
 static int
-file_write(outfile)
-	FILE	*outfile;
+file_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	Uint	should_write;
 
@@ -1752,9 +1770,11 @@
 		 * write out padding to round up to HFS allocation block
 		 */
 		for (i = 0; i < hfs_pad; i++)
+        {
+			jtwrite(buffer, sizeof (buffer), 1, jtfile, 0, FALSE);
 			xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
-
-		last_extent_written += hfs_pad;
+            last_extent_written++;
+        }
 	}
 #endif	/* APPLE_HYB */
 
@@ -1785,17 +1805,21 @@
 				last_extent - session_start);
 	}
 	/* Now write all of the files that we need. */
-	write_files(outfile);
+	write_files(outfile, jtfile);
 
 #ifdef APPLE_HYB
 	/* write out extents/catalog/dt file */
 	if (apple_hyb) {
 
+		jtwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, jtfile, 0, FALSE);
 		xfwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, outfile, 0, FALSE);
 
 		/* round up to a whole CD block */
 		if (HFS_ROUND_UP(hce->hfs_tot_size) -
 					hce->hfs_tot_size * HFS_BLOCKSZ) {
+			jtwrite(buffer,
+				HFS_ROUND_UP(hce->hfs_tot_size) -
+				hce->hfs_tot_size * HFS_BLOCKSZ, 1, jtfile, 0, FALSE);
 			xfwrite(buffer,
 				HFS_ROUND_UP(hce->hfs_tot_size) -
 				hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
@@ -1805,7 +1829,7 @@
 
 		/* write out HFS boot block */
 		if (mac_boot.name)
-			write_one_file(mac_boot.name, mac_boot.size, outfile,
+			write_one_file(mac_boot.name, mac_boot.size, outfile, jtfile,
 								mac_boot.off);
 	}
 #endif	/* APPLE_HYB */
@@ -1855,8 +1879,8 @@
  * Function to write the PVD for the disc.
  */
 static int
-pvd_write(outfile)
-	FILE	*outfile;
+pvd_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char		iso_time[17];
 	int		should_write;
@@ -1973,6 +1997,7 @@
 	}
 
 	/* if not a bootable cd do it the old way */
+	jtwrite(&vol_desc, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
@@ -1982,14 +2007,15 @@
  * Function to write the Extended PVD for the disc.
  */
 static int
-xpvd_write(outfile)
-	FILE	*outfile;
+xpvd_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
 	vol_desc.version[0] = 2;
 	vol_desc.file_structure_version[0] = 2;
 
 	/* if not a bootable cd do it the old way */
+	jtwrite(&vol_desc, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
@@ -1999,8 +2025,8 @@
  * Function to write the EVD for the disc.
  */
 static int
-evd_write(outfile)
-	FILE	*outfile;
+evd_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	struct iso_primary_descriptor evol_desc;
 
@@ -2012,6 +2038,7 @@
 	evol_desc.type[0] = (unsigned char) ISO_VD_END;
 	memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof (ISO_STANDARD_ID));
 	evol_desc.version[0] = 1;
+	jtwrite(&evol_desc, SECTOR_SIZE, 1, jtfile, 0, TRUE);
 	xfwrite(&evol_desc, SECTOR_SIZE, 1, outfile, 0, TRUE);
 	last_extent_written += 1;
 	return (0);
@@ -2021,8 +2048,8 @@
  * Function to write the version information for the disc.
  */
 static int
-vers_write(outfile)
-	FILE	*outfile;
+vers_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char		vers[SECTOR_SIZE+1];
 	int		X_ac;
@@ -2065,7 +2092,17 @@
 	}
 
 	cp[SECTOR_SIZE - 1] = '\0';
-	xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
+ 	/* Per default: keep privacy. Blackout the version and arguments. */
+	if(getenv("ISODEBUG"))
+    {
+		jtwrite(vers, SECTOR_SIZE, 1, jtfile, 0, TRUE);
+		xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
+    }
+	else
+    {
+		jtwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, jtfile, 0, TRUE);
+		xfwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, outfile, 0, TRUE);
+    }
 	last_extent_written += 1;
 	return (0);
 }
@@ -2136,13 +2173,16 @@
  * Function to write the path table for the disc.
  */
 static int
-pathtab_write(outfile)
-	FILE	*outfile;
+pathtab_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	/* Next we write the path tables */
+	jtwrite(path_table_l, path_blocks << 11, 1, jtfile, 0, FALSE);
 	xfwrite(path_table_l, path_blocks << 11, 1, outfile, 0, FALSE);
+	last_extent_written += path_blocks;
+	jtwrite(path_table_m, path_blocks << 11, 1, jtfile, 0, FALSE);
 	xfwrite(path_table_m, path_blocks << 11, 1, outfile, 0, FALSE);
-	last_extent_written += 2 * path_blocks;
+	last_extent_written += path_blocks;
 	free(path_table_l);
 	free(path_table_m);
 	path_table_l = NULL;
@@ -2151,9 +2191,10 @@
 }
 
 static int
-exten_write(outfile)
-	FILE	*outfile;
+exten_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
+	jtwrite(extension_record, SECTOR_SIZE, 1, jtfile, 0, FALSE);
 	xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
 	last_extent_written++;
 	return (0);
@@ -2309,24 +2350,24 @@
 }
 
 static int
-dirtree_write(outfile)
-	FILE	*outfile;
+dirtree_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
-	generate_iso9660_directories(root, outfile);
+	generate_iso9660_directories(root, outfile, jtfile);
 	return (0);
 }
 
 static int
-dirtree_cleanup(outfile)
-	FILE	*outfile;
+dirtree_cleanup(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	free_directories(root);
 	return (0);
 }
 
 static int
-startpad_write(outfile)
-	FILE	*outfile;
+startpad_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	i;
@@ -2337,16 +2378,17 @@
 	npad = session_start + 16 - last_extent_written;
 
 	for (i = 0; i < npad; i++) {
+		jtwrite(buffer, sizeof (buffer), 1, jtfile, 0, FALSE);
 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
+        last_extent_written++;
 	}
 
-	last_extent_written += npad;
 	return (0);
 }
 
 static int
-interpad_write(outfile)
-	FILE	*outfile;
+interpad_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	i;
@@ -2361,16 +2403,17 @@
 		npad += 16 - i;
 
 	for (i = 0; i < npad; i++) {
+		jtwrite(buffer, sizeof (buffer), 1, jtfile, 0, FALSE);
 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
+        last_extent_written++;
 	}
 
-	last_extent_written += npad;
 	return (0);
 }
 
 static int
-endpad_write(outfile)
-	FILE	*outfile;
+endpad_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	i;
@@ -2378,10 +2421,11 @@
 	memset(buffer, 0, sizeof (buffer));
 
 	for (i = 0; i < 150; i++) {
+		jtwrite(buffer, sizeof (buffer), 1, jtfile, 0, FALSE);
 		xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
+        last_extent_written++;
 	}
 
-	last_extent_written += 150;
 	return (0);
 }
 
@@ -2713,8 +2757,8 @@
  *	hfs_hce_write:	write out the HFS header stuff
  */
 static int
-hfs_hce_write(outfile)
-	FILE	*outfile;
+hfs_hce_write(outfile, jtfile)
+	FILE	*outfile, *jtfile;
 {
 	char	buffer[SECTOR_SIZE];
 	int	n = 0;
@@ -2737,10 +2781,12 @@
 	r = tot_size % HFS_BLK_CONV;
 
 	/* write out HFS volume header info */
+	jtwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, jtfile, 0, FALSE);
 	xfwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, outfile, 0, FALSE);
 
 	/* fill up to a complete CD block */
 	if (r) {
+		jtwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, jtfile, 0, FALSE);
 		xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
 		n++;
 	}
