a423ab1c16240e30443e37404d51f96fad030256
[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 /*
16  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
17  *
18  * Written by Eric Youngdale (1993).
19  *
20  * Copyright 1993 Yggdrasil Computing, Incorporated
21  * Copyright (c) 1999-2003 J. Schilling
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 2, or (at your option)
26  * any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36  */
37
38 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
39
40 #include <mconfig.h>
41 #include "genisoimage.h"
42 #include <timedefs.h>
43 #include <fctldefs.h>
44 #ifdef SORTING
45 #include "match.h"
46 #endif /* SORTING */
47 #include <errno.h>
48 #include <schily.h>
49 #ifdef DVD_VIDEO
50 #include "dvd_reader.h"
51 #include "dvd_file.h"
52 #include "ifo_read.h"
53 #endif
54 #ifdef APPLE_HYB
55 #include <ctype.h>
56 #endif
57
58 #ifdef  VMS
59 #include "vms.h"
60 #endif
61
62 /* Max number of sectors we will write at  one time */
63 #define NSECT 16
64
65 /* Counters for statistics */
66
67 static int      table_size = 0;
68 static int      total_dir_size = 0;
69 static int      rockridge_size = 0;
70 static struct directory **pathlist;
71 static int      next_path_index = 1;
72 static int      sort_goof;
73
74 static int      is_rr_dir = 0;
75
76 struct output_fragment *out_tail;
77 struct output_fragment *out_list;
78
79 struct iso_primary_descriptor vol_desc;
80
81 void    set_721(char *pnt, unsigned int i);
82 void    set_722(char *pnt, unsigned int i);
83 void    set_723(char *pnt, unsigned int i);
84 void    set_731(char *pnt, unsigned int i);
85 void    set_732(char *pnt, unsigned int i);
86 void    set_733(char *pnt, unsigned int i);
87 int     get_731(char *p);
88 int     get_732(char *p);
89 int     get_733(char *p);
90 static  int     xawrite(void *buffer, int size, int count, FILE *file, 
91                                                           int submode, BOOL islast);
92 void    xfwrite(void *buffer, int size, int count, FILE *file, int submode, 
93                                   BOOL islast);
94 static  int     assign_directory_addresses(struct directory *node);
95 #ifdef APPLE_HYB
96 static  void    write_one_file(char *filename, off_t size, FILE *outfile, 
97                                                                                 off_t off);
98 #else
99 static  void    write_one_file(char *filename, off_t size, FILE *outfile);
100 #endif
101 static  void    write_files(FILE *outfile);
102 #if 0
103 static  void    dump_filelist   __PR((void));
104 #endif
105 static  int     compare_dirs(const void *rr, const void *ll);
106 int     sort_directory(struct directory_entry **sort_dir, int rr);
107 static  int     root_gen(void);
108 static  BOOL    assign_file_addresses(struct directory *dpnt, BOOL isnest);
109 static  void    free_one_directory(struct directory *dpnt);
110 static  void    free_directories(struct directory *dpnt);
111 void    generate_one_directory(struct directory *dpnt, FILE *outfile);
112 static  void    build_pathlist(struct directory *node);
113 static  int     compare_paths(void const *r, void const *l);
114 static  int     generate_path_tables(void);
115 void    memcpy_max(char *to, char *from, int max);
116 void    outputlist_insert(struct output_fragment *frag);
117 static  int     file_write(FILE *outfile);
118 static  int     pvd_write(FILE *outfile);
119 static  int     xpvd_write(FILE *outfile);
120 static  int     evd_write(FILE *outfile);
121 static  int     vers_write(FILE *outfile);
122 static  int     graftcp(char *to, char *from, char *ep);
123 static  int     pathcp(char *to, char *from, char *ep);
124 static  int     pathtab_write(FILE *outfile);
125 static  int     exten_write(FILE *outfile);
126 int     oneblock_size(int starting_extent);
127 static  int     pathtab_size(int starting_extent);
128 static  int     startpad_size(int starting_extent);
129 static  int     interpad_size(int starting_extent);
130 static  int     endpad_size(int starting_extent);
131 static  int     file_gen(void);
132 static  int     dirtree_dump(void);
133 static  int     dirtree_fixup(int starting_extent);
134 static  int     dirtree_size(int starting_extent);
135 static  int     ext_size(int starting_extent);
136 static  int     dirtree_write(FILE *outfile);
137 static  int     dirtree_cleanup(FILE *outfile);
138 static  int     startpad_write(FILE *outfile);
139 static  int     interpad_write(FILE *outfile);
140 static  int     endpad_write(FILE *outfile);
141 #ifdef APPLE_HYB
142 static  int     hfs_pad;
143 static  int     hfs_get_parms(char *key);
144 static  void    hfs_file_gen(int start_extent);
145 static  void    gen_prepboot(void);
146 Ulong   get_adj_size(int Csize);
147 int     adj_size(int Csize, int start_extent, int extra);
148 void    adj_size_other(struct directory *dpnt);
149 static  int     hfs_hce_write(FILE * outfile);
150 int     insert_padding_file(int size);
151 #endif  /* APPLE_HYB */
152
153 #ifdef SORTING
154 static  int     compare_sort(const void * rr, const void * ll);
155 static  void    reassign_link_addresses(struct directory * dpnt);
156 static  int     sort_file_addresses(void);
157 #endif /* SORTING */
158
159 /*
160  * Routines to actually write the disc.  We write sequentially so that
161  * we could write a tape, or write the disc directly
162  */
163 #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof (vol_desc.X))
164
165 void
166 set_721(char *pnt, unsigned int i)
167 {
168         pnt[0] = i & 0xff;
169         pnt[1] = (i >> 8) & 0xff;
170 }
171
172 void
173 set_722(char *pnt, unsigned int i)
174 {
175         pnt[0] = (i >> 8) & 0xff;
176         pnt[1] = i & 0xff;
177 }
178
179 void
180 set_723(char *pnt, unsigned int i)
181 {
182         pnt[3] = pnt[0] = i & 0xff;
183         pnt[2] = pnt[1] = (i >> 8) & 0xff;
184 }
185
186 void
187 set_731(char *pnt, unsigned int i)
188 {
189         pnt[0] = i & 0xff;
190         pnt[1] = (i >> 8) & 0xff;
191         pnt[2] = (i >> 16) & 0xff;
192         pnt[3] = (i >> 24) & 0xff;
193 }
194
195 void
196 set_732(char *pnt, unsigned int i)
197 {
198         pnt[3] = i & 0xff;
199         pnt[2] = (i >> 8) & 0xff;
200         pnt[1] = (i >> 16) & 0xff;
201         pnt[0] = (i >> 24) & 0xff;
202 }
203
204 void
205 set_733(char *pnt, unsigned int i)
206 {
207         pnt[7] = pnt[0] = i & 0xff;
208         pnt[6] = pnt[1] = (i >> 8) & 0xff;
209         pnt[5] = pnt[2] = (i >> 16) & 0xff;
210         pnt[4] = pnt[3] = (i >> 24) & 0xff;
211 }
212
213 int
214 get_731(char *p)
215 {
216         return ((p[0] & 0xff)
217                 | ((p[1] & 0xff) << 8)
218                 | ((p[2] & 0xff) << 16)
219                 | ((p[3] & 0xff) << 24));
220 }
221
222 int
223 get_732(char *p)
224 {
225         return ((p[3] & 0xff)
226                 | ((p[2] & 0xff) << 8)
227                 | ((p[1] & 0xff) << 16)
228                 | ((p[0] & 0xff) << 24));
229 }
230
231 int
232 get_733(char *p)
233 {
234         return ((p[0] & 0xff)
235                 | ((p[1] & 0xff) << 8)
236                 | ((p[2] & 0xff) << 16)
237                 | ((p[3] & 0xff) << 24));
238 }
239
240 void
241 xfwrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
242 {
243         /*
244          * This is a hack that could be made better.
245          * XXXIs this the only place?
246          * It is definitely needed on Operating Systems that do not allow to
247          * write files that are > 2GB. If the system is fast enough to be able
248          * to feed 1400 KB/s writing speed of a DVD-R drive, use stdout.
249          * If the system cannot do this reliable, you need to use this hacky
250          * option.
251          */
252         static int      idx = 0;
253
254 #ifdef  XFWRITE_DEBUG
255         if (count != 1 || (size % 2048) != 0)
256                 fprintf(stderr, "Count: %d, size: %d\n", count, size);
257 #endif
258
259         if (split_output != 0 &&
260                 (idx == 0 || ftell(file) >= ((off_t)1024 * 1024 * 1024))) {
261                 char            nbuf[512];
262                 extern char     *outfile;
263
264                 if (idx == 0)
265                         unlink(outfile);
266                 sprintf(nbuf, "%s_%02d", outfile, idx++);
267                 file = freopen(nbuf, "wb", file);
268                 if (file == NULL) {
269 #ifdef  USE_LIBSCHILY
270                         comerr("Cannot open '%s'.\n", nbuf);
271 #else
272                         fprintf(stderr, "Cannot open '%s'.\n", nbuf);
273                         exit(1);
274 #endif
275                 }
276         }
277         while (count) {
278                 int     got;
279
280                 seterrno(0);
281                 if (osecsize != 0)
282                         got = xawrite(buffer, size, count, file, submode, islast);
283                 else
284                         got = fwrite(buffer, size, count, file);
285
286                 if (got <= 0) {
287 #ifdef  USE_LIBSCHILY
288                         comerr("cannot fwrite %d*%d\n", size, count);
289 #else
290                         fprintf(stderr, "cannot fwrite %d*%d\n", size, count);
291                         exit(1);
292 #endif
293                 }
294                 /*
295                  * This comment is in hope to prevent silly people from
296                  * e.g. SuSE (who did not yet learn C but believe that
297                  * they need to patch other peoples code) from changing the
298                  * next cast into an illegal lhs cast expression.
299                  * The cast below is the correct way to handle the problem.
300                  * The (void *) cast is to avoid a GCC warning like:
301                  * "warning: dereferencing type-punned pointer will break \
302                  * strict-aliasing rules"
303                  * which is wrong this code. (void *) introduces a compatible
304                  * intermediate type in the cast list.
305                  */
306                 count -= got;
307                 buffer = (void *)(((char *)buffer) + size * got);
308         }
309 }
310
311 static int
312 xawrite(void *buffer, int size, int count, FILE *file, int submode, BOOL islast)
313 {
314         register char   *p = buffer;
315         register int    amt = size * count;
316         register int    n;
317         struct xa_subhdr subhdr[2];
318
319         if (osecsize == 2048)
320                 return (fwrite(buffer, size, count, file));
321
322         if (amt % 2048)
323                 comerrno(EX_BAD,
324                         "Trying to write %d bytes (not a multiple of 2048).\n",
325                         amt);
326
327         subhdr[0].file_number           = subhdr[1].file_number         = 0;
328         subhdr[0].channel_number        = subhdr[1].channel_number      = 0;
329         subhdr[0].coding                = subhdr[1].coding              = 0;
330
331         while (amt > 0) {
332 #ifdef  LATER
333                 if (submode < 0)
334                         subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
335                 else
336                         subhdr[0].sub_mode = subhdr[1].sub_mode = submode;
337 #else
338                 subhdr[0].sub_mode = subhdr[1].sub_mode = XA_SUBH_DATA;
339 #endif
340
341                 if ((amt <= 2048) && islast) {
342                         subhdr[0].sub_mode = subhdr[1].sub_mode
343                                                 |= (XA_SUBH_EOR|XA_SUBH_EOF);
344                 }
345                 n = fwrite(&subhdr, sizeof (subhdr), 1, file);
346                 if (n <= 0)
347                         return (n);
348
349                 n = fwrite(p, 2048, 1, file);
350                 if (n <= 0)
351                         return (n);
352
353                 p += 2048;
354                 amt -= 2048;
355         }
356         return (1);
357 }
358
359 #ifdef APPLE_HYB
360 /*
361  * use the deferred_write struct to store info about the hfs_boot_file
362  */
363 static struct deferred_write mac_boot;
364
365 #endif  /* APPLE_HYB */
366 static struct deferred_write    *dw_head = NULL,
367                                 *dw_tail = NULL;
368
369 unsigned int    last_extent_written = 0;
370 static  Uint    path_table_index;
371 time_t  begun;
372
373 /*
374  * We recursively walk through all of the directories and assign extent
375  * numbers to them.  We have already assigned extent numbers to everything that
376  * goes in front of them
377  */
378 static int
379 assign_directory_addresses(struct directory *node)
380 {
381         int             dir_size;
382         struct directory *dpnt;
383
384         dpnt = node;
385
386         while (dpnt) {
387                 /* skip if it's hidden */
388                 if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
389                         dpnt = dpnt->next;
390                         continue;
391                 }
392                 /*
393                  * If we already have an extent for this (i.e. it came from a
394                  * multisession disc), then don't reassign a new extent.
395                  */
396                 dpnt->path_index = next_path_index++;
397                 if (dpnt->extent == 0) {
398                         dpnt->extent = last_extent;
399                         dir_size = ISO_BLOCKS(dpnt->size);
400
401                         last_extent += dir_size;
402
403                         /*
404                          * Leave room for the CE entries for this directory.
405                          * Keep them close to the reference directory so that
406                          * access will be quick.
407                          */
408                         if (dpnt->ce_bytes) {
409                                 last_extent += ISO_BLOCKS(dpnt->ce_bytes);
410                         }
411                 }
412                 if (dpnt->subdir) {
413                         assign_directory_addresses(dpnt->subdir);
414                 }
415                 dpnt = dpnt->next;
416         }
417         return (0);
418 }
419
420 #ifdef APPLE_HYB
421 static void
422 write_one_file(char *filename, off_t size, FILE *outfile, off_t off)
423 #else
424 static void
425 write_one_file(char *filename, off_t size, FILE *outfile)
426 #endif  /* APPLE_HYB */
427 {
428         /*
429          * It seems that there are still stone age C-compilers
430          * around.
431          * The Metrowerks C found on BeOS/PPC does not allow
432          * more than 32kB of local vars.
433          * As we do not need to call write_one_file() recursively
434          * we make buffer static.
435          */
436 static  char            buffer[SECTOR_SIZE * NSECT];
437         FILE            *infile;
438         off_t           remain;
439         int     use;
440
441         char *mirror_name;
442         unsigned char md5[16];
443         int include_in_jigdo = list_file_in_jigdo(filename, size, &mirror_name, md5);
444
445         if ((infile = fopen(filename, "rb")) == NULL) {
446 #ifdef  USE_LIBSCHILY
447                 comerr("cannot open '%s'\n", filename);
448 #else
449 #ifndef HAVE_STRERROR
450                 fprintf(stderr, "cannot open '%s': (%d)\n",
451                                 filename, errno);
452 #else
453                 fprintf(stderr, "cannot open '%s': %s\n",
454                                 filename, strerror(errno));
455 #endif
456                 exit(1);
457 #endif
458         }
459 #ifdef APPLE_HYB
460         fseek(infile, off, SEEK_SET);
461 #endif  /* APPLE_HYB */
462         remain = size;
463
464         if (include_in_jigdo)
465                 write_jt_match_record(filename, mirror_name, SECTOR_SIZE, size, md5);
466
467         while (remain > 0) {
468                 int     amt;
469
470                 use = (remain > SECTOR_SIZE * NSECT - 1 ?
471                                 NSECT * SECTOR_SIZE : remain);
472                 use = ISO_ROUND_UP(use);        /* Round up to nearest sector */
473                                                 /* boundary */
474                 memset(buffer, 0, use);
475                 seterrno(0);
476                 amt = fread(buffer, 1, use, infile);
477                 if (amt < use && amt < remain) {
478                         /*
479                          * Note that genisoimage is not star and no 100% archiver.
480                          * We only detect file growth if the new size does not
481                          * match 'use' at the last read.
482                          */
483                         if (geterrno() == 0) {
484 #ifdef  USE_LIBSCHILY
485          comerrno(EX_BAD,
486                "File '%s' did shrink.\n"
487                "Files must not be changed while genisoimage runs!\n",
488                filename);
489 #else
490          fprintf(stderr,
491                "File '%s' did shrink.\n"
492                "Files must not be changed while genisoimage runs!\n",
493                filename);
494                                 exit(EX_BAD);
495 #endif
496                         }
497 #ifdef  USE_LIBSCHILY
498                         comerr("Cannot read from '%s'\n", filename);
499 #else
500                         fprintf(stderr, "Cannot read from '%s'\n", filename);
501                         exit(1);
502 #endif
503                 }
504                 if (!include_in_jigdo)
505                         jtwrite(buffer, use, 1,
506                                 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
507                 xfwrite(buffer, use, 1, outfile,
508                                 XA_SUBH_DATA, remain <= (SECTOR_SIZE * NSECT));
509                 last_extent_written += use / SECTOR_SIZE;
510 #if 0
511                 if ((last_extent_written % 1000) < use / SECTOR_SIZE) {
512                         fprintf(stderr, "%d..", last_extent_written);
513                 }
514 #else
515                 if (verbose > 0 &&
516                     (int)(last_extent_written % (gui ? 500 : 5000)) <
517                                                         use / SECTOR_SIZE) {
518                         time_t  now;
519                         time_t  the_end;
520                         double  frac;
521
522                         time(&now);
523                         frac = last_extent_written / (1.0 * last_extent);
524                         the_end = begun + (now - begun) / frac;
525 #ifndef NO_FLOATINGPOINT
526                         fprintf(stderr, "%6.2f%% done, estimate finish %s",
527                                 frac * 100., ctime(&the_end));
528 #else
529                         fprintf(stderr, "%3d.%-02d%% done, estimate finish %s",
530                                 (int)(frac * 100.),
531                                 (int)((frac+.00005) * 10000.)%100,
532                                 ctime(&the_end));
533 #endif
534                         fflush(stderr);
535                 }
536 #endif
537                 remain -= use;
538         }
539         fclose(infile);
540 }/* write_one_file(... */
541
542 static void
543 write_files(FILE *outfile)
544 {
545         struct deferred_write   *dwpnt,
546                                 *dwnext;
547
548         dwpnt = dw_head;
549         while (dwpnt) {
550 /*#define DEBUG*/
551 #ifdef DEBUG
552                 fprintf(stderr,
553                 "The file name is %s and pad is %d, size is %lld and extent is %d\n",
554                                 dwpnt->name, dwpnt->pad,
555                                 (Llong)dwpnt->size, dwpnt->extent);
556 #endif
557                 if (dwpnt->table) {
558                         jtwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1, XA_SUBH_DATA, TRUE);
559                         xfwrite(dwpnt->table, ISO_ROUND_UP(dwpnt->size), 1,
560                                                         outfile,
561                                                         XA_SUBH_DATA, TRUE);
562                         last_extent_written += ISO_BLOCKS(dwpnt->size);
563                         table_size += dwpnt->size;
564 /*                      fprintf(stderr, "Size %lld ", (Llong)dwpnt->size); */
565                         free(dwpnt->table);
566                         dwpnt->table = NULL;
567                 } else {
568
569 #ifdef VMS
570                         vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
571 #else
572 #ifdef APPLE_HYB
573                         write_one_file(dwpnt->name, dwpnt->size, outfile,
574                                                                 dwpnt->off);
575 #else
576                         write_one_file(dwpnt->name, dwpnt->size, outfile);
577 #endif  /* APPLE_HYB */
578 #endif
579                         free(dwpnt->name);
580                         dwpnt->name = NULL;
581                 }
582
583
584 #ifndef DVD_VIDEO
585 #define dvd_video       0
586 #endif
587
588 #ifndef APPLE_HYB
589 #define apple_hyb       0
590 #endif
591
592 #if     defined(APPLE_HYB) || defined(DVD_VIDEO)
593
594                 if (apple_hyb || dvd_video) {
595                         /*
596                          * we may have to pad out ISO files to work with HFS
597                          * clump sizes
598                          */
599                         char    blk[SECTOR_SIZE];
600                         Uint    i;
601
602                         for (i = 0; i < dwpnt->pad; i++) {
603                                 jtwrite(blk, SECTOR_SIZE, 1, 0, FALSE);
604                                 xfwrite(blk, SECTOR_SIZE, 1, outfile, 0, FALSE);
605                                 last_extent_written++;
606                         }
607                 }
608 #endif  /* APPLE_HYB || DVD_VIDEO */
609
610
611                 dwnext = dwpnt;
612                 dwpnt = dwpnt->next;
613                 free(dwnext);
614                 dwnext = NULL;
615         }
616 }/* write_files(... */
617
618 #if 0
619 static void
620 dump_filelist()
621 {
622         struct deferred_write *dwpnt;
623
624         dwpnt = dw_head;
625         while (dwpnt) {
626                 fprintf(stderr, "File %s\n", dwpnt->name);
627                 dwpnt = dwpnt->next;
628         }
629         fprintf(stderr, "\n");
630 }
631
632 #endif
633
634 static int
635 compare_dirs(const void *rr, const void *ll)
636 {
637         char            *rpnt,
638                         *lpnt;
639         struct directory_entry **r,
640                         **l;
641
642         r = (struct directory_entry **) rr;
643         l = (struct directory_entry **) ll;
644         rpnt = (*r)->isorec.name;
645         lpnt = (*l)->isorec.name;
646
647 #ifdef APPLE_HYB
648         /*
649          * resource fork MUST (not sure if this is true for HFS volumes) be
650          * before the data fork - so force it here
651          */
652         if ((*r)->assoc && (*r)->assoc == (*l))
653                 return (1);
654         if ((*l)->assoc && (*l)->assoc == (*r))
655                 return (-1);
656 #endif  /* APPLE_HYB */
657
658         /* If the entries are the same, this is an error. */
659         if (strcmp(rpnt, lpnt) == 0) {
660 #ifdef  USE_LIBSCHILY
661                 errmsgno(EX_BAD,
662                         "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
663                         (*r)->whole_name, (*l)->whole_name,
664                         rpnt);
665 #else
666                 fprintf(stderr,
667                         "Error: '%s' and '%s' have the same ISO9660 name '%s'.\n",
668                         (*r)->whole_name, (*l)->whole_name,
669                         rpnt);
670 #endif
671                 sort_goof++;
672         }
673         /* Check we don't have the same RR name */
674         if (use_RockRidge && !is_rr_dir) {
675                 /*
676                  * entries *can* have the same RR name in the "rr_moved"
677                  * directory so skip checks if we're in reloc_dir
678                  */
679                 if (!(strcmp((*r)->name, (*l)->name))) {
680 #ifdef  USE_LIBSCHILY
681                         errmsgno(EX_BAD,
682                         "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
683                                 (*r)->whole_name, (*l)->whole_name,
684                                 (*r)->name);
685 #else
686                         fprintf(stderr,
687                         "Error: '%s' and '%s' have the same Rock Ridge name '%s'.\n",
688                                 (*r)->whole_name, (*l)->whole_name,
689                                 (*r)->name);
690 #endif
691                         sort_goof++;
692                 }
693         }
694         /*
695          * Put the '.' and '..' entries on the head of the sorted list. For
696          * normal ASCII, this always happens to be the case, but out of band
697          * characters cause this not to be the case sometimes.
698          * FIXME(eric) - these tests seem redundant, in that the name is never
699          * assigned these values.  It will instead be \000 or \001, and thus
700          * should always be sorted correctly.   I need to figure out why I
701          * thought I needed this in the first place.
702          */
703 #if 0
704         if (strcmp(rpnt, ".") == 0)
705                 return (-1);
706         if (strcmp(lpnt, ".") == 0)
707                 return (1);
708
709         if (strcmp(rpnt, "..") == 0)
710                 return (-1);
711         if (strcmp(lpnt, "..") == 0)
712                 return (1);
713 #else
714         /*
715          * The code above is wrong (as explained in Eric's comment), leading to
716          * incorrect sort order iff the -L option ("allow leading dots") is in
717          * effect and a directory contains entries that start with a dot.
718          *  (TF, Tue Dec 29 13:49:24 CET 1998)
719          */
720         if ((*r)->isorec.name_len[0] == 1 && *rpnt == 0)
721                 return (-1);    /* '.' */
722         if ((*l)->isorec.name_len[0] == 1 && *lpnt == 0)
723                 return (1);
724
725         if ((*r)->isorec.name_len[0] == 1 && *rpnt == 1)
726                 return (-1);    /* '..' */
727         if ((*l)->isorec.name_len[0] == 1 && *lpnt == 1)
728                 return (1);
729 #endif
730
731         while (*rpnt && *lpnt) {
732                 if (*rpnt == ';' && *lpnt != ';')
733                         return (-1);
734                 if (*rpnt != ';' && *lpnt == ';')
735                         return (1);
736
737                 if (*rpnt == ';' && *lpnt == ';')
738                         return (0);
739
740                 if (*rpnt == '.' && *lpnt != '.')
741                         return (-1);
742                 if (*rpnt != '.' && *lpnt == '.')
743                         return (1);
744
745                 if ((unsigned char) *rpnt < (unsigned char) *lpnt)
746                         return (-1);
747                 if ((unsigned char) *rpnt > (unsigned char) *lpnt)
748                         return (1);
749                 rpnt++;
750                 lpnt++;
751         }
752         if (*rpnt)
753                 return (1);
754         if (*lpnt)
755                 return (-1);
756         return (0);
757 }
758
759 /*
760  * Function:            sort_directory
761  *
762  * Purpose:             Sort the directory in the appropriate ISO9660
763  *                      order.
764  *
765  * Notes:               Returns 0 if OK, returns > 0 if an error occurred.
766  */
767 int
768 sort_directory(struct directory_entry **sort_dir, int rr)
769 {
770         int             dcount = 0;
771         int             xcount = 0;
772         int             j;
773         int             i,
774                         len;
775         struct directory_entry *s_entry;
776         struct directory_entry **sortlist;
777
778         /* need to keep a count of how many entries are hidden */
779         s_entry = *sort_dir;
780         while (s_entry) {
781                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
782                         xcount++;
783                 dcount++;
784                 s_entry = s_entry->next;
785         }
786
787         if (dcount == 0) {
788                 return (0);
789         }
790         /* OK, now we know how many there are.  Build a vector for sorting. */
791         sortlist = (struct directory_entry **)
792                 e_malloc(sizeof (struct directory_entry *) * dcount);
793
794         j = dcount - 1;
795         dcount = 0;
796         s_entry = *sort_dir;
797         while (s_entry) {
798                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
799                         /* put any hidden entries at the end of the vector */
800                         sortlist[j--] = s_entry;
801                 } else {
802                         sortlist[dcount] = s_entry;
803                         dcount++;
804                 }
805                 len = s_entry->isorec.name_len[0];
806                 s_entry->isorec.name[len] = 0;
807                 s_entry = s_entry->next;
808         }
809
810         /* Each directory is required to contain at least . and .. */
811         if (dcount < 2) {
812 #ifdef  USE_LIBSCHILY
813                 errmsgno(EX_BAD,
814                         "Directory size too small (. or .. missing ??%s)\n",
815                         "?");   /* Try to avoid a GCC trigraph warning */
816 #else
817                 fprintf(stderr,
818                         "Directory size too small (. or .. missing ??%s)\n",
819                         "?");   /* Try to avoid a GCC trigraph warning */
820 #endif
821                 sort_goof = 1;
822
823         } else {
824                 /* only sort the non-hidden entries */
825                 sort_goof = 0;
826                 is_rr_dir = rr;
827 #ifdef PROTOTYPES
828                 qsort(sortlist, dcount, sizeof (struct directory_entry *),
829                         (int (*) (const void *, const void *)) compare_dirs);
830 #else
831                 qsort(sortlist, dcount, sizeof (struct directory_entry *),
832                         compare_dirs);
833 #endif
834
835                 /*
836                  * Now reassemble the linked list in the proper sorted order
837                  * We still need the hidden entries, as they may be used in
838                  * the Joliet tree.
839                  */
840                 for (i = 0; i < dcount + xcount - 1; i++) {
841                         sortlist[i]->next = sortlist[i + 1];
842                 }
843
844                 sortlist[dcount + xcount - 1]->next = NULL;
845                 *sort_dir = sortlist[0];
846         }
847
848         free(sortlist);
849         sortlist = NULL;
850         return (sort_goof);
851 }
852
853 static int
854 root_gen()
855 {
856         init_fstatbuf();
857
858         root_record.length[0] = 1 +
859                         offsetof(struct iso_directory_record, name[0]);
860         root_record.ext_attr_length[0] = 0;
861         set_733((char *) root_record.extent, root->extent);
862         set_733((char *) root_record.size, ISO_ROUND_UP(root->size));
863         iso9660_date(root_record.date, root_statbuf.st_mtime);
864         root_record.flags[0] = ISO_DIRECTORY;
865         root_record.file_unit_size[0] = 0;
866         root_record.interleave[0] = 0;
867         set_723(root_record.volume_sequence_number, volume_sequence_number);
868         root_record.name_len[0] = 1;
869         return (0);
870 }
871
872 #ifdef SORTING
873 /*
874  *      sorts deferred_write entries based on the sort weight
875  */
876 static int
877 compare_sort(const void *rr, const void *ll)
878 {
879         struct deferred_write   **r;
880         struct deferred_write   **l;
881         int                     r_sort;
882         int                     l_sort;
883
884         r = (struct deferred_write **) rr;
885         l = (struct deferred_write **) ll;
886         r_sort = (*r)->s_entry->sort;
887         l_sort = (*l)->s_entry->sort;
888
889         if (r_sort != l_sort)
890                 return (r_sort < l_sort ? 1 : -1);
891         else
892                 return ((*r)->extent - (*l)->extent);
893 }
894
895 /*
896  *      reassign start extents to files that are "hard links" to
897  *      files that may have been sorted
898  */
899 static void
900 reassign_link_addresses(struct directory *dpnt)
901 {
902         struct directory_entry  *s_entry;
903         struct file_hash        *s_hash;
904
905         while (dpnt) {
906                 s_entry = dpnt->contents;
907                 for (s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) {
908                         /* link files have already been given the weight NOT_SORTED */
909                         if (s_entry->sort == NOT_SORTED)
910                         {
911                                 /* update the start extent */
912                                 s_hash = find_hash(s_entry->dev, s_entry->inode);
913                                 if (s_hash) {
914                                         set_733((char *) s_entry->isorec.extent,
915                                                         s_hash->starting_block);
916                                         s_entry->starting_block = s_hash->starting_block;
917                                 }
918                         }
919
920                         if (verbose > 2 && s_entry->size != 0) {
921                                 fprintf(stderr, "%8u %8u ",
922                                         s_entry->starting_block,
923                                         (unsigned int)(s_entry->starting_block + ISO_BLOCKS(s_entry->size) - 1));
924
925                                 if (s_entry->inode != TABLE_INODE) {
926                                         fprintf(stderr, "%s\n", s_entry->whole_name);
927                                 } else {
928                                         fprintf(stderr, "%s%s%s\n",
929                                                 s_entry->filedir->whole_name,
930                                                 SPATH_SEPARATOR, trans_tbl);
931                                 }
932                         }
933                 }
934                 if (dpnt->subdir) {
935                         reassign_link_addresses(dpnt->subdir);
936                 }
937
938                 dpnt = dpnt->next;
939         }
940 }
941
942 /*
943  *      sort files in order of the given sort weight
944  */
945 static int
946 sort_file_addresses()
947 {
948         struct deferred_write   *dwpnt;
949         struct deferred_write   **sortlist;
950         struct directory_entry  *s_entry;
951         int                     start_extent;
952         int                     num = 0;
953         int                     i;
954
955         /* need to store start extents for linked files */
956         flush_hash();
957
958         /* find out how many files we have */
959         dwpnt = dw_head;
960         while (dwpnt) {
961                 num++;
962                 dwpnt = dwpnt->next;
963         }
964
965         /* return if we have none */
966         if (num == 0) {
967                 return (1);
968         }
969
970         /* save the start extent of the first file */
971         start_extent = dw_head->extent;
972
973         /* set up vector to store entries */
974         sortlist = (struct deferred_write **)
975                 e_malloc(sizeof (struct deferred_write *) * num);
976
977         for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next)
978                 sortlist[i] = dwpnt;
979
980         /* sort the list */
981 #ifdef PROTOTYPES
982         qsort(sortlist, num, sizeof (struct deferred_write *),
983                 (int (*)(const void *, const void *))compare_sort);
984 #else
985         qsort(sortlist, num, sizeof (struct deferred_write *), compare_sort);
986 #endif
987
988         /* reconstruct the linked list */
989         for (i = 0; i < num-1; i++) {
990                 sortlist[i]->next = sortlist[i+1];
991         }
992
993         sortlist[num-1]->next = NULL;
994         dw_head = sortlist[0];
995
996         free(sortlist);
997
998         /* set the new start extents for the sorted list */
999         for (i = 0, dwpnt = dw_head; i < num; i++, dwpnt = dwpnt->next) {
1000                 s_entry = dwpnt->s_entry;
1001                 dwpnt->extent = s_entry->starting_block = start_extent;
1002                 set_733((char *) s_entry->isorec.extent, start_extent);
1003
1004                 start_extent += ISO_BLOCKS(s_entry->size);
1005 #ifdef DVD_VIDEO
1006                 /*
1007                  * Shouldn't this be done for every type of sort? Otherwise
1008                  * we will loose every pad info we add if we sort the files
1009                  */
1010                 if (dvd_video) {
1011                         start_extent += dwpnt->pad;
1012                 }
1013 #endif /* DVD_VIDEO */
1014
1015                 /* cache start extents for any linked files */
1016                 add_hash(s_entry);
1017         }
1018
1019         return (0);
1020 }
1021 #endif /* SORTING */
1022
1023
1024
1025 static BOOL
1026 assign_file_addresses(struct directory *dpnt, BOOL isnest)
1027 {
1028         struct directory *finddir;
1029         struct directory_entry *s_entry;
1030         struct file_hash *s_hash;
1031         struct deferred_write *dwpnt;
1032         char            whole_path[PATH_MAX];
1033 #ifdef DVD_VIDEO
1034         char            dvd_path[PATH_MAX];
1035         title_set_info_t * title_set_info = NULL;
1036         char    *p;
1037 #endif
1038         BOOL    ret = FALSE;
1039
1040         while (dpnt) {
1041 #ifdef DVD_VIDEO
1042                 if (dvd_video && root == dpnt->parent &&
1043                     ((p = strstr(dpnt->whole_name, "VIDEO_TS")) != 0)&&
1044                     strcmp(p, "VIDEO_TS") == 0) {
1045
1046                         int     maxlen = strlen(dpnt->whole_name)-8;
1047                         if (maxlen > (sizeof (dvd_path)-1))
1048                                 maxlen = sizeof (dvd_path)-1;
1049                         strncpy(dvd_path, dpnt->whole_name, maxlen);
1050                         dvd_path[maxlen] = '\0';
1051
1052 #ifdef DEBUG
1053                         fprintf(stderr, "Found 'VIDEO_TS', the path is %s \n", dvd_path);
1054 #endif
1055                         title_set_info = DVDGetFileSet(dvd_path);
1056                         if (title_set_info == 0) {
1057                                 /*
1058                                  * Do not switch off -dvd-video but let is fail later.
1059                                  */
1060 /*                              dvd_video = 0;*/
1061                                 errmsgno(EX_BAD, "Unable to parse DVD-Video structures.\n");
1062                         } else {
1063                                 ret = TRUE;
1064                         }
1065                 }
1066 #endif /* DVD_VIDEO */
1067
1068                 s_entry = dpnt->contents;
1069                 for (s_entry = dpnt->contents; s_entry;
1070                                                 s_entry = s_entry->next) {
1071                         /*
1072                          * If we already have an  extent for this entry, then
1073                          * don't assign a new one.  It must have come from a
1074                          * previous session on the disc.  Note that we don't
1075                          * end up scheduling the thing for writing either.
1076                          */
1077                         if (get_733(s_entry->isorec.extent) != 0) {
1078                                 continue;
1079                         }
1080                         /*
1081                          * This saves some space if there are symlinks present
1082                          */
1083                         s_hash = find_hash(s_entry->dev, s_entry->inode);
1084                         if (s_hash) {
1085                                 if (verbose > 2) {
1086                                         fprintf(stderr, "Cache hit for '%s%s%s'\n", s_entry->filedir->de_name,
1087                                                 SPATH_SEPARATOR,
1088                                                 s_entry->name);
1089                                 }
1090                                 set_733((char *) s_entry->isorec.extent,
1091                                                 s_hash->starting_block);
1092                                 set_733((char *) s_entry->isorec.size,
1093                                                 s_hash->size);
1094 #ifdef SORTING
1095                                 /* check for non-directory files */
1096                                 if (do_sort && ((s_entry->isorec.flags[0] & ISO_DIRECTORY) == 0)) {
1097                                         /* make sure the real file has the highest weighting */
1098                                         s_hash->de->sort = MAX(s_entry->sort, s_hash->de->sort);
1099                                         /* flag this as a potential non-sorted file */
1100                                         s_entry->sort = NOT_SORTED;
1101                                 }
1102 #endif /* SORTING */
1103                                 continue;
1104                         }
1105                         /*
1106                          * If this is for a directory that is not a . or
1107                          * a .. entry, then look up the information for the
1108                          * entry.  We have already assigned extents for
1109                          * directories, so we just need to fill in the blanks
1110                          * here.
1111                          */
1112                         if (strcmp(s_entry->name, ".") != 0 &&
1113                                         strcmp(s_entry->name, "..") != 0 &&
1114                                         s_entry->isorec.flags[0] & ISO_DIRECTORY) {
1115                                 finddir = dpnt->subdir;
1116                                 while (1 == 1) {
1117                                         if (finddir->self == s_entry)
1118                                                 break;
1119                                         finddir = finddir->next;
1120                                         if (!finddir) {
1121 #ifdef  DVD_VIDEO
1122                                                 if (title_set_info != 0) {
1123                                                         DVDFreeFileSet(title_set_info);
1124                                                 }
1125 #endif
1126                                                 comerrno(EX_BAD,
1127                                                         "Fatal goof - could not find dir entry for '%s'\n",
1128                                                         s_entry->name);
1129                                         }
1130                                 }
1131                                 set_733((char *) s_entry->isorec.extent,
1132                                                 finddir->extent);
1133                                 s_entry->starting_block = finddir->extent;
1134                                 s_entry->size = ISO_ROUND_UP(finddir->size);
1135                                 total_dir_size += s_entry->size;
1136                                 add_hash(s_entry);
1137                                 set_733((char *) s_entry->isorec.size,
1138                                                 ISO_ROUND_UP(finddir->size));
1139                                 continue;
1140                         }
1141                         /*
1142                          * If this is . or .., then look up the relevant info
1143                          * from the tables.
1144                          */
1145                         if (strcmp(s_entry->name, ".") == 0) {
1146                                 set_733((char *) s_entry->isorec.extent,
1147                                                                 dpnt->extent);
1148
1149                                 /*
1150                                  * Set these so that the hash table has the
1151                                  * correct information
1152                                  */
1153                                 s_entry->starting_block = dpnt->extent;
1154                                 s_entry->size = ISO_ROUND_UP(dpnt->size);
1155
1156                                 add_hash(s_entry);
1157                                 s_entry->starting_block = dpnt->extent;
1158                                 set_733((char *) s_entry->isorec.size,
1159                                                 ISO_ROUND_UP(dpnt->size));
1160                                 continue;
1161                         }
1162                         if (strcmp(s_entry->name, "..") == 0) {
1163                                 if (dpnt == root) {
1164                                         total_dir_size += root->size;
1165                                 }
1166                                 set_733((char *) s_entry->isorec.extent,
1167                                                         dpnt->parent->extent);
1168
1169                                 /*
1170                                  * Set these so that the hash table has the
1171                                  * correct information
1172                                  */
1173                                 s_entry->starting_block = dpnt->parent->extent;
1174                                 s_entry->size =
1175                                         ISO_ROUND_UP(dpnt->parent->size);
1176
1177                                 add_hash(s_entry);
1178                                 s_entry->starting_block = dpnt->parent->extent;
1179                                 set_733((char *) s_entry->isorec.size,
1180                                         ISO_ROUND_UP(dpnt->parent->size));
1181                                 continue;
1182                         }
1183                         /*
1184                          * Some ordinary non-directory file.  Just schedule
1185                          * the file to be written.  This is all quite
1186                          * straightforward, just make a list and assign
1187                          * extents as we go.  Once we get through writing all
1188                          * of the directories, we should be ready write out
1189                          * these files
1190                          */
1191                         if (s_entry->size) {
1192                                 dwpnt = (struct deferred_write *)
1193                                         e_malloc(sizeof (struct deferred_write));
1194                                 /* save this directory entry for later use */
1195                                 dwpnt->s_entry = s_entry;
1196                                 /* set the initial padding to zero */
1197                                 dwpnt->pad = 0;
1198 #ifdef DVD_VIDEO
1199                                 if (dvd_video && (title_set_info != 0)) {
1200                                         int pad;
1201
1202                                         pad = DVDGetFilePad(title_set_info, s_entry->name);
1203                                         if (pad < 0) {
1204                                                 errmsgno(EX_BAD,
1205                                                 "Implementation botch. Video pad for file %s is %d\n",
1206                                                 s_entry->name, pad),
1207                                                 comerrno(EX_BAD,
1208                                                 "Either the *.IFO file is bad or you found a genisoimage bug.\n");
1209                                         }
1210                                         dwpnt->pad = pad;
1211                                         if (verbose > 0 && pad != 0) {
1212                                                 fprintf(stderr,
1213                                                         "The pad was %d for file %s\n", dwpnt->pad, s_entry->name);
1214                                         }
1215                                 }
1216 #endif /* DVD_VIDEO */
1217 #ifdef APPLE_HYB
1218                                 /*
1219                                  * maybe an offset to start of the real
1220                                  * file/fork
1221                                  */
1222                                 dwpnt->off = s_entry->hfs_off;
1223 #else
1224                                 dwpnt->off = (off_t)0;
1225 #endif  /* APPLE_HYB */
1226                                 if (dw_tail) {
1227                                         dw_tail->next = dwpnt;
1228                                         dw_tail = dwpnt;
1229                                 } else {
1230                                         dw_head = dwpnt;
1231                                         dw_tail = dwpnt;
1232                                 }
1233                                 if (s_entry->inode == TABLE_INODE) {
1234                                         dwpnt->table = s_entry->table;
1235                                         dwpnt->name = NULL;
1236                                         sprintf(whole_path, "%s%s%s",
1237                                                 s_entry->filedir->whole_name,
1238                                                 SPATH_SEPARATOR, trans_tbl);
1239                                 } else {
1240                                         dwpnt->table = NULL;
1241                                         strcpy(whole_path, s_entry->whole_name);
1242                                         dwpnt->name = strdup(whole_path);
1243                                 }
1244                                 dwpnt->next = NULL;
1245                                 dwpnt->size = s_entry->size;
1246                                 dwpnt->extent = last_extent;
1247                                 set_733((char *) s_entry->isorec.extent,
1248                                                                 last_extent);
1249                                 s_entry->starting_block = last_extent;
1250                                 add_hash(s_entry);
1251                                 last_extent += ISO_BLOCKS(s_entry->size);
1252 #ifdef DVD_VIDEO
1253                                 /* Shouldn't we always add the pad info? */
1254                                 if (dvd_video) {
1255                                         last_extent += dwpnt->pad;
1256                                 }
1257 #endif /* DVD_VIDEO */
1258                                 if (verbose > 2 && !do_sort) {
1259                                         fprintf(stderr, "%8d %8u %s\n",
1260                                                 s_entry->starting_block,
1261                                                 last_extent - 1, whole_path);
1262                                 }
1263 #ifdef DBG_ISO
1264                                 if (ISO_BLOCKS(s_entry->size) > 500) {
1265                                         fprintf(stderr,
1266                                                 "Warning: large file '%s'\n",
1267                                                 whole_path);
1268                                         fprintf(stderr,
1269                                                 "Starting block is %d\n",
1270                                                 s_entry->starting_block);
1271                                         fprintf(stderr,
1272                                         "Reported file size is %lld\n",
1273                                                 (Llong)s_entry->size);
1274
1275                                 }
1276 #endif
1277 #ifdef  NOT_NEEDED      /* Never use this code if you like to create a DVD */
1278
1279                                 if (last_extent > (800000000 >> 11)) {
1280                                         /* More than 800Mb? Punt */
1281                                         fprintf(stderr,
1282                                         "Extent overflow processing file '%s'\n",
1283                                                 whole_path);
1284                                         fprintf(stderr,
1285                                                 "Starting block is %d\n",
1286                                                 s_entry->starting_block);
1287                                         fprintf(stderr,
1288                                         "Reported file size is %lld\n",
1289                                                         (Llong)s_entry->size);
1290                                         exit(1);
1291                                 }
1292 #endif
1293                                 continue;
1294                         }
1295                         /*
1296                          * This is for zero-length files.  If we leave the
1297                          * extent 0, then we get screwed, because many readers
1298                          * simply drop files that have an extent of zero.
1299                          * Thus we leave the size 0, and just assign the
1300                          * extent number.
1301                          */
1302                         set_733((char *) s_entry->isorec.extent, last_extent);
1303                 }
1304                 if (dpnt->subdir) {
1305                         if (assign_file_addresses(dpnt->subdir, TRUE))
1306                                 ret = TRUE;
1307                 }
1308                 dpnt = dpnt->next;
1309         }
1310 #ifdef DVD_VIDEO
1311         if (title_set_info != NULL) {
1312                 DVDFreeFileSet(title_set_info);
1313         }
1314         if (dvd_video && !ret && !isnest) {
1315                 errmsgno(EX_BAD,
1316                         "Could not find correct 'VIDEO_TS' directory.\n");
1317         }
1318 #endif /* DVD_VIDEO */
1319         return (ret);
1320 } /* assign_file_addresses(... */
1321
1322 static void
1323 free_one_directory(struct directory *dpnt)
1324 {
1325         struct directory_entry *s_entry;
1326         struct directory_entry *s_entry_d;
1327
1328         s_entry = dpnt->contents;
1329         while (s_entry) {
1330                 s_entry_d = s_entry;
1331                 s_entry = s_entry->next;
1332
1333                 if (s_entry_d->rr_attributes) {
1334                         free(s_entry_d->rr_attributes);
1335                         s_entry_d->rr_attributes = NULL;
1336                 }
1337                 if (s_entry_d->name != NULL) {
1338                         free(s_entry_d->name);
1339                         s_entry_d->name = NULL;
1340                 }
1341                 if (s_entry_d->whole_name != NULL) {
1342                         free(s_entry_d->whole_name);
1343                         s_entry_d->whole_name = NULL;
1344                 }
1345 #ifdef APPLE_HYB
1346                 if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc)
1347                         free(s_entry_d->hfs_ent);
1348 #endif  /* APPLE_HYB */
1349
1350                 free(s_entry_d);
1351                 s_entry_d = NULL;
1352         }
1353         dpnt->contents = NULL;
1354 }/* free_one_directory(... */
1355
1356 static void
1357 free_directories(struct directory *dpnt)
1358 {
1359         while (dpnt) {
1360                 free_one_directory(dpnt);
1361                 if (dpnt->subdir)
1362                         free_directories(dpnt->subdir);
1363                 dpnt = dpnt->next;
1364         }
1365 }
1366
1367 void
1368 generate_one_directory(struct directory *dpnt, FILE *outfile)
1369 {
1370         unsigned int    ce_address = 0;
1371         char            *ce_buffer;
1372         unsigned int    ce_index = 0;
1373         unsigned int    ce_size;
1374         unsigned int    dir_index;
1375         char            *directory_buffer;
1376         int             new_reclen;
1377         struct directory_entry *s_entry;
1378         struct directory_entry *s_entry_d;
1379         unsigned int    total_size;
1380
1381         total_size = ISO_ROUND_UP(dpnt->size);
1382         directory_buffer = (char *) e_malloc(total_size);
1383         memset(directory_buffer, 0, total_size);
1384         dir_index = 0;
1385
1386         ce_size = ISO_ROUND_UP(dpnt->ce_bytes);
1387         ce_buffer = NULL;
1388
1389         if (ce_size > 0) {
1390                 ce_buffer = (char *) e_malloc(ce_size);
1391                 memset(ce_buffer, 0, ce_size);
1392
1393                 ce_index = 0;
1394
1395                 /* Absolute byte address of CE entries for this directory */
1396                 ce_address = last_extent_written + (total_size >> 11);
1397                 ce_address = ce_address << 11;
1398         }
1399         s_entry = dpnt->contents;
1400         while (s_entry) {
1401                 /* skip if it's hidden */
1402                 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1403                         s_entry = s_entry->next;
1404                         continue;
1405                 }
1406                 /*
1407                  * We do not allow directory entries to cross sector
1408                  * boundaries. Simply pad, and then start the next entry at
1409                  * the next sector
1410                  */
1411                 new_reclen = s_entry->isorec.length[0];
1412                 if ((dir_index & (SECTOR_SIZE - 1)) + new_reclen >=
1413                                                                 SECTOR_SIZE) {
1414                         dir_index = ISO_ROUND_UP(dir_index);
1415                 }
1416                 memcpy(directory_buffer + dir_index, &s_entry->isorec,
1417                         offsetof(struct iso_directory_record, name[0]) +
1418                         s_entry->isorec.name_len[0]);
1419                 dir_index += offsetof(struct iso_directory_record, name[0]) +
1420                         s_entry->isorec.name_len[0];
1421
1422                 /* Add the Rock Ridge attributes, if present */
1423                 if (s_entry->rr_attr_size) {
1424                         if (dir_index & 1) {
1425                                 directory_buffer[dir_index++] = 0;
1426                         }
1427                         /*
1428                          * If the RR attributes were too long, then write the
1429                          * CE records, as required.
1430                          */
1431                         if (s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
1432                                 struct iso_xa_dir_record *xadp;
1433                                 unsigned char   *pnt;
1434                                 int             len,
1435                                                 nbytes;
1436
1437                                 /*
1438                                  * Go through the entire record, first skip
1439                                  * the XA record and then fix up the
1440                                  * CE entries so that the extent and offset
1441                                  * are correct
1442                                  */
1443                                 pnt = s_entry->rr_attributes;
1444                                 len = s_entry->total_rr_attr_size;
1445
1446                                 if (len >= 14) {
1447                                         xadp = (struct iso_xa_dir_record *)pnt;
1448
1449                                         if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
1450                                                                         xadp->reserved[0] == '\0') {
1451                                                 len -= 14;
1452                                                 pnt += 14;
1453                                         }
1454                                 }
1455
1456                                 while (len > 3) {
1457 #ifdef DEBUG
1458                                         if (ce_size <= 0) {
1459                                                 fprintf(stderr,
1460                                                 "Warning: ce_index(%d) && ce_address(%d) not initialized\n",
1461                                                         ce_index, ce_address);
1462                                         }
1463 #endif
1464
1465                                         if (pnt[0] == 'C' && pnt[1] == 'E') {
1466                                                 nbytes = get_733((char *) pnt + 20);
1467
1468                                                 if ((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
1469                                                         SECTOR_SIZE) {
1470                                                         ce_index = ISO_ROUND_UP(ce_index);
1471                                                 }
1472                                                 set_733((char *) pnt + 4,
1473                                                         (ce_address + ce_index) >> 11);
1474                                                 set_733((char *) pnt + 12,
1475                                                         (ce_address + ce_index) & (SECTOR_SIZE - 1));
1476
1477
1478                                                 /*
1479                                                  * Now store the block in the
1480                                                  * ce buffer
1481                                                  */
1482                                                 memcpy(ce_buffer + ce_index,
1483                                                         pnt + pnt[2], nbytes);
1484                                                 ce_index += nbytes;
1485                                                 if (ce_index & 1) {
1486                                                         ce_index++;
1487                                                 }
1488                                         }
1489                                         len -= pnt[2];
1490                                         pnt += pnt[2];
1491                                 }
1492
1493                         }
1494                         rockridge_size += s_entry->total_rr_attr_size;
1495                         memcpy(directory_buffer + dir_index,
1496                                 s_entry->rr_attributes,
1497                                 s_entry->rr_attr_size);
1498                         dir_index += s_entry->rr_attr_size;
1499                 }
1500                 if (dir_index & 1) {
1501                         directory_buffer[dir_index++] = 0;
1502                 }
1503                 s_entry_d = s_entry;
1504                 s_entry = s_entry->next;
1505
1506                 /*
1507                  * Joliet doesn't use the Rock Ridge attributes, so we free
1508                  * it here.
1509                  */
1510                 if (s_entry_d->rr_attributes) {
1511                         free(s_entry_d->rr_attributes);
1512                         s_entry_d->rr_attributes = NULL;
1513                 }
1514         }
1515
1516         if (dpnt->size != dir_index) {
1517 #ifdef  USE_LIBSCHILY
1518                 errmsgno(EX_BAD,
1519                         "Unexpected directory length %lld expected: %d '%s'\n",
1520                         (Llong)dpnt->size,
1521                         dir_index, dpnt->de_name);
1522 #else
1523                 fprintf(stderr,
1524                         "Unexpected directory length %lld expected: %d '%s'\n",
1525                         (Llong)dpnt->size,
1526                         dir_index, dpnt->de_name);
1527 #endif
1528         }
1529         jtwrite(directory_buffer, total_size, 1, 0, FALSE);
1530         xfwrite(directory_buffer, total_size, 1, outfile, 0, FALSE);
1531         last_extent_written += total_size >> 11;
1532         free(directory_buffer);
1533         directory_buffer = NULL;
1534
1535         if (ce_size > 0) {
1536                 if (ce_index != dpnt->ce_bytes) {
1537 #ifdef  USE_LIBSCHILY
1538                         errmsgno(EX_BAD,
1539                         "Continuation entry record length mismatch %d expected: %d.\n",
1540                                 ce_index, dpnt->ce_bytes);
1541 #else
1542                         fprintf(stderr,
1543                         "Continuation entry record length mismatch %d expected: %d.\n",
1544                                 ce_index, dpnt->ce_bytes);
1545 #endif
1546                 }
1547                 jtwrite(ce_buffer, ce_size, 1, 0, FALSE);
1548                 xfwrite(ce_buffer, ce_size, 1, outfile, 0, FALSE);
1549                 last_extent_written += ce_size >> 11;
1550                 free(ce_buffer);
1551                 ce_buffer = NULL;
1552         }
1553 }/* generate_one_directory(... */
1554
1555 static void
1556 build_pathlist(struct directory *node)
1557 {
1558         struct directory *dpnt;
1559
1560         dpnt = node;
1561
1562         while (dpnt) {
1563                 /* skip if it's hidden */
1564                 if ((dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0)
1565                         pathlist[dpnt->path_index] = dpnt;
1566
1567                 if (dpnt->subdir)
1568                         build_pathlist(dpnt->subdir);
1569                 dpnt = dpnt->next;
1570         }
1571 }/* build_pathlist(... */
1572
1573 static int
1574 compare_paths(void const *r, void const *l)
1575 {
1576         struct directory const *ll = *(struct directory * const *) l;
1577         struct directory const *rr = *(struct directory * const *) r;
1578
1579         if (rr->parent->path_index < ll->parent->path_index) {
1580                 return (-1);
1581         }
1582         if (rr->parent->path_index > ll->parent->path_index) {
1583                 return (1);
1584         }
1585         return (strcmp(rr->self->isorec.name, ll->self->isorec.name));
1586
1587 }/* compare_paths(... */
1588
1589 static int
1590 generate_path_tables()
1591 {
1592         struct directory_entry *de = NULL;
1593         struct directory *dpnt;
1594         int             fix;
1595         int             i;
1596         int             j;
1597         int             namelen;
1598         char            *npnt;
1599         char            *npnt1;
1600         int             tablesize;
1601
1602         /* First allocate memory for the tables and initialize the memory */
1603         tablesize = path_blocks << 11;
1604         path_table_m = (char *) e_malloc(tablesize);
1605         path_table_l = (char *) e_malloc(tablesize);
1606         memset(path_table_l, 0, tablesize);
1607         memset(path_table_m, 0, tablesize);
1608
1609         /*
1610          * Now start filling in the path tables.  Start with root directory
1611          */
1612
1613         path_table_index = 0;
1614         pathlist = (struct directory **) e_malloc(sizeof (struct directory *)
1615                 * next_path_index);
1616         memset(pathlist, 0, sizeof (struct directory *) * next_path_index);
1617         build_pathlist(root);
1618
1619         do {
1620                 fix = 0;
1621 #ifdef PROTOTYPES
1622                 qsort(&pathlist[1], next_path_index - 1,
1623                         sizeof (struct directory *),
1624                         (int (*) (const void *, const void *)) compare_paths);
1625 #else
1626                 qsort(&pathlist[1], next_path_index - 1,
1627                         sizeof (struct directory *),
1628                         compare_paths);
1629 #endif
1630
1631                 for (j = 1; j < next_path_index; j++) {
1632                         if (pathlist[j]->path_index != j) {
1633                                 pathlist[j]->path_index = j;
1634                                 fix++;
1635                         }
1636                 }
1637         } while (fix);
1638
1639         for (j = 1; j < next_path_index; j++) {
1640                 dpnt = pathlist[j];
1641                 if (!dpnt) {
1642 #ifdef  USE_LIBSCHILY
1643                         comerrno(EX_BAD, "Entry %d not in path tables\n", j);
1644 #else
1645                         fprintf(stderr, "Entry %d not in path tables\n", j);
1646                         exit(1);
1647 #endif
1648                 }
1649                 npnt = dpnt->de_name;
1650
1651                 /* So the root comes out OK */
1652                 if ((*npnt == 0) || (dpnt == root)) {
1653                         npnt = ".";
1654                 }
1655                 npnt1 = strrchr(npnt, PATH_SEPARATOR);
1656                 if (npnt1) {
1657                         npnt = npnt1 + 1;
1658                 }
1659                 de = dpnt->self;
1660                 if (!de) {
1661 #ifdef  USE_LIBSCHILY
1662                         comerrno(EX_BAD,
1663                         "Fatal ISO9660 goof - directory has amnesia\n");
1664 #else
1665                         fprintf(stderr,
1666                         "Fatal ISO9660 goof - directory has amnesia\n");
1667                         exit(1);
1668 #endif
1669                 }
1670                 namelen = de->isorec.name_len[0];
1671
1672                 path_table_l[path_table_index] = namelen;
1673                 path_table_m[path_table_index] = namelen;
1674                 path_table_index += 2;
1675
1676                 set_731(path_table_l + path_table_index, dpnt->extent);
1677                 set_732(path_table_m + path_table_index, dpnt->extent);
1678                 path_table_index += 4;
1679
1680                 if (dpnt->parent->path_index > 0xffff) {
1681 #ifdef  USE_LIBSCHILY
1682                         comerrno(EX_BAD,
1683                         "Unable to generate sane path tables - too many directories (%d)\n",
1684                                 dpnt->parent->path_index);
1685 #else
1686                         fprintf(stderr,
1687                         "Unable to generate sane path tables - too many directories (%d)\n",
1688                                 dpnt->parent->path_index);
1689                         exit(1);
1690 #endif
1691                 }
1692
1693                 set_721(path_table_l + path_table_index,
1694                         dpnt->parent->path_index);
1695                 set_722(path_table_m + path_table_index,
1696                         dpnt->parent->path_index);
1697                 path_table_index += 2;
1698
1699                 for (i = 0; i < namelen; i++) {
1700                         path_table_l[path_table_index] = de->isorec.name[i];
1701                         path_table_m[path_table_index] = de->isorec.name[i];
1702                         path_table_index++;
1703                 }
1704                 if (path_table_index & 1) {
1705                         path_table_index++;     /* For odd lengths we pad */
1706                 }
1707         }
1708
1709         free(pathlist);
1710         pathlist = NULL;
1711         if (path_table_index != path_table_size) {
1712 #ifdef  USE_LIBSCHILY
1713                 errmsgno(EX_BAD,
1714                         "Path table lengths do not match %d expected: %d\n",
1715                         path_table_index,
1716                         path_table_size);
1717 #else
1718                 fprintf(stderr,
1719                         "Path table lengths do not match %d expected: %d\n",
1720                         path_table_index,
1721                         path_table_size);
1722 #endif
1723         }
1724         return (0);
1725 }/* generate_path_tables(... */
1726
1727 void
1728 memcpy_max(char *to, char *from, int max)
1729 {
1730         int     n = strlen(from);
1731
1732         if (n > max) {
1733                 n = max;
1734         }
1735         memcpy(to, from, n);
1736
1737 }/* memcpy_max(... */
1738
1739 void
1740 outputlist_insert(struct output_fragment *frag)
1741 {
1742         struct output_fragment *nfrag;
1743
1744         nfrag = e_malloc(sizeof (*frag));
1745         movebytes(frag, nfrag, sizeof (*frag));
1746         nfrag->of_start_extent = 0;
1747
1748         if (out_tail == NULL) {
1749                 out_list = out_tail = nfrag;
1750         } else {
1751                 out_tail->of_next = nfrag;
1752                 out_tail = nfrag;
1753         }
1754 }
1755
1756 static int
1757 file_write(FILE *outfile)
1758 {
1759         Uint    should_write;
1760
1761 #ifdef APPLE_HYB
1762         char    buffer[SECTOR_SIZE];
1763
1764         memset(buffer, 0, sizeof (buffer));
1765
1766         if (apple_hyb) {
1767
1768                 int     i;
1769
1770                 /*
1771                  * write out padding to round up to HFS allocation block
1772                  */
1773                 for (i = 0; i < hfs_pad; i++) {
1774                         jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
1775                         xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
1776                         last_extent_written++;
1777                 }
1778         }
1779 #endif  /* APPLE_HYB */
1780
1781         /*
1782          * OK, all done with that crap.  Now write out the directories. This is
1783          * where the fur starts to fly, because we need to keep track of each
1784          * file as we find it and keep track of where we put it.
1785          */
1786         should_write = last_extent - session_start;
1787
1788         if (verbose > 2) {
1789 #ifdef DBG_ISO
1790                 fprintf(stderr,
1791                         "Total directory extents being written = %d\n",
1792                                                         last_extent);
1793 #endif
1794
1795 #ifdef APPLE_HYB
1796                 if (apple_hyb)
1797                         fprintf(stderr,
1798                         "Total extents scheduled to be written (inc HFS) = %d\n",
1799                                 last_extent - session_start);
1800                 else
1801 #endif  /* APPLE_HYB */
1802
1803                         fprintf(stderr,
1804                                 "Total extents scheduled to be written = %u\n",
1805                                 last_extent - session_start);
1806         }
1807         /* Now write all of the files that we need. */
1808         write_files(outfile);
1809
1810 #ifdef APPLE_HYB
1811         /* write out extents/catalog/dt file */
1812         if (apple_hyb) {
1813
1814                 jtwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, 0, FALSE);
1815                 xfwrite(hce->hfs_ce, HFS_BLOCKSZ, hce->hfs_tot_size, outfile, 0, FALSE);
1816
1817                 /* round up to a whole CD block */
1818                 if (HFS_ROUND_UP(hce->hfs_tot_size) -
1819                                         hce->hfs_tot_size * HFS_BLOCKSZ) {
1820                         jtwrite(buffer,
1821                                 HFS_ROUND_UP(hce->hfs_tot_size) -
1822                                 hce->hfs_tot_size * HFS_BLOCKSZ, 1, 0, FALSE);
1823                         xfwrite(buffer,
1824                                 HFS_ROUND_UP(hce->hfs_tot_size) -
1825                                 hce->hfs_tot_size * HFS_BLOCKSZ, 1, outfile, 0, FALSE);
1826                 }
1827                 last_extent_written += ISO_ROUND_UP(hce->hfs_tot_size *
1828                                                 HFS_BLOCKSZ) / SECTOR_SIZE;
1829
1830                 /* write out HFS boot block */
1831                 if (mac_boot.name)
1832                         write_one_file(mac_boot.name, mac_boot.size, outfile,
1833                                                                 mac_boot.off);
1834         }
1835 #endif  /* APPLE_HYB */
1836
1837         /* The rest is just fluff. */
1838         if (verbose == 0) {
1839                 return (0);
1840         }
1841 #ifdef APPLE_HYB
1842         if (apple_hyb) {
1843                 fprintf(stderr,
1844                         "Total extents actually written (inc HFS) = %d\n",
1845                         last_extent_written - session_start);
1846                 fprintf(stderr, "(Size of ISO volume = %d, HFS extra = %d)\n",
1847                         last_extent_written - session_start - hfs_extra,
1848                         hfs_extra);
1849         } else
1850 #else
1851         fprintf(stderr, "Total extents actually written = %d\n",
1852                 last_extent_written - session_start);
1853 #endif  /* APPLE_HYB */
1854
1855         /* Hard links throw us off here */
1856         if (should_write != (last_extent - session_start)) {
1857                 fprintf(stderr,
1858                 "Number of extents written not what was predicted.  Please fix.\n");
1859                 fprintf(stderr, "Predicted = %d, written = %d\n",
1860                                                 should_write, last_extent);
1861         }
1862         fprintf(stderr, "Total translation table size: %d\n", table_size);
1863         fprintf(stderr, "Total rockridge attributes bytes: %d\n",
1864                                                 rockridge_size);
1865         fprintf(stderr, "Total directory bytes: %d\n", total_dir_size);
1866         fprintf(stderr, "Path table size(bytes): %d\n", path_table_size);
1867
1868 #ifdef DEBUG
1869         fprintf(stderr,
1870                 "next extent, last_extent, last_extent_written %d %d %d\n",
1871                 next_extent, last_extent, last_extent_written);
1872 #endif
1873
1874         return (0);
1875
1876 }/* iso_write(... */
1877
1878 /*
1879  * Function to write the PVD for the disc.
1880  */
1881 static int
1882 pvd_write(FILE *outfile)
1883 {
1884         char            iso_time[17];
1885         int             should_write;
1886         struct tm       local;
1887         struct tm       gmt;
1888
1889
1890         time(&begun);
1891
1892         local = *localtime(&begun);
1893         gmt = *gmtime(&begun);
1894
1895         /*
1896          * There was a comment here about breaking in the year 2000.
1897          * That's not true, in 2000 tm_year == 100, so 1900+tm_year == 2000.
1898          */
1899         sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00",
1900                 1900 + local.tm_year,
1901                 local.tm_mon + 1, local.tm_mday,
1902                 local.tm_hour, local.tm_min, local.tm_sec);
1903
1904         local.tm_min -= gmt.tm_min;
1905         local.tm_hour -= gmt.tm_hour;
1906         local.tm_yday -= gmt.tm_yday;
1907         if (local.tm_yday < -2)         /* Hit new-year limit   */
1908                 local.tm_yday = 1;      /* Local is GMT + 1 day */
1909         iso_time[16] = (local.tm_min + 60 *
1910                                 (local.tm_hour + 24 * local.tm_yday)) / 15;
1911
1912         /* Next we write out the primary descriptor for the disc */
1913         memset(&vol_desc, 0, sizeof (vol_desc));
1914         vol_desc.type[0] = ISO_VD_PRIMARY;
1915         memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof (ISO_STANDARD_ID));
1916         vol_desc.version[0] = 1;
1917
1918         memset(vol_desc.system_id, ' ', sizeof (vol_desc.system_id));
1919         memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
1920
1921         memset(vol_desc.volume_id, ' ', sizeof (vol_desc.volume_id));
1922         memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
1923
1924         should_write = last_extent - session_start;
1925         set_733((char *) vol_desc.volume_space_size, should_write);
1926         set_723(vol_desc.volume_set_size, volume_set_size);
1927         set_723(vol_desc.volume_sequence_number, volume_sequence_number);
1928         set_723(vol_desc.logical_block_size, SECTOR_SIZE);
1929
1930         /*
1931          * The path tables are used by DOS based machines to cache directory
1932          * locations
1933          */
1934         set_733((char *) vol_desc.path_table_size, path_table_size);
1935         set_731(vol_desc.type_l_path_table, path_table[0]);
1936         set_731(vol_desc.opt_type_l_path_table, path_table[1]);
1937         set_732(vol_desc.type_m_path_table, path_table[2]);
1938         set_732(vol_desc.opt_type_m_path_table, path_table[3]);
1939
1940         /* Now we copy the actual root directory record */
1941         memcpy(vol_desc.root_directory_record, &root_record,
1942                 offsetof(struct iso_directory_record, name[0]) + 1);
1943
1944         /*
1945          * The rest is just fluff.  It looks nice to fill in many of these
1946          * fields, though.
1947          */
1948         FILL_SPACE(volume_set_id);
1949         if (volset_id)
1950                 memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id));
1951
1952         FILL_SPACE(publisher_id);
1953         if (publisher)
1954                 memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher));
1955
1956         FILL_SPACE(preparer_id);
1957         if (preparer)
1958                 memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer));
1959
1960         FILL_SPACE(application_id);
1961         if (appid)
1962                 memcpy_max(vol_desc.application_id, appid, strlen(appid));
1963
1964         FILL_SPACE(copyright_file_id);
1965         if (copyright)
1966                 memcpy_max(vol_desc.copyright_file_id, copyright,
1967                         strlen(copyright));
1968
1969         FILL_SPACE(abstract_file_id);
1970         if (abstract)
1971                 memcpy_max(vol_desc.abstract_file_id, abstract,
1972                         strlen(abstract));
1973
1974         FILL_SPACE(bibliographic_file_id);
1975         if (biblio)
1976                 memcpy_max(vol_desc.bibliographic_file_id, biblio,
1977                         strlen(biblio));
1978
1979         FILL_SPACE(creation_date);
1980         FILL_SPACE(modification_date);
1981         FILL_SPACE(expiration_date);
1982         FILL_SPACE(effective_date);
1983         vol_desc.file_structure_version[0] = 1;
1984         FILL_SPACE(application_data);
1985
1986         memcpy(vol_desc.creation_date, iso_time, 17);
1987         memcpy(vol_desc.modification_date, iso_time, 17);
1988         memcpy(vol_desc.expiration_date, "0000000000000000", 17);
1989         memcpy(vol_desc.effective_date, iso_time, 17);
1990
1991         if (use_XA) {
1992                 char    *xap = &((char *)&vol_desc)[1024];
1993
1994                 memcpy(&xap[0], "CD-XA001", 8);                 /* XA Sign.  */
1995                 memcpy(&xap[8], "\0\0", 2);                     /* XA flags  */
1996                 memcpy(&xap[10], "\0\0\0\0\0\0\0\0", 8);        /* Start dir */
1997                 memcpy(&xap[18], "\0\0\0\0\0\0\0\0", 8);        /* Reserved  */
1998         }
1999
2000         /* if not a bootable cd do it the old way */
2001         jtwrite(&vol_desc, SECTOR_SIZE, 1, 0, FALSE);
2002         xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2003         last_extent_written++;
2004         return (0);
2005 }
2006
2007 /*
2008  * Function to write the Extended PVD for the disc.
2009  */
2010 static int
2011 xpvd_write(FILE *outfile)
2012 {
2013         vol_desc.type[0] = ISO_VD_SUPPLEMENTARY;
2014         vol_desc.version[0] = 2;
2015         vol_desc.file_structure_version[0] = 2;
2016
2017         /* if not a bootable cd do it the old way */
2018         jtwrite(&vol_desc, SECTOR_SIZE, 1, 0, FALSE);
2019         xfwrite(&vol_desc, SECTOR_SIZE, 1, outfile, 0, FALSE);
2020         last_extent_written++;
2021         return (0);
2022 }
2023
2024 /*
2025  * Function to write the EVD for the disc.
2026  */
2027 static int
2028 evd_write(FILE *outfile)
2029 {
2030         struct iso_primary_descriptor evol_desc;
2031
2032         /*
2033          * Now write the end volume descriptor.  Much simpler than the other
2034          * one
2035          */
2036         memset(&evol_desc, 0, sizeof (evol_desc));
2037         evol_desc.type[0] = (unsigned char) ISO_VD_END;
2038         memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof (ISO_STANDARD_ID));
2039         evol_desc.version[0] = 1;
2040         jtwrite(&evol_desc, SECTOR_SIZE, 1, 0, TRUE);
2041         xfwrite(&evol_desc, SECTOR_SIZE, 1, outfile, 0, TRUE);
2042         last_extent_written += 1;
2043         return (0);
2044 }
2045
2046 /*
2047  * Function to write the version information for the disc.
2048  */
2049 static int
2050 vers_write(FILE *outfile)
2051 {
2052         char            vers[SECTOR_SIZE+1];
2053         int             X_ac;
2054         char            **X_av;
2055         char            *cp;
2056         int             i;
2057         int             idx = 4;
2058         int             len;
2059         extern char     version_string[];
2060         extern int      path_ind;
2061
2062         /* Now write the version descriptor. */
2063         memset(vers, 0, sizeof (vers));
2064         strcpy(vers, "MKI ");
2065
2066         cp = vers;
2067         X_ac = saved_ac();
2068         X_av = saved_av();
2069         strcpy(&cp[idx], ctime(&begun));
2070         idx += 25;
2071         strcpy(&cp[idx], version_string);
2072         idx += strlen(version_string);
2073         for (i = 1; i < X_ac; i++) {
2074                 len = strlen(X_av[i]);
2075                 if ((idx + len + 2) >= SECTOR_SIZE)
2076                         break;
2077                 cp[idx++] = ' ';
2078                 /*
2079                  * Do not give away secret information when not in debug mode.
2080                  */
2081                 if (debug)
2082                         strcpy(&cp[idx], X_av[i]);
2083                 else if (i >= path_ind)
2084                         len = graftcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2085                 else if (X_av[i][0] == '/')
2086                         len = pathcp(&cp[idx], X_av[i], &vers[SECTOR_SIZE-1]);
2087                 else
2088                         strcpy(&cp[idx], X_av[i]);
2089                 idx += len;
2090         }
2091
2092         cp[SECTOR_SIZE - 1] = '\0';
2093         /* Per default: keep privacy. Blackout the version and arguments. */
2094         if(getenv("ISODEBUG")) {
2095                 jtwrite(vers, SECTOR_SIZE, 1, 0, TRUE);
2096                 xfwrite(vers, SECTOR_SIZE, 1, outfile, 0, TRUE);
2097         } else {
2098                 jtwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, 0, TRUE);
2099                 xfwrite(calloc(SECTOR_SIZE, 1), SECTOR_SIZE, 1, outfile, 0, TRUE);
2100         }
2101     last_extent_written += 1;
2102         return (0);
2103 }
2104
2105 /*
2106  * Avoid to write unwanted information into the version info string.
2107  */
2108 static int
2109 graftcp(char *to, char *from, char *ep)
2110 {
2111         int     len = strlen(from);
2112         char    *node = NULL;
2113
2114         if (use_graft_ptrs)
2115                 node = findgequal(from);
2116
2117         if (node == NULL) {
2118                 len = 0;
2119                 node = from;
2120         } else {
2121                 len = node - from;
2122                 *node = '\0';
2123                 strncpy(to, from, ep - to);
2124                 *node++ = '=';
2125                 to += len++;
2126                 *to++ = '=';
2127         }
2128         return (len + pathcp(to, node, ep));
2129 }
2130
2131 static int
2132 pathcp(char *to, char *from, char *ep)
2133 {
2134         int     len = strlen(from);
2135         char    *p;
2136
2137         p = strrchr(from, '/');
2138         if (p == NULL) {
2139                 strncpy(to, from, ep - to);
2140         } else {
2141                 if (p[1] == '\0') {
2142                         --p;
2143                         while (p > from && *p != '/')
2144                                 --p;
2145                 }
2146                 len = 0;
2147                 if (*p == '/') {
2148                         strncpy(to, "...", ep - to);
2149                         to += 3;
2150                         len = 3;
2151                 }
2152                 if (to < ep) {
2153                         strncpy(to, p, ep - to);
2154                         len += strlen(to);
2155                 }
2156         }
2157         return (len);
2158 }
2159
2160
2161 /*
2162  * Function to write the path table for the disc.
2163  */
2164 static int
2165 pathtab_write(FILE *outfile)
2166 {
2167         /* Next we write the path tables */
2168         jtwrite(path_table_l, path_blocks << 11, 1, 0, FALSE);
2169         xfwrite(path_table_l, path_blocks << 11, 1, outfile, 0, FALSE);
2170         last_extent_written += path_blocks;
2171         jtwrite(path_table_m, path_blocks << 11, 1, 0, FALSE);
2172         xfwrite(path_table_m, path_blocks << 11, 1, outfile, 0, FALSE);
2173         last_extent_written += path_blocks;
2174         free(path_table_l);
2175         free(path_table_m);
2176         path_table_l = NULL;
2177         path_table_m = NULL;
2178         return (0);
2179 }
2180
2181 static int
2182 exten_write(FILE *outfile)
2183 {
2184         jtwrite(extension_record, SECTOR_SIZE, 1, 0, FALSE);
2185         xfwrite(extension_record, SECTOR_SIZE, 1, outfile, 0, FALSE);
2186         last_extent_written++;
2187         return (0);
2188 }
2189
2190 /*
2191  * Functions to describe padding block at the start of the disc.
2192  */
2193 int
2194 oneblock_size(int starting_extent)
2195 {
2196         last_extent++;
2197         return (0);
2198 }
2199
2200 /*
2201  * Functions to describe path table size.
2202  */
2203 static int
2204 pathtab_size(int starting_extent)
2205 {
2206         path_table[0] = starting_extent;
2207
2208         path_table[1] = 0;
2209         path_table[2] = path_table[0] + path_blocks;
2210         path_table[3] = 0;
2211         last_extent += 2 * path_blocks;
2212         return (0);
2213 }
2214
2215 /*
2216  * Functions to describe padding blocks before PVD.
2217  */
2218 static int
2219 startpad_size(int starting_extent)
2220 {
2221         last_extent = session_start + 16;
2222         return (0);
2223 }
2224
2225 /*
2226  * Functions to describe padding blocks between sections.
2227  */
2228 static int
2229 interpad_size(int starting_extent)
2230 {
2231         int     emod = 0;
2232
2233 #ifdef  needed
2234         starting_extent += 16;  /* First add 16 pad blocks */
2235 #endif
2236         if ((emod = starting_extent % 16) != 0) {
2237                 starting_extent += 16 - emod;   /* Now pad to mod 16 #     */
2238         }
2239         last_extent = starting_extent;
2240         return (0);
2241 }
2242
2243 /*
2244  * Functions to describe padding blocks at end of disk.
2245  */
2246 static int
2247 endpad_size(int starting_extent)
2248 {
2249         starting_extent += 150;                 /* 150 pad blocks (post gap) */
2250         last_extent = starting_extent;
2251         return (0);
2252 }
2253
2254 static int
2255 file_gen()
2256 {
2257 #ifdef APPLE_HYB
2258         int     start_extent = last_extent;     /* orig ISO files start */
2259
2260 #endif  /* APPLE_HYB */
2261
2262         if (!assign_file_addresses(root, FALSE)) {
2263 #ifdef DVD_VIDEO
2264                 if (dvd_video) {
2265                         comerrno(EX_BAD, "Unable to make a DVD-Video image.\n"
2266             "Possible reasons:\n"
2267             "  - VIDEO_TS subdirectory was not found on specified location\n"
2268             "  - VIDEO_TS has invalid contents\n"
2269             );
2270                 }
2271 #else
2272                 ;       /* EMPTY */
2273 #endif
2274         }
2275
2276
2277 #ifdef SORTING
2278         if (do_sort) {
2279                 if (sort_file_addresses() == 0)
2280                         reassign_link_addresses(root);
2281         }
2282 #endif /* SORTING */
2283
2284 #ifdef APPLE_HYB
2285         /*
2286          * put this here for the time being - may when I've worked out how to
2287          * use Eric's new system for creating/writing parts of the image it
2288          * may move to it's own routine
2289          */
2290         if (apple_hyb)
2291                 hfs_file_gen(start_extent);
2292 #ifdef PREP_BOOT
2293         else if (use_prep_boot || use_chrp_boot)
2294                 gen_prepboot();
2295 #endif  /* PREP_BOOT */
2296 #endif  /* APPLE_HYB */
2297
2298         return (0);
2299 }
2300
2301 static int
2302 dirtree_dump()
2303 {
2304         if (verbose > 2) {
2305                 dump_tree(root);
2306         }
2307         return (0);
2308 }
2309
2310 static int
2311 dirtree_fixup(int starting_extent)
2312 {
2313         if (use_RockRidge && reloc_dir)
2314                 finish_cl_pl_entries();
2315
2316         if (use_RockRidge)
2317                 update_nlink_field(root);
2318         return (0);
2319 }
2320
2321 static int
2322 dirtree_size(int starting_extent)
2323 {
2324         assign_directory_addresses(root);
2325         return (0);
2326 }
2327
2328 static int
2329 ext_size(int starting_extent)
2330 {
2331         extern int              extension_record_size;
2332         struct directory_entry *s_entry;
2333
2334         extension_record_extent = starting_extent;
2335         s_entry = root->contents;
2336         set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
2337                 extension_record_extent);
2338         set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
2339                 extension_record_size);
2340         last_extent++;
2341         return (0);
2342 }
2343
2344 static int
2345 dirtree_write(FILE *outfile)
2346 {
2347         generate_iso9660_directories(root, outfile);
2348         return (0);
2349 }
2350
2351 static int
2352 dirtree_cleanup(FILE *outfile)
2353 {
2354         free_directories(root);
2355         return (0);
2356 }
2357
2358 static int
2359 startpad_write(FILE *outfile)
2360 {
2361         char    buffer[SECTOR_SIZE];
2362         int     i;
2363         int     npad;
2364
2365         memset(buffer, 0, sizeof (buffer));
2366
2367         npad = session_start + 16 - last_extent_written;
2368
2369         for (i = 0; i < npad; i++) {
2370                 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2371                 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2372                 last_extent_written++;
2373         }
2374
2375         return (0);
2376 }
2377
2378 static int
2379 interpad_write(FILE *outfile)
2380 {
2381         char    buffer[SECTOR_SIZE];
2382         int     i;
2383         int     npad = 0;
2384
2385         memset(buffer, 0, sizeof (buffer));
2386
2387 #ifdef  needed
2388         npad = 16;
2389 #endif
2390         if ((i = last_extent_written % 16) != 0)
2391                 npad += 16 - i;
2392
2393         for (i = 0; i < npad; i++) {
2394                 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2395                 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2396                 last_extent_written++;
2397         }
2398
2399         return (0);
2400 }
2401
2402 static int
2403 endpad_write(FILE *outfile)
2404 {
2405         char    buffer[SECTOR_SIZE];
2406         int     i;
2407
2408         memset(buffer, 0, sizeof (buffer));
2409
2410         for (i = 0; i < 150; i++) {
2411                 jtwrite(buffer, sizeof (buffer), 1, 0, FALSE);
2412                 xfwrite(buffer, sizeof (buffer), 1, outfile, 0, FALSE);
2413                 last_extent_written++;
2414         }
2415
2416         return (0);
2417 }
2418
2419 #ifdef APPLE_HYB
2420
2421 /*
2422  *      hfs_get_parms:  get HFS parameters from the command line
2423  */
2424
2425 static int
2426 hfs_get_parms(char *key)
2427 {
2428         int     ret = 0;
2429         char    *p;
2430
2431         if (hfs_parms == NULL)
2432                 return (ret);
2433
2434         if ((p = strstr(hfs_parms, key)) != NULL) {
2435                 p += strlen(key) + 1;
2436                 sscanf(p, "%d", &ret);
2437         }
2438
2439         return (ret);
2440 }
2441
2442 /*
2443  *      hfs_file_gen:   set up "fake" HFS volume using the ISO9660 tree
2444  */
2445 static void
2446 hfs_file_gen(int start_extent)
2447 {
2448         int     Csize;  /* clump size for HFS vol */
2449         int     loop;
2450         int     last_extent_save = last_extent;
2451         char    *p;
2452
2453         /* allocate memory for the libhfs/genisoimage extra info */
2454         hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2455
2456         hce->error = (char *) e_malloc(1024);
2457
2458         /* mark as unallocated for use later */
2459         hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2460
2461         /* reserve space for the label partition - if it is needed */
2462 #ifdef PREP_BOOT
2463         /* a PReP bootable partition needs the map.. */
2464         if (gen_pt || use_prep_boot || use_chrp_boot)
2465 #else
2466         if (gen_pt)
2467 #endif  /* PREP_BOOT */
2468                 hce->hfs_map_size = HFS_MAP_SIZE;
2469         else
2470                 hce->hfs_map_size = 0;
2471
2472         /* set the HFS parameter string to upper case */
2473         if (hfs_parms) {
2474                 for (p = hfs_parms; *p; p++)
2475                         *p = toupper(*p);
2476         }
2477
2478         /* set the initial factor to increase Catalog file size */
2479         if ((hce->ctc_size = hfs_get_parms("CTC")) == 0)
2480                 hce->ctc_size = CTC;
2481
2482         /* set the max size of the Catalog file */
2483         if ((hce->max_XTCsize = hfs_get_parms("MAX_XTCSIZE")) == 0)
2484                 hce->max_XTCsize = MAX_XTCSIZE;
2485
2486         /* set the number of time to try to make an HFS volume */
2487         if ((loop = hfs_get_parms("CTC_LOOP")) == 0)
2488                 loop = CTC_LOOP;
2489
2490         /*
2491          * "create" the HFS volume (just the header, catalog/extents files) if
2492          * there's a problem with the Catalog file being too small, we keep on
2493          * increasing the size (up to CTC_LOOP) times and try again.
2494          * Unfortunately I don't know enough about the inner workings of HFS,
2495          * so I can't workout the size of the Catalog file in advance (and I
2496          * don't want to "grow" as is is normally allowed to), therefore, this
2497          * approach is a bit over the top as it involves throwing away the
2498          * "volume" we have created and trying again ...
2499          */
2500         do {
2501                 hce->error[0] = '\0';
2502
2503                 /* attempt to create the Mac volume */
2504                 Csize = make_mac_volume(root, start_extent);
2505
2506                 /* if we have a problem ... */
2507                 if (Csize < 0) {
2508                         /*
2509                          * we've made too many attempts, or got some other
2510                          * error
2511                          */
2512                         if (loop == 0 || errno != HCE_ERROR) {
2513                                 /* HCE_ERROR is not a valid errno value */
2514                                 if (errno == HCE_ERROR)
2515                                         errno = 0;
2516
2517                                 /* exit with the error */
2518                                 if (*hce->error)
2519                                         fprintf(stderr, "%s\n", hce->error);
2520                                 perr(hfs_error);
2521                         } else {
2522                                 /* increase Catalog file size factor */
2523                                 hce->ctc_size *= CTC;
2524
2525                                 /*
2526                                  * reset the initial "last_extent" and try
2527                                  * again
2528                                  */
2529                                 last_extent = last_extent_save;
2530                         }
2531                 } else {
2532                         /* everything OK - just carry on ... */
2533                         loop = 0;
2534                 }
2535         }
2536         while (loop--);
2537
2538         hfs_extra = HFS_ROUND_UP(hce->hfs_tot_size) / SECTOR_SIZE;
2539
2540         last_extent += hfs_extra;
2541
2542         /* generate the Mac label and HFS partition maps */
2543         mac_boot.name = hfs_boot_file;
2544
2545         /*
2546          * only generate the partition tables etc. if we are making a bootable
2547          * CD - or if the -part option is given
2548          */
2549         if (gen_pt) {
2550                 if (gen_mac_label(&mac_boot)) {
2551                         if (*hce->error)
2552                                 fprintf(stderr, "%s\n", hce->error);
2553                         perr(hfs_error);
2554                 }
2555         }
2556         /* set Autostart filename if required */
2557         if (autoname) {
2558                 if (autostart())
2559                         perr("Autostart filename must less than 12 characters");
2560         }
2561         /* finished with any HFS type errors */
2562         free(hce->error);
2563         hce->error = 0;
2564
2565         /*
2566          * the ISO files need to start on a multiple of the HFS allocation
2567          * blocks, so find out how much padding we need
2568          */
2569
2570         /*
2571          * take in accout alignment of files wrt HFS volume start - remove any
2572          * previous session as well
2573          */
2574         start_extent -= session_start;
2575         hfs_pad = ROUND_UP(start_extent*SECTOR_SIZE +
2576                         (hce->hfs_hdr_size + hce->hfs_map_size) * HFS_BLOCKSZ,
2577                                                         Csize) / SECTOR_SIZE;
2578
2579         hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size) /
2580                                                         HFS_BLK_CONV);
2581
2582 #ifdef PREP_BOOT
2583         gen_prepboot_label(hce->hfs_map);
2584 #endif  /* PREP_BOOT */
2585
2586 }
2587
2588 #ifdef PREP_BOOT
2589 static void
2590 gen_prepboot()
2591 {
2592         /*
2593          * we need to allocate the hce struct since hce->hfs_map is used to
2594          * generate the fdisk partition map required for PReP booting
2595          */
2596         hce = (hce_mem *) e_malloc(sizeof (hce_mem));
2597
2598         /* mark as unallocated for use later */
2599         hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
2600
2601         /* reserve space for the label partition - if it is needed */
2602         hce->hfs_map_size = HFS_MAP_SIZE;
2603
2604         hce->hfs_map = (unsigned char *) e_malloc(hce->hfs_map_size * HFS_BLOCKSZ);
2605         gen_prepboot_label(hce->hfs_map);
2606 }
2607
2608 #endif  /* PREP_BOOT */
2609
2610 /*
2611  *      get_adj_size:   get the ajusted size of the volume with the HFS
2612  *                      allocation block size for each file
2613  */
2614 Ulong
2615 get_adj_size(int Csize)
2616 {
2617         struct deferred_write *dw;
2618         Ulong           size = 0;
2619         int             count = 0;
2620
2621         /* loop through all the files finding the new total size */
2622         for (dw = dw_head; dw; dw = dw->next) {
2623                 size += (ROUND_UP(dw->size, Csize)/HFS_BLOCKSZ);
2624                 count++;
2625         }
2626
2627         /*
2628          * crude attempt to prevent overflows - HFS can only cope with a
2629          * maximum of about 65536 forks (actually less) - this will trap cases
2630          * when we have far too many files
2631          */
2632
2633         if (count >= 65536)
2634                 return (-1);
2635         else
2636                 return (size);
2637 }
2638
2639 /*
2640  *      adj_size:       adjust the ISO record entries for all files
2641  *                      based on the HFS allocation block size
2642  */
2643 int
2644 adj_size(int Csize, int start_extent, int extra)
2645 {
2646         struct deferred_write *dw;
2647         struct directory_entry *s_entry;
2648         int             size;
2649
2650         /* get the adjusted start_extent (with padding) */
2651         /* take in accout alignment of files wrt HFS volume start */
2652
2653         start_extent -= session_start;
2654
2655         start_extent = ROUND_UP(start_extent*SECTOR_SIZE + extra*HFS_BLOCKSZ,
2656                                                 Csize) / SECTOR_SIZE;
2657
2658         start_extent -= (extra / HFS_BLK_CONV);
2659
2660         start_extent += session_start;
2661
2662         /* initialise file hash */
2663         flush_hash();
2664
2665         /*
2666          * loop through all files changing their starting blocks and finding
2667          * any padding needed to written out latter
2668          */
2669         for (dw = dw_head; dw; dw = dw->next) {
2670                 s_entry = dw->s_entry;
2671                 s_entry->starting_block = dw->extent = start_extent;
2672                 set_733((char *) s_entry->isorec.extent, start_extent);
2673                 size = ROUND_UP(dw->size, Csize) / SECTOR_SIZE;
2674                 dw->pad = size - ISO_ROUND_UP(dw->size) / SECTOR_SIZE;
2675
2676                 /*
2677                  * cache non-HFS files - as there may be multiple links to
2678                  * these files (HFS files can't have multiple links). We will
2679                  * need to change the starting extent of the other links later
2680                  */
2681                 if (!s_entry->hfs_ent)
2682                         add_hash(s_entry);
2683
2684                 start_extent += size;
2685         }
2686
2687         return (start_extent);
2688 }
2689
2690 /*
2691  *      adj_size_other: adjust any non-HFS files that may be linked
2692  *                      to an existing file (i.e. not have a deferred_write
2693  *                      entry of it's own
2694  */
2695 void
2696 adj_size_other(struct directory *dpnt)
2697 {
2698         struct directory_entry *s_entry;
2699         struct file_hash *s_hash;
2700
2701         while (dpnt) {
2702                 s_entry = dpnt->contents;
2703                 for (s_entry = dpnt->contents; s_entry;
2704                                                 s_entry = s_entry->next) {
2705                         /*
2706                          * if it's an HFS file or a directory - then ignore
2707                          * (we're after non-HFS files)
2708                          */
2709                         if (s_entry->hfs_ent ||
2710                             (s_entry->isorec.flags[0] & ISO_DIRECTORY))
2711                                 continue;
2712
2713                         /*
2714                          * find any cached entry and assign new starting
2715                          * extent
2716                          */
2717                         s_hash = find_hash(s_entry->dev, s_entry->inode);
2718                         if (s_hash) {
2719                                 set_733((char *) s_entry->isorec.extent,
2720                                                 s_hash->starting_block);
2721                                 /* not vital - but tidy */
2722                                 s_entry->starting_block =
2723                                                         s_hash->starting_block;
2724                         }
2725                 }
2726                 if (dpnt->subdir) {
2727                         adj_size_other(dpnt->subdir);
2728                 }
2729                 dpnt = dpnt->next;
2730         }
2731
2732         /* clear file hash */
2733         flush_hash();
2734 }
2735
2736 /*
2737  *      hfs_hce_write:  write out the HFS header stuff
2738  */
2739 static int
2740 hfs_hce_write(FILE *outfile)
2741 {
2742         char    buffer[SECTOR_SIZE];
2743         int     n = 0;
2744         int     r;      /* HFS hdr output */
2745         int     tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
2746
2747         memset(buffer, 0, sizeof (buffer));
2748
2749         /*
2750          * hack time ... if the tot_size is greater than 32Kb then
2751          * it won't fit in the first 16 blank SECTORS (64 512 byte
2752          * blocks, as most of this is padding, we just truncate this
2753          * data to 64x4xHFS_BLOCKSZ ... hope this is OK ...
2754          */
2755
2756         if (tot_size > 64) tot_size = 64;
2757
2758         /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
2759         n = tot_size / HFS_BLK_CONV;
2760         r = tot_size % HFS_BLK_CONV;
2761
2762         /* write out HFS volume header info */
2763         jtwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, 0, FALSE);
2764         xfwrite(hce->hfs_map, HFS_BLOCKSZ, tot_size, outfile, 0, FALSE);
2765
2766         /* fill up to a complete CD block */
2767         if (r) {
2768                 jtwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, 0, FALSE);
2769                 xfwrite(buffer, HFS_BLOCKSZ, HFS_BLK_CONV - r, outfile, 0, FALSE);
2770                 n++;
2771         }
2772         last_extent_written += n;
2773         return (0);
2774 }
2775
2776 /*
2777  *      insert_padding_file : insert a dumy file to make volume at least
2778  *                              800k
2779  *
2780  *      XXX If we ever need to write more then 2 GB, make size off_t
2781  */
2782 int
2783 insert_padding_file(int size)
2784 {
2785         struct deferred_write *dwpnt;
2786
2787         /* get the size in bytes */
2788         size *= HFS_BLOCKSZ;
2789
2790         dwpnt = (struct deferred_write *)
2791                 e_malloc(sizeof (struct deferred_write));
2792         dwpnt->s_entry = 0;
2793         /* set the padding to zero */
2794         dwpnt->pad = 0;
2795         /* set offset to zero */
2796         dwpnt->off = (off_t)0;
2797
2798         /*
2799          * don't need to wory about the s_entry stuff as it won't be touched#
2800          * at this point onwards
2801          */
2802
2803         /* insert the entry in the list */
2804         if (dw_tail) {
2805                 dw_tail->next = dwpnt;
2806                 dw_tail = dwpnt;
2807         } else {
2808                 dw_head = dwpnt;
2809                 dw_tail = dwpnt;
2810         }
2811
2812         /* aloocate memory as a "Table" file */
2813         dwpnt->table = e_malloc(size);
2814         dwpnt->name = NULL;
2815
2816         dwpnt->next = NULL;
2817         dwpnt->size = size;
2818         dwpnt->extent = last_extent;
2819         last_extent += ISO_BLOCKS(size);
2820
2821         /* retune the size in HFS blocks */
2822         return (ISO_ROUND_UP(size) / HFS_BLOCKSZ);
2823 }
2824
2825 struct output_fragment hfs_desc         = {NULL, NULL, NULL, hfs_hce_write, "HFS volume header"};
2826
2827 #endif  /* APPLE_HYB */
2828
2829 struct output_fragment startpad_desc    = {NULL, startpad_size, NULL,     startpad_write, "Initial Padblock"};
2830 struct output_fragment voldesc_desc     = {NULL, oneblock_size, root_gen, pvd_write,      "Primary Volume Descriptor"};
2831 struct output_fragment xvoldesc_desc    = {NULL, oneblock_size, NULL,     xpvd_write,     "Enhanced Volume Descriptor"};
2832 struct output_fragment end_vol          = {NULL, oneblock_size, NULL,     evd_write,      "End Volume Descriptor" };
2833 struct output_fragment version_desc     = {NULL, oneblock_size, NULL,     vers_write,     "Version block" };
2834 struct output_fragment pathtable_desc   = {NULL, pathtab_size,  generate_path_tables, pathtab_write, "Path table"};
2835 struct output_fragment dirtree_desc     = {NULL, dirtree_size,  NULL,     dirtree_write,  "Directory tree" };
2836 struct output_fragment dirtree_clean    = {NULL, dirtree_fixup, dirtree_dump, dirtree_cleanup, "Directory tree cleanup" };
2837 struct output_fragment extension_desc   = {NULL, ext_size,      NULL,     exten_write,    "Extension record" };
2838 struct output_fragment files_desc       = {NULL, NULL,          file_gen, file_write,     "The File(s)"};
2839 struct output_fragment interpad_desc    = {NULL, interpad_size, NULL,     interpad_write, "Intermediate Padblock"};
2840 struct output_fragment endpad_desc      = {NULL, endpad_size,   NULL,     endpad_write,   "Ending Padblock"};