--- genisoimage/diag/isoinfo.c
+++ genisoimage/diag/isoinfo.c
@@ -11,6 +11,7 @@
  */
 
 /* @(#)isoinfo.c	1.50 05/05/15 joerg */
+/* Parts from @(#)isoinfo.c	1.63 08/08/25 joerg */
 /*
  * File isodump.c - dump iso9660 directory information.
  *
@@ -618,7 +619,7 @@
 	sprintf(outline+48, "%4d", date_buf[0]+1900);
 
 	sprintf(outline+53, "[%7d", extent);	/* XXX up to 20 GB */
-	sprintf(outline+61, " %02X]", idr->flags[0]);
+	sprintf(outline+61, " %02X]", idr->flags[0] & 0xFF);
 
 	for (i = 0; i < 66; i++) {
 		if (outline[i] == 0) outline[i] = ' ';
@@ -663,6 +664,9 @@
 	int		i;
 	struct iso_directory_record * idr;
 	unsigned char	uh, ul, uc, *up;
+	unsigned char	flags = 0;
+	Llong		size = 0;
+	int		sextent = 0;
 
 
 	if (do_listing)
@@ -776,8 +780,27 @@
 				strcat(testname, name_buf);
 				printf("%s\n", testname);
 			}
-			if (do_listing)
-				dump_stat(idr, isonum_733((unsigned char *)idr->extent));
+			if (do_listing) {
+				if ((idr->flags[0] & ISO_MULTIEXTENT) && size == 0)
+					sextent = isonum_733((unsigned char *)idr->extent);
+				if (debug ||
+				    ((idr->flags[0] & ISO_MULTIEXTENT) == 0 && size == 0)) {
+					dump_stat(idr, isonum_733((unsigned char *)idr->extent));
+				}
+				size += fstat_buf.st_size;
+				if ((flags & ISO_MULTIEXTENT) &&
+				    (idr->flags[0] & ISO_MULTIEXTENT) == 0) {
+					fstat_buf.st_size = size;
+					if (!debug)
+						idr->flags[0] |= ISO_MULTIEXTENT;
+					dump_stat(idr, sextent);
+					if (!debug)
+						idr->flags[0] &= ~ISO_MULTIEXTENT;
+				}
+				flags = idr->flags[0];
+				if ((idr->flags[0] & ISO_MULTIEXTENT) == 0)
+					size = 0;
+			}
 			i += buffer[i];
 			if (i > 2048 - offsetof(struct iso_directory_record, name[0])) break;
 		}
--- genisoimage/genisoimage.1
+++ genisoimage/genisoimage.1
@@ -189,12 +189,14 @@
 file.
 .TP
 .B \-allow\-limited\-size
-When processing files larger than 2GiB which cannot be easily represented in
-ISO9660, add them with a shrunk visible file size to ISO9660 and with the
+When processing files larger than 2GiB which cannot be represented in
+ISO9660 level 1 or 2, add them with a shrunk visible file size to ISO9660 and with the
 correct visible file size to the UDF system. The result is an inconsistent
 filesystem and users need to make sure that they really use UDF rather than
 ISO9660 driver to read a such disk. Implies enabling
 .BR \-udf.
+See also
+.BR \-iso\-level\ 3
 .TP
 .B \-allow\-leading\-dots
 .TP
@@ -685,6 +687,8 @@
 With level 2, files may only consist of one section.
 .IP
 With level 3, no restrictions (other than ISO-9660:1988) do apply.
+Starting with this level, genisoimage also allows files to be larger than 4 GB
+by implementing ISO-9660 multi-extent files.
 .IP
 With all ISO9660 levels from 1 to 3, all filenames are restricted to
 uppercase letters, numbers and underscores (_). Filenames are
