xref: /openbsd/gnu/usr.sbin/mkhybrid/src/write.c (revision 404b540a)
1 /*
2  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
3 
4    Written by Eric Youngdale (1993).
5 
6    Copyright 1993 Yggdrasil Computing, Incorporated
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21 
22 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 16/3/1999 */
23 #include <string.h>
24 #include <stdlib.h>
25 #include <err.h>
26 #include "config.h"
27 #include "mkisofs.h"
28 #include "iso9660.h"
29 #include "volume.h"
30 #include "write.h"
31 #include "apple_proto.h"
32 #include "mac_label_proto.h"
33 #include <time.h>
34 #include <errno.h>
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #ifdef __SVR4
45 extern char * strdup(const char *);
46 #endif
47 
48 #ifdef VMS
49 extern char * strdup(const char *);
50 #endif
51 
52 
53 /* Max number of sectors we will write at  one time */
54 #define NSECT 16
55 
56 /* Counters for statistics */
57 
58 static int table_size       = 0;
59 static int total_dir_size   = 0;
60 static int rockridge_size   = 0;
61 static struct directory ** pathlist;
62 static int next_path_index  = 1;
63 static int sort_goof;
64 
65 struct output_fragment * out_tail;
66 struct output_fragment * out_list;
67 
68 struct iso_primary_descriptor vol_desc;
69 
70 #ifdef APPLE_HYB
71 static int hfs_pad;
72 #endif /* APPLE_HYB */
73 
74 static int root_gen	__PR((void));
75 static int generate_path_tables	__PR((void));
76 static int file_gen	__PR((void));
77 static int dirtree_dump	__PR((void));
78 
79 /* Routines to actually write the disc.  We write sequentially so that
80    we could write a tape, or write the disc directly */
81 
82 
83 #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
84 
85 void FDECL2(set_721, char *, pnt, unsigned int, i)
86 {
87      pnt[0] = i & 0xff;
88      pnt[1] = (i >> 8) &  0xff;
89 }
90 
91 void FDECL2(set_722, char *, pnt, unsigned int, i)
92 {
93      pnt[0] = (i >> 8) &  0xff;
94      pnt[1] = i & 0xff;
95 }
96 
97 void FDECL2(set_723, char *, pnt, unsigned int, i)
98 {
99      pnt[3] = pnt[0] = i & 0xff;
100      pnt[2] = pnt[1] = (i >> 8) &  0xff;
101 }
102 
103 void FDECL2(set_731, char *, pnt, unsigned int, i)
104 {
105      pnt[0] = i & 0xff;
106      pnt[1] = (i >> 8) &  0xff;
107      pnt[2] = (i >> 16) &  0xff;
108      pnt[3] = (i >> 24) &  0xff;
109 }
110 
111 void FDECL2(set_732, char *, pnt, unsigned int, i)
112 {
113      pnt[3] = i & 0xff;
114      pnt[2] = (i >> 8) &  0xff;
115      pnt[1] = (i >> 16) &  0xff;
116      pnt[0] = (i >> 24) &  0xff;
117 }
118 
119 int FDECL1(get_733, char *, p)
120 {
121      return ((p[0] & 0xff)
122 	     | ((p[1] & 0xff) << 8)
123 	     | ((p[2] & 0xff) << 16)
124 	     | ((p[3] & 0xff) << 24));
125 }
126 
127 void FDECL2(set_733, char *, pnt, unsigned int, i)
128 {
129      pnt[7] = pnt[0] = i & 0xff;
130      pnt[6] = pnt[1] = (i >> 8) &  0xff;
131      pnt[5] = pnt[2] = (i >> 16) &  0xff;
132      pnt[4] = pnt[3] = (i >> 24) &  0xff;
133 }
134 
135 void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
136 {
137 	/*
138 	 * This is a hack that could be made better. XXXIs this the only place?
139 	 * It is definitely needed on Operating Systems that do not
140 	 * allow to write files that are > 2GB.
141 	 * If the system is fast enough to be able to feed 1400 KB/s
142 	 * writing speed of a DVD-R drive, use stdout.
143 	 * If the system cannot do this reliable, you need to use this
144 	 * hacky option.
145 	 */
146 	static	int	idx = 0;
147 	if (split_output != 0 &&
148 	    (idx == 0 || ftell(file) >= (1024 * 1024 * 1024) )) {
149 			char	nbuf[512];
150 		extern	char	*outfile;
151 
152 		if (idx == 0)
153 			unlink(outfile);
154 		snprintf(nbuf, sizeof nbuf, "%s_%02d", outfile, idx++);
155 		file = freopen(nbuf, "wb", file);
156 		if (file == NULL) {
157 			fprintf(stderr, "Cannot open '%s'.\n", nbuf);
158 			exit(1);
159 		}
160 
161 	}
162      while(count)
163      {
164 	  int got = fwrite(buffer,size,count,file);
165 
166 	  if(got<=0)
167 	  {
168 	       fprintf(stderr,"cannot fwrite %d*%d\n",size,count);
169 	       exit(1);
170 	  }
171 	  count-=got,*(char**)&buffer+=size*got;
172      }
173 }
174 
175 #ifdef APPLE_HYB
176 /* use the deferred_write struct to store info about the hfs_boot_file */
177 static struct deferred_write mac_boot;
178 #endif /* APPLE_HYB */
179 static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
180 
181 unsigned int last_extent_written  =0;
182 static int path_table_index;
183 static time_t begun;
184 
185 /* We recursively walk through all of the directories and assign extent
186    numbers to them.  We have already assigned extent numbers to everything that
187    goes in front of them */
188 
189 static int FDECL1(assign_directory_addresses, struct directory *, node)
190 {
191      int		dir_size;
192      struct directory * dpnt;
193 
194      dpnt = node;
195 
196      while (dpnt)
197      {
198 	  /* skip if it's hidden */
199 	  if(dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
200 	     dpnt = dpnt->next;
201 	     continue;
202 	  }
203 
204 	  /*
205 	   * If we already have an extent for this (i.e. it came from
206 	   * a multisession disc), then don't reassign a new extent.
207 	   */
208 	  dpnt->path_index = next_path_index++;
209 	  if( dpnt->extent == 0 )
210 	  {
211 	       dpnt->extent = last_extent;
212 	       dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
213 
214 	       last_extent += dir_size;
215 
216 	       /*
217 		* Leave room for the CE entries for this directory.  Keep them
218 		* close to the reference directory so that access will be
219 		* quick.
220 		*/
221 	       if(dpnt->ce_bytes)
222 	       {
223 		    last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
224 	       }
225 	  }
226 
227 	  if(dpnt->subdir)
228 	  {
229 	       assign_directory_addresses(dpnt->subdir);
230 	  }
231 
232 	  dpnt = dpnt->next;
233      }
234      return 0;
235 }
236 
237 #ifdef APPLE_HYB
238 static void FDECL4(write_one_file, char *, filename,
239 		   unsigned int, size, FILE *, outfile, unsigned int, off)
240 #else
241 static void FDECL3(write_one_file, char *, filename,
242 		   unsigned int, size, FILE *, outfile)
243 #endif /* APPLE_HYB */
244 {
245      char		  buffer[SECTOR_SIZE * NSECT];
246      FILE		* infile;
247      int		  remain;
248      int		  use;
249 
250 
251      if ((infile = fopen(filename, "rb")) == NULL)
252      {
253 #if defined(sun) || defined(_AUX_SOURCE)
254 	  fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
255 #else
256 	  fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
257 #endif
258 	  exit(1);
259      }
260 #ifdef APPLE_HYB
261      fseek(infile, off, SEEK_SET);
262 #endif /* APPLE_HYB */
263      remain = size;
264 
265      while(remain > 0)
266      {
267 	  use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
268 	  use = ROUND_UP(use); /* Round up to nearest sector boundary */
269 	  memset(buffer, 0, use);
270 	  if (fread(buffer, 1, use, infile) == 0)
271 	  {
272 		fprintf(stderr,"cannot read from %s\n",filename);
273 		exit(1);
274 	  }
275 	  xfwrite(buffer, 1, use, outfile);
276 	  last_extent_written += use/SECTOR_SIZE;
277 #if 0
278 	  if((last_extent_written % 1000) < use/SECTOR_SIZE)
279 	  {
280 	       fprintf(stderr,"%d..", last_extent_written);
281 	  }
282 #else
283 	  if((last_extent_written % 5000) < use/SECTOR_SIZE)
284 	  {
285 	       time_t now;
286 	       time_t the_end;
287 	       double frac;
288 
289 	       time(&now);
290 	       frac = last_extent_written / (double)last_extent;
291 	       the_end = begun + (now - begun) / frac;
292 	       fprintf(stderr, "%6.2f%% done, estimate finish %s",
293 		       frac * 100., ctime(&the_end));
294 	  }
295 #endif
296 	  remain -= use;
297      }
298      fclose(infile);
299 } /* write_one_file(... */
300 
301 static void FDECL1(write_files, FILE *, outfile)
302 {
303      struct deferred_write * dwpnt, *dwnext;
304      dwpnt = dw_head;
305      while(dwpnt)
306      {
307 	  if(dwpnt->table)
308 	  {
309 	       xfwrite(dwpnt->table,  1, ROUND_UP(dwpnt->size), outfile);
310 	       last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
311 	       table_size += dwpnt->size;
312 /*		  fprintf(stderr,"Size %d ", dwpnt->size); */
313 	       free(dwpnt->table);
314 	  }
315 	  else
316 	  {
317 
318 #ifdef VMS
319 	       vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
320 #else
321 #ifdef APPLE_HYB
322 	       write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off);
323 #else
324 	       write_one_file(dwpnt->name, dwpnt->size, outfile);
325 #endif /* APPLE_HYB */
326 #endif
327 	       free(dwpnt->name);
328 	  }
329 
330 #ifdef APPLE_HYB
331 	  if (apple_hyb)
332 	  {
333 		/* we may have to pad out ISO files to work with
334 		   HFS clump sizes */
335 		char blk[SECTOR_SIZE];
336 		int i;
337 
338 		for(i=0;i<dwpnt->pad;i++)
339 		    xfwrite(blk, 1, SECTOR_SIZE, outfile);
340 
341 		last_extent_written += dwpnt->pad;
342           }
343 #endif /* APPLE_HYB */
344 
345 	  dwnext = dwpnt;
346 	  dwpnt = dwpnt->next;
347 	  free(dwnext);
348      }
349 } /* write_files(... */
350 
351 #if 0
352 static void dump_filelist()
353 {
354      struct deferred_write * dwpnt;
355      dwpnt = dw_head;
356      while(dwpnt)
357      {
358 	  fprintf(stderr, "File %s\n",dwpnt->name);
359 	  dwpnt = dwpnt->next;
360      }
361      fprintf(stderr,"\n");
362 }
363 #endif
364 
365 static int FDECL2(compare_dirs, const void *, rr, const void *, ll)
366 {
367      char * rpnt, *lpnt;
368      struct directory_entry ** r, **l;
369 
370      r = (struct directory_entry **) rr;
371      l = (struct directory_entry **) ll;
372      rpnt = (*r)->isorec.name;
373      lpnt = (*l)->isorec.name;
374 
375 #ifdef APPLE_HYB
376      /* resource fork MUST (not sure if this is true for HFS volumes) be
377         before the data fork - so force it here */
378      if ((*r)->assoc && (*r)->assoc == (*l))
379         return 1;
380      if ((*l)->assoc && (*l)->assoc == (*r))
381 	return -1;
382 #endif /* APPLE_HYB */
383 
384      /*
385       * If the entries are the same, this is an error.
386       */
387      if( strcmp(rpnt, lpnt) == 0 )
388        {
389 	 sort_goof++;
390        }
391 
392      /*
393       *  Put the '.' and '..' entries on the head of the sorted list.
394       *  For normal ASCII, this always happens to be the case, but out of
395       *  band characters cause this not to be the case sometimes.
396       *
397       * FIXME(eric) - these tests seem redundant, in taht the name is
398       * never assigned these values.  It will instead be \000 or \001,
399       * and thus should always be sorted correctly.   I need to figure
400       * out why I thought I needed this in the first place.
401       */
402 #if 0
403      if( strcmp(rpnt, ".") == 0 ) return -1;
404      if( strcmp(lpnt, ".") == 0 ) return  1;
405 
406      if( strcmp(rpnt, "..") == 0 ) return -1;
407      if( strcmp(lpnt, "..") == 0 ) return  1;
408 #else
409      /*
410       * The code above is wrong (as explained in Eric's comment), leading to incorrect
411       * sort order iff the -L option ("allow leading dots") is in effect and a directory
412       * contains entries that start with a dot.
413       *
414       * (TF, Tue Dec 29 13:49:24 CET 1998)
415       */
416      if((*r)->isorec.name_len[0] == 1 && *rpnt == 0) return -1; /* '.' */
417      if((*l)->isorec.name_len[0] == 1 && *lpnt == 0) return 1;
418 
419      if((*r)->isorec.name_len[0] == 1 && *rpnt == 1) return -1; /* '..' */
420      if((*l)->isorec.name_len[0] == 1 && *lpnt == 1) return 1;
421 #endif
422 
423      while(*rpnt && *lpnt)
424      {
425 	  if(*rpnt == ';' && *lpnt != ';') return -1;
426 	  if(*rpnt != ';' && *lpnt == ';') return 1;
427 
428 	  if(*rpnt == ';' && *lpnt == ';') return 0;
429 
430 	  if(*rpnt == '.' && *lpnt != '.') return -1;
431 	  if(*rpnt != '.' && *lpnt == '.') return 1;
432 
433 	  if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1;
434 	  if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1;
435 	  rpnt++;  lpnt++;
436      }
437      if(*rpnt) return 1;
438      if(*lpnt) return -1;
439      return 0;
440 }
441 
442 /*
443  * Function:		sort_directory
444  *
445  * Purpose:		Sort the directory in the appropriate ISO9660
446  *			order.
447  *
448  * Notes:		Returns 0 if OK, returns > 0 if an error occurred.
449  */
450 int FDECL1(sort_directory, struct directory_entry **, sort_dir)
451 {
452      int dcount = 0;
453      int xcount = 0;
454      int j;
455      int i, len;
456      struct directory_entry * s_entry;
457      struct directory_entry ** sortlist;
458 
459      /* need to keep a count of how many entries are hidden */
460      s_entry = *sort_dir;
461      while(s_entry)
462      {
463 	  if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
464 	    xcount++;
465 	  dcount++;
466 	  s_entry = s_entry->next;
467      }
468 
469      if( dcount == 0 )
470      {
471           return 0;
472      }
473 
474      /*
475       * OK, now we know how many there are.  Build a vector for sorting.
476       */
477      sortlist =   (struct directory_entry **)
478 	  e_malloc(sizeof(struct directory_entry *) * dcount);
479 
480      j = dcount - 1;
481      dcount = 0;
482      s_entry = *sort_dir;
483      while(s_entry)
484      {
485 	if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
486 	 {
487 	  /* put any hidden entries at the end of the vector */
488 	  sortlist[j--] = s_entry;
489 	 }
490 	else
491 	 {
492 	  sortlist[dcount] = s_entry;
493 	  dcount++;
494 	 }
495 	 len = s_entry->isorec.name_len[0];
496 	 s_entry->isorec.name[len] = 0;
497 	 s_entry = s_entry->next;
498      }
499 
500      /*
501       * Each directory is required to contain at least . and ..
502       */
503      if( dcount < 2 )
504        {
505 	 sort_goof = 1;
506 
507        }
508      else
509        {
510 	 /* only sort the non-hidden entries */
511 	 sort_goof = 0;
512 #ifdef __STDC__
513 	 qsort(sortlist, dcount, sizeof(struct directory_entry *),
514 	       (int (*)(const void *, const void *))compare_dirs);
515 #else
516 	 qsort(sortlist, dcount, sizeof(struct directory_entry *),
517 	       compare_dirs);
518 #endif
519 
520 	 /*
521 	  * Now reassemble the linked list in the proper sorted order
522 	  * We still need the hidden entries, as they may be used in the
523 	  * Joliet tree.
524 	  */
525 	 for(i=0; i<dcount+xcount-1; i++)
526 	   {
527 	     sortlist[i]->next = sortlist[i+1];
528 	   }
529 
530 	 sortlist[dcount+xcount-1]->next = NULL;
531 	 *sort_dir = sortlist[0];
532        }
533 
534      free(sortlist);
535      return sort_goof;
536 }
537 
538 static int root_gen()
539 {
540      init_fstatbuf();
541 
542      root_record.length[0] = 1 + sizeof(struct iso_directory_record)
543 	  - sizeof(root_record.name);
544      root_record.ext_attr_length[0] = 0;
545      set_733((char *) root_record.extent, root->extent);
546      set_733((char *) root_record.size, ROUND_UP(root->size));
547      iso9660_date(root_record.date, root_statbuf.st_mtime);
548      root_record.flags[0] = 2;
549      root_record.file_unit_size[0] = 0;
550      root_record.interleave[0] = 0;
551      set_723(root_record.volume_sequence_number, volume_sequence_number);
552      root_record.name_len[0] = 1;
553      return 0;
554 }
555 
556 static void FDECL1(assign_file_addresses, struct directory *, dpnt)
557 {
558      struct directory * finddir;
559      struct directory_entry * s_entry;
560      struct file_hash *s_hash;
561      struct deferred_write * dwpnt;
562      char whole_path[1024];
563 
564      while (dpnt)
565      {
566 	  s_entry = dpnt->contents;
567 	  for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
568 	  {
569 	       /*
570 		* If we already have an  extent for this entry,
571 		* then don't assign a new one.  It must have come
572 		* from a previous session on the disc.  Note that
573 		* we don't end up scheduling the thing for writing
574 		* either.
575 		*/
576 	       if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 )
577 	       {
578 		    continue;
579 	       }
580 
581 	       /*
582 		* This saves some space if there are symlinks present
583 		*/
584 	       s_hash = find_hash(s_entry->dev, s_entry->inode);
585 	       if(s_hash)
586 	       {
587 		    if(verbose > 2)
588 		    {
589 			 fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name,
590 				 SPATH_SEPARATOR, s_entry->name);
591 		    }
592 		    set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
593 		    set_733((char *) s_entry->isorec.size, s_hash->size);
594 		    continue;
595 	       }
596 
597 	       /*
598 		* If this is for a directory that is not a . or a .. entry,
599 		* then look up the information for the entry.  We have already
600 		* assigned extents for directories, so we just need to
601 		* fill in the blanks here.
602 		*/
603 	       if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") &&
604 		   s_entry->isorec.flags[0] == 2)
605 	       {
606 		    finddir = dpnt->subdir;
607 		    while(1==1)
608 		    {
609 			 if(finddir->self == s_entry) break;
610 			 finddir = finddir->next;
611 			 if(!finddir)
612 			 {
613 			      fprintf(stderr,"Fatal goof\n"); exit(1);
614 			 }
615 		    }
616 		    set_733((char *) s_entry->isorec.extent, finddir->extent);
617 		    s_entry->starting_block = finddir->extent;
618 		    s_entry->size = ROUND_UP(finddir->size);
619 		    total_dir_size += s_entry->size;
620 		    add_hash(s_entry);
621 		    set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size));
622 		    continue;
623 	       }
624 
625 
626 	       /*
627 		* If this is . or .., then look up the relevant info from the
628 		* tables.
629 		*/
630 	       if(strcmp(s_entry->name,".") == 0)
631 	       {
632 		    set_733((char *) s_entry->isorec.extent, dpnt->extent);
633 
634 		    /*
635 		     * Set these so that the hash table has the
636 		     * correct information
637 		     */
638 		    s_entry->starting_block = dpnt->extent;
639 		    s_entry->size = ROUND_UP(dpnt->size);
640 
641 		    add_hash(s_entry);
642 		    s_entry->starting_block = dpnt->extent;
643 		    set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size));
644 		    continue;
645 	       }
646 
647 	       if(strcmp(s_entry->name,"..") == 0)
648 	       {
649 		    if(dpnt == root)
650 		    {
651 			 total_dir_size += root->size;
652 		    }
653 		    set_733((char *) s_entry->isorec.extent, dpnt->parent->extent);
654 
655 		    /*
656 		     * Set these so that the hash table has the
657 		     * correct information
658 		     */
659 		    s_entry->starting_block = dpnt->parent->extent;
660 		    s_entry->size = ROUND_UP(dpnt->parent->size);
661 
662 		    add_hash(s_entry);
663 		    s_entry->starting_block = dpnt->parent->extent;
664 		    set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size));
665 		    continue;
666 	       }
667 
668 	       /*
669 		* Some ordinary non-directory file.  Just schedule the
670 		* file to be written.  This is all quite
671 		* straightforward, just make a list and assign extents
672 		* as we go.  Once we get through writing all of the
673 		* directories, we should be ready write out these
674 		* files
675 		*/
676 	       if(s_entry->size)
677 	       {
678 		    dwpnt = (struct deferred_write *)
679 			 e_malloc(sizeof(struct deferred_write));
680 #ifdef APPLE_HYB
681 		    /* save this directory entry for later use */
682 		    dwpnt->s_entry = s_entry;
683 		    /* set the initial padding to zero */
684 		    dwpnt->pad = 0;
685 		    /* maybe an offset to start of the real file/fork */
686 		    dwpnt->off = s_entry->hfs_off;
687 #endif /* APPLE_HYB */
688 		    if(dw_tail)
689 		    {
690 			 dw_tail->next = dwpnt;
691 			 dw_tail = dwpnt;
692 		    }
693 		    else
694 		    {
695 			 dw_head = dwpnt;
696 			 dw_tail = dwpnt;
697 		    }
698 		    if(s_entry->inode  ==  TABLE_INODE)
699 		    {
700 			 dwpnt->table = s_entry->table;
701 			 dwpnt->name = NULL;
702 #ifdef APPLE_HYB
703 			 snprintf(whole_path, sizeof whole_path, "%s%s%s",
704 				 s_entry->filedir->whole_name, SPATH_SEPARATOR,
705 					trans_tbl);
706 #else
707 			 snprintf(whole_path, sizeof whole_path,
708 			 	"%s%sTRANS.TBL",
709 				 s_entry->filedir->whole_name, SPATH_SEPARATOR);
710 #endif /* APPLE_HYB */
711 		    }
712 		    else
713 		    {
714 			 dwpnt->table = NULL;
715 			 strcpy(whole_path, s_entry->whole_name);
716 			 dwpnt->name = strdup(whole_path);
717 		    }
718 		    dwpnt->next = NULL;
719 		    dwpnt->size = s_entry->size;
720 		    dwpnt->extent = last_extent;
721 		    set_733((char *) s_entry->isorec.extent, last_extent);
722 		    s_entry->starting_block = last_extent;
723 		    add_hash(s_entry);
724 		    last_extent += ROUND_UP(s_entry->size) >> 11;
725 		    if(verbose > 2)
726 		    {
727 			 fprintf(stderr,"%d %d %s\n", s_entry->starting_block,
728 				 last_extent-1, whole_path);
729 		    }
730 #ifdef DBG_ISO
731 		    if((ROUND_UP(s_entry->size) >> 11) > 500)
732 		    {
733 			 fprintf(stderr,"Warning: large file %s\n", whole_path);
734 			 fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
735 			 fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
736 
737 		    }
738 #endif
739 #ifdef	NOT_NEEDED	/* Never use this code if you like to create a DVD */
740 
741 		    if(last_extent > (800000000 >> 11))
742 		    {
743 			 /*
744 			  * More than 800Mb? Punt
745 			  */
746 			 fprintf(stderr,"Extent overflow processing file %s\n", whole_path);
747 			 fprintf(stderr,"Starting block is %d\n", s_entry->starting_block);
748 			 fprintf(stderr,"Reported file size is %d extents\n", s_entry->size);
749 			 exit(1);
750 		    }
751 #endif
752 		    continue;
753 	       }
754 
755 	       /*
756 		* This is for zero-length files.  If we leave the extent 0,
757 		* then we get screwed, because many readers simply drop files
758 		* that have an extent of zero.  Thus we leave the size 0,
759 		* and just assign the extent number.
760 		*/
761 	       set_733((char *) s_entry->isorec.extent, last_extent);
762 	  }
763 	  if(dpnt->subdir)
764 	  {
765 	       assign_file_addresses(dpnt->subdir);
766 	  }
767 	  dpnt = dpnt->next;
768      }
769 } /* assign_file_addresses(... */
770 
771 static void FDECL1(free_one_directory, struct directory *, dpnt)
772 {
773      struct directory_entry		* s_entry;
774      struct directory_entry		* s_entry_d;
775 
776      s_entry = dpnt->contents;
777      while(s_entry)
778      {
779 	 s_entry_d = s_entry;
780 	 s_entry = s_entry->next;
781 
782 	 if( s_entry_d->name != NULL )
783 	 {
784 	     free (s_entry_d->name);
785 	 }
786 	 if( s_entry_d->whole_name != NULL )
787 	 {
788 	     free (s_entry_d->whole_name);
789 	 }
790 #ifdef APPLE_HYB
791 	 if (apple_both && s_entry_d->hfs_ent && !s_entry_d->assoc)
792 	     free(s_entry_d->hfs_ent);
793 #endif /* APPLE_HYB */
794 
795 	 free (s_entry_d);
796      }
797      dpnt->contents = NULL;
798 } /* free_one_directory(... */
799 
800 static void FDECL1(free_directories, struct directory *, dpnt)
801 {
802   while (dpnt)
803     {
804       free_one_directory(dpnt);
805       if(dpnt->subdir) free_directories(dpnt->subdir);
806       dpnt = dpnt->next;
807     }
808 }
809 
810 void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile)
811 {
812      unsigned int			  ce_address = 0;
813      char				* ce_buffer;
814      unsigned int			  ce_index = 0;
815      unsigned int			  ce_size;
816      unsigned int			  dir_index;
817      char				* directory_buffer;
818      int				  new_reclen;
819      struct directory_entry		* s_entry;
820      struct directory_entry		* s_entry_d;
821      unsigned int			  total_size;
822 
823      total_size = (dpnt->size + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
824      directory_buffer = (char *) e_malloc(total_size);
825      memset(directory_buffer, 0, total_size);
826      dir_index = 0;
827 
828      ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) &  ~(SECTOR_SIZE - 1);
829      ce_buffer = NULL;
830 
831      if(ce_size)
832      {
833 	  ce_buffer = (char *) e_malloc(ce_size);
834 	  memset(ce_buffer, 0, ce_size);
835 
836 	  ce_index = 0;
837 
838 	  /*
839 	   * Absolute byte address of CE entries for this directory
840 	   */
841 	  ce_address = last_extent_written + (total_size >> 11);
842 	  ce_address = ce_address << 11;
843      }
844 
845      s_entry = dpnt->contents;
846      while(s_entry)
847      {
848 	  /* skip if it's hidden */
849 	  if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
850 	    s_entry = s_entry->next;
851 	    continue;
852 	  }
853 
854 	  /*
855 	   * We do not allow directory entries to cross sector boundaries.
856 	   * Simply pad, and then start the next entry at the next sector
857 	   */
858 	  new_reclen = s_entry->isorec.length[0];
859 	  if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE )
860 	  {
861 	       dir_index = (dir_index + (SECTOR_SIZE - 1)) &
862 		    ~(SECTOR_SIZE - 1);
863 	  }
864 
865 	  memcpy(directory_buffer + dir_index, &s_entry->isorec,
866 		 sizeof(struct iso_directory_record) -
867 		 sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]);
868 	  dir_index += sizeof(struct iso_directory_record) -
869 	       sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0];
870 
871 	  /*
872 	   * Add the Rock Ridge attributes, if present
873 	   */
874 	  if(s_entry->rr_attr_size)
875 	  {
876 	       if(dir_index & 1)
877 	       {
878 		    directory_buffer[dir_index++] = 0;
879 	       }
880 
881 	       /*
882 		* If the RR attributes were too long, then write the
883 		* CE records, as required.
884 		*/
885 	       if(s_entry->rr_attr_size != s_entry->total_rr_attr_size)
886 	       {
887 		    unsigned char * pnt;
888 		    int len, nbytes;
889 
890 		    /*
891 		     * Go through the entire record and fix up the CE entries
892 		     * so that the extent and offset are correct
893 		     */
894 
895 		    pnt = s_entry->rr_attributes;
896 		    len = s_entry->total_rr_attr_size;
897 		    while(len > 3)
898 		    {
899 #ifdef DEBUG
900 			 if (!ce_size)
901 			 {
902 			      fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n",
903 				      ce_index, ce_address);
904 			 }
905 #endif
906 
907 			 if(pnt[0] == 'C' && pnt[1] == 'E')
908 			 {
909 			      nbytes = get_733( (char *) pnt+20);
910 
911 			      if((ce_index & (SECTOR_SIZE - 1)) + nbytes >=
912 				 SECTOR_SIZE)
913 			      {
914 				   ce_index = ROUND_UP(ce_index);
915 			      }
916 
917 			      set_733( (char *) pnt+4,
918 				       (ce_address + ce_index) >> 11);
919 			      set_733( (char *) pnt+12,
920 				       (ce_address + ce_index) & (SECTOR_SIZE - 1));
921 
922 
923 			      /*
924 			       * Now store the block in the ce buffer
925 			       */
926 			      memcpy(ce_buffer + ce_index,
927 				     pnt + pnt[2], nbytes);
928 			      ce_index += nbytes;
929 			      if(ce_index & 1)
930 			      {
931 				   ce_index++;
932 			      }
933 			 }
934 			 len -= pnt[2];
935 			 pnt += pnt[2];
936 		    }
937 
938 	       }
939 
940 	       rockridge_size += s_entry->total_rr_attr_size;
941 	       memcpy(directory_buffer + dir_index, s_entry->rr_attributes,
942 		      s_entry->rr_attr_size);
943 	       dir_index += s_entry->rr_attr_size;
944 	  }
945 	  if(dir_index & 1)
946 	  {
947 	       directory_buffer[dir_index++] = 0;
948 	  }
949 
950 	  s_entry_d = s_entry;
951 	  s_entry = s_entry->next;
952 
953 	  /*
954 	   * Joliet doesn't use the Rock Ridge attributes, so we free it here.
955 	   */
956 	  if (s_entry_d->rr_attributes)
957 	    {
958 	      free(s_entry_d->rr_attributes);
959 	      s_entry_d->rr_attributes = NULL;
960 	    }
961      }
962 
963      if(dpnt->size != dir_index)
964      {
965 	  fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size,
966 	    dir_index, dpnt->de_name);
967      }
968 
969      xfwrite(directory_buffer, 1, total_size, outfile);
970      last_extent_written += total_size >> 11;
971      free(directory_buffer);
972 
973      if(ce_size)
974      {
975 	  if(ce_index != dpnt->ce_bytes)
976 	  {
977 	       fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n",
978 		       ce_index, dpnt->ce_bytes);
979 	  }
980 	  xfwrite(ce_buffer, 1, ce_size, outfile);
981 	  last_extent_written += ce_size >> 11;
982 	  free(ce_buffer);
983      }
984 
985 } /* generate_one_directory(... */
986 
987 static
988 void FDECL1(build_pathlist, struct directory *, node)
989 {
990      struct directory * dpnt;
991 
992      dpnt = node;
993 
994      while (dpnt)
995      {
996 	/* skip if it's hidden */
997 	if( (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0 )
998 	  pathlist[dpnt->path_index] = dpnt;
999 
1000 	if(dpnt->subdir) build_pathlist(dpnt->subdir);
1001 	dpnt = dpnt->next;
1002      }
1003 } /* build_pathlist(... */
1004 
1005 static int FDECL2(compare_paths, void const *, r, void const *, l)
1006 {
1007   struct directory const *ll = *(struct directory * const *)l;
1008   struct directory const *rr = *(struct directory * const *)r;
1009 
1010   if (rr->parent->path_index < ll->parent->path_index)
1011   {
1012        return -1;
1013   }
1014 
1015   if (rr->parent->path_index > ll->parent->path_index)
1016   {
1017        return 1;
1018   }
1019 
1020   return strcmp(rr->self->isorec.name, ll->self->isorec.name);
1021 
1022 } /* compare_paths(... */
1023 
1024 static int generate_path_tables()
1025 {
1026   struct directory_entry * de;
1027   struct directory	 * dpnt;
1028   int			   fix;
1029   int			   i;
1030   int			   j;
1031   int			   namelen;
1032   char			 * npnt;
1033   char			 * npnt1;
1034   int			   tablesize;
1035 
1036   /*
1037    * First allocate memory for the tables and initialize the memory
1038    */
1039   tablesize = path_blocks << 11;
1040   path_table_m = (char *) e_malloc(tablesize);
1041   path_table_l = (char *) e_malloc(tablesize);
1042   memset(path_table_l, 0, tablesize);
1043   memset(path_table_m, 0, tablesize);
1044 
1045   /*
1046    * Now start filling in the path tables.  Start with root directory
1047    */
1048   if( next_path_index > 0xffff )
1049   {
1050       fprintf(stderr, "Unable to generate sane path tables - too many directories (%d)\n",
1051 	      next_path_index);
1052       exit(1);
1053   }
1054 
1055   path_table_index = 0;
1056   pathlist = (struct directory **) e_malloc(sizeof(struct directory *)
1057 					    * next_path_index);
1058   memset(pathlist, 0, sizeof(struct directory *) * next_path_index);
1059   build_pathlist(root);
1060 
1061   do
1062   {
1063        fix = 0;
1064 #ifdef __STDC__
1065        qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
1066 	     (int (*)(const void *, const void *))compare_paths);
1067 #else
1068        qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *),
1069 	     compare_paths);
1070 #endif
1071 
1072        for(j=1; j<next_path_index; j++)
1073        {
1074 	    if(pathlist[j]->path_index != j)
1075 	    {
1076 		 pathlist[j]->path_index = j;
1077 		 fix++;
1078 	    }
1079        }
1080   } while(fix);
1081 
1082   for(j=1; j<next_path_index; j++)
1083   {
1084        dpnt = pathlist[j];
1085        if(!dpnt)
1086        {
1087 	    fprintf(stderr,"Entry %d not in path tables\n", j);
1088 	    exit(1);
1089        }
1090        npnt = dpnt->de_name;
1091 
1092        /*
1093 	* So the root comes out OK
1094 	*/
1095        if( (*npnt == 0) || (dpnt == root) )
1096        {
1097 	    npnt = ".";
1098        }
1099        npnt1 = strrchr(npnt, PATH_SEPARATOR);
1100        if(npnt1)
1101        {
1102 	    npnt = npnt1 + 1;
1103        }
1104 
1105        de = dpnt->self;
1106        if(!de)
1107        {
1108 	    fprintf(stderr,"Fatal goof\n");
1109 	    exit(1);
1110        }
1111 
1112 
1113        namelen = de->isorec.name_len[0];
1114 
1115        path_table_l[path_table_index] = namelen;
1116        path_table_m[path_table_index] = namelen;
1117        path_table_index += 2;
1118 
1119        set_731(path_table_l + path_table_index, dpnt->extent);
1120        set_732(path_table_m + path_table_index, dpnt->extent);
1121        path_table_index += 4;
1122 
1123        set_721(path_table_l + path_table_index,
1124 	       dpnt->parent->path_index);
1125        set_722(path_table_m + path_table_index,
1126 	       dpnt->parent->path_index);
1127        path_table_index += 2;
1128 
1129        for(i =0; i<namelen; i++)
1130        {
1131 	    path_table_l[path_table_index] = de->isorec.name[i];
1132 	    path_table_m[path_table_index] = de->isorec.name[i];
1133 	    path_table_index++;
1134        }
1135        if(path_table_index & 1)
1136        {
1137 	    path_table_index++;  /* For odd lengths we pad */
1138        }
1139   }
1140 
1141   free(pathlist);
1142   if(path_table_index != path_table_size)
1143   {
1144        fprintf(stderr,"Path table lengths do not match %d %d\n",
1145 	       path_table_index,
1146 	       path_table_size);
1147   }
1148   return 0;
1149 } /* generate_path_tables(... */
1150 
1151 void
1152 FDECL3(memcpy_max, char *, to, char *, from, int, max)
1153 {
1154   int n = strlen(from);
1155   if (n > max)
1156   {
1157        n = max;
1158   }
1159   memcpy(to, from, n);
1160 
1161 } /* memcpy_max(... */
1162 
1163 void FDECL1(outputlist_insert, struct output_fragment *, frag)
1164 {
1165   if( out_tail == NULL )
1166     {
1167       out_list = out_tail = frag;
1168     }
1169   else
1170     {
1171       out_tail->of_next = frag;
1172       out_tail = frag;
1173     }
1174 }
1175 
1176 static int FDECL1(file_write, FILE *, outfile)
1177 {
1178   int				should_write;
1179 #ifdef APPLE_HYB
1180   char	buffer[2048];
1181 
1182   memset(buffer, 0, sizeof(buffer));
1183 
1184   if (apple_hyb) {
1185 
1186 	int i;
1187 
1188 	/* write out padding to round up to HFS allocation block */
1189 	for(i=0;i<hfs_pad;i++)
1190 	    xfwrite(buffer, 1, sizeof(buffer), outfile);
1191 
1192 	last_extent_written += hfs_pad;
1193   }
1194 #endif /* APPLE_HYB */
1195 
1196   /*
1197    * OK, all done with that crap.  Now write out the directories.
1198    * This is where the fur starts to fly, because we need to keep track of
1199    * each file as we find it and keep track of where we put it.
1200    */
1201 
1202   should_write = last_extent - session_start;
1203 
1204   if( print_size > 0 )
1205     {
1206 #ifdef APPLE_HYB
1207       if (apple_hyb)
1208 	fprintf(stderr,"Total extents scheduled to be written (inc HFS) = %d\n",
1209 		last_extent - session_start);
1210       else
1211 #endif
1212       fprintf(stderr,"Total extents scheduled to be written = %d\n",
1213 	      last_extent - session_start);
1214 	exit(0);
1215     }
1216   if( verbose > 2 )
1217     {
1218 #ifdef DBG_ISO
1219       fprintf(stderr,"Total directory extents being written = %d\n", last_extent);
1220 #endif
1221 
1222 #ifdef APPLE_HYB
1223       if (apple_hyb)
1224 	fprintf(stderr,"Total extents scheduled to be written (inc HFS) = %d\n",
1225 		last_extent - session_start);
1226       else
1227 #endif
1228       fprintf(stderr,"Total extents scheduled to be written = %d\n",
1229 	      last_extent - session_start);
1230     }
1231 
1232   /*
1233    * Now write all of the files that we need.
1234    */
1235   write_files(outfile);
1236 
1237 #ifdef APPLE_HYB
1238   /* write out extents/catalog/dt file */
1239   if (apple_hyb) {
1240 
1241 	xfwrite(hce->hfs_ce, hce->hfs_tot_size, HFS_BLOCKSZ, outfile);
1242 
1243 	/* round up to a whole CD block */
1244 	if (H_ROUND_UP(hce->hfs_tot_size) - hce->hfs_tot_size*HFS_BLOCKSZ)
1245 	    xfwrite(buffer, 1, H_ROUND_UP(hce->hfs_tot_size) - hce->hfs_tot_size*HFS_BLOCKSZ, outfile);
1246 
1247 	last_extent_written += ROUND_UP(hce->hfs_tot_size*HFS_BLOCKSZ)/SECTOR_SIZE;
1248 
1249 	/* write out HFS boot block */
1250 	if (mac_boot.name)
1251 	    write_one_file(mac_boot.name, mac_boot.size, outfile, mac_boot.off);
1252   }
1253 #endif /* APPLE_HYB */
1254 
1255   /*
1256    * The rest is just fluff.
1257    */
1258   if( verbose == 0 )
1259     {
1260       return 0;
1261     }
1262 
1263 #ifdef APPLE_HYB
1264   if (apple_hyb) {
1265     fprintf(stderr, "Total extents actually written (inc HFS) = %d\n",
1266       last_extent_written - session_start);
1267     fprintf(stderr, "(Size of ISO volume = %d, HFS extra = %d)\n",
1268       last_extent_written - session_start - hfs_extra, hfs_extra);
1269   }
1270   else
1271 #else
1272     fprintf(stderr,"Total extents actually written = %d\n",
1273 	  last_extent_written - session_start);
1274 #endif /* APPLE_HYB */
1275   /*
1276    * Hard links throw us off here
1277    */
1278   if(should_write != last_extent - session_start)
1279     {
1280       fprintf(stderr,"Number of extents written not what was predicted.  Please fix.\n");
1281       fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent);
1282     }
1283 
1284   fprintf(stderr,"Total translation table size: %d\n", table_size);
1285   fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size);
1286   fprintf(stderr,"Total directory bytes: %d\n", total_dir_size);
1287   fprintf(stderr,"Path table size(bytes): %d\n", path_table_size);
1288 
1289 #ifdef DEBUG
1290   fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n",
1291 	  next_extent, last_extent, last_extent_written);
1292 #endif
1293 
1294   return 0;
1295 
1296 } /* iso_write(... */
1297 
1298 /*
1299  * Function to write the PVD for the disc.
1300  */
1301 static int FDECL1(pvd_write, FILE *, outfile)
1302 {
1303   char				iso_time[17];
1304   int				should_write;
1305   struct tm			local;
1306   struct tm			gmt;
1307 
1308 
1309   time(&begun);
1310 
1311   local = *localtime(&begun);
1312   gmt   = *gmtime(&begun);
1313 
1314   /*
1315    * This will break  in the year  2000, I supose, but there is no good way
1316    * to get the top two digits of the year.
1317    */
1318   snprintf(iso_time, sizeof iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00",
1319 	  1900 + local.tm_year,
1320 	  local.tm_mon+1, local.tm_mday,
1321 	  local.tm_hour, local.tm_min, local.tm_sec);
1322 
1323   local.tm_min -= gmt.tm_min;
1324   local.tm_hour -= gmt.tm_hour;
1325   local.tm_yday -= gmt.tm_yday;
1326   iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15;
1327 
1328   /*
1329    * Next we write out the primary descriptor for the disc
1330    */
1331   memset(&vol_desc, 0, sizeof(vol_desc));
1332   vol_desc.type[0] = ISO_VD_PRIMARY;
1333   memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
1334   vol_desc.version[0] = 1;
1335 
1336   memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id));
1337   memcpy_max(vol_desc.system_id, system_id, strlen(system_id));
1338 
1339   memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id));
1340   memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id));
1341 
1342   should_write = last_extent - session_start;
1343   set_733((char *) vol_desc.volume_space_size, should_write);
1344   set_723(vol_desc.volume_set_size, volume_set_size);
1345   set_723(vol_desc.volume_sequence_number, volume_sequence_number);
1346   set_723(vol_desc.logical_block_size, 2048);
1347 
1348   /*
1349    * The path tables are used by DOS based machines to cache directory
1350    * locations
1351    */
1352 
1353   set_733((char *) vol_desc.path_table_size, path_table_size);
1354   set_731(vol_desc.type_l_path_table, path_table[0]);
1355   set_731(vol_desc.opt_type_l_path_table, path_table[1]);
1356   set_732(vol_desc.type_m_path_table, path_table[2]);
1357   set_732(vol_desc.opt_type_m_path_table, path_table[3]);
1358 
1359   /*
1360    * Now we copy the actual root directory record
1361    */
1362   memcpy(vol_desc.root_directory_record, &root_record,
1363 	 sizeof(struct iso_directory_record) + 1);
1364 
1365   /*
1366    * The rest is just fluff.  It looks nice to fill in many of these fields,
1367    * though.
1368    */
1369   FILL_SPACE(volume_set_id);
1370   if(volset_id)  memcpy_max(vol_desc.volume_set_id,  volset_id, strlen(volset_id));
1371 
1372   FILL_SPACE(publisher_id);
1373   if(publisher)  memcpy_max(vol_desc.publisher_id,  publisher, strlen(publisher));
1374 
1375   FILL_SPACE(preparer_id);
1376   if(preparer)  memcpy_max(vol_desc.preparer_id,  preparer, strlen(preparer));
1377 
1378   FILL_SPACE(application_id);
1379   if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid));
1380 
1381   FILL_SPACE(copyright_file_id);
1382   if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright,
1383 		       strlen(copyright));
1384 
1385   FILL_SPACE(abstract_file_id);
1386   if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract,
1387 			  strlen(abstract));
1388 
1389   FILL_SPACE(bibliographic_file_id);
1390   if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio,
1391 		       strlen(biblio));
1392 
1393   FILL_SPACE(creation_date);
1394   FILL_SPACE(modification_date);
1395   FILL_SPACE(expiration_date);
1396   FILL_SPACE(effective_date);
1397   vol_desc.file_structure_version[0] = 1;
1398   FILL_SPACE(application_data);
1399 
1400   memcpy(vol_desc.creation_date,  iso_time, 17);
1401   memcpy(vol_desc.modification_date,  iso_time, 17);
1402   memcpy(vol_desc.expiration_date, "0000000000000000", 17);
1403   memcpy(vol_desc.effective_date,  iso_time,  17);
1404 
1405   /*
1406    * if not a bootable cd do it the old way
1407    */
1408   xfwrite(&vol_desc, 1, 2048, outfile);
1409   last_extent_written++;
1410   return 0;
1411 }
1412 
1413 /*
1414  * Function to write the EVD for the disc.
1415  */
1416 static int FDECL1(evd_write, FILE *, outfile)
1417 {
1418   struct iso_primary_descriptor evol_desc;
1419 
1420   /*
1421    * Now write the end volume descriptor.  Much simpler than the other one
1422    */
1423   memset(&evol_desc, 0, sizeof(evol_desc));
1424   evol_desc.type[0] = ISO_VD_END;
1425   memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID));
1426   evol_desc.version[0] = 1;
1427   xfwrite(&evol_desc, 1, 2048, outfile);
1428   last_extent_written += 1;
1429   return 0;
1430 }
1431 
1432 /*
1433  * Function to write the EVD for the disc.
1434  */
1435 static int FDECL1(pathtab_write, FILE *, outfile)
1436 {
1437   /*
1438    * Next we write the path tables
1439    */
1440   xfwrite(path_table_l, 1, path_blocks << 11, outfile);
1441   xfwrite(path_table_m, 1, path_blocks << 11, outfile);
1442   last_extent_written += 2*path_blocks;
1443   free(path_table_l);
1444   free(path_table_m);
1445   path_table_l = NULL;
1446   path_table_m = NULL;
1447   return 0;
1448 }
1449 
1450 static int FDECL1(exten_write, FILE *, outfile)
1451 {
1452   xfwrite(extension_record, 1, SECTOR_SIZE, outfile);
1453   last_extent_written++;
1454   return 0;
1455 }
1456 
1457 /*
1458  * Functions to describe padding block at the start of the disc.
1459  */
1460 int FDECL1(oneblock_size, int, starting_extent)
1461 {
1462   last_extent++;
1463   return 0;
1464 }
1465 
1466 /*
1467  * Functions to describe padding block at the start of the disc.
1468  */
1469 static int FDECL1(pathtab_size, int, starting_extent)
1470 {
1471   path_table[0] = starting_extent;
1472 
1473   path_table[1] = 0;
1474   path_table[2] = path_table[0] + path_blocks;
1475   path_table[3] = 0;
1476   last_extent += 2*path_blocks;
1477   return 0;
1478 }
1479 
1480 static int FDECL1(padblock_size, int, starting_extent)
1481 {
1482   last_extent += 16;
1483   return 0;
1484 }
1485 
1486 static int file_gen()
1487 {
1488 #ifdef APPLE_HYB
1489   int start_extent = last_extent;	/* orig ISO files start */
1490 #endif /* APPLE_HYB */
1491   assign_file_addresses(root);
1492 #ifdef APPLE_HYB
1493   /* put this here for the time being - may when I've worked out how
1494      to use Eric's new system for creating/writing parts of the image
1495      it may move to it's own routine */
1496 
1497   if (apple_hyb)
1498   {
1499     int	Csize;				/* clump size for HFS vol */
1500     int loop = CTC_LOOP;
1501     int last_extent_save = last_extent;
1502 
1503     /* allocate memory for the libhfs/mkisofs extra info */
1504     hce = (hce_mem *)e_malloc(sizeof(hce_mem));
1505 
1506     hce->error = (char *)e_malloc(ERROR_SIZE);
1507 
1508     /* mark as unallocated for use later */
1509     hce->hfs_ce = hce->hfs_hdr = hce->hfs_map = 0;
1510 
1511     /* reserve space for the label partition - if it is needed */
1512     if (gen_pt)
1513 	hce->hfs_map_size = HFS_MAP_SIZE;
1514     else
1515 	hce->hfs_map_size = 0;
1516 
1517     /* set the intial factor to increase Catalog file size */
1518     hce->ctc_size = CTC;
1519 
1520     /* "create" the HFS volume (just the header, catalog/extents files)
1521 	if there's a problem with the Catalog file being too small,
1522 	we keep on increasing the size (up to CTC_LOOP) times and try again.
1523 	Unfortunately I don't know enough about the inner workings of
1524 	HFS, so I can't workout the size of the Catalog file in
1525 	advance (and I don't want to "grow" as is is normally allowed to),
1526 	therefore, this approach is a bit over the top as it involves
1527 	throwing away the "volume" we have created and trying again ...  */
1528     do
1529     {
1530 	hce->error[0] = '\0';
1531 
1532 	/* attempt to create the Mac volume */
1533 	Csize = make_mac_volume(root, start_extent);
1534 
1535 	/* if we have a problem ... */
1536 	if (Csize < 0)
1537 	{
1538 	    /* we've made too many attempts, or got some other error */
1539 	    if (loop == 0 || errno != HCE_ERROR)
1540 	    {
1541 		/* HCE_ERROR is not a valid errno value */
1542 		if (errno == HCE_ERROR)
1543 		     errno = 0;
1544 
1545 		/* exit with the error */
1546 		if (*hce->error)
1547 		    fprintf(stderr, "%s\n", hce->error);
1548 		err(1, hfs_error);
1549 	    }
1550 	    else
1551 	    {
1552 		/* increase Catalog file size factor */
1553 		hce->ctc_size *= CTC;
1554 
1555 		/* reset the initial "last_extent" and try again */
1556 		last_extent = last_extent_save;
1557 	    }
1558 	}
1559 	else
1560 	    /* everything OK - just carry on ... */
1561 	    loop = 0;
1562     }
1563     while (loop--);
1564 
1565     hfs_extra = H_ROUND_UP(hce->hfs_tot_size)/SECTOR_SIZE;
1566 
1567     last_extent += hfs_extra;
1568 
1569     /* generate the Mac label and HFS partition maps */
1570     mac_boot.name = hfs_boot_file;
1571 
1572     /* only generate the partition tables etc. if we are making a bootable
1573        CD - or if the -part option is given */
1574     if (gen_pt) {
1575       if (gen_mac_label(&mac_boot)) {
1576 	if (*hce->error)
1577 	    fprintf(stderr, "%s\n", hce->error);
1578 	err(1, hfs_error);
1579       }
1580     }
1581 
1582     /* set Autostart filename if required */
1583     if (autoname) {
1584 	if(autostart())
1585 	    errx(1, "Autostart filename must less than 12 characters");
1586     }
1587 
1588     /* finished with any HFS type errors */
1589     free(hce->error);
1590     hce->error = 0;
1591 
1592     /* the ISO files need to start on a multiple of the HFS allocation
1593        blocks, so find out how much padding we need */
1594 
1595     /* take in accout alignment of files wrt HFS volume start */
1596     hfs_pad = V_ROUND_UP(start_extent*SECTOR_SIZE + (hce->hfs_hdr_size + hce->hfs_map_size)*HFS_BLOCKSZ, Csize)/SECTOR_SIZE;
1597 
1598     hfs_pad -= (start_extent + (hce->hfs_hdr_size + hce->hfs_map_size)/BLK_CONV);
1599   }
1600 #endif /* APPLE_HYB */
1601   return 0;
1602 }
1603 
1604 static int dirtree_dump()
1605 {
1606   if (verbose > 2)
1607   {
1608       dump_tree(root);
1609   }
1610   return 0;
1611 }
1612 
1613 static int FDECL1(dirtree_fixup, int, starting_extent)
1614 {
1615   if (use_RockRidge && reloc_dir)
1616 	  finish_cl_pl_entries();
1617 
1618   if (use_RockRidge )
1619 	  update_nlink_field(root);
1620   return 0;
1621 }
1622 
1623 static int FDECL1(dirtree_size, int, starting_extent)
1624 {
1625   assign_directory_addresses(root);
1626   return 0;
1627 }
1628 
1629 static int FDECL1(ext_size, int, starting_extent)
1630 {
1631   extern int extension_record_size;
1632   struct directory_entry * s_entry;
1633   extension_record_extent = starting_extent;
1634   s_entry = root->contents;
1635   set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
1636 	  extension_record_extent);
1637   set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
1638 	  extension_record_size);
1639   last_extent++;
1640   return 0;
1641 }
1642 
1643 static int FDECL1(dirtree_write, FILE *, outfile)
1644 {
1645   generate_iso9660_directories(root, outfile);
1646   return 0;
1647 }
1648 
1649 static int FDECL1(dirtree_cleanup, FILE *, outfile)
1650 {
1651   free_directories(root);
1652   return 0;
1653 }
1654 
1655 static int FDECL1(padblock_write, FILE *, outfile)
1656 {
1657   char				buffer[2048];
1658   int				i;
1659 #ifdef APPLE_HYB
1660   int				n = 0;
1661 #endif /* APPLE_HYB */
1662 
1663   memset(buffer, 0, sizeof(buffer));
1664 
1665 #ifdef APPLE_HYB
1666   if (apple_hyb)
1667   {
1668     int		r;		/* HFS hdr output */
1669     int		tot_size = hce->hfs_map_size + hce->hfs_hdr_size;
1670 
1671     /* get size in CD blocks == 4xHFS_BLOCKSZ == 2048 */
1672     n = tot_size/BLK_CONV;
1673     r = tot_size%BLK_CONV;
1674 
1675     /* write out HFS volume header info */
1676     xfwrite(hce->hfs_map, tot_size, HFS_BLOCKSZ, outfile);
1677 
1678     /* write out any partial CD block */
1679     if (r)
1680     {
1681       xfwrite(buffer, BLK_CONV-r, HFS_BLOCKSZ, outfile);
1682       n++;
1683     }
1684   }
1685 
1686   /* write out the remainder of the ISO header */
1687   for(i=n; i<16; i++)
1688 #else
1689   for(i=0; i<16; i++)
1690 #endif /* APPLE_HYB */
1691     {
1692       xfwrite(buffer, 1, sizeof(buffer), outfile);
1693     }
1694 
1695   last_extent_written += 16;
1696   return 0;
1697 }
1698 
1699 #ifdef APPLE_HYB
1700 
1701 /*
1702 **	get_adj_size:	get the ajusted size of the volume with the HFS
1703 **			allocation block size for each file
1704 */
1705 int FDECL1(get_adj_size, int, Csize)
1706 {
1707 	struct deferred_write *dw;
1708 	int     size = 0;
1709 	int	count = 0;
1710 
1711 	/* loop through all the files finding the new total size */
1712 	for(dw = dw_head; dw; dw = dw->next)
1713 	{
1714 	    size += V_ROUND_UP(dw->size, Csize);
1715 	    count++;
1716 	}
1717 
1718 	/* crude attempt to prevent overflows - HFS can only cope with a
1719 	   maximum of about 65536 forks (actually less) - this will trap
1720 	   cases when we have far too many files */
1721 	if (count >= 65536)
1722 	    return (-1);
1723 	else
1724 	    return(size);
1725 }
1726 /*
1727 **	adj_size:	adjust the ISO record entries for all files
1728 **			based on the HFS allocation block size
1729 */
1730 int FDECL3(adj_size, int, Csize, int, start_extent, int, extra)
1731 {
1732 	struct deferred_write *dw;
1733 	struct directory_entry *s_entry;
1734 	int	size;
1735 
1736 	/* get the adjusted start_extent (with padding) */
1737 	/* take in accout alignment of files wrt HFS volume start */
1738 
1739 	start_extent = V_ROUND_UP(start_extent*SECTOR_SIZE + extra *HFS_BLOCKSZ, Csize)/SECTOR_SIZE;
1740 
1741 	start_extent -= (extra/BLK_CONV);
1742 
1743 	/* initialise file hash */
1744 	flush_hash();
1745 
1746 	/* loop through all files changing their starting blocks and
1747 	   finding any padding needed to written out latter */
1748 	for(dw = dw_head; dw; dw = dw->next)
1749 	{
1750 	    s_entry = dw->s_entry;
1751 	    s_entry->starting_block = dw->extent = start_extent;
1752 	    set_733((char *) s_entry->isorec.extent, start_extent);
1753 	    size = V_ROUND_UP(dw->size, Csize)/SECTOR_SIZE;
1754 	    dw->pad = size - ROUND_UP(dw->size)/SECTOR_SIZE;
1755 
1756 	    /* cache non-HFS files - as there may be multiple links to
1757 	       these files (HFS files can't have multiple links). We will
1758 	       need to change the starting extent of the other links later */
1759 	    if (!s_entry->hfs_ent)
1760 		add_hash(s_entry);
1761 
1762 	    start_extent += size;
1763 	}
1764 
1765 	return(start_extent);
1766 }
1767 
1768 /*
1769 **	adj_size_other:	adjust any non-HFS files that may be linked
1770 **			to an existing file (i.e. not have a deferred_write
1771 **			entry of it's own
1772 */
1773 void FDECL1(adj_size_other, struct directory *, dpnt)
1774 {
1775 	struct directory_entry * s_entry;
1776 	struct file_hash *s_hash;
1777 
1778 	while (dpnt)
1779 	{
1780 	    s_entry = dpnt->contents;
1781 	    for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next)
1782 	    {
1783 		/* if it's an HFS file or a directory - then ignore
1784 		   (we're after non-HFS files) */
1785 		if (s_entry->hfs_ent || (s_entry->isorec.flags[0] & 2))
1786 		    continue;
1787 
1788 		/* find any cached entry and assign new starting extent */
1789 		s_hash = find_hash(s_entry->dev, s_entry->inode);
1790 		if(s_hash)
1791 		{
1792 		    set_733((char *) s_entry->isorec.extent, s_hash->starting_block);
1793 		    /* not vital - but tidy */
1794 		    s_entry->starting_block = s_hash->starting_block;
1795 		}
1796 
1797 	    }
1798 	    if(dpnt->subdir)
1799 	    {
1800 		adj_size_other(dpnt->subdir);
1801 	    }
1802 	    dpnt = dpnt->next;
1803 	}
1804 
1805 	/* clear file hash */
1806 	flush_hash();
1807 }
1808 
1809 #endif /* APPLE_HYB */
1810 
1811 struct output_fragment padblock_desc  = {NULL, padblock_size, NULL,     padblock_write};
1812 struct output_fragment voldesc_desc   = {NULL, oneblock_size, root_gen, pvd_write};
1813 struct output_fragment end_vol	      = {NULL, oneblock_size, NULL,     evd_write};
1814 struct output_fragment pathtable_desc = {NULL, pathtab_size,  generate_path_tables,     pathtab_write};
1815 struct output_fragment dirtree_desc   = {NULL, dirtree_size,  NULL,     dirtree_write};
1816 struct output_fragment dirtree_clean  = {NULL, dirtree_fixup, dirtree_dump,     dirtree_cleanup};
1817 struct output_fragment extension_desc = {NULL, ext_size,      NULL,     exten_write};
1818 struct output_fragment files_desc     = {NULL, NULL,          file_gen, file_write};
1819