xref: /openbsd/gnu/usr.sbin/mkhybrid/src/write.c (revision 22fe1ffc)
1 /*
2  * Program write.c - dump memory  structures to  file for iso9660 filesystem.
3 
4    Written by Eric Youngdale (1993).
5 
6    Copyright 1993 Yggdrasil Computing, Incorporated
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21 
22 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 16/3/1999 */
23 #include <string.h>
24 #include <stdlib.h>
25 #include <err.h>
26 #include "config.h"
27 #include "mkisofs.h"
28 #include "iso9660.h"
29 #include "volume.h"
30 #include "write.h"
31 #include "apple_proto.h"
32 #include "mac_label_proto.h"
33 #include <time.h>
34 #include <errno.h>
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #ifdef __SVR4
45 extern char * strdup(const char *);
46 #endif
47 
48 #ifdef VMS
49 extern char * strdup(const char *);
50 #endif
51 
52 
53 /* Max number of sectors we will write at  one time */
54 #define NSECT 16
55 
56 /* Counters for statistics */
57 
58 static int table_size       = 0;
59 static int total_dir_size   = 0;
60 static int rockridge_size   = 0;
61 static struct directory ** pathlist;
62 static int next_path_index  = 1;
63 static int sort_goof;
64 
65 struct output_fragment * out_tail;
66 struct output_fragment * out_list;
67 
68 struct iso_primary_descriptor vol_desc;
69 
70 #ifdef APPLE_HYB
71 static int hfs_pad;
72 #endif /* APPLE_HYB */
73 
74 static int root_gen	__PR((void));
75 static int generate_path_tables	__PR((void));
76 static int file_gen	__PR((void));
77 static int dirtree_dump	__PR((void));
78 
79 /* Routines to actually write the disc.  We write sequentially so that
80    we could write a tape, or write the disc directly */
81 
82 
83 #define FILL_SPACE(X)   memset(vol_desc.X, ' ', sizeof(vol_desc.X))
84 
FDECL2(set_721,char *,pnt,unsigned int,i)85 void FDECL2(set_721, char *, pnt, unsigned int, i)
86 {
87      pnt[0] = i & 0xff;
88      pnt[1] = (i >> 8) &  0xff;
89 }
90 
FDECL2(set_722,char *,pnt,unsigned int,i)91 void FDECL2(set_722, char *, pnt, unsigned int, i)
92 {
93      pnt[0] = (i >> 8) &  0xff;
94      pnt[1] = i & 0xff;
95 }
96 
FDECL2(set_723,char *,pnt,unsigned int,i)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 
FDECL2(set_731,char *,pnt,unsigned int,i)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 
FDECL2(set_732,char *,pnt,unsigned int,i)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 
FDECL1(get_733,char *,p)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 
FDECL2(set_733,char *,pnt,unsigned int,i)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 
FDECL4(xfwrite,void *,buffer,int,count,int,size,FILE *,file)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 
FDECL1(assign_directory_addresses,struct directory *,node)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
FDECL4(write_one_file,char *,filename,unsigned int,size,FILE *,outfile,unsigned int,off)238 static void FDECL4(write_one_file, char *, filename,
239 		   unsigned int, size, FILE *, outfile, unsigned int, off)
240 #else
241 static void FDECL3(write_one_file, char *, filename,
242 		   unsigned int, size, FILE *, outfile)
243 #endif /* APPLE_HYB */
244 {
245      char		  buffer[SECTOR_SIZE * NSECT];
246      FILE		* infile;
247      int		  remain;
248      int		  use;
249 
250 
251      if ((infile = fopen(filename, "rb")) == NULL)
252      {
253 #if defined(sun) || defined(_AUX_SOURCE)
254 	  fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);
255 #else
256 	  fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
257 #endif
258 	  exit(1);
259      }
260 #ifdef APPLE_HYB
261      fseek(infile, off, SEEK_SET);
262 #endif /* APPLE_HYB */
263      remain = size;
264 
265      while(remain > 0)
266      {
267 	  use =  (remain >  SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
268 	  use = ROUND_UP(use); /* Round up to nearest sector boundary */
269 	  memset(buffer, 0, use);
270 	  if (fread(buffer, 1, use, infile) == 0)
271 	  {
272 		fprintf(stderr,"cannot read from %s\n",filename);
273 		exit(1);
274 	  }
275 	  xfwrite(buffer, 1, use, outfile);
276 	  last_extent_written += use/SECTOR_SIZE;
277 #if 0
278 	  if((last_extent_written % 1000) < use/SECTOR_SIZE)
279 	  {
280 	       fprintf(stderr,"%d..", last_extent_written);
281 	  }
282 #else
283 	  if((last_extent_written % 5000) < use/SECTOR_SIZE
284 	    && verbose > 3)
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 
FDECL1(write_files,FILE *,outfile)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 
FDECL2(compare_dirs,const void *,rr,const void *,ll)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  */
FDECL1(sort_directory,struct directory_entry **,sort_dir)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 
root_gen()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 
FDECL1(assign_file_addresses,struct directory *,dpnt)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 
FDECL1(free_one_directory,struct directory *,dpnt)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 
FDECL1(free_directories,struct directory *,dpnt)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 
FDECL2(generate_one_directory,struct directory *,dpnt,FILE *,outfile)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
FDECL1(build_pathlist,struct directory *,node)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 
FDECL2(compare_paths,void const *,r,void const *,l)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 
generate_path_tables()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
FDECL3(memcpy_max,char *,to,char *,from,int,max)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 
FDECL1(outputlist_insert,struct output_fragment *,frag)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 
FDECL1(file_write,FILE *,outfile)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  */
FDECL1(pvd_write,FILE *,outfile)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  */
FDECL1(evd_write,FILE *,outfile)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  */
FDECL1(pathtab_write,FILE *,outfile)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 
FDECL1(exten_write,FILE *,outfile)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  */
FDECL1(oneblock_size,int,starting_extent)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  */
FDECL1(pathtab_size,int,starting_extent)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 
FDECL1(padblock_size,int,starting_extent)1481 static int FDECL1(padblock_size, int, starting_extent)
1482 {
1483   last_extent += 16;
1484   return 0;
1485 }
1486 
file_gen()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, "%s", 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, "%s", 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 
dirtree_dump()1605 static int dirtree_dump()
1606 {
1607   if (verbose > 2)
1608   {
1609       dump_tree(root);
1610   }
1611   return 0;
1612 }
1613 
FDECL1(dirtree_fixup,int,starting_extent)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 
FDECL1(dirtree_size,int,starting_extent)1624 static int FDECL1(dirtree_size, int, starting_extent)
1625 {
1626   assign_directory_addresses(root);
1627   return 0;
1628 }
1629 
FDECL1(ext_size,int,starting_extent)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 
FDECL1(dirtree_write,FILE *,outfile)1644 static int FDECL1(dirtree_write, FILE *, outfile)
1645 {
1646   generate_iso9660_directories(root, outfile);
1647   return 0;
1648 }
1649 
FDECL1(dirtree_cleanup,FILE *,outfile)1650 static int FDECL1(dirtree_cleanup, FILE *, outfile)
1651 {
1652   free_directories(root);
1653   return 0;
1654 }
1655 
FDECL1(padblock_write,FILE *,outfile)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 */
FDECL1(get_adj_size,int,Csize)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 */
FDECL3(adj_size,int,Csize,int,start_extent,int,extra)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 */
FDECL1(adj_size_other,struct directory *,dpnt)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