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