patch genisoimage multi extent
[platform/upstream/cdrkit.git] / genisoimage / write.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
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 */
16 /*
17  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
18  *
19  * Written by Eric Youngdale (1993).
20  *
21  * Copyright 1993 Yggdrasil Computing, Incorporated
22  * Copyright (c) 1999-2003 J. Schilling
23  *
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)
27  * any later version.
28  *
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.
33  *
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.
37  */
38
39 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
40
41 #include <mconfig.h>
42 #include "genisoimage.h"
43 #include <timedefs.h>
44 #include <fctldefs.h>
45 #ifdef SORTING
46 #include "match.h"
47 #endif /* SORTING */
48 #include <errno.h>
49 #include <schily.h>
50 #ifdef DVD_VIDEO
51 #include "dvd_reader.h"
52 #include "dvd_file.h"
53 #include "ifo_read.h"
54 #endif
55 #ifdef APPLE_HYB
56 #include <ctype.h>
57 #endif
58
59 #ifdef  VMS
60 #include "vms.h"
61 #endif
62
63 /* Max number of sectors we will write at  one time */
64 #define NSECT 16
65
66 /* Counters for statistics */
67
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;
73 static int      sort_goof;
74
75 static int      is_rr_dir = 0;
76
77 struct output_fragment *out_tail;
78 struct output_fragment *out_list;
79
80 struct iso_primary_descriptor vol_desc;
81
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);
88 int     get_731(char *p);
89 int     get_732(char *p);
90 int     get_733(char *p);
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, 
94                                   BOOL islast);
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, 
98                                                                                 off_t off);
99 #else
100 static  void    write_one_file(char *filename, off_t size, FILE *outfile);
101 #endif
102 static  void    write_files(FILE *outfile);
103 #if 0
104 static  void    dump_filelist   __PR((void));
105 #endif
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);
142 #ifdef APPLE_HYB
143 static  int     hfs_pad;
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 */
153
154 #ifdef SORTING
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);
158 #endif /* SORTING */
159
160 /*
161  * Routines to actually write the disc.  We write sequentially so that
162  * we could write a tape, or write the disc directly
163  */
164 #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof (vol_desc.X))
165
166 void
167 set_721(char *pnt, unsigned int i)
168 {
169         pnt[0] = i & 0xff;
170         pnt[1] = (i >> 8) & 0xff;
171 }
172
173 void
174 set_722(char *pnt, unsigned int i)
175 {
176         pnt[0] = (i >> 8) & 0xff;
177         pnt[1] = i & 0xff;
178 }
179
180 void
181 set_723(char *pnt, unsigned int i)
182 {
183         pnt[3] = pnt[0] = i & 0xff;
184         pnt[2] = pnt[1] = (i >> 8) & 0xff;
185 }
186
187 void
188 set_731(char *pnt, unsigned int i)
189 {
190         pnt[0] = i & 0xff;
191         pnt[1] = (i >> 8) & 0xff;
192         pnt[2] = (i >> 16) & 0xff;
193         pnt[3] = (i >> 24) & 0xff;
194 }
195
196 void
197 set_732(char *pnt, unsigned int i)
198 {
199         pnt[3] = i & 0xff;
200         pnt[2] = (i >> 8) & 0xff;
201         pnt[1] = (i >> 16) & 0xff;
202         pnt[0] = (i >> 24) & 0xff;
203 }
204
205 void
206 set_733(char *pnt, unsigned int i)
207 {
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;
212 }
213
214 int
215 get_731(char *p)
216 {
217         return ((p[0] & 0xff)
218                 | ((p[1] & 0xff) << 8)
219                 | ((p[2] & 0xff) << 16)
220                 | ((p[3] & 0xff) << 24));
221 }
222
223 int
224 get_732(char *p)
225 {
226         return ((p[3] & 0xff)
227                 | ((p[2] & 0xff) << 8)
228                 | ((p[1] & 0xff) << 16)
229                 | ((p[0] & 0xff) << 24));
230 }
231
232 int
233 get_733(char *p)
234 {
235         return ((p[0] & 0xff)
236                 | ((p[1] & 0xff) << 8)
237                 | ((p[2] & 0xff) << 16)
238                 | ((p[3] & 0xff) << 24));
239 }
240
241 void
242 xfwrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
243 {
244         /*
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
251          * option.
252          */
253         static int      idx = 0;
254
255 #ifdef  XFWRITE_DEBUG
256         if (count != 1 || (size % 2048) != 0)
257                 fprintf(stderr, "Count: %d, size: %d\n", count, size);
258 #endif
259
260         if (split_output != 0 &&
261                 (idx == 0 || ftell(file) >= ((off_t)1024 * 1024 * 1024))) {
262                 char            nbuf[512];
263                 extern char     *outfile;
264
265                 if (idx == 0)
266                         unlink(outfile);
267                 sprintf(nbuf, "%s_%02d", outfile, idx++);
268                 file = freopen(nbuf, "wb", file);
269                 if (file == NULL) {
270 #ifdef  USE_LIBSCHILY
271                         comerr("Cannot open '%s'.\n", nbuf);
272 #else
273                         fprintf(stderr, "Cannot open '%s'.\n", nbuf);
274                         exit(1);
275 #endif
276                 }
277         }
278         while (count) {
279                 int     got;
280
281                 seterrno(0);
282                 if (osecsize != 0)
283                         got = xawrite(buffer, size, count, file, submode, islast);
284                 else
285                         got = fwrite(buffer, size, count, file);
286
287                 if (got <= 0) {
288 #ifdef  USE_LIBSCHILY
289                         comerr("cannot fwrite %d*%d\n", size, count);
290 #else
291                         fprintf(stderr, "cannot fwrite %d*%d\n", size, count);
292                         exit(1);
293 #endif
294                 }
295                 /*
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.
306                  */
307                 count -= got;
308                 buffer = (void *)(((char *)buffer) + size * got);
309         }
310 }
311
312 static int
313 xawrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
314 {
315         register char   *p = buffer;
316         register int    amt = size * count;
317         register int    n;
318         struct xa_subhdr subhdr[2];
319
320         if (osecsize == 2048)
321                 return (fwrite(buffer, size, count, file));
322
323         if (amt % 2048)
324                 comerrno(EX_BAD,
325                         "Trying to write %d bytes (not a multiple of 2048).\n",
326                         amt);
327
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;
331
332         while (amt > 0) {
333 #ifdef  LATER
334                 if (submode < 0)
335                         subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
336                 else
337                         subhdr[0].sub_mode = subhdr[1].sub_mode = submode;
338 #else
339                 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
340 #endif
341
342                 if ((amt <= 2048) && islast) {
343                         subhdr[0].sub_mode = subhdr[1].sub_mode
344                                                 |= (XA_SUBH_EOR|XA_SUBH_EOF);
345                 }
346                 n = fwrite(&subhdr, sizeof (subhdr), 1, file);
347                 if (n <= 0)
348                         return (n);
349
350                 n = fwrite(p, 2048, 1, file);
351                 if (n <= 0)
352                         return (n);
353
354                 p += 2048;
355                 amt -= 2048;
356         }
357         return (1);
358 }
359
360 #ifdef APPLE_HYB
361 /*
362  * use the deferred_write struct to store info about the hfs_boot_file
363  */
364 static struct deferred_write mac_boot;
365
366 #endif  /* APPLE_HYB */
367 static struct deferred_write    *dw_head = NULL,
368                                 *dw_tail = NULL;
369
370 unsigned int    last_extent_written = 0;
371 static  Uint    path_table_index;
372 time_t  begun;
373
374 /*
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
378  */
379 static int
380 assign_directory_addresses(struct directory *node)
381 {
382         int             dir_size;
383         struct directory *dpnt;
384
385         dpnt = node;
386
387         while (dpnt) {
388                 /* skip if it's hidden */
389                 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
390                         dpnt = dpnt->next;
391                         continue;
392                 }
393                 /*
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.
396                  */
397                 dpnt->path_index = next_path_index++;
398                 if (dpnt->extent == 0) {
399                         dpnt->extent = last_extent;
400                         dir_size = ISO_BLOCKS(dpnt->size);
401
402                         last_extent += dir_size;
403
404                         /*
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.
408                          */
409                         if (dpnt->ce_bytes) {
410                                 last_extent += ISO_BLOCKS(dpnt->ce_bytes);
411                         }
412                 }
413                 if (dpnt->subdir) {
414                         assign_directory_addresses(dpnt->subdir);
415                 }
416                 dpnt = dpnt->next;
417         }
418         return (0);
419 }
420
421 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
422 static void
423 write_one_file(char *filename, off_t size, FILE *outfile, off_t off)
424 #else
425 static void
426 write_one_file(char *filename, off_t size, FILE *outfile)
427 #endif  /* APPLE_HYB || USE_LARGEFILES */
428 {
429         /*
430          * It seems that there are still stone age C-compilers
431          * around.
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.
436          */
437 static  char            buffer[SECTOR_SIZE * NSECT];
438         FILE            *infile;
439         off_t           remain;
440         int     use;
441
442         char *mirror_name;
443         unsigned char md5[16];
444         int include_in_jigdo = list_file_in_jigdo(filename, size, &mirror_name, md5);
445
446         if ((infile = fopen(filename, "rb")) == NULL) {
447 #ifdef  USE_LIBSCHILY
448                 comerr("cannot open '%s'\n", filename);
449 #else
450 #ifndef HAVE_STRERROR
451                 fprintf(stderr, "cannot open '%s': (%d)\n",
452                                 filename, errno);
453 #else
454                 fprintf(stderr, "cannot open '%s': %s\n",
455                                 filename, strerror(errno));
456 #endif
457                 exit(1);
458 #endif
459         }
460 #if defined(APPLE_HYB) || defined(USE_LARGEFILES)
461         fseek(infile, off, SEEK_SET);
462 #endif  /* APPLE_HYB || USE_LARGEFILES */
463         remain = size;
464
465         if (include_in_jigdo)
466                 write_jt_match_record(filename, mirror_name, SECTOR_SIZE, size, md5);
467
468         while (remain > 0) {
469                 int     amt;
470
471                 use = (remain > SECTOR_SIZE * NSECT - 1 ?
472                                 NSECT * SECTOR_SIZE : remain);
473                 use = ISO_ROUND_UP(use);        /* Round up to nearest sector */
474                                                 /* boundary */
475                 memset(buffer, 0, use);
476                 seterrno(0);
477                 amt = fread(buffer, 1, use, infile);
478                 if (amt < use && amt < remain) {
479                         /*
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.
483                          */
484                         if (geterrno() == 0) {
485 #ifdef  USE_LIBSCHILY
486          comerrno(EX_BAD,
487                "File '%s' did shrink.\n"
488                "Files must not be changed while genisoimage runs!\n",
489                filename);
490 #else
491          fprintf(stderr,
492                "File '%s' did shrink.\n"
493                "Files must not be changed while genisoimage runs!\n",
494                filename);
495                                 exit(EX_BAD);
496 #endif
497                         }
498 #ifdef  USE_LIBSCHILY
499                         comerr("Cannot read from '%s'\n", filename);
500 #else
501                         fprintf(stderr, "Cannot read from '%s'\n", filename);
502                         exit(1);
503 #endif
504                 }
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;
511 #if 0
512                 if ((last_extent_written % 1000) < use / SECTOR_SIZE) {
513                         fprintf(stderr, "%d..", last_extent_written);
514                 }
515 #else
516                 if (verbose > 0 &&
517                     (int)(last_extent_written % (gui ? 500 : 5000)) <
518                                                         use / SECTOR_SIZE) {
519                         time_t  now;
520                         time_t  the_end;
521                         double  frac;
522
523                         time(&now);
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));
529 #else
530                         fprintf(stderr, "%3d.%-02d%% done, estimate finish %s",
531                                 (int)(frac * 100.),
532                                 (int)((frac+.00005) * 10000.)%100,
533                                 ctime(&the_end));
534 #endif
535                         fflush(stderr);
536                 }
537 #endif
538                 remain -= use;
539         }
540         fclose(infile);
541 }/* write_one_file(... */
542
543 static void
544 write_files(FILE *outfile)
545 {
546         struct deferred_write   *dwpnt,
547                                 *dwnext;
548
549         dwpnt = dw_head;
550         while (dwpnt) {
551 /*#define DEBUG*/
552 #ifdef DEBUG
553                 fprintf(stderr,
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);
557 #endif
558                 if (dwpnt->table) {
559                         jtwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1, XA_SUBH_DATA, TRUE);
560                         xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
561                                                         outfile,
562                                                         XA_SUBH_DATA, TRUE);
563                         last_extent_written += ISO_BLOCKS(dwpnt->size);
564                         table_size += dwpnt->size;
565 /*                      fprintf(stderr, "Size %lld ", (Llong)dwpnt->size); */
566                         free(dwpnt->table);
567                         dwpnt->table = NULL;
568                 } else {
569
570 #ifdef VMS
571                         vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
572 #else
573 #ifdef APPLE_HYB
574                         write_one_file(dwpnt->name, dwpnt->size, outfile,
575                                                                 dwpnt->off);
576 #else
577                         write_one_file(dwpnt->name, dwpnt->size, outfile);
578 #endif  /* APPLE_HYB */
579 #endif
580                         free(dwpnt->name);
581                         dwpnt->name = NULL;
582                 }
583
584
585 #ifndef DVD_VIDEO
586 #define dvd_video       0
587 #endif
588
589 #ifndef APPLE_HYB
590 #define apple_hyb       0
591 #endif
592
593 #if     defined(APPLE_HYB) || defined(DVD_VIDEO)
594
595                 if (apple_hyb || dvd_video) {
596                         /*
597                          * we may have to pad out ISO files to work with HFS
598                          * clump sizes
599                          */
600                         char    blk[SECTOR_SIZE];
601                         Uint    i;
602
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++;
607                         }
608                 }
609 #endif  /* APPLE_HYB || DVD_VIDEO */
610
611
612                 dwnext = dwpnt;
613                 dwpnt = dwpnt->next;
614                 free(dwnext);
615                 dwnext = NULL;
616         }
617 }/* write_files(... */
618
619 #if 0
620 static void
621 dump_filelist()
622 {
623         struct deferred_write *dwpnt;
624
625         dwpnt = dw_head;
626         while (dwpnt) {
627                 fprintf(stderr, "File %s\n", dwpnt->name);
628                 dwpnt = dwpnt->next;
629         }
630         fprintf(stderr, "\n");
631 }
632
633 #endif
634
635 static int
636 compare_dirs(const void *rr, const void *ll)
637 {
638         char            *rpnt,
639                         *lpnt;
640         struct directory_entry **r,
641                         **l;
642
643         r = (struct directory_entry **) rr;
644         l = (struct directory_entry **) ll;
645         rpnt = (*r)->isorec.name;
646         lpnt = (*l)->isorec.name;
647
648 #ifdef APPLE_HYB
649         /*
650          * resource fork MUST (not sure if this is true for HFS volumes) be
651          * before the data fork - so force it here
652          */
653         if ((*r)->assoc && (*r)->assoc == (*l))
654                 return (1);
655         if ((*l)->assoc && (*l)->assoc == (*r))
656                 return (-1);
657 #endif  /* APPLE_HYB */
658
659         /*
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
662          * is an error.
663          */
664         if (strcmp(rpnt, lpnt) == 0) {
665 #ifdef USE_LARGEFILES
666                 if ((*r)->mxpart < (*l)->mxpart)
667                         return (-1);
668                 else if ((*r)->mxpart > (*l)->mxpart)
669                         return (1);
670 #endif
671 #ifdef  USE_LIBSCHILY
672                 errmsgno(EX_BAD,
673                         "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
674                         (*r)->whole_name, (*l)->whole_name,
675                         rpnt);
676 #else
677                 fprintf(stderr,
678                         "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
679                         (*r)->whole_name, (*l)->whole_name,
680                         rpnt);
681 #endif
682                 sort_goof++;
683         }
684         /* Check we don't have the same RR name */
685         if (use_RockRidge && !is_rr_dir) {
686                 /*
687                  * entries *can* have the same RR name in the "rr_moved"
688                  * directory so skip checks if we're in reloc_dir
689                  */
690                 if (!(strcmp((*r)->name, (*l)->name))) {
691 #ifdef  USE_LIBSCHILY
692                         errmsgno(EX_BAD,
693                         "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
694                                 (*r)->whole_name, (*l)->whole_name,
695                                 (*r)->name);
696 #else
697                         fprintf(stderr,
698                         "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
699                                 (*r)->whole_name, (*l)->whole_name,
700                                 (*r)->name);
701 #endif
702                         sort_goof++;
703                 }
704         }
705         /*
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.
713          */
714 #if 0
715         if (strcmp(rpnt, ".") == 0)
716                 return (-1);
717         if (strcmp(lpnt, ".") == 0)
718                 return (1);
719
720         if (strcmp(rpnt, "..") == 0)
721                 return (-1);
722         if (strcmp(lpnt, "..") == 0)
723                 return (1);
724 #else
725         /*
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)
730          */
731         if ((*r)->isorec.name_len[0] == 1 && *rpnt == 0)
732                 return (-1);    /* '.' */
733         if ((*l)->isorec.name_len[0] == 1 && *lpnt == 0)
734                 return (1);
735
736         if ((*r)->isorec.name_len[0] == 1 && *rpnt == 1)
737                 return (-1);    /* '..' */
738         if ((*l)->isorec.name_len[0] == 1 && *lpnt == 1)
739                 return (1);
740 #endif
741
742         while (*rpnt && *lpnt) {
743                 if (*rpnt == ';' && *lpnt != ';')
744                         return (-1);
745                 if (*rpnt != ';' && *lpnt == ';')
746                         return (1);
747
748                 if (*rpnt == ';' && *lpnt == ';')
749                         return (0);
750
751                 if (*rpnt == '.' && *lpnt != '.')
752                         return (-1);
753                 if (*rpnt != '.' && *lpnt == '.')
754                         return (1);
755
756                 if ((unsigned char) *rpnt < (unsigned char) *lpnt)
757                         return (-1);
758                 if ((unsigned char) *rpnt > (unsigned char) *lpnt)
759                         return (1);
760                 rpnt++;
761                 lpnt++;
762         }
763         if (*rpnt)
764                 return (1);
765         if (*lpnt)
766                 return (-1);
767         return (0);
768 }
769
770 /*
771  * Function:            sort_directory
772  *
773  * Purpose:             Sort the directory in the appropriate ISO9660
774  *                      order.
775  *
776  * Notes:               Returns 0 if OK, returns > 0 if an error occurred.
777  */
778 int
779 sort_directory(struct directory_entry **sort_dir, int rr)
780 {
781         int             dcount = 0;
782         int             xcount = 0;
783         int             j;
784         int             i,
785                         len;
786         struct directory_entry *s_entry;
787         struct directory_entry **sortlist;
788
789         /* need to keep a count of how many entries are hidden */
790         s_entry = *sort_dir;
791         while (s_entry) {
792                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
793                         xcount++;
794                 dcount++;
795                 s_entry = s_entry->next;
796         }
797
798         if (dcount == 0) {
799                 return (0);
800         }
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);
804
805         j = dcount - 1;
806         dcount = 0;
807         s_entry = *sort_dir;
808         while (s_entry) {
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;
812                 } else {
813                         sortlist[dcount] = s_entry;
814                         dcount++;
815                 }
816                 len = s_entry->isorec.name_len[0];
817                 s_entry->isorec.name[len] = 0;
818                 s_entry = s_entry->next;
819         }
820
821         /* Each directory is required to contain at least . and .. */
822         if (dcount < 2) {
823 #ifdef  USE_LIBSCHILY
824                 errmsgno(EX_BAD,
825                         "Directory size too small (. or .. missing ??%s)\n",
826                         "?");   /* Try to avoid a GCC trigraph warning */
827 #else
828                 fprintf(stderr,
829                         "Directory size too small (. or .. missing ??%s)\n",
830                         "?");   /* Try to avoid a GCC trigraph warning */
831 #endif
832                 sort_goof = 1;
833
834         } else {
835                 /* only sort the non-hidden entries */
836                 sort_goof = 0;
837                 is_rr_dir = rr;
838 #ifdef PROTOTYPES
839                 qsort(sortlist, dcount, sizeof (struct directory_entry *),
840                         (int (*) (const void *, const void *)) compare_dirs);
841 #else
842                 qsort(sortlist, dcount, sizeof (struct directory_entry *),
843                         compare_dirs);
844 #endif
845
846                 /*
847                  * Now reassemble the linked list in the proper sorted order
848                  * We still need the hidden entries, as they may be used in
849                  * the Joliet tree.
850                  */
851                 for (i = 0; i < dcount + xcount - 1; i++) {
852                         sortlist[i]->next = sortlist[i + 1];
853                 }
854
855                 sortlist[dcount + xcount - 1]->next = NULL;
856                 *sort_dir = sortlist[0];
857         }
858
859         free(sortlist);
860         sortlist = NULL;
861         return (sort_goof);
862 }
863
864 static int
865 root_gen()
866 {
867         init_fstatbuf();
868
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;
880         return (0);
881 }
882
883 #ifdef SORTING
884 /*
885  *      sorts deferred_write entries based on the sort weight
886  */
887 static int
888 compare_sort(const void *rr, const void *ll)
889 {
890         struct deferred_write   **r;
891         struct deferred_write   **l;
892         int                     r_sort;
893         int                     l_sort;
894
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;
899
900         if (r_sort != l_sort)
901                 return (r_sort < l_sort ? 1 : -1);
902         else
903                 return ((*r)->extent - (*l)->extent);
904 }
905
906 /*
907  *      reassign start extents to files that are "hard links" to
908  *      files that may have been sorted
909  */
910 static void
911 reassign_link_addresses(struct directory *dpnt)
912 {
913         struct directory_entry  *s_entry;
914         struct file_hash        *s_hash;
915
916         while (dpnt) {
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)
921                         {
922                                 /* update the start extent */
923                                 s_hash = find_hash(s_entry->dev, s_entry->inode);
924                                 if (s_hash) {
925                                         set_733((char *) s_entry->isorec.extent,
926                                                         s_hash->starting_block);
927                                         s_entry->starting_block = s_hash->starting_block;
928                                 }
929                         }
930
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));
935
936                                 if (s_entry->inode != TABLE_INODE) {
937                                         fprintf(stderr, "%s\n", s_entry->whole_name);
938                                 } else {
939                                         fprintf(stderr, "%s%s%s\n",
940                                                 s_entry->filedir->whole_name,
941                                                 SPATH_SEPARATOR, trans_tbl);
942                                 }
943                         }
944                 }
945                 if (dpnt->subdir) {
946                         reassign_link_addresses(dpnt->subdir);
947                 }
948
949                 dpnt = dpnt->next;
950         }
951 }
952
953 /*
954  *      sort files in order of the given sort weight
955  */
956 static int
957 sort_file_addresses()
958 {
959         struct deferred_write   *dwpnt;
960         struct deferred_write   **sortlist;
961         struct directory_entry  *s_entry;
962         int                     start_extent;
963         int                     num = 0;
964         int                     i;
965
966         /* need to store start extents for linked files */
967         flush_hash();
968
969         /* find out how many files we have */
970         dwpnt = dw_head;
971         while (dwpnt) {
972                 num++;
973                 dwpnt = dwpnt->next;
974         }
975
976         /* return if we have none */
977         if (num == 0) {
978                 return (1);
979         }
980
981         /* save the start extent of the first file */
982         start_extent = dw_head->extent;
983
984         /* set up vector to store entries */
985         sortlist = (struct deferred_write **)
986                 e_malloc(sizeof (struct deferred_write *) * num);
987
988         for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next)
989                 sortlist[i] = dwpnt;
990
991         /* sort the list */
992 #ifdef PROTOTYPES
993         qsort(sortlist, num, sizeof (struct deferred_write *),
994                 (int (*)(const void *, const void *))compare_sort);
995 #else
996         qsort(sortlist, num, sizeof (struct deferred_write *), compare_sort);
997 #endif
998
999         /* reconstruct the linked list */
1000         for (i = 0; i < num-1; i++) {
1001                 sortlist[i]->next = sortlist[i+1];
1002         }
1003
1004         sortlist[num-1]->next = NULL;
1005         dw_head = sortlist[0];
1006
1007         free(sortlist);
1008
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);
1014
1015                 start_extent += ISO_BLOCKS(s_entry->size);
1016 #ifdef DVD_VIDEO
1017                 /*
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
1020                  */
1021                 if (dvd_video) {
1022                         start_extent += dwpnt->pad;
1023                 }
1024 #endif /* DVD_VIDEO */
1025
1026                 /* cache start extents for any linked files */
1027                 add_hash(s_entry);
1028         }
1029
1030         return (0);
1031 }
1032 #endif /* SORTING */
1033
1034
1035
1036 static BOOL
1037 assign_file_addresses(struct directory *dpnt, BOOL isnest)
1038 {
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];
1044 #ifdef DVD_VIDEO
1045         char            dvd_path[PATH_MAX];
1046         title_set_info_t * title_set_info = NULL;
1047         char    *p;
1048 #endif
1049         BOOL    ret = FALSE;
1050
1051         while (dpnt) {
1052 #ifdef DVD_VIDEO
1053                 if (dvd_video && root == dpnt->parent &&
1054                     ((p = strstr(dpnt->whole_name, "VIDEO_TS")) != 0)&&
1055                     strcmp(p, "VIDEO_TS") == 0) {
1056
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';
1062
1063 #ifdef DEBUG
1064                         fprintf(stderr, "Found 'VIDEO_TS', the path is %s \n", dvd_path);
1065 #endif
1066                         title_set_info = DVDGetFileSet(dvd_path);
1067                         if (title_set_info == 0) {
1068                                 /*
1069                                  * Do not switch off -dvd-video but let is fail later.
1070                                  */
1071 /*                              dvd_video = 0;*/
1072                                 errmsgno(EX_BAD, "Unable to parse DVD-Video structures.\n");
1073                         } else {
1074                                 ret = TRUE;
1075                         }
1076                 }
1077 #endif /* DVD_VIDEO */
1078
1079                 for (s_entry = dpnt->contents; s_entry;
1080                                                 s_entry = s_entry->next) {
1081                         /*
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.
1086                          */
1087                         if (get_733(s_entry->isorec.extent) != 0) {
1088                                 continue;
1089                         }
1090                         /*
1091                          * This saves some space if there are symlinks present.
1092                          * If this is a multi-extent file, we get mxpart == 1
1093                          * from find_hash().
1094                          */
1095                         s_hash = find_hash(s_entry->dev, s_entry->inode);
1096                         if (s_hash) {
1097                                 if (verbose > 2) {
1098                                         fprintf(stderr, "Cache hit for '%s%s%s'\n", s_entry->filedir->de_name,
1099                                                 SPATH_SEPARATOR,
1100                                                 s_entry->name);
1101                                 }
1102                                 set_733((char *) s_entry->isorec.extent,
1103                                                 s_hash->starting_block);
1104                                 set_733((char *) s_entry->isorec.size,
1105                                                 s_hash->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;
1110
1111                                         /*
1112                                          * Skip the multi extent root entry.
1113                                          */
1114                                         if (s_entry->mxpart == 0)
1115                                                 continue;
1116                                         /*
1117                                          * The directory is sorted, so we should
1118                                          * see s_entry->mxpart == 1 first.
1119                                          */
1120                                         if (s_entry->mxpart != 1) {
1121                                                 comerrno(EX_BAD,
1122                                                 "Panic: Multi extent parts for %s not sorted.\n",
1123                                                 s_entry->whole_name);
1124                                         }
1125                                         s_entry->mxroot->starting_block = ext;
1126                                         for (s_e = s_entry;
1127                                             s_e && s_e->mxroot == s_entry->mxroot;
1128                                                                 s_e = s_e->next) {
1129                                                 set_733((char *) s_e->isorec.extent,
1130                                                                         ext);
1131                                                 ext += ISO_BLOCKS(s_e->size);
1132                                         }
1133                                 }
1134 #endif
1135
1136 #ifdef SORTING
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;
1143                                 }
1144 #endif /* SORTING */
1145                                 continue;
1146                         }
1147                         /*
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
1152                          * here.
1153                          */
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;
1158                                 while (1 == 1) {
1159                                         if (finddir->self == s_entry)
1160                                                 break;
1161                                         finddir = finddir->next;
1162                                         if (!finddir) {
1163 #ifdef  DVD_VIDEO
1164                                                 if (title_set_info != 0) {
1165                                                         DVDFreeFileSet(title_set_info);
1166                                                 }
1167 #endif
1168                                                 comerrno(EX_BAD,
1169                                                         "Fatal goof - could not find dir entry for '%s'\n",
1170                                                         s_entry->name);
1171                                         }
1172                                 }
1173                                 set_733((char *) s_entry->isorec.extent,
1174                                                 finddir->extent);
1175                                 s_entry->starting_block = finddir->extent;
1176                                 s_entry->size = ISO_ROUND_UP(finddir->size);
1177                                 total_dir_size += s_entry->size;
1178                                 add_hash(s_entry);
1179                                 set_733((char *) s_entry->isorec.size,
1180                                                 ISO_ROUND_UP(finddir->size));
1181                                 continue;
1182                         }
1183                         /*
1184                          * If this is . or .., then look up the relevant info
1185                          * from the tables.
1186                          */
1187                         if (strcmp(s_entry->name, ".") == 0) {
1188                                 set_733((char *) s_entry->isorec.extent,
1189                                                                 dpnt->extent);
1190
1191                                 /*
1192                                  * Set these so that the hash table has the
1193                                  * correct information
1194                                  */
1195                                 s_entry->starting_block = dpnt->extent;
1196                                 s_entry->size = ISO_ROUND_UP(dpnt->size);
1197
1198                                 add_hash(s_entry);
1199                                 s_entry->starting_block = dpnt->extent;
1200                                 set_733((char *) s_entry->isorec.size,
1201                                                 ISO_ROUND_UP(dpnt->size));
1202                                 continue;
1203                         }
1204                         if (strcmp(s_entry->name, "..") == 0) {
1205                                 if (dpnt == root) {
1206                                         total_dir_size += root->size;
1207                                 }
1208                                 set_733((char *) s_entry->isorec.extent,
1209                                                         dpnt->parent->extent);
1210
1211                                 /*
1212                                  * Set these so that the hash table has the
1213                                  * correct information
1214                                  */
1215                                 s_entry->starting_block = dpnt->parent->extent;
1216                                 s_entry->size =
1217                                         ISO_ROUND_UP(dpnt->parent->size);
1218
1219                                 add_hash(s_entry);
1220                                 s_entry->starting_block = dpnt->parent->extent;
1221                                 set_733((char *) s_entry->isorec.size,
1222                                         ISO_ROUND_UP(dpnt->parent->size));
1223                                 continue;
1224                         }
1225                         /*
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
1231                          * these files
1232                          */
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 */
1239                                 dwpnt->pad = 0;
1240 #ifdef DVD_VIDEO
1241                                 if (dvd_video && (title_set_info != 0)) {
1242                                         int pad;
1243
1244                                         pad = DVDGetFilePad(title_set_info, s_entry->name);
1245                                         if (pad < 0) {
1246                                                 errmsgno(EX_BAD,
1247                                                 "Implementation botch. Video pad for file %s is %d\n",
1248                                                 s_entry->name, pad),
1249                                                 comerrno(EX_BAD,
1250                                                 "Either the *.IFO file is bad or you found a genisoimage bug.\n");
1251                                         }
1252                                         dwpnt->pad = pad;
1253                                         if (verbose > 0 && pad != 0) {
1254                                                 fprintf(stderr,
1255                                                         "The pad was %d for file %s\n", dwpnt->pad, s_entry->name);
1256                                         }
1257                                 }
1258 #endif /* DVD_VIDEO */
1259 #ifdef APPLE_HYB
1260                                 /*
1261                                  * maybe an offset to start of the real
1262                                  * file/fork
1263                                  */
1264                                 dwpnt->off = s_entry->hfs_off;
1265 #else
1266                                 dwpnt->off = (off_t)0;
1267 #endif  /* APPLE_HYB */
1268                                 if (dw_tail) {
1269                                         dw_tail->next = dwpnt;
1270                                         dw_tail = dwpnt;
1271                                 } else {
1272                                         dw_head = dwpnt;
1273                                         dw_tail = dwpnt;
1274                                 }
1275                                 if (s_entry->inode == TABLE_INODE) {
1276                                         dwpnt->table = s_entry->table;
1277                                         dwpnt->name = NULL;
1278                                         sprintf(whole_path, "%s%s%s",
1279                                                 s_entry->filedir->whole_name,
1280                                                 SPATH_SEPARATOR, trans_tbl);
1281                                 } else {
1282                                         dwpnt->table = NULL;
1283                                         strcpy(whole_path, s_entry->whole_name);
1284                                         dwpnt->name = strdup(whole_path);
1285                                 }
1286                                 dwpnt->next = NULL;
1287                                 dwpnt->size = s_entry->size;
1288                                 dwpnt->extent = last_extent;
1289                                 set_733((char *) s_entry->isorec.extent,
1290                                                                 last_extent);
1291                                 s_entry->starting_block = last_extent;
1292 #ifdef USE_LARGEFILES
1293                                 /*
1294                                  * Update the entries for multi-section files
1295                                  * as we now know the starting extent numbers.
1296                                  */
1297                                 if (s_entry->de_flags & MULTI_EXTENT) {
1298                                         struct directory_entry *s_e;
1299                                         unsigned int            ext = last_extent;
1300
1301                                         /*
1302                                          * Skip the multi extent root entry.
1303                                          */
1304                                         if (s_entry->mxpart == 0)
1305                                                 continue;
1306                                         /*
1307                                          * The directory is sorted, so we should
1308                                          * see s_entry->mxpart == 1 first.
1309                                          */
1310                                         if (s_entry->mxpart != 1) {
1311                                                 comerrno(EX_BAD,
1312                                                 "Panic: Multi extent parts for %s not sorted.\n",
1313                                                 s_entry->whole_name);
1314                                         }
1315                                         dwpnt->size = s_entry->mxroot->size;
1316                                         s_entry->mxroot->starting_block = ext;
1317                                         /*
1318                                          * Set the mxroot (mxpart == 0) to allow
1319                                          * the UDF code to fetch the starting
1320                                          * extent number.
1321                                          */
1322                                         set_733((char *) s_entry->mxroot->isorec.extent, ext);
1323                                         for (s_e = s_entry;
1324                                             s_e && s_e->mxroot == s_entry->mxroot;
1325                                                                 s_e = s_e->next) {
1326                                                 if (s_e->mxpart == 0)
1327                                                         continue;
1328                                                 set_733((char *) s_e->isorec.extent,
1329                                                                         ext);
1330                                                 ext += ISO_BLOCKS(s_e->size);
1331                                         }
1332                                         add_hash(s_entry);
1333                                 }
1334 #endif
1335                                 add_hash(s_entry);
1336                                 /*
1337                                  * The cache holds the full size of the file
1338                                  */
1339                                 last_extent += ISO_BLOCKS(dwpnt->size);
1340 #ifdef DVD_VIDEO
1341                                 /* Shouldn't we always add the pad info? */
1342                                 if (dvd_video) {
1343                                         last_extent += dwpnt->pad;
1344                                 }
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);
1350                                 }
1351 #ifdef DBG_ISO
1352                                 if (ISO_BLOCKS(s_entry->size) > 500) {
1353                                         fprintf(stderr,
1354                                                 "Warning: large file '%s'\n",
1355                                                 whole_path);
1356                                         fprintf(stderr,
1357                                                 "Starting block is %d\n",
1358                                                 s_entry->starting_block);
1359                                         fprintf(stderr,
1360                                         "Reported file size is %lld\n",
1361                                                 (Llong)s_entry->size);
1362
1363                                 }
1364 #endif
1365 #ifdef  NOT_NEEDED      /* Never use this code if you like to create a DVD */
1366
1367                                 if (last_extent > (800000000 >> 11)) {
1368                                         /* More than 800Mb? Punt */
1369                                         fprintf(stderr,
1370                                         "Extent overflow processing file '%s'\n",
1371                                                 whole_path);
1372                                         fprintf(stderr,
1373                                                 "Starting block is %d\n",
1374                                                 s_entry->starting_block);
1375                                         fprintf(stderr,
1376                                         "Reported file size is %lld\n",
1377                                                         (Llong)s_entry->size);
1378                                         exit(1);
1379                                 }
1380 #endif
1381                                 continue;
1382                         }
1383                         /*
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
1388                          * extent number.
1389                          */
1390                         set_733((char *) s_entry->isorec.extent, last_extent);
1391                 }
1392                 if (dpnt->subdir) {
1393                         if (assign_file_addresses(dpnt->subdir, TRUE))
1394                                 ret = TRUE;
1395                 }
1396                 dpnt = dpnt->next;
1397         }
1398 #ifdef DVD_VIDEO
1399         if (title_set_info != NULL) {
1400                 DVDFreeFileSet(title_set_info);
1401         }
1402         if (dvd_video && !ret && !isnest) {
1403                 errmsgno(EX_BAD,
1404                         "Could not find correct 'VIDEO_TS' directory.\n");
1405         }
1406 #endif /* DVD_VIDEO */
1407         return (ret);
1408 } /* assign_file_addresses(... */
1409
1410 static void
1411 free_one_directory(struct directory *dpnt)
1412 {
1413         struct directory_entry *s_entry;
1414         struct directory_entry *s_entry_d;
1415
1416         s_entry = dpnt->contents;
1417         while (s_entry) {
1418                 s_entry_d = s_entry;
1419                 s_entry = s_entry->next;
1420
1421                 if (s_entry_d->rr_attributes) {
1422                         free(s_entry_d->rr_attributes);
1423                         s_entry_d->rr_attributes = NULL;
1424                 }
1425                 if (s_entry_d->name != NULL) {
1426                         free(s_entry_d->name);
1427                         s_entry_d->name = NULL;
1428                 }
1429                 if (s_entry_d->whole_name != NULL) {
1430                         free(s_entry_d->whole_name);
1431                         s_entry_d->whole_name = NULL;
1432                 }
1433 #ifdef APPLE_HYB
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);
1437                 }
1438 #endif  /* APPLE_HYB */
1439
1440                 free(s_entry_d);
1441                 s_entry_d = NULL;
1442         }
1443         dpnt->contents = NULL;
1444 }/* free_one_directory(... */
1445
1446 static void
1447 free_directories(struct directory *dpnt)
1448 {
1449         while (dpnt) {
1450                 free_one_directory(dpnt);
1451                 if (dpnt->subdir)
1452                         free_directories(dpnt->subdir);
1453                 dpnt = dpnt->next;
1454         }
1455 }
1456
1457 void
1458 generate_one_directory(struct directory *dpnt, FILE *outfile)
1459 {
1460         unsigned int    ce_address = 0;
1461         char            *ce_buffer;
1462         unsigned int    ce_index = 0;
1463         unsigned int    ce_size;
1464         unsigned int    dir_index;
1465         char            *directory_buffer;
1466         int             new_reclen;
1467         struct directory_entry *s_entry;
1468         struct directory_entry *s_entry_d;
1469         unsigned int    total_size;
1470
1471         total_size = ISO_ROUND_UP(dpnt->size);
1472         directory_buffer = (char *) e_malloc(total_size);
1473         memset(directory_buffer, 0, total_size);
1474         dir_index = 0;
1475
1476         ce_size = ISO_ROUND_UP(dpnt->ce_bytes);
1477         ce_buffer = NULL;
1478
1479         if (ce_size > 0) {
1480                 ce_buffer = (char *) e_malloc(ce_size);
1481                 memset(ce_buffer, 0, ce_size);
1482
1483                 ce_index = 0;
1484
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;
1488         }
1489         s_entry = dpnt->contents;
1490         while (s_entry) {
1491                 /* skip if it's hidden */
1492                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1493                         s_entry = s_entry->next;
1494                         continue;
1495                 }
1496                 /*
1497                  * We do not allow directory entries to cross sector
1498                  * boundaries. Simply pad, and then start the next entry at
1499                  * the next sector
1500                  */
1501                 new_reclen = s_entry->isorec.length[0];
1502                 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >=
1503                                                                 SECTOR_SIZE) {
1504                         dir_index = ISO_ROUND_UP(dir_index);
1505                 }
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];
1511
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;
1516                         }
1517                         /*
1518                          * If the RR attributes were too long, then write the
1519                          * CE records, as required.
1520                          */
1521                         if (s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
1522                                 struct iso_xa_dir_record *xadp;
1523                                 unsigned char   *pnt;
1524                                 int             len,
1525                                                 nbytes;
1526
1527                                 /*
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
1531                                  * are correct
1532                                  */
1533                                 pnt = s_entry->rr_attributes;
1534                                 len = s_entry->total_rr_attr_size;
1535
1536                                 if (len >= 14) {
1537                                         xadp = (struct iso_xa_dir_record *)pnt;
1538
1539                                         if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
1540                                                                         xadp->reserved[0] == '\0') {
1541                                                 len -= 14;
1542                                                 pnt += 14;
1543                                         }
1544                                 }
1545
1546                                 while (len > 3) {
1547 #ifdef DEBUG
1548                                         if (ce_size <= 0) {
1549                                                 fprintf(stderr,
1550                                                 "Warning: ce_index(%d) && ce_address(%d) not initialized\n",
1551                                                         ce_index, ce_address);
1552                                         }
1553 #endif
1554
1555                                         if (pnt[0] == 'C' && pnt[1] == 'E') {
1556                                                 nbytes = get_733((char *) pnt + 20);
1557
1558                                                 if ((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
1559                                                         SECTOR_SIZE) {
1560                                                         ce_index = ISO_ROUND_UP(ce_index);
1561                                                 }
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));
1566
1567
1568                                                 /*
1569                                                  * Now store the block in the
1570                                                  * ce buffer
1571                                                  */
1572                                                 memcpy(ce_buffer + ce_index,
1573                                                         pnt + pnt[2], nbytes);
1574                                                 ce_index += nbytes;
1575                                                 if (ce_index & 1) {
1576                                                         ce_index++;
1577                                                 }
1578                                         }
1579                                         len -= pnt[2];
1580                                         pnt += pnt[2];
1581                                 }
1582
1583                         }
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;
1589                 }
1590                 if (dir_index & 1) {
1591                         directory_buffer[dir_index++] = 0;
1592                 }
1593                 s_entry_d = s_entry;
1594                 s_entry = s_entry->next;
1595
1596                 /*
1597                  * Joliet doesn't use the Rock Ridge attributes, so we free
1598                  * it here.
1599                  */
1600                 if (s_entry_d->rr_attributes) {
1601                         free(s_entry_d->rr_attributes);
1602                         s_entry_d->rr_attributes = NULL;
1603                 }
1604         }
1605
1606         if (dpnt->size != dir_index) {
1607 #ifdef  USE_LIBSCHILY
1608                 errmsgno(EX_BAD,
1609                         "Unexpected directory length %lld expected: %d '%s'\n",
1610                         (Llong)dpnt->size,
1611                         dir_index, dpnt->de_name);
1612 #else
1613                 fprintf(stderr,
1614                         "Unexpected directory length %lld expected: %d '%s'\n",
1615                         (Llong)dpnt->size,
1616                         dir_index, dpnt->de_name);
1617 #endif
1618         }
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;
1624
1625         if (ce_size > 0) {
1626                 if (ce_index != dpnt->ce_bytes) {
1627 #ifdef  USE_LIBSCHILY
1628                         errmsgno(EX_BAD,
1629                         "Continuation entry record length mismatch %d expected: %d.\n",
1630                                 ce_index, dpnt->ce_bytes);
1631 #else
1632                         fprintf(stderr,
1633                         "Continuation entry record length mismatch %d expected: %d.\n",
1634                                 ce_index, dpnt->ce_bytes);
1635 #endif
1636                 }
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;
1640                 free(ce_buffer);
1641                 ce_buffer = NULL;
1642         }
1643 }/* generate_one_directory(... */
1644
1645 static void
1646 build_pathlist(struct directory *node)
1647 {
1648         struct directory *dpnt;
1649
1650         dpnt = node;
1651
1652         while (dpnt) {
1653                 /* skip if it's hidden */
1654                 if ((dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
1655                         pathlist[dpnt->path_index] = dpnt;
1656
1657                 if (dpnt->subdir)
1658                         build_pathlist(dpnt->subdir);
1659                 dpnt = dpnt->next;
1660         }
1661 }/* build_pathlist(... */
1662
1663 static int
1664 compare_paths(void const *r, void const *l)
1665 {
1666         struct directory const *ll = *(struct directory * const *) l;
1667         struct directory const *rr = *(struct directory * const *) r;
1668
1669         if (rr->parent->path_index < ll->parent->path_index) {
1670                 return (-1);
1671         }
1672         if (rr->parent->path_index > ll->parent->path_index) {
1673                 return (1);
1674         }
1675         return (strcmp(rr->self->isorec.name, ll->self->isorec.name));
1676
1677 }/* compare_paths(... */
1678
1679 static int
1680 generate_path_tables()
1681 {
1682         struct directory_entry *de = NULL;
1683         struct directory *dpnt;
1684         int             fix;
1685         int             i;
1686         int             j;
1687         int             namelen;
1688         char            *npnt;
1689         char            *npnt1;
1690         int             tablesize;
1691
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);
1698
1699         /*
1700          * Now start filling in the path tables.  Start with root directory
1701          */
1702
1703         path_table_index = 0;
1704         pathlist = (struct directory **) e_malloc(sizeof (struct directory *)
1705                 * next_path_index);
1706         memset(pathlist, 0, sizeof (struct directory *) * next_path_index);
1707         build_pathlist(root);
1708
1709         do {
1710                 fix = 0;
1711 #ifdef PROTOTYPES
1712                 qsort(&pathlist[1], next_path_index - 1,
1713                         sizeof (struct directory *),
1714                         (int (*) (const void *, const void *)) compare_paths);
1715 #else
1716                 qsort(&pathlist[1], next_path_index - 1,
1717                         sizeof (struct directory *),
1718                         compare_paths);
1719 #endif
1720
1721                 for (j = 1; j < next_path_index; j++) {
1722                         if (pathlist[j]->path_index != j) {
1723                                 pathlist[j]->path_index = j;
1724                                 fix++;
1725                         }
1726                 }
1727         } while (fix);
1728
1729         for (j = 1; j < next_path_index; j++) {
1730                 dpnt = pathlist[j];
1731                 if (!dpnt) {
1732 #ifdef  USE_LIBSCHILY
1733                         comerrno(EX_BAD, "Entry %d not in path tables\n", j);
1734 #else
1735                         fprintf(stderr, "Entry %d not in path tables\n", j);
1736                         exit(1);
1737 #endif
1738                 }
1739                 npnt = dpnt->de_name;
1740
1741                 /* So the root comes out OK */
1742                 if ((*npnt == 0) || (dpnt == root)) {
1743                         npnt = ".";
1744                 }
1745                 npnt1 = strrchr(npnt, PATH_SEPARATOR);
1746                 if (npnt1) {
1747                         npnt = npnt1 + 1;
1748                 }
1749                 de = dpnt->self;
1750                 if (!de) {
1751 #ifdef  USE_LIBSCHILY
1752                         comerrno(EX_BAD,
1753                         "Fatal ISO9660 goof - directory has amnesia\n");
1754 #else
1755                         fprintf(stderr,
1756                         "Fatal ISO9660 goof - directory has amnesia\n");
1757                         exit(1);
1758 #endif
1759                 }
1760                 namelen = de->isorec.name_len[0];
1761
1762                 path_table_l[path_table_index] = namelen;
1763                 path_table_m[path_table_index] = namelen;
1764                 path_table_index += 2;
1765
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;
1769
1770                 if (dpnt->parent->path_index > 0xffff) {
1771 #ifdef  USE_LIBSCHILY
1772                         comerrno(EX_BAD,
1773                         "Unable to generate sane path tables - too many directories (%d)\n",
1774                                 dpnt->parent->path_index);
1775 #else
1776                         fprintf(stderr,
1777                         "Unable to generate sane path tables - too many directories (%d)\n",
1778                                 dpnt->parent->path_index);
1779                         exit(1);
1780 #endif
1781                 }
1782
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;
1788
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];
1792                         path_table_index++;
1793                 }
1794                 if (path_table_index & 1) {
1795                         path_table_index++;     /* For odd lengths we pad */
1796                 }
1797         }
1798
1799         free(pathlist);
1800         pathlist = NULL;
1801         if (path_table_index != path_table_size) {
1802 #ifdef  USE_LIBSCHILY
1803                 errmsgno(EX_BAD,
1804                         "Path table lengths do not match %d expected: %d\n",
1805                         path_table_index,
1806                         path_table_size);
1807 #else
1808                 fprintf(stderr,
1809                         "Path table lengths do not match %d expected: %d\n",
1810                         path_table_index,
1811                         path_table_size);
1812 #endif
1813         }
1814         return (0);
1815 }/* generate_path_tables(... */
1816
1817 void
1818 memcpy_max(char *to, char *from, int max)
1819 {
1820         int     n = strlen(from);
1821
1822         if (n > max) {
1823                 n = max;
1824         }
1825         memcpy(to, from, n);
1826
1827 }/* memcpy_max(... */
1828
1829 void
1830 outputlist_insert(struct output_fragment *frag)
1831 {
1832         struct output_fragment *nfrag;
1833
1834         nfrag = e_malloc(sizeof (*frag));
1835         movebytes(frag, nfrag, sizeof (*frag));
1836         nfrag->of_start_extent = 0;
1837
1838         if (out_tail == NULL) {
1839                 out_list = out_tail = nfrag;
1840         } else {
1841                 out_tail->of_next = nfrag;
1842                 out_tail = nfrag;
1843         }
1844 }
1845
1846 static int
1847 file_write(FILE *outfile)
1848 {
1849         Uint    should_write;
1850
1851 #ifdef APPLE_HYB
1852         char    buffer[SECTOR_SIZE];
1853
1854         memset(buffer, 0, sizeof (buffer));
1855
1856         if (apple_hyb) {
1857
1858                 int     i;
1859
1860                 /*
1861                  * write out padding to round up to HFS allocation block
1862                  */
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++;
1867                 }
1868         }
1869 #endif  /* APPLE_HYB */
1870
1871         /*
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.
1875          */
1876         should_write = last_extent - session_start;
1877
1878         if (verbose > 2) {
1879 #ifdef DBG_ISO
1880                 fprintf(stderr,
1881                         "Total directory extents being written = %d\n",
1882                                                         last_extent);
1883 #endif
1884
1885 #ifdef APPLE_HYB
1886                 if (apple_hyb)
1887                         fprintf(stderr,
1888                         "Total extents scheduled to be written (inc HFS) = %d\n",
1889                                 last_extent - session_start);
1890                 else
1891 #endif  /* APPLE_HYB */
1892
1893                         fprintf(stderr,
1894                                 "Total extents scheduled to be written = %u\n",
1895                                 last_extent - session_start);
1896         }
1897         /* Now write all of the files that we need. */
1898         write_files(outfile);
1899
1900 #ifdef APPLE_HYB
1901         /* write out extents/catalog/dt file */
1902         if (apple_hyb) {
1903
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);
1906
1907                 /* round up to a whole CD block */
1908                 if (HFS_ROUND_UP(hce->hfs_tot_size) -
1909                                         hce->hfs_tot_size * HFS_BLOCKSZ) {
1910                         jtwrite(buffer,
1911                                 HFS_ROUND_UP(hce->hfs_tot_size) -
1912                                 hce->hfs_tot_size * HFS_BLOCKSZ, 1, 0, FALSE);
1913                         xfwrite(buffer,
1914                                 HFS_ROUND_UP(hce->hfs_tot_size) -
1915                                 hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
1916                 }
1917                 last_extent_written += ISO_ROUND_UP(hce->hfs_tot_size *
1918                                                 HFS_BLOCKSZ) / SECTOR_SIZE;
1919
1920                 /* write out HFS boot block */
1921                 if (mac_boot.name)
1922                         write_one_file(mac_boot.name, mac_boot.size, outfile,
1923                                                                 mac_boot.off);
1924         }
1925 #endif  /* APPLE_HYB */
1926
1927         /* The rest is just fluff. */
1928         if (verbose == 0) {
1929                 return (0);
1930         }
1931 #ifdef APPLE_HYB
1932         if (apple_hyb) {
1933                 fprintf(stderr,
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,
1938                         hfs_extra);
1939         } else
1940 #else
1941         fprintf(stderr, "Total extents actually written = %d\n",
1942                 last_extent_written - session_start);
1943 #endif  /* APPLE_HYB */
1944
1945         /* Hard links throw us off here */
1946         if (should_write != (last_extent - session_start)) {
1947                 fprintf(stderr,
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);
1951         }
1952         fprintf(stderr, "Total translation table size: %d\n", table_size);
1953         fprintf(stderr, "Total rockridge attributes bytes: %d\n",
1954                                                 rockridge_size);
1955         fprintf(stderr, "Total directory bytes: %d\n", total_dir_size);
1956         fprintf(stderr, "Path table size(bytes): %d\n", path_table_size);
1957
1958 #ifdef DEBUG
1959         fprintf(stderr,
1960                 "next extent, last_extent, last_extent_written %d %d %d\n",
1961                 next_extent, last_extent, last_extent_written);
1962 #endif
1963
1964         return (0);
1965
1966 }/* iso_write(... */
1967
1968 /*
1969  * Function to write the PVD for the disc.
1970  */
1971 static int
1972 pvd_write(FILE *outfile)
1973 {
1974         char            iso_time[17];
1975         int             should_write;
1976         struct tm       local;
1977         struct tm       gmt;
1978
1979
1980         time(&begun);
1981
1982         local = *localtime(&begun);
1983         gmt = *gmtime(&begun);
1984
1985         /*
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.
1988          */
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);
1993
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;
2001
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;
2007
2008         memset(vol_desc.system_id, ' ', sizeof (vol_desc.system_id));
2009         memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
2010
2011         memset(vol_desc.volume_id, ' ', sizeof (vol_desc.volume_id));
2012         memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
2013
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);
2019
2020         /*
2021          * The path tables are used by DOS based machines to cache directory
2022          * locations
2023          */
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]);
2029
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);
2033
2034         /*
2035          * The rest is just fluff.  It looks nice to fill in many of these
2036          * fields, though.
2037          */
2038         FILL_SPACE(volume_set_id);
2039         if (volset_id)
2040                 memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
2041
2042         FILL_SPACE(publisher_id);
2043         if (publisher)
2044                 memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
2045
2046         FILL_SPACE(preparer_id);
2047         if (preparer)
2048                 memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
2049
2050         FILL_SPACE(application_id);
2051         if (appid)
2052                 memcpy_max(vol_desc.application_id, appid, strlen(appid));
2053
2054         FILL_SPACE(copyright_file_id);
2055         if (copyright)
2056                 memcpy_max(vol_desc.copyright_file_id, copyright,
2057                         strlen(copyright));
2058
2059         FILL_SPACE(abstract_file_id);
2060         if (abstract)
2061                 memcpy_max(vol_desc.abstract_file_id, abstract,
2062                         strlen(abstract));
2063
2064         FILL_SPACE(bibliographic_file_id);
2065         if (biblio)
2066                 memcpy_max(vol_desc.bibliographic_file_id, biblio,
2067                         strlen(biblio));
2068
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);
2075
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);
2080
2081         if (use_XA) {
2082                 char    *xap = &((char *)&vol_desc)[1024];
2083
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  */
2088         }
2089
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++;
2094         return (0);
2095 }
2096
2097 /*
2098  * Function to write the Extended PVD for the disc.
2099  */
2100 static int
2101 xpvd_write(FILE *outfile)
2102 {
2103         vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
2104         vol_desc.version[0] = 2;
2105         vol_desc.file_structure_version[0] = 2;
2106
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++;
2111         return (0);
2112 }
2113
2114 /*
2115  * Function to write the EVD for the disc.
2116  */
2117 static int
2118 evd_write(FILE *outfile)
2119 {
2120         struct iso_primary_descriptor evol_desc;
2121
2122         /*
2123          * Now write the end volume descriptor.  Much simpler than the other
2124          * one
2125          */
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;
2133         return (0);
2134 }
2135
2136 /*
2137  * Function to write the version information for the disc.
2138  */
2139 static int
2140 vers_write(FILE *outfile)
2141 {
2142         char            vers[SECTOR_SIZE+1];
2143         int             X_ac;
2144         char            **X_av;
2145         char            *cp;
2146         int             i;
2147         int             idx = 4;
2148         int             len;
2149         extern char     version_string[];
2150         extern int      path_ind;
2151
2152         /* Now write the version descriptor. */
2153         memset(vers, 0, sizeof (vers));
2154         strcpy(vers, "MKI ");
2155
2156         cp = vers;
2157         X_ac = saved_ac();
2158         X_av = saved_av();
2159         strcpy(&cp[idx], ctime(&begun));
2160         idx += 25;
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)
2166                         break;
2167                 cp[idx++] = ' ';
2168                 /*
2169                  * Do not give away secret information when not in debug mode.
2170                  */
2171                 if (debug)
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]);
2177                 else
2178                         strcpy(&cp[idx], X_av[i]);
2179                 idx += len;
2180         }
2181
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);
2187         } else {
2188                 jtwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, 0, TRUE);
2189                 xfwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, outfile, 0, TRUE);
2190         }
2191     last_extent_written += 1;
2192         return (0);
2193 }
2194
2195 /*
2196  * Avoid to write unwanted information into the version info string.
2197  */
2198 static int
2199 graftcp(char *to, char *from, char *ep)
2200 {
2201         int     len = strlen(from);
2202         char    *node = NULL;
2203
2204         if (use_graft_ptrs)
2205                 node = findgequal(from);
2206
2207         if (node == NULL) {
2208                 len = 0;
2209                 node = from;
2210         } else {
2211                 len = node - from;
2212                 *node = '\0';
2213                 strncpy(to, from, ep - to);
2214                 *node++ = '=';
2215                 to += len++;
2216                 *to++ = '=';
2217         }
2218         return (len + pathcp(to, node, ep));
2219 }
2220
2221 static int
2222 pathcp(char *to, char *from, char *ep)
2223 {
2224         int     len = strlen(from);
2225         char    *p;
2226
2227         p = strrchr(from, '/');
2228         if (p == NULL) {
2229                 strncpy(to, from, ep - to);
2230         } else {
2231                 if (p[1] == '\0') {
2232                         --p;
2233                         while (p > from && *p != '/')
2234                                 --p;
2235                 }
2236                 len = 0;
2237                 if (*p == '/') {
2238                         strncpy(to, "...", ep - to);
2239                         to += 3;
2240                         len = 3;
2241                 }
2242                 if (to < ep) {
2243                         strncpy(to, p, ep - to);
2244                         len += strlen(to);
2245                 }
2246         }
2247         return (len);
2248 }
2249
2250
2251 /*
2252  * Function to write the path table for the disc.
2253  */
2254 static int
2255 pathtab_write(FILE *outfile)
2256 {
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;
2264         free(path_table_l);
2265         free(path_table_m);
2266         path_table_l = NULL;
2267         path_table_m = NULL;
2268         return (0);
2269 }
2270
2271 static int
2272 exten_write(FILE *outfile)
2273 {
2274         jtwrite(extension_record, SECTOR_SIZE, 1, 0, FALSE);
2275         xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
2276         last_extent_written++;
2277         return (0);
2278 }
2279
2280 /*
2281  * Functions to describe padding block at the start of the disc.
2282  */
2283 int
2284 oneblock_size(int starting_extent)
2285 {
2286         last_extent++;
2287         return (0);
2288 }
2289
2290 /*
2291  * Functions to describe path table size.
2292  */
2293 static int
2294 pathtab_size(int starting_extent)
2295 {
2296         path_table[0] = starting_extent;
2297
2298         path_table[1] = 0;
2299         path_table[2] = path_table[0] + path_blocks;
2300         path_table[3] = 0;
2301         last_extent += 2 * path_blocks;
2302         return (0);
2303 }
2304
2305 /*
2306  * Functions to describe padding blocks before PVD.
2307  */
2308 static int
2309 startpad_size(int starting_extent)
2310 {
2311         last_extent = session_start + 16;
2312         return (0);
2313 }
2314
2315 /*
2316  * Functions to describe padding blocks between sections.
2317  */
2318 static int
2319 interpad_size(int starting_extent)
2320 {
2321         int     emod = 0;
2322
2323 #ifdef  needed
2324         starting_extent += 16;  /* First add 16 pad blocks */
2325 #endif
2326         if ((emod = starting_extent % 16) != 0) {
2327                 starting_extent += 16 - emod;   /* Now pad to mod 16 #     */
2328         }
2329         last_extent = starting_extent;
2330         return (0);
2331 }
2332
2333 /*
2334  * Functions to describe padding blocks at end of disk.
2335  */
2336 static int
2337 endpad_size(int starting_extent)
2338 {
2339         starting_extent += 150;                 /* 150 pad blocks (post gap) */
2340         last_extent = starting_extent;
2341         return (0);
2342 }
2343
2344 static int
2345 file_gen()
2346 {
2347 #ifdef APPLE_HYB
2348         int     start_extent = last_extent;     /* orig ISO files start */
2349
2350 #endif  /* APPLE_HYB */
2351
2352         if (!assign_file_addresses(root, FALSE)) {
2353 #ifdef DVD_VIDEO
2354                 if (dvd_video) {
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"
2359             );
2360                 }
2361 #else
2362                 ;       /* EMPTY */
2363 #endif
2364         }
2365
2366
2367 #ifdef SORTING
2368         if (do_sort) {
2369                 if (sort_file_addresses() == 0)
2370                         reassign_link_addresses(root);
2371         }
2372 #endif /* SORTING */
2373
2374 #ifdef APPLE_HYB
2375         /*
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
2379          */
2380         if (apple_hyb)
2381                 hfs_file_gen(start_extent);
2382 #ifdef PREP_BOOT
2383         else if (use_prep_boot || use_chrp_boot)
2384                 gen_prepboot();
2385 #endif  /* PREP_BOOT */
2386 #endif  /* APPLE_HYB */
2387
2388         return (0);
2389 }
2390
2391 static int
2392 dirtree_dump()
2393 {
2394         if (verbose > 2) {
2395                 dump_tree(root);
2396         }
2397         return (0);
2398 }
2399
2400 static int
2401 dirtree_fixup(int starting_extent)
2402 {
2403         if (use_RockRidge && reloc_dir)
2404                 finish_cl_pl_entries();
2405
2406         if (use_RockRidge)
2407                 update_nlink_field(root);
2408         return (0);
2409 }
2410
2411 static int
2412 dirtree_size(int starting_extent)
2413 {
2414         assign_directory_addresses(root);
2415         return (0);
2416 }
2417
2418 static int
2419 ext_size(int starting_extent)
2420 {
2421         extern int              extension_record_size;
2422         struct directory_entry *s_entry;
2423
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);
2430         last_extent++;
2431         return (0);
2432 }
2433
2434 static int
2435 dirtree_write(FILE *outfile)
2436 {
2437         generate_iso9660_directories(root, outfile);
2438         return (0);
2439 }
2440
2441 static int
2442 dirtree_cleanup(FILE *outfile)
2443 {
2444         free_directories(root);
2445         return (0);
2446 }
2447
2448 static int
2449 startpad_write(FILE *outfile)
2450 {
2451         char    buffer[SECTOR_SIZE];
2452         int     i;
2453         int     npad;
2454
2455         memset(buffer, 0, sizeof (buffer));
2456
2457         npad = session_start + 16 - last_extent_written;
2458
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++;
2463         }
2464
2465         return (0);
2466 }
2467
2468 static int
2469 interpad_write(FILE *outfile)
2470 {
2471         char    buffer[SECTOR_SIZE];
2472         int     i;
2473         int     npad = 0;
2474
2475         memset(buffer, 0, sizeof (buffer));
2476
2477 #ifdef  needed
2478         npad = 16;
2479 #endif
2480         if ((i = last_extent_written % 16) != 0)
2481                 npad += 16 - i;
2482
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++;
2487         }
2488
2489         return (0);
2490 }
2491
2492 static int
2493 endpad_write(FILE *outfile)
2494 {
2495         char    buffer[SECTOR_SIZE];
2496         int     i;
2497
2498         memset(buffer, 0, sizeof (buffer));
2499
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++;
2504         }
2505
2506         return (0);
2507 }
2508
2509 #ifdef APPLE_HYB
2510
2511 /*
2512  *      hfs_get_parms:  get HFS parameters from the command line
2513  */
2514
2515 static int
2516 hfs_get_parms(char *key)
2517 {
2518         int     ret = 0;
2519         char    *p;
2520
2521         if (hfs_parms == NULL)
2522                 return (ret);
2523
2524         if ((p = strstr(hfs_parms, key)) != NULL) {
2525                 p += strlen(key) + 1;
2526                 sscanf(p, "%d", &ret);
2527         }
2528
2529         return (ret);
2530 }
2531
2532 /*
2533  *      hfs_file_gen:   set up "fake" HFS volume using the ISO9660 tree
2534  */
2535 static void
2536 hfs_file_gen(int start_extent)
2537 {
2538         int     Csize;  /* clump size for HFS vol */
2539         int     loop;
2540         int     last_extent_save = last_extent;
2541         char    *p;
2542
2543         /* allocate memory for the libhfs/genisoimage extra info */
2544         hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2545
2546         hce->error = (char *) e_malloc(1024);
2547
2548         /* mark as unallocated for use later */
2549         hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2550
2551         /* reserve space for the label partition - if it is needed */
2552 #ifdef PREP_BOOT
2553         /* a PReP bootable partition needs the map.. */
2554         if (gen_pt || use_prep_boot || use_chrp_boot)
2555 #else
2556         if (gen_pt)
2557 #endif  /* PREP_BOOT */
2558                 hce->hfs_map_size = HFS_MAP_SIZE;
2559         else
2560                 hce->hfs_map_size = 0;
2561
2562         /* set the HFS parameter string to upper case */
2563         if (hfs_parms) {
2564                 for (p = hfs_parms; *p; p++)
2565                         *p = toupper(*p);
2566         }
2567
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;
2571
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;
2575
2576         /* set the number of time to try to make an HFS volume */
2577         if ((loop = hfs_get_parms("CTC_LOOP")) == 0)
2578                 loop = CTC_LOOP;
2579
2580         /*
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 ...
2589          */
2590         do {
2591                 hce->error[0] = '\0';
2592
2593                 /* attempt to create the Mac volume */
2594                 Csize = make_mac_volume(root, start_extent);
2595
2596                 /* if we have a problem ... */
2597                 if (Csize < 0) {
2598                         /*
2599                          * we've made too many attempts, or got some other
2600                          * error
2601                          */
2602                         if (loop == 0 || errno != HCE_ERROR) {
2603                                 /* HCE_ERROR is not a valid errno value */
2604                                 if (errno == HCE_ERROR)
2605                                         errno = 0;
2606
2607                                 /* exit with the error */
2608                                 if (*hce->error)
2609                                         fprintf(stderr, "%s\n", hce->error);
2610                                 perr(hfs_error);
2611                         } else {
2612                                 /* increase Catalog file size factor */
2613                                 hce->ctc_size *= CTC;
2614
2615                                 /*
2616                                  * reset the initial "last_extent" and try
2617                                  * again
2618                                  */
2619                                 last_extent = last_extent_save;
2620                         }
2621                 } else {
2622                         /* everything OK - just carry on ... */
2623                         loop = 0;
2624                 }
2625         }
2626         while (loop--);
2627
2628         hfs_extra = HFS_ROUND_UP(hce->hfs_tot_size) / SECTOR_SIZE;
2629
2630         last_extent += hfs_extra;
2631
2632         /* generate the Mac label and HFS partition maps */
2633         mac_boot.name = hfs_boot_file;
2634
2635         /*
2636          * only generate the partition tables etc. if we are making a bootable
2637          * CD - or if the -part option is given
2638          */
2639         if (gen_pt) {
2640                 if (gen_mac_label(&mac_boot)) {
2641                         if (*hce->error)
2642                                 fprintf(stderr, "%s\n", hce->error);
2643                         perr(hfs_error);
2644                 }
2645         }
2646         /* set Autostart filename if required */
2647         if (autoname) {
2648                 if (autostart())
2649                         perr("Autostart filename must less than 12 characters");
2650         }
2651         /* finished with any HFS type errors */
2652         free(hce->error);
2653         hce->error = 0;
2654
2655         /*
2656          * the ISO files need to start on a multiple of the HFS allocation
2657          * blocks, so find out how much padding we need
2658          */
2659
2660         /*
2661          * take in accout alignment of files wrt HFS volume start - remove any
2662          * previous session as well
2663          */
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;
2668
2669         hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size) /
2670                                                         HFS_BLK_CONV);
2671
2672 #ifdef PREP_BOOT
2673         gen_prepboot_label(hce->hfs_map);
2674 #endif  /* PREP_BOOT */
2675
2676 }
2677
2678 #ifdef PREP_BOOT
2679 static void
2680 gen_prepboot()
2681 {
2682         /*
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
2685          */
2686         hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2687
2688         /* mark as unallocated for use later */
2689         hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2690
2691         /* reserve space for the label partition - if it is needed */
2692         hce->hfs_map_size = HFS_MAP_SIZE;
2693
2694         hce->hfs_map = (unsigned char *) e_malloc(hce->hfs_map_size * HFS_BLOCKSZ);
2695         gen_prepboot_label(hce->hfs_map);
2696 }
2697
2698 #endif  /* PREP_BOOT */
2699
2700 /*
2701  *      get_adj_size:   get the ajusted size of the volume with the HFS
2702  *                      allocation block size for each file
2703  */
2704 Ulong
2705 get_adj_size(int Csize)
2706 {
2707         struct deferred_write *dw;
2708         Ulong           size = 0;
2709         int             count = 0;
2710
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);
2714                 count++;
2715         }
2716
2717         /*
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
2721          */
2722
2723         if (count >= 65536)
2724                 return (-1);
2725         else
2726                 return (size);
2727 }
2728
2729 /*
2730  *      adj_size:       adjust the ISO record entries for all files
2731  *                      based on the HFS allocation block size
2732  */
2733 int
2734 adj_size(int Csize, int start_extent, int extra)
2735 {
2736         struct deferred_write *dw;
2737         struct directory_entry *s_entry;
2738         int             size;
2739
2740         /* get the adjusted start_extent (with padding) */
2741         /* take in accout alignment of files wrt HFS volume start */
2742
2743         start_extent -= session_start;
2744
2745         start_extent = ROUND_UP(start_extent*SECTOR_SIZE + extra*HFS_BLOCKSZ,
2746                                                 Csize) / SECTOR_SIZE;
2747
2748         start_extent -= (extra / HFS_BLK_CONV);
2749
2750         start_extent += session_start;
2751
2752         /* initialise file hash */
2753         flush_hash();
2754
2755         /*
2756          * loop through all files changing their starting blocks and finding
2757          * any padding needed to written out latter
2758          */
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;
2765
2766                 /*
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
2770                  */
2771                 if (!s_entry->hfs_ent)
2772                         add_hash(s_entry);
2773
2774                 start_extent += size;
2775         }
2776
2777         return (start_extent);
2778 }
2779
2780 /*
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
2783  *                      entry of it's own
2784  */
2785 void
2786 adj_size_other(struct directory *dpnt)
2787 {
2788         struct directory_entry *s_entry;
2789         struct file_hash *s_hash;
2790
2791         while (dpnt) {
2792                 s_entry = dpnt->contents;
2793                 for (s_entry = dpnt->contents; s_entry;
2794                                                 s_entry = s_entry->next) {
2795                         /*
2796                          * if it's an HFS file or a directory - then ignore
2797                          * (we're after non-HFS files)
2798                          */
2799                         if (s_entry->hfs_ent ||
2800                             (s_entry->isorec.flags[0] & ISO_DIRECTORY))
2801                                 continue;
2802
2803                         /*
2804                          * find any cached entry and assign new starting
2805                          * extent
2806                          */
2807                         s_hash = find_hash(s_entry->dev, s_entry->inode);
2808                         if (s_hash) {
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;
2814                         }
2815                 }
2816                 if (dpnt->subdir) {
2817                         adj_size_other(dpnt->subdir);
2818                 }
2819                 dpnt = dpnt->next;
2820         }
2821
2822         /* clear file hash */
2823         flush_hash();
2824 }
2825
2826 /*
2827  *      hfs_hce_write:  write out the HFS header stuff
2828  */
2829 static int
2830 hfs_hce_write(FILE *outfile)
2831 {
2832         char    buffer[SECTOR_SIZE];
2833         int     n = 0;
2834         int     r;      /* HFS hdr output */
2835         int     tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
2836
2837         memset(buffer, 0, sizeof (buffer));
2838
2839         /*
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 ...
2844          */
2845
2846         if (tot_size > 64) tot_size = 64;
2847
2848         /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
2849         n = tot_size / HFS_BLK_CONV;
2850         r = tot_size % HFS_BLK_CONV;
2851
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);
2855
2856         /* fill up to a complete CD block */
2857         if (r) {
2858                 jtwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, 0, FALSE);
2859                 xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
2860                 n++;
2861         }
2862         last_extent_written += n;
2863         return (0);
2864 }
2865
2866 /*
2867  *      insert_padding_file : insert a dumy file to make volume at least
2868  *                              800k
2869  *
2870  *      XXX If we ever need to write more then 2 GB, make size off_t
2871  */
2872 int
2873 insert_padding_file(int size)
2874 {
2875         struct deferred_write *dwpnt;
2876
2877         /* get the size in bytes */
2878         size *= HFS_BLOCKSZ;
2879
2880         dwpnt = (struct deferred_write *)
2881                 e_malloc(sizeof (struct deferred_write));
2882         dwpnt->s_entry = 0;
2883         /* set the padding to zero */
2884         dwpnt->pad = 0;
2885         /* set offset to zero */
2886         dwpnt->off = (off_t)0;
2887
2888         /*
2889          * don't need to wory about the s_entry stuff as it won't be touched#
2890          * at this point onwards
2891          */
2892
2893         /* insert the entry in the list */
2894         if (dw_tail) {
2895                 dw_tail->next = dwpnt;
2896                 dw_tail = dwpnt;
2897         } else {
2898                 dw_head = dwpnt;
2899                 dw_tail = dwpnt;
2900         }
2901
2902         /* aloocate memory as a "Table" file */
2903         dwpnt->table = e_malloc(size);
2904         dwpnt->name = NULL;
2905
2906         dwpnt->next = NULL;
2907         dwpnt->size = size;
2908         dwpnt->extent = last_extent;
2909         last_extent += ISO_BLOCKS(size);
2910
2911         /* retune the size in HFS blocks */
2912         return (ISO_ROUND_UP(size) / HFS_BLOCKSZ);
2913 }
2914
2915 struct output_fragment hfs_desc         = {NULL, NULL, NULL, hfs_hce_write, "HFS volume header"};
2916
2917 #endif  /* APPLE_HYB */
2918
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"};