@@ -2792,7 +2796,7 @@
 Copyright 1996-1997 by Robert Leslie
 Copyright 1997-2001 by James Pearson
 Copyright 1999-2006 by J\(:org Schilling
-Copyright 2007 by J\(:org Schilling (originating few updates)
+Copyright 2007-2008 by J\(:org Schilling (originating few updates)
 Copyright 2002-2003 by Jungshik Shin
 Copyright 2003 by Jaakko Heinonen
 Copyright 2006 by the Cdrkit maintainers
--- genisoimage/genisoimage.c
+++ genisoimage/genisoimage.c
@@ -19,6 +19,7 @@
 */
 /* @(#)mkisofs.c	1.167 06/01/30 joerg */
 /* Parts from @(#)mkisofs.c	1.206 07/02/26 joerg */
+/* Parts from @(#)mkisofs.c	1.238 08/06/13 joerg */
 /*
  * Program genisoimage.c - generate iso9660 filesystem  based upon directory
  * tree on hard disk.
@@ -189,6 +190,8 @@
 int	no_rr = 0;		/* Do not use RR attributes from old session */
 int	force_rr = 0;		/* Force to use RR attributes from old session */
 Uint	RR_relocation_depth = 6; /* Violates iso9660, but most systems work */
+int	do_largefiles = 0;	/* Whether to allow multi-extent files */
+off_t	maxnonlarge = (off_t)0xFFFFFFFF;
 int	iso9660_level = 1;
 int	iso9660_namelen = LEN_ISONAME; /* 31 characters, may be set to 37 */
 int	full_iso9660_filenames = 0; /* Full 31 character iso9660 filenames */
@@ -1388,6 +1391,7 @@
 				/*
 				 * No restrictions
 				 */
+				do_largefiles++;
 				break;
 			case 4:
 				/*
@@ -1406,6 +1410,7 @@
 				relaxed_filenames++;		/* all chars	*/
 				allow_lowercase++;		/* even lowcase	*/
 				allow_multidot++;		/* > 1 dots	*/
+				do_largefiles++;
 				break;
 
 			default:
@@ -2718,6 +2723,11 @@
 		exit(1);
 #endif
 	}
+	if (apple_hyb) {
+		if (do_largefiles) printf("Warning: cannot support large files with -hfs\n");
+		do_largefiles = 0;
+		maxnonlarge = (off_t)0x7FFFFFFF;
+	}
 	if (apple_hyb && use_genboot) {
 #ifdef	USE_LIBSCHILY
 		comerrno(EX_BAD, "Can't have -hfs with -generic-boot\n");
--- genisoimage/genisoimage.h
+++ genisoimage/genisoimage.h
@@ -11,6 +11,7 @@
  */
 
 /* @(#)genisoimage.h	1.95 05/05/01 joerg */
+/* Parts from @(#)      1.132 08/08/06 joerg */
 /*
  * Header file genisoimage.h - assorted structure definitions and typecasts.
  *
@@ -60,8 +61,7 @@
 #endif
 #endif
 
-/*#if	_LFS_LARGEFILE*/
-#ifdef	HAVE_LARGEFILES
+#ifdef	USE_LARGEFILES
 /*
  * XXX Hack until fseeko()/ftello() are available everywhere or until
  * XXX we know a secure way to let autoconf ckeck for fseeko()/ftello()
@@ -106,6 +106,9 @@
 	struct iso_directory_record isorec;
 	unsigned int	starting_block;
 	off_t		size;
+#ifdef	USE_LARGEFILES
+	int		mxpart;		/* Extent number	  */
+#endif
 	unsigned short	priority;
 	unsigned char	jreclen;	/* Joliet record len */
 	char		*name;
@@ -113,6 +116,7 @@
 	char		*whole_name;
 	struct directory *filedir;
 	struct directory_entry *parent_rec;
+	struct directory_entry *mxroot;	/* Pointer to orig entry */
 	unsigned int	de_flags;
 	ino_t		inode;		/* Used in the hash table */
 	dev_t		dev;		/* Used in the hash table */
@@ -364,6 +368,8 @@
 extern int	no_rr;
 extern int	transparent_compression;
 extern Uint	RR_relocation_depth;
+extern int	do_largefiles;
+extern off_t	maxnonlarge;
 extern int	iso9660_level;
 extern int	iso9660_namelen;
 extern int	full_iso9660_filenames;
@@ -447,6 +453,8 @@
 extern int	insert_file_entry(struct directory *, char *, char *);
 #endif	/* APPLE_HYB */
 
+extern	struct directory_entry *
+		dup_directory_entry	__PR((struct directory_entry *s_entry));
 extern void generate_iso9660_directories(struct directory *, FILE *);
 extern void dump_tree(struct directory * node);
 extern struct directory_entry *
@@ -749,6 +757,8 @@
 #define	MEMORY_FILE		   0x80		/* de_flags only  */
 #define	HIDDEN_FILE		   0x100	/* de_flags only  */
 #define	DIR_WAS_SCANNED		   0x200	/* dir_flags only */
+#define	MULTI_EXTENT		   0x1000	/* de_flags only  */
+#define	INHIBIT_UDF_ENTRY	   0x2000
 
 /*
  * Volume sequence number to use in all of the iso directory records.
--- genisoimage/iso9660.h
+++ genisoimage/iso9660.h
@@ -10,7 +10,7 @@
  *
  */
 
-/* @(#)iso9660.h	1.19 04/03/02 joerg */
+/* @(#)iso9660.h	1.21 07/07/26 joerg */
 /*
  * Header file iso9660.h - assorted structure definitions and typecasts.
  * specific to iso9660 filesystem.
@@ -18,7 +18,7 @@
  * Written by Eric Youngdale (1993).
  *
  * Copyright 1993 Yggdrasil Computing, Incorporated
- * Copyright (c) 1999,2000-2004 J. Schilling
+ * Copyright (c) 1999,2000-2008 J. Schilling
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -231,7 +231,7 @@
 	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)];
+	unsigned 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 */
--- genisoimage/joliet.c
+++ genisoimage/joliet.c
@@ -11,6 +11,7 @@
  */
 
 /* @(#)joliet.c	1.38 05/05/01 joerg */
+/* Parts from  @(#)joliet.c>1.54 07/10/20 joerg */
 /*
  * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660.
  *
@@ -507,7 +508,9 @@
 			}
 		}
 		/* skip if hidden - but not for the rr_moved dir */
-		if (dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) {
+		if (dpnt->subdir &&
+		    ((dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ||
+		    dpnt == reloc_dir)) {
 			assign_joliet_directory_addresses(dpnt->subdir);
 		}
 		dpnt = dpnt->next;
@@ -643,6 +646,7 @@
 	char		*npnt;
 	char		*npnt1;
 	int		tablesize;
+	unsigned int	jpindex;
 
 	/* First allocate memory for the tables and initialize the memory */
 	tablesize = jpath_blocks << 11;
@@ -723,10 +727,10 @@
 		set_732(jpath_table_m + jpath_table_index, dpnt->jextent);
 		jpath_table_index += 4;
 
-		if (dpnt->parent->jpath_index > 0xffff) {
+
+		if (dpnt->parent != reloc_dir) {
 #ifdef	USE_LIBSCHILY
-			comerrno(EX_BAD,
-			"Unable to generate sane path tables - too many directories (%d)\n",
+			set_721(jpath_table_l + jpath_table_index,
 				dpnt->parent->jpath_index);
 #else
 			fprintf(stderr,
@@ -734,18 +738,31 @@
 				dpnt->parent->jpath_index);
 			exit(1);
 #endif
-		}
-
-		if (dpnt->parent != reloc_dir) {
-			set_721(jpath_table_l + jpath_table_index,
-				dpnt->parent->jpath_index);
 			set_722(jpath_table_m + jpath_table_index,
 				dpnt->parent->jpath_index);
+			jpindex = dpnt->parent->jpath_index;
 		} else {
 			set_721(jpath_table_l + jpath_table_index,
 				dpnt->self->parent_rec->filedir->jpath_index);
 			set_722(jpath_table_m + jpath_table_index,
 				dpnt->self->parent_rec->filedir->jpath_index);
+			jpindex = dpnt->self->parent_rec->filedir->jpath_index;
+		}
+
+		if (jpindex > 0xffff) {
+			static int warned = 0;
+
+			if (!warned) {
+				warned++;
+				errmsgno(EX_BAD,
+			"Unable to generate sane Joliet path tables - too many directories (%u)\n",
+					jpindex);
+			}
+			/*
+			 * Let it point to the root directory instead.
+			 */
+			set_721(jpath_table_l + jpath_table_index, 1);
+			set_722(jpath_table_m + jpath_table_index, 1);
 		}
 
 		jpath_table_index += 2;
@@ -1149,18 +1166,25 @@
 	/*
 	 * If the entries are the same, this is an error.
 	 * Joliet specs allow for a maximum of 64 characters.
+	 * If we see different multi extent parts, it is OK to
+	 * have the same name more than once.
 	 */
 	if (strncmp(rpnt, lpnt, jlen) == 0) {
+#ifdef USE_LARGEFILES
+		if ((*r)->mxpart == (*l)->mxpart)
+#endif
+		{
 #ifdef	USE_LIBSCHILY
-		errmsgno(EX_BAD,
-			"Error: %s and %s have the same Joliet name\n",
-			(*r)->whole_name, (*l)->whole_name);
+			errmsgno(EX_BAD,
+				"Error: %s and %s have the same Joliet name\n",
+				(*r)->whole_name, (*l)->whole_name);
 #else
-		fprintf(stderr,
-			"Error: %s and %s have the same Joliet name\n",
-			(*r)->whole_name, (*l)->whole_name);
+			fprintf(stderr,
+				"Error: %s and %s have the same Joliet name\n",
+				(*r)->whole_name, (*l)->whole_name);
 #endif
-		jsort_goof++;
+			jsort_goof++;
+		}
 	}
 	/*
 	 * Put the '.' and '..' entries on the head of the sorted list.
@@ -1253,6 +1277,15 @@
 		return (1);
 	if (*lpnt)
 		return (-1);
+#ifdef USE_LARGEFILES
+	/*
+	 * (*r)->mxpart == (*l)->mxpart cannot happen here
+	 */
+	if ((*r)->mxpart < (*l)->mxpart)
+		return (-1);
+	else if ((*r)->mxpart > (*l)->mxpart)
+		return (1);
+#endif
 	return (0);
 }
 
@@ -1275,8 +1308,11 @@
 
 	s_entry = *sort_dir;
 	while (s_entry) {
-		/* skip hidden entries */
-		if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY))
+		/*
+		 * only colletc non-hidden entries
+		 */
+		if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
+					(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY))
 			dcount++;
 		s_entry = s_entry->next;
 	}
@@ -1288,8 +1324,11 @@
 	dcount = 0;
 	s_entry = *sort_dir;
 	while (s_entry) {
-	/* skip hidden entries */
-		if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) {
+		/*
+		 * only collect non-hidden entries
+		 */
+		if ((s_entry->de_flags & (INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) !=
+					(INHIBIT_JOLIET_ENTRY|INHIBIT_UDF_ENTRY)) {
 			sortlist[dcount] = s_entry;
 			dcount++;
 		}
--- genisoimage/multi.c
+++ genisoimage/multi.c
@@ -11,6 +11,7 @@
  */
 
 /* @(#)multi.c	1.68 05/05/15 joerg */
+/* Parts from @(#)multi.c	1.88 08/08/28 joerg */
 /*
  * File multi.c - scan existing iso9660 image and merge into
  * iso9660 filesystem.  Used for multisession support.
@@ -90,6 +91,9 @@
 static	void	free_directory_entry(struct directory_entry * dirp);
 static	void	merge_remaining_entries(struct directory *,
 													struct directory_entry **, int);
+LOCAL	int	iso_dir_ents	__PR((struct directory_entry *de));
+LOCAL	void	copy_mult_extent __PR((struct directory_entry *se1,
+					struct directory_entry *se2));
 
 static	int	merge_old_directory_into_tree(struct directory_entry *,
 															struct directory *);
@@ -586,6 +590,8 @@
 	int		len;
 	int		nbytes;
 	int		nent;
+	int		nmult;		/* # of multi extent root entries */
+	int		mx;
 	struct directory_entry **pnt;
 	int		rlen;
 	struct directory_entry **rtn;
@@ -620,6 +626,8 @@
 	i = 0;
 	*nentp = 0;
 	nent = 0;
+	nmult = 0;
+	mx = 0;
 	while (i < len) {
 		idr = (struct iso_directory_record *) & dirbuff[i];
 		if (idr->length[0] == 0) {
@@ -627,14 +635,20 @@
 			continue;
 		}
 		nent++;
+		if ((mx & ISO_MULTIEXTENT) == 0 &&
+		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
+			nmult++;	/* Need a multi extent root entry */
+		}
+		mx = idr->flags[0];
 		i += idr->length[0];
 	}
 
 	/*
 	 * Now allocate the buffer which will hold the array we are about to
-	 * return.
+	 * return. We need one entry per real directory entry and in addition
+	 * one multi-extent root entry per multi-extent file.
 	 */
-	rtn = (struct directory_entry **) e_malloc(nent * sizeof (*rtn));
+	rtn = (struct directory_entry **) e_malloc((nent+nmult) * sizeof (*rtn));
 
 	/*
 	 * Finally, scan the directory one last time, and pick out the relevant
@@ -646,6 +660,7 @@
 	tt_extent = 0;
 	seen_rockridge = 0;
 	tt_size = 0;
+	mx = 0;
 	while (i < len) {
 		idr = (struct iso_directory_record *) & dirbuff[i];
 		if (idr->length[0] == 0) {
@@ -790,7 +805,52 @@
 			if (tt_extent == 0)
 				tt_size = 0;
 		}
+		/*
+		 * The beginning of a new multi extent directory chain is when
+		 * the last directory had no ISO_MULTIEXTENT flag set and the
+		 * current entry did set ISO_MULTIEXTENT.
+		 */
+		if ((mx & ISO_MULTIEXTENT) == 0 &&
+		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
+			struct directory_entry		*s_entry;
+			struct iso_directory_record	*idr2 = idr;
+			int				i2 = i;
+			off_t				tsize = 0;
+
+			/*
+			 * Sum up the total file size for the multi extent file
+			 */
+			while (i2 < len) {
+				idr2 = (struct iso_directory_record *) &dirbuff[i2];
+
+				tsize += get_733(idr2->size);
+				if ((idr2->flags[0] & ISO_MULTIEXTENT) == 0)
+					break;
+				i2 += idr2->length[0];
+			}
+
+			s_entry = dup_directory_entry(*pnt);	/* dup first for mxroot */
+			s_entry->de_flags |= MULTI_EXTENT;
+			s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
+			s_entry->size = tsize;
+			s_entry->starting_block = (*pnt)->starting_block;
+			s_entry->mxroot = s_entry;
+			s_entry->mxpart = 0;
+			s_entry->next = *pnt;	/* Next in list		*/
+			pnt[1] = pnt[0];	/* Move to next slot	*/
+			*pnt = s_entry;		/* First slot is mxroot	*/
+			pnt++;			/* Point again to cur.	*/
+		}
+		if ((mx & ISO_MULTIEXTENT) != 0 ||
+		    (idr->flags[0] & ISO_MULTIEXTENT) != 0) {
+			(*pnt)->de_flags |= MULTI_EXTENT;
+			(*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
+			(pnt[-1])->next = *pnt;
+			(*pnt)->mxroot = (pnt[-1])->mxroot;
+			(*pnt)->mxpart = (pnt[-1])->mxpart + 1;
+		}
 		pnt++;
+		mx = idr->flags[0];
 		i += idr->length[0];
 	}
 #ifdef APPLE_HYB
@@ -814,6 +874,10 @@
 					 * in the Joliet tree
 					 */
 					(*pnt)->de_flags |= INHIBIT_JOLIET_ENTRY;
+					/*
+					 * XXX Is it correct to exclude UDF too?
+					 */
+					(*pnt)->de_flags |= INHIBIT_UDF_ENTRY;
 
 					/*
 					 * as we have associated files, then
@@ -927,7 +991,7 @@
 	if (dirbuff != NULL) {
 		free(dirbuff);
 	}
-	*nentp = nent;
+	*nentp = nent + nmult;
 	return (rtn);
 }/* read_merging_directory */
 
@@ -989,7 +1053,7 @@
 {
 	int		i;
 	int		rr;
-	int		retcode = 0;	/* Default not found */
+	int		retcode = -2;	/* Default not found */
 
 	for (i = 0; i < len; i++) {
 		if (ptr[i] == NULL) {	/* Used or empty entry skip */
@@ -1024,7 +1088,7 @@
 		 * in tree.c for an explaination of why this must be the case.
 		 */
 		if ((curr_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
-			retcode = 2;	/* Flag directory case */
+			retcode = i;
 			goto found_it;
 		}
 		/*
@@ -1037,7 +1101,7 @@
 		 * we probably have a different file, and we need to write it
 		 * out again.
 		 */
-		retcode = 1;	/* We found a non directory */
+		retcode = i;
 
 		if (ptr[i]->rr_attributes != NULL) {
 			if ((rr = check_rr_dates(ptr[i], curr_entry, statbuf,
@@ -1066,11 +1130,24 @@
 		memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8);
 		curr_entry->starting_block = isonum_733((unsigned char *)ptr[i]->isorec.extent);
 		curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+
+		if ((curr_entry->isorec.flags[0] & ISO_MULTIEXTENT) ||
+		    (ptr[i]->isorec.flags[0] & ISO_MULTIEXTENT)) {
+			copy_mult_extent(curr_entry, ptr[i]);
+		}
 		goto found_it;
 	}
 	return (retcode);
 
 found_it:
+	if (ptr[i]->mxroot == ptr[i]) {	/* Remove all multi ext. entries   */
+		int	j = i + 1;	/* First one will be removed below */
+
+		while (j < len && ptr[j] && ptr[j]->mxroot == ptr[i]) {
+			free(ptr[j]);
+			ptr[j++] = NULL;
+		}
+	}
 	if (odpnt != NULL) {
 		*odpnt = ptr[i];
 	} else {
@@ -1081,6 +1158,106 @@
 }
 
 /*
+ * Return the number of directory entries for a file. This is usually 1
+ * but may be 3 or more in case of multi extent files.
+ */
+LOCAL int
+iso_dir_ents(de)
+	struct directory_entry	*de;
+{
+	struct directory_entry	*de2;
+	int	ret = 0;
+
+	if (de->mxroot == NULL)
+		return (1);
+	de2 = de;
+	while (de2 != NULL && de2->mxroot == de->mxroot) {
+		ret++;
+		de2 = de2->next;
+	}
+	return (ret);
+}
+
+/*
+ * Copy old multi-extent directory information from the previous session.
+ * If both the old session and the current session are created by genisoimage
+ * then this code could be extremely simple as the information is only copied
+ * in case that the file did not change since the last session was made.
+ * As we don't know the other ISO formatter program, any combination of
+ * multi-extent files and even a single extent file could be possible.
+ * We need to handle all files the same way ad the old session was created as
+ * we reuse the data extents from the file in the old session.
+ */
+LOCAL void
+copy_mult_extent(se1, se2)
+	struct directory_entry	*se1;
+	struct directory_entry	*se2;
+{
+	struct directory_entry	*curr_entry = se1;
+	int			len1;
+	int			len2;
+	int			mxpart = 0;
+
+	len1 = iso_dir_ents(se1);
+	len2 = iso_dir_ents(se2);
+
+	if (len1 == 1) {
+		/*
+		 * Convert single-extent to multi-extent.
+		 * If *se1 is not multi-extent, *se2 definitely is
+		 * and we need to set up a MULTI_EXTENT directory header.
+		 */
+		se1->de_flags |= MULTI_EXTENT;
+		se1->isorec.flags[0] |= ISO_MULTIEXTENT;
+		se1->mxroot = curr_entry;
+		se1->mxpart = 0;
+		se1 = dup_directory_entry(se1);
+		curr_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
+		se1->de_flags |= INHIBIT_UDF_ENTRY;
+		se1->next = curr_entry->next;
+		curr_entry->next = se1;
+		se1 = curr_entry;
+		len1 = 2;
+	}
+
+	while (se2->isorec.flags[0] & ISO_MULTIEXTENT) {
+		len1--;
+		len2--;
+		if (len1 <= 0) {
+			struct directory_entry *sex = dup_directory_entry(se1);
+
+			sex->mxroot = curr_entry;
+			sex->next = se1->next;
+			se1->next = sex;
+			len1++;
+		}
+		memcpy(se1->isorec.extent, se2->isorec.extent, 8);
+		se1->starting_block = get_733(se2->isorec.extent);
+		se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+		se1->de_flags |= MULTI_EXTENT;
+		se1->isorec.flags[0] |= ISO_MULTIEXTENT;
+		se1->mxroot = curr_entry;
+		se1->mxpart = mxpart++;
+
+		se1 = se1->next;
+		se2 = se2->next;
+	}
+	memcpy(se1->isorec.extent, se2->isorec.extent, 8);
+	se1->starting_block = get_733(se2->isorec.extent);
+	se1->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY;
+	se1->isorec.flags[0] &= ~ISO_MULTIEXTENT;	/* Last entry */
+	se1->mxpart = mxpart;
+	while (len1 > 1) {				/* Drop other entries */
+		struct directory_entry	*sex;
+
+		sex = se1->next;
+		se1->next = sex->next;
+		free(sex);	
+		len1--;
+	}
+}
+
+/*
  * open_merge_image:  Open an existing image.
  */
 int
@@ -1631,6 +1808,19 @@
 			    &statbuf, &lstatbuf, NULL);
 			if (retcode == -1)
 				return (-1);
+			/*
+			 * Skip other directory entries for multi-extent files
+			 */
+			if (s_entry->de_flags & MULTI_EXTENT) {
+				struct directory_entry	*s_e;
+
+				for (s_e = s_entry->mxroot;
+					s_e && s_e->mxroot == s_entry->mxroot;
+						s_e = s_e->next) {
+					s_entry = s_e;
+					;
+				}
+			}
 		}
 		merge_remaining_entries(this_dir, orig_contents, n_orig);
 
@@ -1682,14 +1872,14 @@
 		 * The check_prev_session function looks for an identical
 		 * entry in the previous session.  If we see it, then we copy
 		 * the extent number to s_entry, and cross it off the list.
-		 * It returns 2 if it's a directory
 		 */
 		retcode = check_prev_session(orig_contents, n_orig, s_entry,
 			&statbuf, &lstatbuf, &odpnt);
 		if (retcode == -1)
 			return (-1);
 
-		if (retcode == 2 && odpnt != NULL) {
+		if (odpnt != NULL &&
+		    (s_entry->isorec.flags[0] & ISO_DIRECTORY) != 0) {
 			int	dflag;
 
 			if (strcmp(s_entry->name, ".") != 0 &&
@@ -1718,6 +1908,23 @@
 				odpnt = NULL;
 			}
 		}
+		if (odpnt) {
+			free(odpnt);
+			odpnt = NULL;
+		}
+		/*
+		 * Skip other directory entries for multi-extent files
+		 */
+		if (s_entry->de_flags & MULTI_EXTENT) {
+			struct directory_entry	*s_e;
+
+			for (s_e = s_entry->mxroot;
+				s_e && s_e->mxroot == s_entry->mxroot;
+					s_e = s_e->next) {
+				s_entry = s_e;
+				;
+			}
+		}
 	}
 
 	if (!reloc_old_root) {
--- genisoimage/tree.c
+++ genisoimage/tree.c
@@ -11,6 +11,7 @@
  */
 
 /* @(#)tree.c	1.82 04/06/12 joerg */
+/* Parets from @(#)tree.c	1.112 08/08/14 joerg */
 /*
  * File tree.c - scan directory  tree and build memory structures for iso9660
  * filesystem
@@ -101,6 +102,8 @@
 						struct stat* stat_template);
 static	void	delete_directory(struct directory *parent,
 										  struct directory *child);
+EXPORT	struct directory_entry *
+		dup_directory_entry	__PR((struct directory_entry *s_entry));
 int	sort_tree(struct directory *node);
 void	dump_tree(struct directory *node);
 void	update_nlink_field(struct directory *node);
@@ -292,6 +295,17 @@
 	flush_file_hash();
 	s_entry = this_dir->contents;
 	while (s_entry) {
+#ifdef	USE_LARGEFILES
+		/*
+		 * Skip all but the last extent from a multi extent file,
+		 * we like them all have the same name.
+		 */
+		if ((s_entry->de_flags & MULTI_EXTENT) &&
+		    (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)) {
+			s_entry = s_entry->next;
+			continue;
+		}
+#endif
 		/* ignore if it's hidden */
 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
 			s_entry = s_entry->next;
@@ -438,6 +452,7 @@
 					this_dir->whole_name, SPATH_SEPARATOR,
 					s_entry->name, s_entry1->name);
 			}
+
 			s_entry->isorec.name_len[0] = strlen(newname);
 			new_reclen = offsetof(struct iso_directory_record,
 				name[0]) +
@@ -451,6 +466,22 @@
 				new_reclen++;	/* Pad to an even byte */
 			s_entry->isorec.length[0] = new_reclen;
 			strcpy(s_entry->isorec.name, newname);
+#ifdef	USE_LARGEFILES
+			if (s_entry->de_flags & MULTI_EXTENT) {
+				struct directory_entry	*s_e;
+
+				/*
+				 * Copy over the new name to all other entries
+				 */
+				for (s_e = s_entry->mxroot;
+				    s_e && s_e->mxroot == s_entry->mxroot;
+							s_e = s_e->next) {
+					s_e->isorec.length[0] = new_reclen;
+					s_e->isorec.name_len[0] = s_entry->isorec.name_len[0];
+					strcpy(s_e->isorec.name, newname);
+				}
+			}
+#endif
 #ifdef APPLE_HYB
 			/* has resource fork - needs new name */
 			if (apple_both && s_entry->assoc) {
@@ -489,6 +520,22 @@
 				new_reclen++;	/* Pad to an even byte */
 			s_entry1->isorec.length[0] = new_reclen;
 			strcpy(s_entry1->isorec.name, newname);
+#ifdef	USE_LARGEFILES
+			if (s_entry1->de_flags & MULTI_EXTENT) {
+				struct directory_entry	*s_e;
+
+				/*
+				 * Copy over the new name to all other entries
+				 */
+				for (s_e = s_entry1->mxroot;
+				    s_e && s_e->mxroot == s_entry1->mxroot;
+							s_e = s_e->next) {
+					s_e->isorec.length[0] = new_reclen;
+					s_e->isorec.name_len[0] = s_entry1->isorec.name_len[0];
+					strcpy(s_e->isorec.name, newname);
+				}
+			}
+#endif
 			add_file_hash(s_entry1);
 #ifdef APPLE_HYB
 			/* has resource fork - needs new name */
@@ -562,6 +609,10 @@
 		table->filedir = this_dir;
 		if (jhide_trans_tbl)
 			table->de_flags |= INHIBIT_JOLIET_ENTRY;
+		/*
+		 * Always hide transtable from UDF tree.
+		 */
+		table->de_flags |= INHIBIT_UDF_ENTRY;
 /*		table->name = strdup("<translation table>");*/
 		table->name = strdup(trans_tbl);
 		/*
@@ -808,9 +859,12 @@
 	s_entry->next = root->contents;
 	reloc_dir->self = s_entry;
 
-	/* The rr_moved entry will not appear in the Joliet tree. */
+	/* The rr_moved entry will not appear in the Joliet nor the UDF tree. */
 	reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
 	s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+	
+	reloc_dir->dir_flags |= INHIBIT_UDF_ENTRY;
+	s_entry->de_flags |= INHIBIT_UDF_ENTRY;
 
 	/* Hiding RR_MOVED seems not to be possible..... */
 #ifdef	HIDE_RR
@@ -1551,14 +1605,14 @@
 		return (0);
 	}
 	/* print a warning but don't spam too much */
-	if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0xFFFFFFFF)) {
+	if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= maxnonlarge) && !do_largefiles) {
 		static int udf_warned;
 
 		if( !allow_limited_size || verbose>1)
 			fprintf(stderr, "File %s is larger than 4GiB-1.\n", whole_path);
 		if( !allow_limited_size)
 		{
-			fprintf(stderr, "-allow-limited-size was not specified. There is no way do represent this file size. Aborting.\n");
+			fprintf(stderr, "There is no way do represent this file size. Aborting. See -iso-level 3 or -allow-limited-size options\n");
 			exit(1);
 		}
 		if(verbose>=1 && ! udf_warned ) {
@@ -1773,6 +1827,20 @@
 			s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
 		}
 	}
+	if (this_dir != reloc_dir &&
+				this_dir->dir_flags & INHIBIT_UDF_ENTRY) {
+		s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+	} /* else if (strcmp(short_name, ".") != 0 &&
+		    strcmp(short_name, "..") != 0) {
+		if (u_matches(short_name) || u_matches(whole_path)) {
+			if (verbose > 1) {
+				fprintf(stderr,
+					"Hidden from UDF tree: %s\n",
+					whole_path);
+			}
+			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+		}
+	} */
 
 #ifdef SORTING
 	/* inherit any sort weight from parent directory */
@@ -1829,9 +1897,10 @@
 			s_entry->hfs_type = have_rsrc;
 			/*
 			 * don't want the rsrc file to be included in any
-			 * Joliet tree
+			 * Joliet/UDF tree
 			 */
 			s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
+			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
 		} else if (s_entry->next) {
 			/*
 			 * if previous entry is an associated file,
@@ -2161,8 +2230,10 @@
 			 * directory
 			 */
 			if (s_entry->hfs_ent &&
-				!(s_entry->de_flags & RELOCATED_DIRECTORY))
+			    !(s_entry->de_flags & RELOCATED_DIRECTORY) &&
+			    (s_entry->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
 				free(s_entry->hfs_ent);
+			}
 			s_entry->hfs_ent = NULL;
 		}
 		/*
@@ -2194,9 +2265,110 @@
 			&statbuf, &lstatbuf, deep_flag);
 
 	}
+
+#ifdef	USE_LARGEFILES
+#define	LARGE_EXTENT	0xFFFFF800UL
+#define	MAX_EXTENT	0xFFFFFFFEUL
+	/*
+	 * Break up files greater than (4GB -2) into multiple extents.
+	 * The original entry, with ->size untouched, remains for UDF.
+	 * Each of the new file sections will get its own entry.
+	 * The file sections are the only entries actually written out to the
+	 * disk. The UDF entry will use "mxroot" to get the same start
+	 * block as the first file section, and all the sections will end up
+	 * in the ISO9660 directory in the correct order by "mxpart",
+	 * which the directory sorting routine knows about.
+	 *
+	 * If we ever need to be able to find mxpart == 1 after sorting,
+	 * we need to add another pointer to s_entry or to be very careful
+	 * with the loops above where the ISO-9660 name is copied back to
+	 * all multi-extent parts.
+	 */
+	if (s_entry->size > MAX_EXTENT && do_largefiles) {
+		off_t	size;
+
+		s_entry->de_flags |= MULTI_EXTENT;
+		s_entry->isorec.flags[0] |= ISO_MULTIEXTENT;
+		s_entry->mxroot = s_entry;
+		s_entry->mxpart = 0;
+		set_733((char *)s_entry->isorec.size, LARGE_EXTENT);
+		s_entry1 = dup_directory_entry(s_entry);
+		s_entry->next = s_entry1;
+
+		/*
+		 * full size UDF version
+		 */
+		s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
+		if (s_entry->size > (((off_t)190)*0x3FFFF800)) {
+#ifndef	EOVERFLOW
+#define	EOVERFLOW	EFBIG
+#endif
+			errmsgno(EOVERFLOW,
+			"File %s is too large - hiding from UDF tree.\n",
+							whole_path);
+			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+		}
+
+		/*
+		 * Prepare the first file multi-extent section of the file.
+		 */
+		s_entry = s_entry1;
+		s_entry->de_flags |= INHIBIT_UDF_ENTRY;
+		size = s_entry->size;
+		s_entry->size = LARGE_EXTENT;
+		s_entry->mxpart++;
+
+		/*
+		 * Additional extents, as needed
+		 */
+		while (size > MAX_EXTENT) {
+			s_entry1 = dup_directory_entry(s_entry);
+			s_entry->next = s_entry1;
+
+			s_entry = s_entry1;
+			s_entry->mxpart++;
+			size -= LARGE_EXTENT;
+		}
+		/*
+		 * That was the last one.
+		 */
+		s_entry->isorec.flags[0] &= ~ISO_MULTIEXTENT;
+		s_entry->size = size;
+		set_733((char *)s_entry->isorec.size, (UInt32_t)s_entry->size);
+	}
+#endif /* USE_LARGEFILES */
+
 	return (1);
 }
 
+EXPORT struct directory_entry *
+dup_directory_entry(s_entry)
+	struct directory_entry	*s_entry;
+{
+	struct directory_entry	*s_entry1;
+
+	s_entry1 = (struct directory_entry *)
+		e_malloc(sizeof (struct directory_entry));
+	memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
+
+	if (s_entry->rr_attributes) {
+		s_entry1->rr_attributes =
+				e_malloc(s_entry->total_rr_attr_size);
+		memcpy(s_entry1->rr_attributes, s_entry->rr_attributes,
+					s_entry->total_rr_attr_size);
+	}
+	if (s_entry->name)
+		s_entry1->name = strdup(s_entry->name);
+	if (s_entry->whole_name)
+		s_entry1->whole_name = strdup(s_entry->whole_name);
+#ifdef	APPLE_HYB
+	/*
+	 * If we also duplicate s_entry->hfs_ent, we would need to change
+	 * free_one_directory() and other calls to free(s_entry->hfs_ent) too.
+	 */
+#endif
+	return (s_entry1);
+}
 
 void
 generate_iso9660_directories(struct directory *node, FILE *outfile)
--- genisoimage/udf.c
+++ genisoimage/udf.c
@@ -11,6 +11,7 @@
  */
 
 /* @(#)udf.c	1.14 04/04/15 Copyright 2001 J. Schilling */
+/* Parts from  @(#)udf.c	1.31 08/08/13 Copyright 2001-2007 J. Schilling */
 /*
  * udf.c - UDF support for genisoimage
  *
@@ -136,7 +137,7 @@
 
 	/* directory contents */
 	for (de = dpnt->jcontents; de; de = de->jnext) {
-		if (!(de->de_flags & INHIBIT_JOLIET_ENTRY)) {
+		if (!(de->de_flags & INHIBIT_UDF_ENTRY)) {
 			char *name = USE_MAC_NAME(de) ? de->hfs_ent->name : de->name;
 			/* skip . and .. */
 			if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
@@ -150,12 +151,12 @@
 static void
 assign_udf_directory_addresses(struct directory *dpnt)
 {
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY)) {
 		dpnt->self->udf_file_entry_sector = last_extent;
 		last_extent += 1 + ISO_BLOCKS(directory_size(dpnt));
 		++num_udf_directories;
 	}
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
 			assign_udf_directory_addresses(dpnt);
 		}
@@ -165,7 +166,7 @@
 static void
 assign_udf_file_entry_addresses(struct directory *dpnt)
 {
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY)) {
 		struct directory_entry *de;
 		for (de = dpnt->jcontents; de; de = de->jnext) {
 			if (!(de->de_flags & RELOCATED_DIRECTORY) &&
@@ -175,7 +176,7 @@
 			}
 		}
 	}
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
 			assign_udf_file_entry_addresses(dpnt);
 		}
@@ -654,6 +655,13 @@
 }
 
 static void
+udf_size_panic(int n)
+{
+	comerrno(EX_BAD,
+		"Panic: UDF file size error, too many extents (%d).\n", n);
+}
+
+static void
 set_file_entry(unsigned char *buf, unsigned rba, unsigned file_rba,
 					uint64_t length, const char *iso_date, int is_directory,
 					unsigned link_count, unsigned unique_id)
@@ -752,6 +760,18 @@
 		file_rba += chunk >> 11;
 		allocation_desc++;
 	}
