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