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