+	if (((Uchar *)allocation_desc) > &buf[2048])
+		udf_size_panic(allocation_desc - &fe->allocation_desc);
+
+	if (((Uchar *)allocation_desc) > &buf[2048])
+		udf_size_panic(allocation_desc - &fe->allocation_desc);
+
+	if (((Uchar *)allocation_desc) > &buf[2048])
+		udf_size_panic(allocation_desc - &fe->allocation_desc);
+
+	if (((Uchar *)allocation_desc) > &buf[2048])
+		udf_size_panic(allocation_desc - &fe->allocation_desc);
+
 	set32(&fe->length_of_allocation_descs,
 				(unsigned char *) allocation_desc -
 				(unsigned char *) &fe->allocation_desc);
@@ -772,14 +792,14 @@
 	/* count relocated subdirectories */
 	for (de = dpnt->jcontents; de; de = de->jnext) {
 		if ((de->de_flags &
-		    (INHIBIT_JOLIET_ENTRY | RELOCATED_DIRECTORY)) ==
+		    (INHIBIT_UDF_ENTRY | RELOCATED_DIRECTORY)) ==
 							RELOCATED_DIRECTORY) {
 			link_count++;
 		}
 	}
 	/* count ordinary subdirectories */
 	for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
-		if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
+		if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY)) {
 			link_count++;
 		}
 	}
