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