1 /* 2 * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660. 3 4 Copyright 1997 Eric Youngdale. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 19 20 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 12/3/99 */ 21 22 /* 23 * Joliet extensions for ISO9660. These are spottily documented by 24 * Microsoft. In their infinite stupidity, they completely ignored 25 * the possibility of using an SUSP record with the long filename 26 * in it, and instead wrote out a duplicate directory tree with the 27 * long filenames in it. 28 * 29 * I am not sure why they did this. One reason is that they get the path 30 * tables with the long filenames in them. 31 * 32 * There are two basic principles to Joliet, and the non-Unicode variant 33 * known as Romeo. Long filenames seem to be the main one, and the second 34 * is that the character set and a few other things is substantially relaxed. 35 * 36 * The SVD is identical to the PVD, except: 37 * 38 * Id is 2, not 1 (indicates SVD). 39 * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3). 40 * The root directory record points to a different extent (with different 41 * size). 42 * There are different path tables for the two sets of directory trees. 43 * 44 * The following fields are recorded in Unicode: 45 * system_id 46 * volume_id 47 * volume_set_id 48 * publisher_id 49 * preparer_id 50 * application_id 51 * copyright_file_id 52 * abstract_file_id 53 * bibliographic_file_id 54 * 55 * Unicode strings are always encoded in big-endian format. 56 * 57 * In a directory record, everything is the same as with iso9660, except 58 * that the name is recorded in unicode. The name length is specified in 59 * total bytes, not in number of unicode characters. 60 * 61 * The character set used for the names is different with UCS - the 62 * restrictions are that the following are not allowed: 63 * 64 * Characters (00)(00) through (00)(1f) (control chars) 65 * (00)(2a) '*' 66 * (00)(2f) '/' 67 * (00)(3a) ':' 68 * (00)(3b) ';' 69 * (00)(3f) '?' 70 * (00)(5c) '\' 71 */ 72 #include "config.h" 73 #include "mkisofs.h" 74 #include "iso9660.h" 75 76 77 #include <stdlib.h> 78 #include <time.h> 79 80 static int jpath_table_index; 81 static struct directory ** jpathlist; 82 static int next_jpath_index = 1; 83 static int sort_goof; 84 85 static int generate_joliet_path_tables __PR((void)); 86 static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir)); 87 static void DECL(assign_joliet_directory_addresses, (struct directory * node)); 88 static int jroot_gen __PR((void)); 89 90 /* 91 * Function: convert_to_unicode 92 * 93 * Purpose: Perform a 1/2 assed unicode conversion on a text 94 * string. 95 * 96 * Notes: 97 */ 98 static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char *, source ) 99 { 100 unsigned char * tmpbuf; 101 int i; 102 int j; 103 104 /* 105 * If we get a NULL pointer for the source, it means we have an inplace 106 * copy, and we need to make a temporary working copy first. 107 */ 108 if( source == NULL ) 109 { 110 tmpbuf = (u_char *) e_malloc(size); 111 memcpy( tmpbuf, buffer, size); 112 } 113 else 114 { 115 tmpbuf = (u_char *)source; 116 } 117 118 /* 119 * Now start copying characters. If the size was specified to be 0, then 120 * assume the input was 0 terminated. 121 */ 122 j = 0; 123 for(i=0; i < size ; i += 2, j++) 124 { 125 buffer[i] = 0; 126 /* 127 * JS integrated from: Achim_Kaiser@t-online.de 128 * 129 * Let all valid unicode characters pass through (assuming ISO-8859-1). 130 * Others are set to '_' . 131 */ 132 if( tmpbuf[j] != 0 && 133 (tmpbuf[j] <= 0x1f || (tmpbuf[j] >= 0x7F && tmpbuf[j] <= 0xA0)) ) 134 { 135 buffer[i+1] = '_'; 136 } 137 else 138 { 139 switch(tmpbuf[j]) 140 { 141 case '*': 142 case '/': 143 case ':': 144 case ';': 145 case '?': 146 case '\\': 147 /* 148 * Even Joliet has some standards as to what is allowed in a pathname. 149 * Pretty tame in comparison to what DOS restricts you to. 150 */ 151 buffer[i+1] = '_'; 152 break; 153 default: 154 buffer[i+1] = tmpbuf[j]; 155 break; 156 } 157 } 158 } 159 160 if( source == NULL ) 161 { 162 free(tmpbuf); 163 } 164 } 165 166 /* 167 * Function: joliet_strlen 168 * 169 * Purpose: Return length in bytes of string after conversion to unicode. 170 * 171 * Notes: This is provided mainly as a convenience so that when more intelligent 172 * Unicode conversion for either Multibyte or 8-bit codes is available that 173 * we can easily adapt. 174 */ 175 static int FDECL1(joliet_strlen, const char *, string) 176 { 177 int rtn; 178 179 rtn = strlen(string) << 1; 180 181 /* 182 * We do clamp the maximum length of a Joliet string to be the 183 * maximum path size. This helps to ensure that we don't completely 184 * bolix things up with very long paths. The Joliet specs say 185 * that the maximum length is 128 bytes, or 64 unicode characters. 186 */ 187 if( rtn > 0x80) 188 { 189 rtn = 0x80; 190 } 191 return rtn; 192 } 193 194 /* 195 * Function: get_joliet_vol_desc 196 * 197 * Purpose: generate a Joliet compatible volume desc. 198 * 199 * Notes: Assume that we have the non-joliet vol desc 200 * already present in the buffer. Just modifiy the 201 * appropriate fields. 202 */ 203 static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, jvol_desc) 204 { 205 jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY; 206 207 /* 208 * For now, always do Unicode level 3. I don't really know what 1 and 2 209 * are - perhaps a more limited Unicode set. 210 * 211 * FIXME(eric) - how does Romeo fit in here? As mkisofs just 212 * "expands" 8 bit character codes to 16 bits and does nothing 213 * special with the Unicode characters, therefore shouldn't mkisofs 214 * really be stating that it's using UCS-2 Level 1, not Level 3 for 215 * the Joliet directory tree. 216 */ 217 strcpy(jvol_desc->escape_sequences, "%/@"); 218 219 /* 220 * Until we have Unicode path tables, leave these unset. 221 */ 222 set_733((char *) jvol_desc->path_table_size, jpath_table_size); 223 set_731(jvol_desc->type_l_path_table, jpath_table[0]); 224 set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]); 225 set_732(jvol_desc->type_m_path_table, jpath_table[2]); 226 set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]); 227 228 /* 229 * Set this one up. 230 */ 231 memcpy(jvol_desc->root_directory_record, &jroot_record, 232 sizeof(jvol_desc->root_directory_record)); 233 234 /* 235 * Finally, we have a bunch of strings to convert to Unicode. 236 * FIXME(eric) - I don't know how to do this in general, so we will 237 * just be really lazy and do a char -> short conversion. We probably 238 * will want to filter any characters >= 0x80. 239 */ 240 convert_to_unicode((u_char *)jvol_desc->system_id, sizeof(jvol_desc->system_id), NULL); 241 convert_to_unicode((u_char *)jvol_desc->volume_id, sizeof(jvol_desc->volume_id), NULL); 242 convert_to_unicode((u_char *)jvol_desc->volume_set_id, sizeof(jvol_desc->volume_set_id), NULL); 243 convert_to_unicode((u_char *)jvol_desc->publisher_id, sizeof(jvol_desc->publisher_id), NULL); 244 convert_to_unicode((u_char *)jvol_desc->preparer_id, sizeof(jvol_desc->preparer_id), NULL); 245 convert_to_unicode((u_char *)jvol_desc->application_id, sizeof(jvol_desc->application_id), NULL); 246 convert_to_unicode((u_char *)jvol_desc->copyright_file_id, sizeof(jvol_desc->copyright_file_id), NULL); 247 convert_to_unicode((u_char *)jvol_desc->abstract_file_id, sizeof(jvol_desc->abstract_file_id), NULL); 248 convert_to_unicode((u_char *)jvol_desc->bibliographic_file_id, sizeof(jvol_desc->bibliographic_file_id), NULL); 249 250 251 } 252 253 static void FDECL1(assign_joliet_directory_addresses, struct directory *, node) 254 { 255 int dir_size; 256 struct directory * dpnt; 257 258 dpnt = node; 259 260 while (dpnt) 261 { 262 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) 263 { 264 /* 265 * If we already have an extent for this (i.e. it came from 266 * a multisession disc), then don't reassign a new extent. 267 */ 268 dpnt->jpath_index = next_jpath_index++; 269 if( dpnt->jextent == 0 ) 270 { 271 dpnt->jextent = last_extent; 272 dir_size = (dpnt->jsize + (SECTOR_SIZE - 1)) >> 11; 273 last_extent += dir_size; 274 } 275 } 276 277 /* skip if hidden - but not for the rr_moved dir */ 278 if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) 279 { 280 assign_joliet_directory_addresses(dpnt->subdir); 281 } 282 dpnt = dpnt->next; 283 } 284 } 285 286 static 287 void FDECL1(build_jpathlist, struct directory *, node) 288 { 289 struct directory * dpnt; 290 291 dpnt = node; 292 293 while (dpnt) 294 295 { 296 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) 297 { 298 jpathlist[dpnt->jpath_index] = dpnt; 299 } 300 if(dpnt->subdir) build_jpathlist(dpnt->subdir); 301 dpnt = dpnt->next; 302 } 303 } /* build_jpathlist(... */ 304 305 static int FDECL2(joliet_compare_paths, void const *, r, void const *, l) 306 { 307 struct directory const *ll = *(struct directory * const *)l; 308 struct directory const *rr = *(struct directory * const *)r; 309 int rparent, lparent; 310 311 rparent = rr->parent->jpath_index; 312 lparent = ll->parent->jpath_index; 313 if( rr->parent == reloc_dir ) 314 { 315 rparent = rr->self->parent_rec->filedir->jpath_index; 316 } 317 318 if( ll->parent == reloc_dir ) 319 { 320 lparent = ll->self->parent_rec->filedir->jpath_index; 321 } 322 323 if (rparent < lparent) 324 { 325 return -1; 326 } 327 328 if (rparent > lparent) 329 { 330 return 1; 331 } 332 #ifdef APPLE_HYB 333 /* use Mac name for Joliet name */ 334 if (USE_MAC_NAME(mac_name, rr->self) && USE_MAC_NAME(mac_name, ll->self)) 335 return strcmp(rr->self->hfs_ent->name, ll->self->hfs_ent->name); 336 else 337 #endif /* APPLE_HYB */ 338 return strcmp(rr->self->name, ll->self->name); 339 340 } /* compare_paths(... */ 341 342 static int generate_joliet_path_tables() 343 { 344 struct directory_entry * de; 345 struct directory * dpnt; 346 int fix; 347 int j; 348 int namelen; 349 char * npnt; 350 char * npnt1; 351 int tablesize; 352 353 /* 354 * First allocate memory for the tables and initialize the memory 355 */ 356 tablesize = jpath_blocks << 11; 357 jpath_table_m = (char *) e_malloc(tablesize); 358 jpath_table_l = (char *) e_malloc(tablesize); 359 memset(jpath_table_l, 0, tablesize); 360 memset(jpath_table_m, 0, tablesize); 361 362 if( next_jpath_index > 0xffff ) 363 { 364 fprintf(stderr, "Unable to generate sane path tables - too many directories (%d)\n", 365 next_jpath_index); 366 exit(1); 367 } 368 /* 369 * Now start filling in the path tables. Start with root directory 370 */ 371 jpath_table_index = 0; 372 jpathlist = (struct directory **) e_malloc(sizeof(struct directory *) 373 * next_jpath_index); 374 memset(jpathlist, 0, sizeof(struct directory *) * next_jpath_index); 375 build_jpathlist(root); 376 377 do 378 { 379 fix = 0; 380 #ifdef __STDC__ 381 qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), 382 (int (*)(const void *, const void *))joliet_compare_paths); 383 #else 384 qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), 385 joliet_compare_paths); 386 #endif 387 388 for(j=1; j<next_jpath_index; j++) 389 { 390 if(jpathlist[j]->jpath_index != j) 391 { 392 jpathlist[j]->jpath_index = j; 393 fix++; 394 } 395 } 396 } while(fix); 397 398 for(j=1; j<next_jpath_index; j++) 399 { 400 dpnt = jpathlist[j]; 401 if(!dpnt) 402 { 403 fprintf(stderr,"Entry %d not in path tables\n", j); 404 exit(1); 405 } 406 npnt = dpnt->de_name; 407 408 npnt1 = strrchr(npnt, PATH_SEPARATOR); 409 if(npnt1) 410 { 411 npnt = npnt1 + 1; 412 } 413 414 de = dpnt->self; 415 if(!de) 416 { 417 fprintf(stderr,"Fatal goof - directory has amnesia\n"); 418 exit(1); 419 } 420 421 #ifdef APPLE_HYB 422 if (USE_MAC_NAME(mac_name, de)) 423 namelen = joliet_strlen(de->hfs_ent->name); 424 else 425 #endif /* APPLE_HYB */ 426 namelen = joliet_strlen(de->name); 427 428 if( dpnt == root ) 429 { 430 jpath_table_l[jpath_table_index] = 1; 431 jpath_table_m[jpath_table_index] = 1; 432 } 433 else 434 { 435 jpath_table_l[jpath_table_index] = namelen; 436 jpath_table_m[jpath_table_index] = namelen; 437 } 438 jpath_table_index += 2; 439 440 set_731(jpath_table_l + jpath_table_index, dpnt->jextent); 441 set_732(jpath_table_m + jpath_table_index, dpnt->jextent); 442 jpath_table_index += 4; 443 444 if( dpnt->parent != reloc_dir ) 445 { 446 set_721(jpath_table_l + jpath_table_index, 447 dpnt->parent->jpath_index); 448 set_722(jpath_table_m + jpath_table_index, 449 dpnt->parent->jpath_index); 450 } 451 else 452 { 453 set_721(jpath_table_l + jpath_table_index, 454 dpnt->self->parent_rec->filedir->jpath_index); 455 set_722(jpath_table_m + jpath_table_index, 456 dpnt->self->parent_rec->filedir->jpath_index); 457 } 458 459 jpath_table_index += 2; 460 461 /* 462 * The root directory is still represented in non-unicode fashion. 463 */ 464 if( dpnt == root ) 465 { 466 jpath_table_l[jpath_table_index] = 0; 467 jpath_table_m[jpath_table_index] = 0; 468 jpath_table_index ++; 469 } 470 else 471 { 472 #ifdef APPLE_HYB 473 if (USE_MAC_NAME(mac_name , de)) { 474 convert_to_unicode((u_char *)jpath_table_l + jpath_table_index, 475 namelen, de->hfs_ent->name); 476 convert_to_unicode((u_char *)jpath_table_m + jpath_table_index, 477 namelen, de->hfs_ent->name); 478 } 479 else { 480 #endif /* APPLE_HYB */ 481 convert_to_unicode((u_char *)jpath_table_l + jpath_table_index, 482 namelen, de->name); 483 convert_to_unicode((u_char *)jpath_table_m + jpath_table_index, 484 namelen, de->name); 485 #ifdef APPLE_HYB 486 } 487 #endif /* APPLE_HYB */ 488 489 jpath_table_index += namelen; 490 } 491 492 if(jpath_table_index & 1) 493 { 494 jpath_table_index++; /* For odd lengths we pad */ 495 } 496 } 497 498 free(jpathlist); 499 if(jpath_table_index != jpath_table_size) 500 { 501 fprintf(stderr,"Joliet path table lengths do not match %d %d\n", 502 jpath_table_index, 503 jpath_table_size); 504 } 505 return 0; 506 } /* generate_path_tables(... */ 507 508 static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE *, outfile) 509 { 510 unsigned int dir_index; 511 char * directory_buffer; 512 int new_reclen; 513 struct directory_entry * s_entry; 514 struct directory_entry * s_entry1; 515 struct iso_directory_record jrec; 516 unsigned int total_size; 517 int cvt_len; 518 struct directory * finddir; 519 520 total_size = (dpnt->jsize + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); 521 directory_buffer = (char *) e_malloc(total_size); 522 memset(directory_buffer, 0, total_size); 523 dir_index = 0; 524 525 s_entry = dpnt->jcontents; 526 while(s_entry) 527 { 528 if(s_entry->de_flags & INHIBIT_JOLIET_ENTRY) { 529 s_entry = s_entry->jnext; 530 continue; 531 } 532 533 /* 534 * If this entry was a directory that was relocated, we have a bit 535 * of trouble here. We need to dig out the real thing and put it 536 * back here. In the Joliet tree, there is no relocated rock 537 * ridge, as there are no depth limits to a directory tree. 538 */ 539 if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 ) 540 { 541 for(s_entry1 = reloc_dir->contents; s_entry1; s_entry1 = s_entry1->next) 542 { 543 if( s_entry1->parent_rec == s_entry ) 544 { 545 break; 546 } 547 } 548 if( s_entry1 == NULL ) 549 { 550 /* 551 * We got trouble. 552 */ 553 fprintf(stderr, "Unable to locate relocated directory\n"); 554 exit(1); 555 } 556 } 557 else 558 { 559 s_entry1 = s_entry; 560 } 561 562 /* 563 * We do not allow directory entries to cross sector boundaries. 564 * Simply pad, and then start the next entry at the next sector 565 */ 566 new_reclen = s_entry1->jreclen; 567 if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE ) 568 { 569 dir_index = (dir_index + (SECTOR_SIZE - 1)) & 570 ~(SECTOR_SIZE - 1); 571 } 572 573 memcpy(&jrec, &s_entry1->isorec, sizeof(struct iso_directory_record) - 574 sizeof(s_entry1->isorec.name)); 575 576 #ifdef APPLE_HYB 577 /* Use the HFS name if it exists */ 578 if (USE_MAC_NAME(mac_name, s_entry1)) 579 cvt_len = joliet_strlen(s_entry1->hfs_ent->name); 580 else 581 #endif /* APPLE_HYB */ 582 cvt_len = joliet_strlen(s_entry1->name); 583 584 /* 585 * Fix the record length - this was the non-Joliet version we 586 * were seeing. 587 */ 588 jrec.name_len[0] = cvt_len; 589 jrec.length[0] = s_entry1->jreclen; 590 591 /* 592 * If this is a directory, fix the correct size and extent 593 * number. 594 */ 595 if( (jrec.flags[0] & 2) != 0 ) 596 { 597 if(strcmp(s_entry1->name,".") == 0) 598 { 599 jrec.name_len[0] = 1; 600 set_733((char *) jrec.extent, dpnt->jextent); 601 set_733((char *) jrec.size, ROUND_UP(dpnt->jsize)); 602 } 603 else if(strcmp(s_entry1->name,"..") == 0) 604 { 605 jrec.name_len[0] = 1; 606 if( dpnt->parent == reloc_dir ) 607 { 608 set_733((char *) jrec.extent, dpnt->self->parent_rec->filedir->jextent); 609 set_733((char *) jrec.size, ROUND_UP(dpnt->self->parent_rec->filedir->jsize)); 610 } 611 else 612 613 { 614 set_733((char *) jrec.extent, dpnt->parent->jextent); 615 set_733((char *) jrec.size, ROUND_UP(dpnt->parent->jsize)); 616 } 617 } 618 else 619 { 620 if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 ) 621 { 622 finddir = reloc_dir->subdir; 623 } 624 else 625 { 626 finddir = dpnt->subdir; 627 } 628 while(1==1) 629 { 630 if(finddir->self == s_entry1) break; 631 finddir = finddir->next; 632 if(!finddir) 633 { 634 fprintf(stderr,"Fatal goof - unable to find directory location\n"); exit(1); 635 } 636 } 637 set_733((char *) jrec.extent, finddir->jextent); 638 set_733((char *) jrec.size, ROUND_UP(finddir->jsize)); 639 } 640 } 641 642 memcpy(directory_buffer + dir_index, &jrec, 643 sizeof(struct iso_directory_record) - 644 sizeof(s_entry1->isorec.name)); 645 646 647 dir_index += sizeof(struct iso_directory_record) - 648 sizeof (s_entry1->isorec.name); 649 650 /* 651 * Finally dump the Unicode version of the filename. 652 * Note - . and .. are the same as with non-Joliet discs. 653 */ 654 if( (jrec.flags[0] & 2) != 0 655 && strcmp(s_entry1->name, ".") == 0 ) 656 { 657 directory_buffer[dir_index++] = 0; 658 } 659 else if( (jrec.flags[0] & 2) != 0 660 && strcmp(s_entry1->name, "..") == 0 ) 661 { 662 directory_buffer[dir_index++] = 1; 663 } 664 else 665 { 666 #ifdef APPLE_HYB 667 if (USE_MAC_NAME(mac_name, s_entry1)) 668 /* Use the HFS name if it exists */ 669 convert_to_unicode((u_char *)directory_buffer + dir_index, 670 cvt_len, 671 s_entry1->hfs_ent->name); 672 else 673 #endif /* APPLE_HYB */ 674 convert_to_unicode((u_char *)directory_buffer + dir_index, 675 cvt_len, 676 s_entry1->name); 677 dir_index += cvt_len; 678 } 679 680 if(dir_index & 1) 681 { 682 directory_buffer[dir_index++] = 0; 683 } 684 685 s_entry = s_entry->jnext; 686 } 687 688 if(dpnt->jsize != dir_index) 689 { 690 fprintf(stderr,"Unexpected joliet directory length %d %d %s\n",dpnt->jsize, 691 dir_index, dpnt->de_name); 692 } 693 694 xfwrite(directory_buffer, 1, total_size, outfile); 695 last_extent_written += total_size >> 11; 696 free(directory_buffer); 697 } /* generate_one_joliet_directory(... */ 698 699 static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir) 700 { 701 struct directory_entry * s_entry; 702 int status = 0; 703 704 /* don't want to skip this directory if it's the reloc_dir at the moment */ 705 if(this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) 706 { 707 return 0; 708 } 709 710 for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 711 { 712 /* skip hidden entries */ 713 if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 ) 714 { 715 continue; 716 } 717 718 /* 719 * First update the path table sizes for directories. 720 * 721 * Finally, set the length of the directory entry if Joliet is used. 722 * The name is longer, but no Rock Ridge is ever used here, so 723 * depending upon the options the entry size might turn out to be about 724 * the same. The Unicode name is always a multiple of 2 bytes, so 725 * we always add 1 to make it an even number. 726 */ 727 if(s_entry->isorec.flags[0] == 2) 728 { 729 if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 730 { 731 #ifdef APPLE_HYB 732 if (USE_MAC_NAME(mac_name, s_entry)) 733 /* Use the HFS name if it exists */ 734 jpath_table_size += joliet_strlen(s_entry->hfs_ent->name) + sizeof(struct iso_path_table) - 1; 735 else 736 #endif /* APPLE_HYB */ 737 jpath_table_size += joliet_strlen(s_entry->name) + sizeof(struct iso_path_table) - 1; 738 if (jpath_table_size & 1) 739 { 740 jpath_table_size++; 741 } 742 } 743 else 744 { 745 if (this_dir == root && strlen(s_entry->name) == 1) 746 { 747 jpath_table_size += sizeof(struct iso_path_table); 748 if (jpath_table_size & 1) jpath_table_size++; 749 } 750 } 751 } 752 753 if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 754 { 755 #ifdef APPLE_HYB 756 if (USE_MAC_NAME(mac_name, s_entry)) 757 /* Use the HFS name if it exists */ 758 s_entry->jreclen = sizeof(struct iso_directory_record) 759 - sizeof(s_entry->isorec.name) 760 + joliet_strlen(s_entry->hfs_ent->name) 761 + 1; 762 else 763 #endif /* APPLE_HYB */ 764 s_entry->jreclen = sizeof(struct iso_directory_record) 765 - sizeof(s_entry->isorec.name) 766 + joliet_strlen(s_entry->name) 767 + 1; 768 } 769 else 770 { 771 /* 772 * Special - for '.' and '..' we generate the same records we 773 * did for non-Joliet discs. 774 */ 775 s_entry->jreclen = sizeof(struct iso_directory_record) 776 - sizeof(s_entry->isorec.name) 777 + 1; 778 } 779 780 781 } 782 783 if( (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0 ) 784 { 785 return 0; 786 } 787 788 this_dir->jcontents = this_dir->contents; 789 status = joliet_sort_directory(&this_dir->jcontents); 790 791 /* 792 * Now go through the directory and figure out how large this one will be. 793 * Do not split a directory entry across a sector boundary 794 */ 795 s_entry = this_dir->jcontents; 796 /* 797 * XXX Is it ok to comment this out? 798 */ 799 /*XXX JS this_dir->ce_bytes = 0;*/ 800 for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext) 801 { 802 int jreclen; 803 804 if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 ) 805 { 806 continue; 807 } 808 809 jreclen = s_entry->jreclen; 810 811 if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >= SECTOR_SIZE) 812 { 813 this_dir->jsize = (this_dir->jsize + (SECTOR_SIZE - 1)) & 814 ~(SECTOR_SIZE - 1); 815 } 816 this_dir->jsize += jreclen; 817 } 818 return status; 819 } 820 821 /* 822 * Similar to the iso9660 case, except here we perform a full sort based upon the 823 * regular name of the file, not the 8.3 version. 824 */ 825 static int FDECL2(joliet_compare_dirs, const void *, rr, const void *, ll) 826 { 827 char * rpnt, *lpnt; 828 struct directory_entry ** r, **l; 829 830 r = (struct directory_entry **) rr; 831 l = (struct directory_entry **) ll; 832 rpnt = (*r)->name; 833 lpnt = (*l)->name; 834 835 /* 836 * If the entries are the same, this is an error. 837 */ 838 if( strcmp(rpnt, lpnt) == 0 ) 839 { 840 sort_goof++; 841 } 842 843 /* 844 * Put the '.' and '..' entries on the head of the sorted list. 845 * For normal ASCII, this always happens to be the case, but out of 846 * band characters cause this not to be the case sometimes. 847 */ 848 if( strcmp(rpnt, ".") == 0 ) return -1; 849 if( strcmp(lpnt, ".") == 0 ) return 1; 850 851 if( strcmp(rpnt, "..") == 0 ) return -1; 852 if( strcmp(lpnt, "..") == 0 ) return 1; 853 854 while(*rpnt && *lpnt) 855 { 856 if(*rpnt == ';' && *lpnt != ';') return -1; 857 if(*rpnt != ';' && *lpnt == ';') return 1; 858 859 if(*rpnt == ';' && *lpnt == ';') return 0; 860 861 /* 862 * Extensions are not special here. Don't treat the dot as something that 863 * must be bumped to the start of the list. 864 */ 865 #if 0 866 if(*rpnt == '.' && *lpnt != '.') return -1; 867 if(*rpnt != '.' && *lpnt == '.') return 1; 868 #endif 869 870 if(*rpnt < *lpnt) return -1; 871 if(*rpnt > *lpnt) return 1; 872 rpnt++; lpnt++; 873 } 874 if(*rpnt) return 1; 875 if(*lpnt) return -1; 876 return 0; 877 } 878 879 880 /* 881 * Function: sort_directory 882 * 883 * Purpose: Sort the directory in the appropriate ISO9660 884 * order. 885 * 886 * Notes: Returns 0 if OK, returns > 0 if an error occurred. 887 */ 888 static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir) 889 { 890 int dcount = 0; 891 int i; 892 struct directory_entry * s_entry; 893 struct directory_entry ** sortlist; 894 895 s_entry = *sort_dir; 896 while(s_entry) 897 { 898 /* skip hidden entries */ 899 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) 900 dcount++; 901 s_entry = s_entry->next; 902 } 903 904 /* 905 * OK, now we know how many there are. Build a vector for sorting. 906 */ 907 sortlist = (struct directory_entry **) 908 e_malloc(sizeof(struct directory_entry *) * dcount); 909 910 dcount = 0; 911 s_entry = *sort_dir; 912 while(s_entry) 913 { 914 /* skip hidden entries */ 915 if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) { 916 sortlist[dcount] = s_entry; 917 dcount++; 918 } 919 s_entry = s_entry->next; 920 } 921 922 sort_goof = 0; 923 #ifdef __STDC__ 924 qsort(sortlist, dcount, sizeof(struct directory_entry *), 925 (int (*)(const void *, const void *))joliet_compare_dirs); 926 #else 927 qsort(sortlist, dcount, sizeof(struct directory_entry *), 928 joliet_compare_dirs); 929 #endif 930 931 /* 932 * Now reassemble the linked list in the proper sorted order 933 */ 934 for(i=0; i<dcount-1; i++) 935 { 936 sortlist[i]->jnext = sortlist[i+1]; 937 } 938 939 sortlist[dcount-1]->jnext = NULL; 940 *sort_dir = sortlist[0]; 941 942 free(sortlist); 943 return sort_goof; 944 } 945 946 int FDECL1(joliet_sort_tree, struct directory *, node) 947 { 948 struct directory * dpnt; 949 int ret = 0; 950 951 dpnt = node; 952 953 while (dpnt){ 954 ret = joliet_sort_n_finish(dpnt); 955 if( ret ) 956 { 957 break; 958 } 959 if(dpnt->subdir) ret = joliet_sort_tree(dpnt->subdir); 960 if( ret ) 961 { 962 break; 963 } 964 dpnt = dpnt->next; 965 } 966 return ret; 967 } 968 969 static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){ 970 struct directory * dpnt; 971 972 dpnt = node; 973 974 while (dpnt) 975 { 976 if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) 977 { 978 /* 979 * In theory we should never reuse a directory, so this doesn't 980 * make much sense. 981 */ 982 if( dpnt->jextent > session_start ) 983 { 984 generate_one_joliet_directory(dpnt, outfile); 985 } 986 } 987 /* skip if hidden - but not for the rr_moved dir */ 988 if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) 989 generate_joliet_directories(dpnt->subdir, outfile); 990 dpnt = dpnt->next; 991 } 992 } 993 994 995 /* 996 * Function to write the EVD for the disc. 997 */ 998 static int FDECL1(jpathtab_write, FILE *, outfile) 999 { 1000 /* 1001 * Next we write the path tables 1002 */ 1003 xfwrite(jpath_table_l, 1, jpath_blocks << 11, outfile); 1004 xfwrite(jpath_table_m, 1, jpath_blocks << 11, outfile); 1005 last_extent_written += 2*jpath_blocks; 1006 free(jpath_table_l); 1007 free(jpath_table_m); 1008 jpath_table_l = NULL; 1009 jpath_table_m = NULL; 1010 return 0; 1011 } 1012 1013 static int FDECL1(jdirtree_size, int, starting_extent) 1014 { 1015 assign_joliet_directory_addresses(root); 1016 return 0; 1017 } 1018 1019 static int jroot_gen() 1020 { 1021 jroot_record.length[0] = 1 + sizeof(struct iso_directory_record) 1022 - sizeof(jroot_record.name); 1023 jroot_record.ext_attr_length[0] = 0; 1024 set_733((char *) jroot_record.extent, root->jextent); 1025 set_733((char *) jroot_record.size, ROUND_UP(root->jsize)); 1026 iso9660_date(jroot_record.date, root_statbuf.st_mtime); 1027 jroot_record.flags[0] = 2; 1028 jroot_record.file_unit_size[0] = 0; 1029 jroot_record.interleave[0] = 0; 1030 set_723(jroot_record.volume_sequence_number, volume_sequence_number); 1031 jroot_record.name_len[0] = 1; 1032 return 0; 1033 } 1034 1035 static int FDECL1(jdirtree_write, FILE *, outfile) 1036 { 1037 generate_joliet_directories(root, outfile); 1038 return 0; 1039 } 1040 1041 /* 1042 * Function to write the EVD for the disc. 1043 */ 1044 static int FDECL1(jvd_write, FILE *, outfile) 1045 { 1046 struct iso_primary_descriptor jvol_desc; 1047 1048 /* 1049 * Next we write out the boot volume descriptor for the disc 1050 */ 1051 jvol_desc = vol_desc; 1052 get_joliet_vol_desc(&jvol_desc); 1053 xfwrite(&jvol_desc, 1, 2048, outfile); 1054 last_extent_written ++; 1055 return 0; 1056 } 1057 1058 /* 1059 * Functions to describe padding block at the start of the disc. 1060 */ 1061 static int FDECL1(jpathtab_size, int, starting_extent) 1062 { 1063 jpath_table[0] = starting_extent; 1064 jpath_table[1] = 0; 1065 jpath_table[2] = jpath_table[0] + jpath_blocks; 1066 jpath_table[3] = 0; 1067 1068 last_extent += 2*jpath_blocks; 1069 return 0; 1070 } 1071 1072 struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen,jvd_write}; 1073 struct output_fragment jpathtable_desc= {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write}; 1074 struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write}; 1075