2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)write.c 1.88 06/02/01 joerg */
14 /* Parts from @(#)write.c 1.106 07/02/17 joerg */
15 /* Parts from @(#)write.c 1.117 07/12/16 joerg */
17 * Program write.c - dump memory structures to file for iso9660 filesystem.
19 * Written by Eric Youngdale (1993).
21 * Copyright 1993 Yggdrasil Computing, Incorporated
22 * Copyright (c) 1999-2003 J. Schilling
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License as published by
26 * the Free Software Foundation; either version 2, or (at your option)
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
39 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
42 #include "genisoimage.h"
51 #include "dvd_reader.h"
63 /* Max number of sectors we will write at one time */
66 /* Counters for statistics */
68 static int table_size = 0;
69 static int total_dir_size = 0;
70 static int rockridge_size = 0;
71 static struct directory **pathlist;
72 static int next_path_index = 1;
75 static int is_rr_dir = 0;
77 struct output_fragment *out_tail;
78 struct output_fragment *out_list;
80 struct iso_primary_descriptor vol_desc;
82 void set_721(char *pnt, unsigned int i);
83 void set_722(char *pnt, unsigned int i);
84 void set_723(char *pnt, unsigned int i);
85 void set_731(char *pnt, unsigned int i);
86 void set_732(char *pnt, unsigned int i);
87 void set_733(char *pnt, unsigned int i);
91 static int xawrite(void *buffer, int size, int count, FILE *file,
92 int submode, BOOL islast);
93 void xfwrite(void *buffer, int size, int count, FILE *file, int submode,
95 static int assign_directory_addresses(struct directory *node);
96 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
97 static void write_one_file(char *filename, off_t size, FILE *outfile,
100 static void write_one_file(char *filename, off_t size, FILE *outfile);
102 static void write_files(FILE *outfile);
104 static void dump_filelist __PR((void));
106 static int compare_dirs(const void *rr, const void *ll);
107 int sort_directory(struct directory_entry **sort_dir, int rr);
108 static int root_gen(void);
109 static BOOL assign_file_addresses(struct directory *dpnt, BOOL isnest);
110 static void free_one_directory(struct directory *dpnt);
111 static void free_directories(struct directory *dpnt);
112 void generate_one_directory(struct directory *dpnt, FILE *outfile);
113 static void build_pathlist(struct directory *node);
114 static int compare_paths(void const *r, void const *l);
115 static int generate_path_tables(void);
116 void memcpy_max(char *to, char *from, int max);
117 void outputlist_insert(struct output_fragment *frag);
118 static int file_write(FILE *outfile);
119 static int pvd_write(FILE *outfile);
120 static int xpvd_write(FILE *outfile);
121 static int evd_write(FILE *outfile);
122 static int vers_write(FILE *outfile);
123 static int graftcp(char *to, char *from, char *ep);
124 static int pathcp(char *to, char *from, char *ep);
125 static int pathtab_write(FILE *outfile);
126 static int exten_write(FILE *outfile);
127 int oneblock_size(int starting_extent);
128 static int pathtab_size(int starting_extent);
129 static int startpad_size(int starting_extent);
130 static int interpad_size(int starting_extent);
131 static int endpad_size(int starting_extent);
132 static int file_gen(void);
133 static int dirtree_dump(void);
134 static int dirtree_fixup(int starting_extent);
135 static int dirtree_size(int starting_extent);
136 static int ext_size(int starting_extent);
137 static int dirtree_write(FILE *outfile);
138 static int dirtree_cleanup(FILE *outfile);
139 static int startpad_write(FILE *outfile);
140 static int interpad_write(FILE *outfile);
141 static int endpad_write(FILE *outfile);
144 static int hfs_get_parms(char *key);
145 static void hfs_file_gen(int start_extent);
146 static void gen_prepboot(void);
147 Ulong get_adj_size(int Csize);
148 int adj_size(int Csize, int start_extent, int extra);
149 void adj_size_other(struct directory *dpnt);
150 static int hfs_hce_write(FILE * outfile);
151 int insert_padding_file(int size);
152 #endif /* APPLE_HYB */
155 static int compare_sort(const void * rr, const void * ll);
156 static void reassign_link_addresses(struct directory * dpnt);
157 static int sort_file_addresses(void);
161 * Routines to actually write the disc. We write sequentially so that
162 * we could write a tape, or write the disc directly
164 #define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof (vol_desc.X))
167 set_721(char *pnt, unsigned int i)
170 pnt[1] = (i >> 8) & 0xff;
174 set_722(char *pnt, unsigned int i)
176 pnt[0] = (i >> 8) & 0xff;
181 set_723(char *pnt, unsigned int i)
183 pnt[3] = pnt[0] = i & 0xff;
184 pnt[2] = pnt[1] = (i >> 8) & 0xff;
188 set_731(char *pnt, unsigned int i)
191 pnt[1] = (i >> 8) & 0xff;
192 pnt[2] = (i >> 16) & 0xff;
193 pnt[3] = (i >> 24) & 0xff;
197 set_732(char *pnt, unsigned int i)
200 pnt[2] = (i >> 8) & 0xff;
201 pnt[1] = (i >> 16) & 0xff;
202 pnt[0] = (i >> 24) & 0xff;
206 set_733(char *pnt, unsigned int i)
208 pnt[7] = pnt[0] = i & 0xff;
209 pnt[6] = pnt[1] = (i >> 8) & 0xff;
210 pnt[5] = pnt[2] = (i >> 16) & 0xff;
211 pnt[4] = pnt[3] = (i >> 24) & 0xff;
217 return ((p[0] & 0xff)
218 | ((p[1] & 0xff) << 8)
219 | ((p[2] & 0xff) << 16)
220 | ((p[3] & 0xff) << 24));
226 return ((p[3] & 0xff)
227 | ((p[2] & 0xff) << 8)
228 | ((p[1] & 0xff) << 16)
229 | ((p[0] & 0xff) << 24));
235 return ((p[0] & 0xff)
236 | ((p[1] & 0xff) << 8)
237 | ((p[2] & 0xff) << 16)
238 | ((p[3] & 0xff) << 24));
242 xfwrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
245 * This is a hack that could be made better.
246 * XXXIs this the only place?
247 * It is definitely needed on Operating Systems that do not allow to
248 * write files that are > 2GB. If the system is fast enough to be able
249 * to feed 1400 KB/s writing speed of a DVD-R drive, use stdout.
250 * If the system cannot do this reliable, you need to use this hacky
256 if (count != 1 || (size % 2048) != 0)
257 fprintf(stderr, "Count: %d, size: %d\n", count, size);
260 if (split_output != 0 &&
261 (idx == 0 || ftell(file) >= ((off_t)1024 * 1024 * 1024))) {
263 extern char *outfile;
267 sprintf(nbuf, "%s_%02d", outfile, idx++);
268 file = freopen(nbuf, "wb", file);
271 comerr("Cannot open '%s'.\n", nbuf);
273 fprintf(stderr, "Cannot open '%s'.\n", nbuf);
283 got = xawrite(buffer, size, count, file, submode, islast);
285 got = fwrite(buffer, size, count, file);
289 comerr("cannot fwrite %d*%d\n", size, count);
291 fprintf(stderr, "cannot fwrite %d*%d\n", size, count);
296 * This comment is in hope to prevent silly people from
297 * e.g. SuSE (who did not yet learn C but believe that
298 * they need to patch other peoples code) from changing the
299 * next cast into an illegal lhs cast expression.
300 * The cast below is the correct way to handle the problem.
301 * The (void *) cast is to avoid a GCC warning like:
302 * "warning: dereferencing type-punned pointer will break \
303 * strict-aliasing rules"
304 * which is wrong this code. (void *) introduces a compatible
305 * intermediate type in the cast list.
308 buffer = (void *)(((char *)buffer) + size * got);
313 xawrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
315 register char *p = buffer;
316 register int amt = size * count;
318 struct xa_subhdr subhdr[2];
320 if (osecsize == 2048)
321 return (fwrite(buffer, size, count, file));
325 "Trying to write %d bytes (not a multiple of 2048).\n",
328 subhdr[0].file_number = subhdr[1].file_number = 0;
329 subhdr[0].channel_number = subhdr[1].channel_number = 0;
330 subhdr[0].coding = subhdr[1].coding = 0;
335 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
337 subhdr[0].sub_mode = subhdr[1].sub_mode = submode;
339 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
342 if ((amt <= 2048) && islast) {
343 subhdr[0].sub_mode = subhdr[1].sub_mode
344 |= (XA_SUBH_EOR|XA_SUBH_EOF);
346 n = fwrite(&subhdr, sizeof (subhdr), 1, file);
350 n = fwrite(p, 2048, 1, file);
362 * use the deferred_write struct to store info about the hfs_boot_file
364 static struct deferred_write mac_boot;
366 #endif /* APPLE_HYB */
367 static struct deferred_write *dw_head = NULL,
370 unsigned int last_extent_written = 0;
371 static Uint path_table_index;
375 * We recursively walk through all of the directories and assign extent
376 * numbers to them. We have already assigned extent numbers to everything that
377 * goes in front of them
380 assign_directory_addresses(struct directory *node)
383 struct directory *dpnt;
388 /* skip if it's hidden */
389 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
394 * If we already have an extent for this (i.e. it came from a
395 * multisession disc), then don't reassign a new extent.
397 dpnt->path_index = next_path_index++;
398 if (dpnt->extent == 0) {
399 dpnt->extent = last_extent;
400 dir_size = ISO_BLOCKS(dpnt->size);
402 last_extent += dir_size;
405 * Leave room for the CE entries for this directory.
406 * Keep them close to the reference directory so that
407 * access will be quick.
409 if (dpnt->ce_bytes) {
410 last_extent += ISO_BLOCKS(dpnt->ce_bytes);
414 assign_directory_addresses(dpnt->subdir);
421 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
423 write_one_file(char *filename, off_t size, FILE *outfile, off_t off)
426 write_one_file(char *filename, off_t size, FILE *outfile)
427 #endif /* APPLE_HYB || USE_LARGEFILES */
430 * It seems that there are still stone age C-compilers
432 * The Metrowerks C found on BeOS/PPC does not allow
433 * more than 32kB of local vars.
434 * As we do not need to call write_one_file() recursively
435 * we make buffer static.
437 static char buffer[SECTOR_SIZE * NSECT];
443 unsigned char md5[16];
444 int include_in_jigdo = list_file_in_jigdo(filename, size, &mirror_name, md5);
446 if ((infile = fopen(filename, "rb")) == NULL) {
448 comerr("cannot open '%s'\n", filename);
450 #ifndef HAVE_STRERROR
451 fprintf(stderr, "cannot open '%s': (%d)\n",
454 fprintf(stderr, "cannot open '%s': %s\n",
455 filename, strerror(errno));
460 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
461 fseek(infile, off, SEEK_SET);
462 #endif /* APPLE_HYB || USE_LARGEFILES */
465 if (include_in_jigdo)
466 write_jt_match_record(filename, mirror_name, SECTOR_SIZE, size, md5);
471 use = (remain > SECTOR_SIZE * NSECT - 1 ?
472 NSECT * SECTOR_SIZE : remain);
473 use = ISO_ROUND_UP(use); /* Round up to nearest sector */
475 memset(buffer, 0, use);
477 amt = fread(buffer, 1, use, infile);
478 if (amt < use && amt < remain) {
480 * Note that genisoimage is not star and no 100% archiver.
481 * We only detect file growth if the new size does not
482 * match 'use' at the last read.
484 if (geterrno() == 0) {
487 "File '%s' did shrink.\n"
488 "Files must not be changed while genisoimage runs!\n",
492 "File '%s' did shrink.\n"
493 "Files must not be changed while genisoimage runs!\n",
499 comerr("Cannot read from '%s'\n", filename);
501 fprintf(stderr, "Cannot read from '%s'\n", filename);
505 if (!include_in_jigdo)
506 jtwrite(buffer, use, 1,
507 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
508 xfwrite(buffer, use, 1, outfile,
509 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
510 last_extent_written += use / SECTOR_SIZE;
512 if ((last_extent_written % 1000) < use / SECTOR_SIZE) {
513 fprintf(stderr, "%d..", last_extent_written);
517 (int)(last_extent_written % (gui ? 500 : 5000)) <
524 frac = last_extent_written / (1.0 * last_extent);
525 the_end = begun + (now - begun) / frac;
526 #ifndef NO_FLOATINGPOINT
527 fprintf(stderr, "%6.2f%% done, estimate finish %s",
528 frac * 100., ctime(&the_end));
530 fprintf(stderr, "%3d.%-02d%% done, estimate finish %s",
532 (int)((frac+.00005) * 10000.)%100,
541 }/* write_one_file(... */
544 write_files(FILE *outfile)
546 struct deferred_write *dwpnt,
554 "The file name is %s and pad is %d, size is %lld and extent is %d\n",
555 dwpnt->name, dwpnt->pad,
556 (Llong)dwpnt->size, dwpnt->extent);
559 jtwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1, XA_SUBH_DATA, TRUE);
560 xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
563 last_extent_written += ISO_BLOCKS(dwpnt->size);
564 table_size += dwpnt->size;
565 /* fprintf(stderr, "Size %lld ", (Llong)dwpnt->size); */
571 vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
574 write_one_file(dwpnt->name, dwpnt->size, outfile,
577 write_one_file(dwpnt->name, dwpnt->size, outfile);
578 #endif /* APPLE_HYB */
593 #if defined(APPLE_HYB) || defined(DVD_VIDEO)
595 if (apple_hyb || dvd_video) {
597 * we may have to pad out ISO files to work with HFS
600 char blk[SECTOR_SIZE];
603 for (i = 0; i < dwpnt->pad; i++) {
604 jtwrite(blk, SECTOR_SIZE, 1, 0, FALSE);
605 xfwrite(blk, SECTOR_SIZE, 1, outfile, 0, FALSE);
606 last_extent_written++;
609 #endif /* APPLE_HYB || DVD_VIDEO */
617 }/* write_files(... */
623 struct deferred_write *dwpnt;
627 fprintf(stderr, "File %s\n", dwpnt->name);
630 fprintf(stderr, "\n");
636 compare_dirs(const void *rr, const void *ll)
640 struct directory_entry **r,
643 r = (struct directory_entry **) rr;
644 l = (struct directory_entry **) ll;
645 rpnt = (*r)->isorec.name;
646 lpnt = (*l)->isorec.name;
650 * resource fork MUST (not sure if this is true for HFS volumes) be
651 * before the data fork - so force it here
653 if ((*r)->assoc && (*r)->assoc == (*l))
655 if ((*l)->assoc && (*l)->assoc == (*r))
657 #endif /* APPLE_HYB */
660 * If the names are the same, multiple extent sections of the same file
661 * are sorted by part number. If the part numbers do not differ, this
664 if (strcmp(rpnt, lpnt) == 0) {
665 #ifdef USE_LARGEFILES
666 if ((*r)->mxpart < (*l)->mxpart)
668 else if ((*r)->mxpart > (*l)->mxpart)
673 "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
674 (*r)->whole_name, (*l)->whole_name,
678 "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
679 (*r)->whole_name, (*l)->whole_name,
684 /* Check we don't have the same RR name */
685 if (use_RockRidge && !is_rr_dir) {
687 * entries *can* have the same RR name in the "rr_moved"
688 * directory so skip checks if we're in reloc_dir
690 if (!(strcmp((*r)->name, (*l)->name))) {
693 "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
694 (*r)->whole_name, (*l)->whole_name,
698 "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
699 (*r)->whole_name, (*l)->whole_name,
706 * Put the '.' and '..' entries on the head of the sorted list. For
707 * normal ASCII, this always happens to be the case, but out of band
708 * characters cause this not to be the case sometimes.
709 * FIXME(eric) - these tests seem redundant, in that the name is never
710 * assigned these values. It will instead be \000 or \001, and thus
711 * should always be sorted correctly. I need to figure out why I
712 * thought I needed this in the first place.
715 if (strcmp(rpnt, ".") == 0)
717 if (strcmp(lpnt, ".") == 0)
720 if (strcmp(rpnt, "..") == 0)
722 if (strcmp(lpnt, "..") == 0)
726 * The code above is wrong (as explained in Eric's comment), leading to
727 * incorrect sort order iff the -L option ("allow leading dots") is in
728 * effect and a directory contains entries that start with a dot.
729 * (TF, Tue Dec 29 13:49:24 CET 1998)
731 if ((*r)->isorec.name_len[0] == 1 && *rpnt == 0)
732 return (-1); /* '.' */
733 if ((*l)->isorec.name_len[0] == 1 && *lpnt == 0)
736 if ((*r)->isorec.name_len[0] == 1 && *rpnt == 1)
737 return (-1); /* '..' */
738 if ((*l)->isorec.name_len[0] == 1 && *lpnt == 1)
742 while (*rpnt && *lpnt) {
743 if (*rpnt == ';' && *lpnt != ';')
745 if (*rpnt != ';' && *lpnt == ';')
748 if (*rpnt == ';' && *lpnt == ';')
751 if (*rpnt == '.' && *lpnt != '.')
753 if (*rpnt != '.' && *lpnt == '.')
756 if ((unsigned char) *rpnt < (unsigned char) *lpnt)
758 if ((unsigned char) *rpnt > (unsigned char) *lpnt)
771 * Function: sort_directory
773 * Purpose: Sort the directory in the appropriate ISO9660
776 * Notes: Returns 0 if OK, returns > 0 if an error occurred.
779 sort_directory(struct directory_entry **sort_dir, int rr)
786 struct directory_entry *s_entry;
787 struct directory_entry **sortlist;
789 /* need to keep a count of how many entries are hidden */
792 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
795 s_entry = s_entry->next;
801 /* OK, now we know how many there are. Build a vector for sorting. */
802 sortlist = (struct directory_entry **)
803 e_malloc(sizeof (struct directory_entry *) * dcount);
809 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
810 /* put any hidden entries at the end of the vector */
811 sortlist[j--] = s_entry;
813 sortlist[dcount] = s_entry;
816 len = s_entry->isorec.name_len[0];
817 s_entry->isorec.name[len] = 0;
818 s_entry = s_entry->next;
821 /* Each directory is required to contain at least . and .. */
825 "Directory size too small (. or .. missing ??%s)\n",
826 "?"); /* Try to avoid a GCC trigraph warning */
829 "Directory size too small (. or .. missing ??%s)\n",
830 "?"); /* Try to avoid a GCC trigraph warning */
835 /* only sort the non-hidden entries */
839 qsort(sortlist, dcount, sizeof (struct directory_entry *),
840 (int (*) (const void *, const void *)) compare_dirs);
842 qsort(sortlist, dcount, sizeof (struct directory_entry *),
847 * Now reassemble the linked list in the proper sorted order
848 * We still need the hidden entries, as they may be used in
851 for (i = 0; i < dcount + xcount - 1; i++) {
852 sortlist[i]->next = sortlist[i + 1];
855 sortlist[dcount + xcount - 1]->next = NULL;
856 *sort_dir = sortlist[0];
869 root_record.length[0] = 1 +
870 offsetof(struct iso_directory_record, name[0]);
871 root_record.ext_attr_length[0] = 0;
872 set_733((char *) root_record.extent, root->extent);
873 set_733((char *) root_record.size, ISO_ROUND_UP(root->size));
874 iso9660_date(root_record.date, root_statbuf.st_mtime);
875 root_record.flags[0] = ISO_DIRECTORY;
876 root_record.file_unit_size[0] = 0;
877 root_record.interleave[0] = 0;
878 set_723(root_record.volume_sequence_number, volume_sequence_number);
879 root_record.name_len[0] = 1;
885 * sorts deferred_write entries based on the sort weight
888 compare_sort(const void *rr, const void *ll)
890 struct deferred_write **r;
891 struct deferred_write **l;
895 r = (struct deferred_write **) rr;
896 l = (struct deferred_write **) ll;
897 r_sort = (*r)->s_entry->sort;
898 l_sort = (*l)->s_entry->sort;
900 if (r_sort != l_sort)
901 return (r_sort < l_sort ? 1 : -1);
903 return ((*r)->extent - (*l)->extent);
907 * reassign start extents to files that are "hard links" to
908 * files that may have been sorted
911 reassign_link_addresses(struct directory *dpnt)
913 struct directory_entry *s_entry;
914 struct file_hash *s_hash;
917 s_entry = dpnt->contents;
918 for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
919 /* link files have already been given the weight NOT_SORTED */
920 if (s_entry->sort == NOT_SORTED)
922 /* update the start extent */
923 s_hash = find_hash(s_entry->dev, s_entry->inode);
925 set_733((char *) s_entry->isorec.extent,
926 s_hash->starting_block);
927 s_entry->starting_block = s_hash->starting_block;
931 if (verbose > 2 && s_entry->size != 0) {
932 fprintf(stderr, "%8u %8u ",
933 s_entry->starting_block,
934 (unsigned int)(s_entry->starting_block + ISO_BLOCKS(s_entry->size) - 1));
936 if (s_entry->inode != TABLE_INODE) {
937 fprintf(stderr, "%s\n", s_entry->whole_name);
939 fprintf(stderr, "%s%s%s\n",
940 s_entry->filedir->whole_name,
941 SPATH_SEPARATOR, trans_tbl);
946 reassign_link_addresses(dpnt->subdir);
954 * sort files in order of the given sort weight
957 sort_file_addresses()
959 struct deferred_write *dwpnt;
960 struct deferred_write **sortlist;
961 struct directory_entry *s_entry;
966 /* need to store start extents for linked files */
969 /* find out how many files we have */
976 /* return if we have none */
981 /* save the start extent of the first file */
982 start_extent = dw_head->extent;
984 /* set up vector to store entries */
985 sortlist = (struct deferred_write **)
986 e_malloc(sizeof (struct deferred_write *) * num);
988 for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next)
993 qsort(sortlist, num, sizeof (struct deferred_write *),
994 (int (*)(const void *, const void *))compare_sort);
996 qsort(sortlist, num, sizeof (struct deferred_write *), compare_sort);
999 /* reconstruct the linked list */
1000 for (i = 0; i < num-1; i++) {
1001 sortlist[i]->next = sortlist[i+1];
1004 sortlist[num-1]->next = NULL;
1005 dw_head = sortlist[0];
1009 /* set the new start extents for the sorted list */
1010 for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next) {
1011 s_entry = dwpnt->s_entry;
1012 dwpnt->extent = s_entry->starting_block = start_extent;
1013 set_733((char *) s_entry->isorec.extent, start_extent);
1015 start_extent += ISO_BLOCKS(s_entry->size);
1018 * Shouldn't this be done for every type of sort? Otherwise
1019 * we will loose every pad info we add if we sort the files
1022 start_extent += dwpnt->pad;
1024 #endif /* DVD_VIDEO */
1026 /* cache start extents for any linked files */
1032 #endif /* SORTING */
1037 assign_file_addresses(struct directory *dpnt, BOOL isnest)
1039 struct directory *finddir;
1040 struct directory_entry *s_entry;
1041 struct file_hash *s_hash;
1042 struct deferred_write *dwpnt;
1043 char whole_path[PATH_MAX];
1045 char dvd_path[PATH_MAX];
1046 title_set_info_t * title_set_info = NULL;
1053 if (dvd_video && root == dpnt->parent &&
1054 ((p = strstr(dpnt->whole_name, "VIDEO_TS")) != 0)&&
1055 strcmp(p, "VIDEO_TS") == 0) {
1057 int maxlen = strlen(dpnt->whole_name)-8;
1058 if (maxlen > (sizeof (dvd_path)-1))
1059 maxlen = sizeof (dvd_path)-1;
1060 strncpy(dvd_path, dpnt->whole_name, maxlen);
1061 dvd_path[maxlen] = '\0';
1064 fprintf(stderr, "Found 'VIDEO_TS', the path is %s \n", dvd_path);
1066 title_set_info = DVDGetFileSet(dvd_path);
1067 if (title_set_info == 0) {
1069 * Do not switch off -dvd-video but let is fail later.
1072 errmsgno(EX_BAD, "Unable to parse DVD-Video structures.\n");
1077 #endif /* DVD_VIDEO */
1079 for (s_entry = dpnt->contents; s_entry;
1080 s_entry = s_entry->next) {
1082 * If we already have an extent for this entry, then
1083 * don't assign a new one. It must have come from a
1084 * previous session on the disc. Note that we don't
1085 * end up scheduling the thing for writing either.
1087 if (get_733(s_entry->isorec.extent) != 0) {
1091 * This saves some space if there are symlinks present.
1092 * If this is a multi-extent file, we get mxpart == 1
1095 s_hash = find_hash(s_entry->dev, s_entry->inode);
1098 fprintf(stderr, "Cache hit for '%s%s%s'\n", s_entry->filedir->de_name,
1102 set_733((char *) s_entry->isorec.extent,
1103 s_hash->starting_block);
1104 set_733((char *) s_entry->isorec.size,
1106 #ifdef USE_LARGEFILES
1107 if (s_entry->de_flags & MULTI_EXTENT) {
1108 struct directory_entry *s_e;
1109 unsigned int ext = s_hash->starting_block;
1112 * Skip the multi extent root entry.
1114 if (s_entry->mxpart == 0)
1117 * The directory is sorted, so we should
1118 * see s_entry->mxpart == 1 first.
1120 if (s_entry->mxpart != 1) {
1122 "Panic: Multi extent parts for %s not sorted.\n",
1123 s_entry->whole_name);
1125 s_entry->mxroot->starting_block = ext;
1127 s_e && s_e->mxroot == s_entry->mxroot;
1129 set_733((char *) s_e->isorec.extent,
1131 ext += ISO_BLOCKS(s_e->size);
1137 /* check for non-directory files */
1138 if (do_sort && ((s_entry->isorec.flags[0] & ISO_DIRECTORY) == 0)) {
1139 /* make sure the real file has the highest weighting */
1140 s_hash->de->sort = MAX(s_entry->sort, s_hash->de->sort);
1141 /* flag this as a potential non-sorted file */
1142 s_entry->sort = NOT_SORTED;
1144 #endif /* SORTING */
1148 * If this is for a directory that is not a . or
1149 * a .. entry, then look up the information for the
1150 * entry. We have already assigned extents for
1151 * directories, so we just need to fill in the blanks
1154 if (strcmp(s_entry->name, ".") != 0 &&
1155 strcmp(s_entry->name, "..") != 0 &&
1156 s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1157 finddir = dpnt->subdir;
1159 if (finddir->self == s_entry)
1161 finddir = finddir->next;
1164 if (title_set_info != 0) {
1165 DVDFreeFileSet(title_set_info);
1169 "Fatal goof - could not find dir entry for '%s'\n",
1173 set_733((char *) s_entry->isorec.extent,
1175 s_entry->starting_block = finddir->extent;
1176 s_entry->size = ISO_ROUND_UP(finddir->size);
1177 total_dir_size += s_entry->size;
1179 set_733((char *) s_entry->isorec.size,
1180 ISO_ROUND_UP(finddir->size));
1184 * If this is . or .., then look up the relevant info
1187 if (strcmp(s_entry->name, ".") == 0) {
1188 set_733((char *) s_entry->isorec.extent,
1192 * Set these so that the hash table has the
1193 * correct information
1195 s_entry->starting_block = dpnt->extent;
1196 s_entry->size = ISO_ROUND_UP(dpnt->size);
1199 s_entry->starting_block = dpnt->extent;
1200 set_733((char *) s_entry->isorec.size,
1201 ISO_ROUND_UP(dpnt->size));
1204 if (strcmp(s_entry->name, "..") == 0) {
1206 total_dir_size += root->size;
1208 set_733((char *) s_entry->isorec.extent,
1209 dpnt->parent->extent);
1212 * Set these so that the hash table has the
1213 * correct information
1215 s_entry->starting_block = dpnt->parent->extent;
1217 ISO_ROUND_UP(dpnt->parent->size);
1220 s_entry->starting_block = dpnt->parent->extent;
1221 set_733((char *) s_entry->isorec.size,
1222 ISO_ROUND_UP(dpnt->parent->size));
1226 * Some ordinary non-directory file. Just schedule
1227 * the file to be written. This is all quite
1228 * straightforward, just make a list and assign
1229 * extents as we go. Once we get through writing all
1230 * of the directories, we should be ready write out
1233 if (s_entry->size) {
1234 dwpnt = (struct deferred_write *)
1235 e_malloc(sizeof (struct deferred_write));
1236 /* save this directory entry for later use */
1237 dwpnt->s_entry = s_entry;
1238 /* set the initial padding to zero */
1241 if (dvd_video && (title_set_info != 0)) {
1244 pad = DVDGetFilePad(title_set_info, s_entry->name);
1247 "Implementation botch. Video pad for file %s is %d\n",
1248 s_entry->name, pad),
1250 "Either the *.IFO file is bad or you found a genisoimage bug.\n");
1253 if (verbose > 0 && pad != 0) {
1255 "The pad was %d for file %s\n", dwpnt->pad, s_entry->name);
1258 #endif /* DVD_VIDEO */
1261 * maybe an offset to start of the real
1264 dwpnt->off = s_entry->hfs_off;
1266 dwpnt->off = (off_t)0;
1267 #endif /* APPLE_HYB */
1269 dw_tail->next = dwpnt;
1275 if (s_entry->inode == TABLE_INODE) {
1276 dwpnt->table = s_entry->table;
1278 sprintf(whole_path, "%s%s%s",
1279 s_entry->filedir->whole_name,
1280 SPATH_SEPARATOR, trans_tbl);
1282 dwpnt->table = NULL;
1283 strcpy(whole_path, s_entry->whole_name);
1284 dwpnt->name = strdup(whole_path);
1287 dwpnt->size = s_entry->size;
1288 dwpnt->extent = last_extent;
1289 set_733((char *) s_entry->isorec.extent,
1291 s_entry->starting_block = last_extent;
1292 #ifdef USE_LARGEFILES
1294 * Update the entries for multi-section files
1295 * as we now know the starting extent numbers.
1297 if (s_entry->de_flags & MULTI_EXTENT) {
1298 struct directory_entry *s_e;
1299 unsigned int ext = last_extent;
1302 * Skip the multi extent root entry.
1304 if (s_entry->mxpart == 0)
1307 * The directory is sorted, so we should
1308 * see s_entry->mxpart == 1 first.
1310 if (s_entry->mxpart != 1) {
1312 "Panic: Multi extent parts for %s not sorted.\n",
1313 s_entry->whole_name);
1315 dwpnt->size = s_entry->mxroot->size;
1316 s_entry->mxroot->starting_block = ext;
1318 * Set the mxroot (mxpart == 0) to allow
1319 * the UDF code to fetch the starting
1322 set_733((char *) s_entry->mxroot->isorec.extent, ext);
1324 s_e && s_e->mxroot == s_entry->mxroot;
1326 if (s_e->mxpart == 0)
1328 set_733((char *) s_e->isorec.extent,
1330 ext += ISO_BLOCKS(s_e->size);
1337 * The cache holds the full size of the file
1339 last_extent += ISO_BLOCKS(dwpnt->size);
1341 /* Shouldn't we always add the pad info? */
1343 last_extent += dwpnt->pad;
1345 #endif /* DVD_VIDEO */
1346 if (verbose > 2 && !do_sort) {
1347 fprintf(stderr, "%8d %8u %s\n",
1348 s_entry->starting_block,
1349 last_extent - 1, whole_path);
1352 if (ISO_BLOCKS(s_entry->size) > 500) {
1354 "Warning: large file '%s'\n",
1357 "Starting block is %d\n",
1358 s_entry->starting_block);
1360 "Reported file size is %lld\n",
1361 (Llong)s_entry->size);
1365 #ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */
1367 if (last_extent > (800000000 >> 11)) {
1368 /* More than 800Mb? Punt */
1370 "Extent overflow processing file '%s'\n",
1373 "Starting block is %d\n",
1374 s_entry->starting_block);
1376 "Reported file size is %lld\n",
1377 (Llong)s_entry->size);
1384 * This is for zero-length files. If we leave the
1385 * extent 0, then we get screwed, because many readers
1386 * simply drop files that have an extent of zero.
1387 * Thus we leave the size 0, and just assign the
1390 set_733((char *) s_entry->isorec.extent, last_extent);
1393 if (assign_file_addresses(dpnt->subdir, TRUE))
1399 if (title_set_info != NULL) {
1400 DVDFreeFileSet(title_set_info);
1402 if (dvd_video && !ret && !isnest) {
1404 "Could not find correct 'VIDEO_TS' directory.\n");
1406 #endif /* DVD_VIDEO */
1408 } /* assign_file_addresses(... */
1411 free_one_directory(struct directory *dpnt)
1413 struct directory_entry *s_entry;
1414 struct directory_entry *s_entry_d;
1416 s_entry = dpnt->contents;
1418 s_entry_d = s_entry;
1419 s_entry = s_entry->next;
1421 if (s_entry_d->rr_attributes) {
1422 free(s_entry_d->rr_attributes);
1423 s_entry_d->rr_attributes = NULL;
1425 if (s_entry_d->name != NULL) {
1426 free(s_entry_d->name);
1427 s_entry_d->name = NULL;
1429 if (s_entry_d->whole_name != NULL) {
1430 free(s_entry_d->whole_name);
1431 s_entry_d->whole_name = NULL;
1434 if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc &&
1435 (s_entry_d->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
1436 free(s_entry_d->hfs_ent);
1438 #endif /* APPLE_HYB */
1443 dpnt->contents = NULL;
1444 }/* free_one_directory(... */
1447 free_directories(struct directory *dpnt)
1450 free_one_directory(dpnt);
1452 free_directories(dpnt->subdir);
1458 generate_one_directory(struct directory *dpnt, FILE *outfile)
1460 unsigned int ce_address = 0;
1462 unsigned int ce_index = 0;
1463 unsigned int ce_size;
1464 unsigned int dir_index;
1465 char *directory_buffer;
1467 struct directory_entry *s_entry;
1468 struct directory_entry *s_entry_d;
1469 unsigned int total_size;
1471 total_size = ISO_ROUND_UP(dpnt->size);
1472 directory_buffer = (char *) e_malloc(total_size);
1473 memset(directory_buffer, 0, total_size);
1476 ce_size = ISO_ROUND_UP(dpnt->ce_bytes);
1480 ce_buffer = (char *) e_malloc(ce_size);
1481 memset(ce_buffer, 0, ce_size);
1485 /* Absolute byte address of CE entries for this directory */
1486 ce_address = last_extent_written + (total_size >> 11);
1487 ce_address = ce_address << 11;
1489 s_entry = dpnt->contents;
1491 /* skip if it's hidden */
1492 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1493 s_entry = s_entry->next;
1497 * We do not allow directory entries to cross sector
1498 * boundaries. Simply pad, and then start the next entry at
1501 new_reclen = s_entry->isorec.length[0];
1502 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >=
1504 dir_index = ISO_ROUND_UP(dir_index);
1506 memcpy(directory_buffer + dir_index, &s_entry->isorec,
1507 offsetof(struct iso_directory_record, name[0]) +
1508 s_entry->isorec.name_len[0]);
1509 dir_index += offsetof(struct iso_directory_record, name[0]) +
1510 s_entry->isorec.name_len[0];
1512 /* Add the Rock Ridge attributes, if present */
1513 if (s_entry->rr_attr_size) {
1514 if (dir_index & 1) {
1515 directory_buffer[dir_index++] = 0;
1518 * If the RR attributes were too long, then write the
1519 * CE records, as required.
1521 if (s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
1522 struct iso_xa_dir_record *xadp;
1528 * Go through the entire record, first skip
1529 * the XA record and then fix up the
1530 * CE entries so that the extent and offset
1533 pnt = s_entry->rr_attributes;
1534 len = s_entry->total_rr_attr_size;
1537 xadp = (struct iso_xa_dir_record *)pnt;
1539 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
1540 xadp->reserved[0] == '\0') {
1550 "Warning: ce_index(%d) && ce_address(%d) not initialized\n",
1551 ce_index, ce_address);
1555 if (pnt[0] == 'C' && pnt[1] == 'E') {
1556 nbytes = get_733((char *) pnt + 20);
1558 if ((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
1560 ce_index = ISO_ROUND_UP(ce_index);
1562 set_733((char *) pnt + 4,
1563 (ce_address + ce_index) >> 11);
1564 set_733((char *) pnt + 12,
1565 (ce_address + ce_index) & (SECTOR_SIZE - 1));
1569 * Now store the block in the
1572 memcpy(ce_buffer + ce_index,
1573 pnt + pnt[2], nbytes);
1584 rockridge_size += s_entry->total_rr_attr_size;
1585 memcpy(directory_buffer + dir_index,
1586 s_entry->rr_attributes,
1587 s_entry->rr_attr_size);
1588 dir_index += s_entry->rr_attr_size;
1590 if (dir_index & 1) {
1591 directory_buffer[dir_index++] = 0;
1593 s_entry_d = s_entry;
1594 s_entry = s_entry->next;
1597 * Joliet doesn't use the Rock Ridge attributes, so we free
1600 if (s_entry_d->rr_attributes) {
1601 free(s_entry_d->rr_attributes);
1602 s_entry_d->rr_attributes = NULL;
1606 if (dpnt->size != dir_index) {
1607 #ifdef USE_LIBSCHILY
1609 "Unexpected directory length %lld expected: %d '%s'\n",
1611 dir_index, dpnt->de_name);
1614 "Unexpected directory length %lld expected: %d '%s'\n",
1616 dir_index, dpnt->de_name);
1619 jtwrite(directory_buffer, total_size, 1, 0, FALSE);
1620 xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
1621 last_extent_written += total_size >> 11;
1622 free(directory_buffer);
1623 directory_buffer = NULL;
1626 if (ce_index != dpnt->ce_bytes) {
1627 #ifdef USE_LIBSCHILY
1629 "Continuation entry record length mismatch %d expected: %d.\n",
1630 ce_index, dpnt->ce_bytes);
1633 "Continuation entry record length mismatch %d expected: %d.\n",
1634 ce_index, dpnt->ce_bytes);
1637 jtwrite(ce_buffer, ce_size, 1, 0, FALSE);
1638 xfwrite(ce_buffer, ce_size, 1, outfile, 0, FALSE);
1639 last_extent_written += ce_size >> 11;
1643 }/* generate_one_directory(... */
1646 build_pathlist(struct directory *node)
1648 struct directory *dpnt;
1653 /* skip if it's hidden */
1654 if ((dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
1655 pathlist[dpnt->path_index] = dpnt;
1658 build_pathlist(dpnt->subdir);
1661 }/* build_pathlist(... */
1664 compare_paths(void const *r, void const *l)
1666 struct directory const *ll = *(struct directory * const *) l;
1667 struct directory const *rr = *(struct directory * const *) r;
1669 if (rr->parent->path_index < ll->parent->path_index) {
1672 if (rr->parent->path_index > ll->parent->path_index) {
1675 return (strcmp(rr->self->isorec.name, ll->self->isorec.name));
1677 }/* compare_paths(... */
1680 generate_path_tables()
1682 struct directory_entry *de = NULL;
1683 struct directory *dpnt;
1692 /* First allocate memory for the tables and initialize the memory */
1693 tablesize = path_blocks << 11;
1694 path_table_m = (char *) e_malloc(tablesize);
1695 path_table_l = (char *) e_malloc(tablesize);
1696 memset(path_table_l, 0, tablesize);
1697 memset(path_table_m, 0, tablesize);
1700 * Now start filling in the path tables. Start with root directory
1703 path_table_index = 0;
1704 pathlist = (struct directory **) e_malloc(sizeof (struct directory *)
1706 memset(pathlist, 0, sizeof (struct directory *) * next_path_index);
1707 build_pathlist(root);
1712 qsort(&pathlist[1], next_path_index - 1,
1713 sizeof (struct directory *),
1714 (int (*) (const void *, const void *)) compare_paths);
1716 qsort(&pathlist[1], next_path_index - 1,
1717 sizeof (struct directory *),
1721 for (j = 1; j < next_path_index; j++) {
1722 if (pathlist[j]->path_index != j) {
1723 pathlist[j]->path_index = j;
1729 for (j = 1; j < next_path_index; j++) {
1732 #ifdef USE_LIBSCHILY
1733 comerrno(EX_BAD, "Entry %d not in path tables\n", j);
1735 fprintf(stderr, "Entry %d not in path tables\n", j);
1739 npnt = dpnt->de_name;
1741 /* So the root comes out OK */
1742 if ((*npnt == 0) || (dpnt == root)) {
1745 npnt1 = strrchr(npnt, PATH_SEPARATOR);
1751 #ifdef USE_LIBSCHILY
1753 "Fatal ISO9660 goof - directory has amnesia\n");
1756 "Fatal ISO9660 goof - directory has amnesia\n");
1760 namelen = de->isorec.name_len[0];
1762 path_table_l[path_table_index] = namelen;
1763 path_table_m[path_table_index] = namelen;
1764 path_table_index += 2;
1766 set_731(path_table_l + path_table_index, dpnt->extent);
1767 set_732(path_table_m + path_table_index, dpnt->extent);
1768 path_table_index += 4;
1770 if (dpnt->parent->path_index > 0xffff) {
1771 #ifdef USE_LIBSCHILY
1773 "Unable to generate sane path tables - too many directories (%d)\n",
1774 dpnt->parent->path_index);
1777 "Unable to generate sane path tables - too many directories (%d)\n",
1778 dpnt->parent->path_index);
1783 set_721(path_table_l + path_table_index,
1784 dpnt->parent->path_index);
1785 set_722(path_table_m + path_table_index,
1786 dpnt->parent->path_index);
1787 path_table_index += 2;
1789 for (i = 0; i < namelen; i++) {
1790 path_table_l[path_table_index] = de->isorec.name[i];
1791 path_table_m[path_table_index] = de->isorec.name[i];
1794 if (path_table_index & 1) {
1795 path_table_index++; /* For odd lengths we pad */
1801 if (path_table_index != path_table_size) {
1802 #ifdef USE_LIBSCHILY
1804 "Path table lengths do not match %d expected: %d\n",
1809 "Path table lengths do not match %d expected: %d\n",
1815 }/* generate_path_tables(... */
1818 memcpy_max(char *to, char *from, int max)
1820 int n = strlen(from);
1825 memcpy(to, from, n);
1827 }/* memcpy_max(... */
1830 outputlist_insert(struct output_fragment *frag)
1832 struct output_fragment *nfrag;
1834 nfrag = e_malloc(sizeof (*frag));
1835 movebytes(frag, nfrag, sizeof (*frag));
1836 nfrag->of_start_extent = 0;
1838 if (out_tail == NULL) {
1839 out_list = out_tail = nfrag;
1841 out_tail->of_next = nfrag;
1847 file_write(FILE *outfile)
1852 char buffer[SECTOR_SIZE];
1854 memset(buffer, 0, sizeof (buffer));
1861 * write out padding to round up to HFS allocation block
1863 for (i = 0; i < hfs_pad; i++) {
1864 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
1865 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
1866 last_extent_written++;
1869 #endif /* APPLE_HYB */
1872 * OK, all done with that crap. Now write out the directories. This is
1873 * where the fur starts to fly, because we need to keep track of each
1874 * file as we find it and keep track of where we put it.
1876 should_write = last_extent - session_start;
1881 "Total directory extents being written = %d\n",
1888 "Total extents scheduled to be written (inc HFS) = %d\n",
1889 last_extent - session_start);
1891 #endif /* APPLE_HYB */
1894 "Total extents scheduled to be written = %u\n",
1895 last_extent - session_start);
1897 /* Now write all of the files that we need. */
1898 write_files(outfile);
1901 /* write out extents/catalog/dt file */
1904 jtwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, 0, FALSE);
1905 xfwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, outfile, 0, FALSE);
1907 /* round up to a whole CD block */
1908 if (HFS_ROUND_UP(hce->hfs_tot_size) -
1909 hce->hfs_tot_size * HFS_BLOCKSZ) {
1911 HFS_ROUND_UP(hce->hfs_tot_size) -
1912 hce->hfs_tot_size * HFS_BLOCKSZ, 1, 0, FALSE);
1914 HFS_ROUND_UP(hce->hfs_tot_size) -
1915 hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
1917 last_extent_written += ISO_ROUND_UP(hce->hfs_tot_size *
1918 HFS_BLOCKSZ) / SECTOR_SIZE;
1920 /* write out HFS boot block */
1922 write_one_file(mac_boot.name, mac_boot.size, outfile,
1925 #endif /* APPLE_HYB */
1927 /* The rest is just fluff. */
1934 "Total extents actually written (inc HFS) = %d\n",
1935 last_extent_written - session_start);
1936 fprintf(stderr, "(Size of ISO volume = %d, HFS extra = %d)\n",
1937 last_extent_written - session_start - hfs_extra,
1941 fprintf(stderr, "Total extents actually written = %d\n",
1942 last_extent_written - session_start);
1943 #endif /* APPLE_HYB */
1945 /* Hard links throw us off here */
1946 if (should_write != (last_extent - session_start)) {
1948 "Number of extents written not what was predicted. Please fix.\n");
1949 fprintf(stderr, "Predicted = %d, written = %d\n",
1950 should_write, last_extent);
1952 fprintf(stderr, "Total translation table size: %d\n", table_size);
1953 fprintf(stderr, "Total rockridge attributes bytes: %d\n",
1955 fprintf(stderr, "Total directory bytes: %d\n", total_dir_size);
1956 fprintf(stderr, "Path table size(bytes): %d\n", path_table_size);
1960 "next extent, last_extent, last_extent_written %d %d %d\n",
1961 next_extent, last_extent, last_extent_written);
1966 }/* iso_write(... */
1969 * Function to write the PVD for the disc.
1972 pvd_write(FILE *outfile)
1982 local = *localtime(&begun);
1983 gmt = *gmtime(&begun);
1986 * There was a comment here about breaking in the year 2000.
1987 * That's not true, in 2000 tm_year == 100, so 1900+tm_year == 2000.
1989 sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00",
1990 1900 + local.tm_year,
1991 local.tm_mon + 1, local.tm_mday,
1992 local.tm_hour, local.tm_min, local.tm_sec);
1994 local.tm_min -= gmt.tm_min;
1995 local.tm_hour -= gmt.tm_hour;
1996 local.tm_yday -= gmt.tm_yday;
1997 if (local.tm_yday < -2) /* Hit new-year limit */
1998 local.tm_yday = 1; /* Local is GMT + 1 day */
1999 iso_time[16] = (local.tm_min + 60 *
2000 (local.tm_hour + 24 * local.tm_yday)) / 15;
2002 /* Next we write out the primary descriptor for the disc */
2003 memset(&vol_desc, 0, sizeof (vol_desc));
2004 vol_desc.type[0] = ISO_VD_PRIMARY;
2005 memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof (ISO_STANDARD_ID));
2006 vol_desc.version[0] = 1;
2008 memset(vol_desc.system_id, ' ', sizeof (vol_desc.system_id));
2009 memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
2011 memset(vol_desc.volume_id, ' ', sizeof (vol_desc.volume_id));
2012 memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
2014 should_write = last_extent - session_start;
2015 set_733((char *) vol_desc.volume_space_size, should_write);
2016 set_723(vol_desc.volume_set_size, volume_set_size);
2017 set_723(vol_desc.volume_sequence_number, volume_sequence_number);
2018 set_723(vol_desc.logical_block_size, SECTOR_SIZE);
2021 * The path tables are used by DOS based machines to cache directory
2024 set_733((char *) vol_desc.path_table_size, path_table_size);
2025 set_731(vol_desc.type_l_path_table, path_table[0]);
2026 set_731(vol_desc.opt_type_l_path_table, path_table[1]);
2027 set_732(vol_desc.type_m_path_table, path_table[2]);
2028 set_732(vol_desc.opt_type_m_path_table, path_table[3]);
2030 /* Now we copy the actual root directory record */
2031 memcpy(vol_desc.root_directory_record, &root_record,
2032 offsetof(struct iso_directory_record, name[0]) + 1);
2035 * The rest is just fluff. It looks nice to fill in many of these
2038 FILL_SPACE(volume_set_id);
2040 memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
2042 FILL_SPACE(publisher_id);
2044 memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
2046 FILL_SPACE(preparer_id);
2048 memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
2050 FILL_SPACE(application_id);
2052 memcpy_max(vol_desc.application_id, appid, strlen(appid));
2054 FILL_SPACE(copyright_file_id);
2056 memcpy_max(vol_desc.copyright_file_id, copyright,
2059 FILL_SPACE(abstract_file_id);
2061 memcpy_max(vol_desc.abstract_file_id, abstract,
2064 FILL_SPACE(bibliographic_file_id);
2066 memcpy_max(vol_desc.bibliographic_file_id, biblio,
2069 FILL_SPACE(creation_date);
2070 FILL_SPACE(modification_date);
2071 FILL_SPACE(expiration_date);
2072 FILL_SPACE(effective_date);
2073 vol_desc.file_structure_version[0] = 1;
2074 FILL_SPACE(application_data);
2076 memcpy(vol_desc.creation_date, iso_time, 17);
2077 memcpy(vol_desc.modification_date, iso_time, 17);
2078 memcpy(vol_desc.expiration_date, "0000000000000000", 17);
2079 memcpy(vol_desc.effective_date, iso_time, 17);
2082 char *xap = &((char *)&vol_desc)[1024];
2084 memcpy(&xap[0], "CD-XA001", 8); /* XA Sign. */
2085 memcpy(&xap[8], "\0\0", 2); /* XA flags */
2086 memcpy(&xap[10], "\0\0\0\0\0\0\0\0", 8); /* Start dir */
2087 memcpy(&xap[18], "\0\0\0\0\0\0\0\0", 8); /* Reserved */
2090 /* if not a bootable cd do it the old way */
2091 jtwrite(&vol_desc, SECTOR_SIZE, 1, 0, FALSE);
2092 xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2093 last_extent_written++;
2098 * Function to write the Extended PVD for the disc.
2101 xpvd_write(FILE *outfile)
2103 vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
2104 vol_desc.version[0] = 2;
2105 vol_desc.file_structure_version[0] = 2;
2107 /* if not a bootable cd do it the old way */
2108 jtwrite(&vol_desc, SECTOR_SIZE, 1, 0, FALSE);
2109 xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2110 last_extent_written++;
2115 * Function to write the EVD for the disc.
2118 evd_write(FILE *outfile)
2120 struct iso_primary_descriptor evol_desc;
2123 * Now write the end volume descriptor. Much simpler than the other
2126 memset(&evol_desc, 0, sizeof (evol_desc));
2127 evol_desc.type[0] = (unsigned char) ISO_VD_END;
2128 memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof (ISO_STANDARD_ID));
2129 evol_desc.version[0] = 1;
2130 jtwrite(&evol_desc, SECTOR_SIZE, 1, 0, TRUE);
2131 xfwrite(&evol_desc, SECTOR_SIZE, 1, outfile, 0, TRUE);
2132 last_extent_written += 1;
2137 * Function to write the version information for the disc.
2140 vers_write(FILE *outfile)
2142 char vers[SECTOR_SIZE+1];
2149 extern char version_string[];
2150 extern int path_ind;
2152 /* Now write the version descriptor. */
2153 memset(vers, 0, sizeof (vers));
2154 strcpy(vers, "MKI ");
2159 strcpy(&cp[idx], ctime(&begun));
2161 strcpy(&cp[idx], version_string);
2162 idx += strlen(version_string);
2163 for (i = 1; i < X_ac; i++) {
2164 len = strlen(X_av[i]);
2165 if ((idx + len + 2) >= SECTOR_SIZE)
2169 * Do not give away secret information when not in debug mode.
2172 strcpy(&cp[idx], X_av[i]);
2173 else if (i >= path_ind)
2174 len = graftcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2175 else if (X_av[i][0] == '/')
2176 len = pathcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2178 strcpy(&cp[idx], X_av[i]);
2182 cp[SECTOR_SIZE - 1] = '\0';
2183 /* Per default: keep privacy. Blackout the version and arguments. */
2184 if(getenv("ISODEBUG")) {
2185 jtwrite(vers, SECTOR_SIZE, 1, 0, TRUE);
2186 xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
2188 jtwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, 0, TRUE);
2189 xfwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, outfile, 0, TRUE);
2191 last_extent_written += 1;
2196 * Avoid to write unwanted information into the version info string.
2199 graftcp(char *to, char *from, char *ep)
2201 int len = strlen(from);
2205 node = findgequal(from);
2213 strncpy(to, from, ep - to);
2218 return (len + pathcp(to, node, ep));
2222 pathcp(char *to, char *from, char *ep)
2224 int len = strlen(from);
2227 p = strrchr(from, '/');
2229 strncpy(to, from, ep - to);
2233 while (p > from && *p != '/')
2238 strncpy(to, "...", ep - to);
2243 strncpy(to, p, ep - to);
2252 * Function to write the path table for the disc.
2255 pathtab_write(FILE *outfile)
2257 /* Next we write the path tables */
2258 jtwrite(path_table_l, path_blocks << 11, 1, 0, FALSE);
2259 xfwrite(path_table_l, path_blocks << 11, 1, outfile, 0, FALSE);
2260 last_extent_written += path_blocks;
2261 jtwrite(path_table_m, path_blocks << 11, 1, 0, FALSE);
2262 xfwrite(path_table_m, path_blocks << 11, 1, outfile, 0, FALSE);
2263 last_extent_written += path_blocks;
2266 path_table_l = NULL;
2267 path_table_m = NULL;
2272 exten_write(FILE *outfile)
2274 jtwrite(extension_record, SECTOR_SIZE, 1, 0, FALSE);
2275 xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
2276 last_extent_written++;
2281 * Functions to describe padding block at the start of the disc.
2284 oneblock_size(int starting_extent)
2291 * Functions to describe path table size.
2294 pathtab_size(int starting_extent)
2296 path_table[0] = starting_extent;
2299 path_table[2] = path_table[0] + path_blocks;
2301 last_extent += 2 * path_blocks;
2306 * Functions to describe padding blocks before PVD.
2309 startpad_size(int starting_extent)
2311 last_extent = session_start + 16;
2316 * Functions to describe padding blocks between sections.
2319 interpad_size(int starting_extent)
2324 starting_extent += 16; /* First add 16 pad blocks */
2326 if ((emod = starting_extent % 16) != 0) {
2327 starting_extent += 16 - emod; /* Now pad to mod 16 # */
2329 last_extent = starting_extent;
2334 * Functions to describe padding blocks at end of disk.
2337 endpad_size(int starting_extent)
2339 starting_extent += 150; /* 150 pad blocks (post gap) */
2340 last_extent = starting_extent;
2348 int start_extent = last_extent; /* orig ISO files start */
2350 #endif /* APPLE_HYB */
2352 if (!assign_file_addresses(root, FALSE)) {
2355 comerrno(EX_BAD, "Unable to make a DVD-Video image.\n"
2356 "Possible reasons:\n"
2357 " - VIDEO_TS subdirectory was not found on specified location\n"
2358 " - VIDEO_TS has invalid contents\n"
2369 if (sort_file_addresses() == 0)
2370 reassign_link_addresses(root);
2372 #endif /* SORTING */
2376 * put this here for the time being - may when I've worked out how to
2377 * use Eric's new system for creating/writing parts of the image it
2378 * may move to it's own routine
2381 hfs_file_gen(start_extent);
2383 else if (use_prep_boot || use_chrp_boot)
2385 #endif /* PREP_BOOT */
2386 #endif /* APPLE_HYB */
2401 dirtree_fixup(int starting_extent)
2403 if (use_RockRidge && reloc_dir)
2404 finish_cl_pl_entries();
2407 update_nlink_field(root);
2412 dirtree_size(int starting_extent)
2414 assign_directory_addresses(root);
2419 ext_size(int starting_extent)
2421 extern int extension_record_size;
2422 struct directory_entry *s_entry;
2424 extension_record_extent = starting_extent;
2425 s_entry = root->contents;
2426 set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
2427 extension_record_extent);
2428 set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
2429 extension_record_size);
2435 dirtree_write(FILE *outfile)
2437 generate_iso9660_directories(root, outfile);
2442 dirtree_cleanup(FILE *outfile)
2444 free_directories(root);
2449 startpad_write(FILE *outfile)
2451 char buffer[SECTOR_SIZE];
2455 memset(buffer, 0, sizeof (buffer));
2457 npad = session_start + 16 - last_extent_written;
2459 for (i = 0; i < npad; i++) {
2460 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2461 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2462 last_extent_written++;
2469 interpad_write(FILE *outfile)
2471 char buffer[SECTOR_SIZE];
2475 memset(buffer, 0, sizeof (buffer));
2480 if ((i = last_extent_written % 16) != 0)
2483 for (i = 0; i < npad; i++) {
2484 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2485 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2486 last_extent_written++;
2493 endpad_write(FILE *outfile)
2495 char buffer[SECTOR_SIZE];
2498 memset(buffer, 0, sizeof (buffer));
2500 for (i = 0; i < 150; i++) {
2501 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2502 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2503 last_extent_written++;
2512 * hfs_get_parms: get HFS parameters from the command line
2516 hfs_get_parms(char *key)
2521 if (hfs_parms == NULL)
2524 if ((p = strstr(hfs_parms, key)) != NULL) {
2525 p += strlen(key) + 1;
2526 sscanf(p, "%d", &ret);
2533 * hfs_file_gen: set up "fake" HFS volume using the ISO9660 tree
2536 hfs_file_gen(int start_extent)
2538 int Csize; /* clump size for HFS vol */
2540 int last_extent_save = last_extent;
2543 /* allocate memory for the libhfs/genisoimage extra info */
2544 hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2546 hce->error = (char *) e_malloc(1024);
2548 /* mark as unallocated for use later */
2549 hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2551 /* reserve space for the label partition - if it is needed */
2553 /* a PReP bootable partition needs the map.. */
2554 if (gen_pt || use_prep_boot || use_chrp_boot)
2557 #endif /* PREP_BOOT */
2558 hce->hfs_map_size = HFS_MAP_SIZE;
2560 hce->hfs_map_size = 0;
2562 /* set the HFS parameter string to upper case */
2564 for (p = hfs_parms; *p; p++)
2568 /* set the initial factor to increase Catalog file size */
2569 if ((hce->ctc_size = hfs_get_parms("CTC")) == 0)
2570 hce->ctc_size = CTC;
2572 /* set the max size of the Catalog file */
2573 if ((hce->max_XTCsize = hfs_get_parms("MAX_XTCSIZE")) == 0)
2574 hce->max_XTCsize = MAX_XTCSIZE;
2576 /* set the number of time to try to make an HFS volume */
2577 if ((loop = hfs_get_parms("CTC_LOOP")) == 0)
2581 * "create" the HFS volume (just the header, catalog/extents files) if
2582 * there's a problem with the Catalog file being too small, we keep on
2583 * increasing the size (up to CTC_LOOP) times and try again.
2584 * Unfortunately I don't know enough about the inner workings of HFS,
2585 * so I can't workout the size of the Catalog file in advance (and I
2586 * don't want to "grow" as is is normally allowed to), therefore, this
2587 * approach is a bit over the top as it involves throwing away the
2588 * "volume" we have created and trying again ...
2591 hce->error[0] = '\0';
2593 /* attempt to create the Mac volume */
2594 Csize = make_mac_volume(root, start_extent);
2596 /* if we have a problem ... */
2599 * we've made too many attempts, or got some other
2602 if (loop == 0 || errno != HCE_ERROR) {
2603 /* HCE_ERROR is not a valid errno value */
2604 if (errno == HCE_ERROR)
2607 /* exit with the error */
2609 fprintf(stderr, "%s\n", hce->error);
2612 /* increase Catalog file size factor */
2613 hce->ctc_size *= CTC;
2616 * reset the initial "last_extent" and try
2619 last_extent = last_extent_save;
2622 /* everything OK - just carry on ... */
2628 hfs_extra = HFS_ROUND_UP(hce->hfs_tot_size) / SECTOR_SIZE;
2630 last_extent += hfs_extra;
2632 /* generate the Mac label and HFS partition maps */
2633 mac_boot.name = hfs_boot_file;
2636 * only generate the partition tables etc. if we are making a bootable
2637 * CD - or if the -part option is given
2640 if (gen_mac_label(&mac_boot)) {
2642 fprintf(stderr, "%s\n", hce->error);
2646 /* set Autostart filename if required */
2649 perr("Autostart filename must less than 12 characters");
2651 /* finished with any HFS type errors */
2656 * the ISO files need to start on a multiple of the HFS allocation
2657 * blocks, so find out how much padding we need
2661 * take in accout alignment of files wrt HFS volume start - remove any
2662 * previous session as well
2664 start_extent -= session_start;
2665 hfs_pad = ROUND_UP(start_extent*SECTOR_SIZE +
2666 (hce->hfs_hdr_size + hce->hfs_map_size) * HFS_BLOCKSZ,
2667 Csize) / SECTOR_SIZE;
2669 hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size) /
2673 gen_prepboot_label(hce->hfs_map);
2674 #endif /* PREP_BOOT */
2683 * we need to allocate the hce struct since hce->hfs_map is used to
2684 * generate the fdisk partition map required for PReP booting
2686 hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2688 /* mark as unallocated for use later */
2689 hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2691 /* reserve space for the label partition - if it is needed */
2692 hce->hfs_map_size = HFS_MAP_SIZE;
2694 hce->hfs_map = (unsigned char *) e_malloc(hce->hfs_map_size * HFS_BLOCKSZ);
2695 gen_prepboot_label(hce->hfs_map);
2698 #endif /* PREP_BOOT */
2701 * get_adj_size: get the ajusted size of the volume with the HFS
2702 * allocation block size for each file
2705 get_adj_size(int Csize)
2707 struct deferred_write *dw;
2711 /* loop through all the files finding the new total size */
2712 for (dw = dw_head; dw; dw = dw->next) {
2713 size += (ROUND_UP(dw->size, Csize)/HFS_BLOCKSZ);
2718 * crude attempt to prevent overflows - HFS can only cope with a
2719 * maximum of about 65536 forks (actually less) - this will trap cases
2720 * when we have far too many files
2730 * adj_size: adjust the ISO record entries for all files
2731 * based on the HFS allocation block size
2734 adj_size(int Csize, int start_extent, int extra)
2736 struct deferred_write *dw;
2737 struct directory_entry *s_entry;
2740 /* get the adjusted start_extent (with padding) */
2741 /* take in accout alignment of files wrt HFS volume start */
2743 start_extent -= session_start;
2745 start_extent = ROUND_UP(start_extent*SECTOR_SIZE + extra*HFS_BLOCKSZ,
2746 Csize) / SECTOR_SIZE;
2748 start_extent -= (extra / HFS_BLK_CONV);
2750 start_extent += session_start;
2752 /* initialise file hash */
2756 * loop through all files changing their starting blocks and finding
2757 * any padding needed to written out latter
2759 for (dw = dw_head; dw; dw = dw->next) {
2760 s_entry = dw->s_entry;
2761 s_entry->starting_block = dw->extent = start_extent;
2762 set_733((char *) s_entry->isorec.extent, start_extent);
2763 size = ROUND_UP(dw->size, Csize) / SECTOR_SIZE;
2764 dw->pad = size - ISO_ROUND_UP(dw->size) / SECTOR_SIZE;
2767 * cache non-HFS files - as there may be multiple links to
2768 * these files (HFS files can't have multiple links). We will
2769 * need to change the starting extent of the other links later
2771 if (!s_entry->hfs_ent)
2774 start_extent += size;
2777 return (start_extent);
2781 * adj_size_other: adjust any non-HFS files that may be linked
2782 * to an existing file (i.e. not have a deferred_write
2786 adj_size_other(struct directory *dpnt)
2788 struct directory_entry *s_entry;
2789 struct file_hash *s_hash;
2792 s_entry = dpnt->contents;
2793 for (s_entry = dpnt->contents; s_entry;
2794 s_entry = s_entry->next) {
2796 * if it's an HFS file or a directory - then ignore
2797 * (we're after non-HFS files)
2799 if (s_entry->hfs_ent ||
2800 (s_entry->isorec.flags[0] & ISO_DIRECTORY))
2804 * find any cached entry and assign new starting
2807 s_hash = find_hash(s_entry->dev, s_entry->inode);
2809 set_733((char *) s_entry->isorec.extent,
2810 s_hash->starting_block);
2811 /* not vital - but tidy */
2812 s_entry->starting_block =
2813 s_hash->starting_block;
2817 adj_size_other(dpnt->subdir);
2822 /* clear file hash */
2827 * hfs_hce_write: write out the HFS header stuff
2830 hfs_hce_write(FILE *outfile)
2832 char buffer[SECTOR_SIZE];
2834 int r; /* HFS hdr output */
2835 int tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
2837 memset(buffer, 0, sizeof (buffer));
2840 * hack time ... if the tot_size is greater than 32Kb then
2841 * it won't fit in the first 16 blank SECTORS (64 512 byte
2842 * blocks, as most of this is padding, we just truncate this
2843 * data to 64x4xHFS_BLOCKSZ ... hope this is OK ...
2846 if (tot_size > 64) tot_size = 64;
2848 /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
2849 n = tot_size / HFS_BLK_CONV;
2850 r = tot_size % HFS_BLK_CONV;
2852 /* write out HFS volume header info */
2853 jtwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, 0, FALSE);
2854 xfwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, outfile, 0, FALSE);
2856 /* fill up to a complete CD block */
2858 jtwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, 0, FALSE);
2859 xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
2862 last_extent_written += n;
2867 * insert_padding_file : insert a dumy file to make volume at least
2870 * XXX If we ever need to write more then 2 GB, make size off_t
2873 insert_padding_file(int size)
2875 struct deferred_write *dwpnt;
2877 /* get the size in bytes */
2878 size *= HFS_BLOCKSZ;
2880 dwpnt = (struct deferred_write *)
2881 e_malloc(sizeof (struct deferred_write));
2883 /* set the padding to zero */
2885 /* set offset to zero */
2886 dwpnt->off = (off_t)0;
2889 * don't need to wory about the s_entry stuff as it won't be touched#
2890 * at this point onwards
2893 /* insert the entry in the list */
2895 dw_tail->next = dwpnt;
2902 /* aloocate memory as a "Table" file */
2903 dwpnt->table = e_malloc(size);
2908 dwpnt->extent = last_extent;
2909 last_extent += ISO_BLOCKS(size);
2911 /* retune the size in HFS blocks */
2912 return (ISO_ROUND_UP(size) / HFS_BLOCKSZ);
2915 struct output_fragment hfs_desc = {NULL, NULL, NULL, hfs_hce_write, "HFS volume header"};
2917 #endif /* APPLE_HYB */
2919 struct output_fragment startpad_desc = {NULL, startpad_size, NULL, startpad_write, "Initial Padblock"};
2920 struct output_fragment voldesc_desc = {NULL, oneblock_size, root_gen, pvd_write, "Primary Volume Descriptor"};
2921 struct output_fragment xvoldesc_desc = {NULL, oneblock_size, NULL, xpvd_write, "Enhanced Volume Descriptor"};
2922 struct output_fragment end_vol = {NULL, oneblock_size, NULL, evd_write, "End Volume Descriptor" };
2923 struct output_fragment version_desc = {NULL, oneblock_size, NULL, vers_write, "Version block" };
2924 struct output_fragment pathtable_desc = {NULL, pathtab_size, generate_path_tables, pathtab_write, "Path table"};
2925 struct output_fragment dirtree_desc = {NULL, dirtree_size, NULL, dirtree_write, "Directory tree" };
2926 struct output_fragment dirtree_clean = {NULL, dirtree_fixup, dirtree_dump, dirtree_cleanup, "Directory tree cleanup" };
2927 struct output_fragment extension_desc = {NULL, ext_size, NULL, exten_write, "Extension record" };
2928 struct output_fragment files_desc = {NULL, NULL, file_gen, file_write, "The File(s)"};
2929 struct output_fragment interpad_desc = {NULL, interpad_size, NULL, interpad_write, "Intermediate Padblock"};
2930 struct output_fragment endpad_desc = {NULL, endpad_size, NULL, endpad_write, "Ending Padblock"};