patch genisoimage multi extent
authorErwan Le Blond <erwan.LEBLOND@eurogiciel.fr>
Tue, 5 Mar 2013 17:32:30 +0000 (18:32 +0100)
committerErwan Le Blond <erwan.LEBLOND@eurogiciel.fr>
Tue, 5 Mar 2013 17:32:30 +0000 (18:32 +0100)
genisoimage/diag/isoinfo.c
genisoimage/genisoimage.1
genisoimage/genisoimage.c
genisoimage/genisoimage.h
genisoimage/iso9660.h
genisoimage/joliet.c
genisoimage/multi.c
genisoimage/tree.c
genisoimage/udf.c
genisoimage/write.c

index 55396c2..07720c6 100644 (file)
@@ -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 @@ dump_stat(struct iso_directory_record *idr, int extent)
        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 @@ parse_dir(char *rootname, int extent, int len)
        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 @@ parse_dir(char *rootname, int extent, int len)
                                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;
                }
index d05b24a..f5473db 100644 (file)
@@ -189,12 +189,14 @@ in the
 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 @@ restricted to 8.3 characters.
 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
@@ -2800,7 +2804,7 @@ Copyright 1993-1998 by Yggdrasil Computing, Inc.
 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
index 46f0cb7..2008e73 100644 (file)
@@ -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 omit_version_number = 0; /* May violate iso9660, but noone uses vers */
 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 */
@@ -1395,6 +1398,7 @@ int main(int argc, char *argv[])
                                /*
                                 * No restrictions
                                 */
+                               do_largefiles++;
                                break;
                        case 4:
                                /*
@@ -1413,6 +1417,7 @@ int main(int argc, char *argv[])
                                relaxed_filenames++;            /* all chars    */
                                allow_lowercase++;              /* even lowcase */
                                allow_multidot++;               /* > 1 dots     */
+                               do_largefiles++;
                                break;
 
                        default:
@@ -2751,6 +2756,11 @@ parse_input_files:
                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");
index bbedfb0..fdd5a11 100644 (file)
@@ -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 directory_entry {
        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 @@ struct directory_entry {
        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  omit_version_number;
 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 *, int);
 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 @@ extern void *e_malloc(size_t);
 #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.
index c74c2a9..3b6df21 100644 (file)
@@ -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 @@ struct iso_directory_record {
        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 */
index b36f8f7..9c10d21 100644 (file)
@@ -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 @@ assign_joliet_directory_addresses(struct directory *node)
                        }
                }
                /* 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 @@ generate_joliet_path_tables()
        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 @@ generate_joliet_path_tables()
                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 @@ generate_joliet_path_tables()
                                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 @@ joliet_compare_dirs(const void *rr, const void *ll)
        /*
         * 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 @@ joliet_compare_dirs(const void *rr, const void *ll)
                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 @@ joliet_sort_directory(struct directory_entry **sort_dir)
 
        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 @@ joliet_sort_directory(struct directory_entry **sort_dir)
        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++;
                }
index e069c91..db83ba8 100644 (file)
@@ -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        int     free_mdinfo(struct directory_entry **, int len);
 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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
        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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
        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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
                        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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
        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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
                        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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
                                         * 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 @@ read_merging_directory(struct iso_directory_record *mrootp, int *nentp)
        if (dirbuff != NULL) {
                free(dirbuff);
        }
-       *nentp = nent;
+       *nentp = nent + nmult;
        return (rtn);
 }/* read_merging_directory */
 
@@ -989,7 +1053,7 @@ check_prev_session(struct directory_entry **ptr, int len,
 {
        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 @@ check_prev_session(struct directory_entry **ptr, int len,
                 * 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 @@ check_prev_session(struct directory_entry **ptr, int len,
                 * 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 @@ check_prev_session(struct directory_entry **ptr, int len,
                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 @@ found_it:
 }
 
 /*
+ * 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 @@ merge_previous_session(struct directory *this_dir,
                            &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 @@ merge_previous_session(struct directory *this_dir,
                 * 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 @@ merge_previous_session(struct directory *this_dir,
                                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) {
index 7805888..913012c 100644 (file)
@@ -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 directory *find_or_create_directory(struct directory *parent,
                                                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 @@ sort_n_finish(struct directory *this_dir)
        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 @@ got_valid_name:
                                        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 @@ got_valid_name:
                                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 @@ got_valid_name:
                                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 @@ got_valid_name:
                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 @@ generate_reloc_directory()
        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 @@ insert_file_entry(struct directory *this_dir, char *whole_path,
                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 @@ insert_file_entry(struct directory *this_dir, char *whole_path,
                        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 @@ insert_file_entry(struct directory *this_dir, char *whole_path,
                        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 @@ insert_file_entry(struct directory *this_dir, char *whole_path,
                         * 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 @@ insert_file_entry(struct directory *this_dir, char *whole_path,
                        &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)
index c63d372..eff14e3 100644 (file)
@@ -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_size(struct directory *dpnt)
 
        /* 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 @@ directory_size(struct directory *dpnt)
 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 @@ assign_udf_directory_addresses(struct directory *dpnt)
 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 @@ assign_udf_file_entry_addresses(struct directory *dpnt)
                        }
                }
        }
-       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 @@ set_file_ident_desc(unsigned char *buf, unsigned rba, char *name,
 }
 
 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 @@ set_file_entry(unsigned char *buf, unsigned rba, unsigned file_rba,
                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 @@ directory_link_count(struct directory *dpnt)
        /* 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 @@ write_one_udf_directory(struct directory *dpnt, FILE *outfile)
                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 @@ write_one_udf_directory(struct directory *dpnt, FILE *outfile)
 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 @@ write_udf_file_entries(struct directory *dpnt, FILE *outfile)
 
        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 @@ write_udf_file_entries(struct directory *dpnt, FILE *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_file_entries(dpnt, outfile);
                }
index a423ab1..27ece8e 100644 (file)
@@ -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 @@ static        int     xawrite(void *buffer, int size, int count, FILE *file,
 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 @@ assign_directory_addresses(struct directory *node)
        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 @@ static      char            buffer[SECTOR_SIZE * NSECT];
                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 @@ compare_dirs(const void *rr, const void *ll)
                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 @@ assign_file_addresses(struct directory *dpnt, BOOL isnest)
                }
 #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 @@ assign_file_addresses(struct directory *dpnt, BOOL isnest)
                                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 @@ assign_file_addresses(struct directory *dpnt, BOOL isnest)
                                                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 @@ assign_file_addresses(struct directory *dpnt, BOOL isnest)
                                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 @@ free_one_directory(struct directory *dpnt)
                        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);