@@ -833,7 +853,7 @@
 		char *name;
 		struct directory_entry *de1;
 
-		if (de->de_flags & INHIBIT_JOLIET_ENTRY)
+		if (de->de_flags & INHIBIT_UDF_ENTRY)
 			continue;
 
 		name = USE_MAC_NAME(de) ? de->hfs_ent->name : de->name;
@@ -888,10 +908,10 @@
 static void
 write_udf_directories(struct directory *dpnt, FILE *outfile)
 {
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY)) {
 		write_one_udf_directory(dpnt, outfile);
 	}
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
 			write_udf_directories(dpnt, outfile);
 		}
@@ -905,7 +925,7 @@
 
 	memset(buf, 0, SECTOR_SIZE);
 
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY)) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY)) {
 		struct directory_entry *de;
 		for (de = dpnt->jcontents; de; de = de->jnext) {
 			if (!(de->de_flags & RELOCATED_DIRECTORY) &&
@@ -926,7 +946,7 @@
 			}
 		}
 	}
-	if (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir) {
+	if (!(dpnt->dir_flags & INHIBIT_UDF_ENTRY) || dpnt == reloc_dir) {
 		for (dpnt = dpnt->subdir; dpnt; dpnt = dpnt->next) {
 			write_udf_file_entries(dpnt, outfile);
 		}
--- genisoimage/write.c
+++ genisoimage/write.c
@@ -12,6 +12,7 @@
 
 /* @(#)write.c	1.88 06/02/01 joerg */
 /* Parts from @(#)write.c	1.106 07/02/17 joerg */
+/* Parts from @(#)write.c	1.117 07/12/16 joerg */
 /*
  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
  *
@@ -92,7 +93,7 @@
 void	xfwrite(void *buffer, int size, int count, FILE *file, int submode, 
 				  BOOL islast);
 static 	int	assign_directory_addresses(struct directory *node);
-#ifdef APPLE_HYB
+#if defined(APPLE_HYB) || defined(USE_LARGEFILES)
 static 	void	write_one_file(char *filename, off_t size, FILE *outfile, 
 										off_t off);
 #else
@@ -417,13 +418,13 @@
 	return (0);
 }
 
-#ifdef APPLE_HYB
+#if defined(APPLE_HYB) || defined(USE_LARGEFILES)
 static void
 write_one_file(char *filename, off_t size, FILE *outfile, off_t off)
 #else
 static void
 write_one_file(char *filename, off_t size, FILE *outfile)
-#endif	/* APPLE_HYB */
+#endif	/* APPLE_HYB || USE_LARGEFILES */
 {
 	/*
 	 * It seems that there are still stone age C-compilers
@@ -456,9 +457,9 @@
 		exit(1);
 #endif
 	}
-#ifdef APPLE_HYB
+#if defined(APPLE_HYB) || defined(USE_LARGEFILES)
 	fseek(infile, off, SEEK_SET);
-#endif	/* APPLE_HYB */
+#endif	/* APPLE_HYB || USE_LARGEFILES */
 	remain = size;
 
 	if (include_in_jigdo)
@@ -655,8 +656,18 @@
 		return (-1);
 #endif	/* APPLE_HYB */
 
-	/* If the entries are the same, this is an error. */
+	/*
+	 * If the names are the same, multiple extent sections of the same file
+	 * are sorted by part number.  If the part numbers do not differ, this
+	 * is an error.
+	 */
 	if (strcmp(rpnt, lpnt) == 0) {
+#ifdef USE_LARGEFILES
+		if ((*r)->mxpart < (*l)->mxpart)
+			return (-1);
+		else if ((*r)->mxpart > (*l)->mxpart)
+			return (1);
+#endif
 #ifdef	USE_LIBSCHILY
 		errmsgno(EX_BAD,
 			"Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
@@ -1065,11 +1076,10 @@
 		}
 #endif /* DVD_VIDEO */
 
-		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
+			 * 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.
@@ -1078,7 +1088,9 @@
 				continue;
 			}
 			/*
-			 * This saves some space if there are symlinks present
+			 * This saves some space if there are symlinks present.
+			 * If this is a multi-extent file, we get mxpart == 1
+			 * from find_hash().
 			 */
 			s_hash = find_hash(s_entry->dev, s_entry->inode);
 			if (s_hash) {
@@ -1091,6 +1103,36 @@
 						s_hash->starting_block);
 				set_733((char *) s_entry->isorec.size,
 						s_hash->size);
+#ifdef USE_LARGEFILES
+				if (s_entry->de_flags & MULTI_EXTENT) {
+					struct directory_entry *s_e;
+					unsigned int		ext = s_hash->starting_block;
+
+					/*
+					 * Skip the multi extent root entry.
+					 */
+					if (s_entry->mxpart == 0)
+						continue;
+					/*
+					 * The directory is sorted, so we should
+					 * see s_entry->mxpart == 1 first.
+					 */
+					if (s_entry->mxpart != 1) {
+						comerrno(EX_BAD,
+						"Panic: Multi extent parts for %s not sorted.\n",
+						s_entry->whole_name);
+					}
+					s_entry->mxroot->starting_block = ext;
+					for (s_e = s_entry;
+					    s_e && s_e->mxroot == s_entry->mxroot;
+								s_e = s_e->next) {
+						set_733((char *) s_e->isorec.extent,
+									ext);
+						ext += ISO_BLOCKS(s_e->size);
+					}
+				}
+#endif
+
 #ifdef SORTING
 				/* check for non-directory files */
 				if (do_sort && ((s_entry->isorec.flags[0] & ISO_DIRECTORY) == 0)) {
@@ -1247,8 +1289,54 @@
 				set_733((char *) s_entry->isorec.extent,
 								last_extent);
 				s_entry->starting_block = last_extent;
+#ifdef USE_LARGEFILES
+				/*
+				 * Update the entries for multi-section files
+				 * as we now know the starting extent numbers.
+				 */
+				if (s_entry->de_flags & MULTI_EXTENT) {
+					struct directory_entry *s_e;
+					unsigned int		ext = last_extent;
+
+					/*
+					 * Skip the multi extent root entry.
+					 */
+					if (s_entry->mxpart == 0)
+						continue;
+					/*
+					 * The directory is sorted, so we should
+					 * see s_entry->mxpart == 1 first.
+					 */
+					if (s_entry->mxpart != 1) {
+						comerrno(EX_BAD,
+						"Panic: Multi extent parts for %s not sorted.\n",
+						s_entry->whole_name);
+					}
+					dwpnt->size = s_entry->mxroot->size;
+					s_entry->mxroot->starting_block = ext;
+					/*
+					 * Set the mxroot (mxpart == 0) to allow
+					 * the UDF code to fetch the starting
+					 * extent number.
+					 */
+					set_733((char *) s_entry->mxroot->isorec.extent, ext);
+					for (s_e = s_entry;
+					    s_e && s_e->mxroot == s_entry->mxroot;
+								s_e = s_e->next) {
+						if (s_e->mxpart == 0)
+							continue;
+						set_733((char *) s_e->isorec.extent,
+									ext);
+						ext += ISO_BLOCKS(s_e->size);
+					}
+					add_hash(s_entry);
+				}
+#endif
 				add_hash(s_entry);
-				last_extent += ISO_BLOCKS(s_entry->size);
+				/*
+				 * The cache holds the full size of the file
+				 */
+				last_extent += ISO_BLOCKS(dwpnt->size);
 #ifdef DVD_VIDEO
 				/* Shouldn't we always add the pad info? */
 				if (dvd_video) {
@@ -1343,8 +1431,10 @@
 			s_entry_d->whole_name = NULL;
 		}
 #ifdef APPLE_HYB
-		if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc)
+		if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc &&
+		    (s_entry_d->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
 			free(s_entry_d->hfs_ent);
+		}
 #endif	/* APPLE_HYB */
 
 		free(s_entry_d);
