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