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