1 /* 2 * File multi.c - scan existing iso9660 image and merge into 3 * iso9660 filesystem. Used for multisession support. 4 * 5 * Written by Eric Youngdale (1996). 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22 #include <stdlib.h> 23 #include <string.h> 24 #include <time.h> 25 #include <errno.h> 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 29 #include "config.h" 30 31 #ifndef VMS 32 33 #ifdef HAVE_UNISTD_H 34 #include <unistd.h> 35 #endif 36 37 #else 38 #include <sys/file.h> 39 #include <vms/fabdef.h> 40 #include "vms.h" 41 extern char * strdup(const char *); 42 #endif 43 44 #include "mkisofs.h" 45 #include "iso9660.h" 46 47 #define TF_CREATE 1 48 #define TF_MODIFY 2 49 #define TF_ACCESS 4 50 #define TF_ATTRIBUTES 8 51 52 static int isonum_711 __PR((unsigned char * p)); 53 static int isonum_721 __PR((unsigned char * p)); 54 static int isonum_723 __PR((unsigned char * p)); 55 static int isonum_731 __PR((unsigned char * p)); 56 57 static int DECL(merge_old_directory_into_tree, (struct directory_entry *, 58 struct directory *)); 59 60 #ifdef __STDC__ 61 static int 62 isonum_711 (unsigned char * p) 63 #else 64 static int 65 isonum_711 (p) 66 unsigned char * p; 67 #endif 68 { 69 return (*p & 0xff); 70 } 71 72 #ifdef __STDC__ 73 static int 74 isonum_721 (unsigned char * p) 75 #else 76 static int 77 isonum_721 (p) 78 unsigned char * p; 79 #endif 80 { 81 return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); 82 } 83 84 #ifdef __STDC__ 85 static int 86 isonum_723 (unsigned char * p) 87 #else 88 static int 89 isonum_723 (p) 90 unsigned char * p; 91 #endif 92 { 93 #if 0 94 if (p[0] != p[3] || p[1] != p[2]) { 95 fprintf (stderr, "invalid format 7.2.3 number\n"); 96 exit (1); 97 } 98 #endif 99 return (isonum_721 (p)); 100 } 101 102 #ifdef __STDC__ 103 static int 104 isonum_731 (unsigned char * p) 105 #else 106 static int 107 isonum_731 (p) 108 unsigned char * p; 109 #endif 110 { 111 return ((p[0] & 0xff) 112 | ((p[1] & 0xff) << 8) 113 | ((p[2] & 0xff) << 16) 114 | ((p[3] & 0xff) << 24)); 115 } 116 117 #ifdef __STDC__ 118 int 119 isonum_733 (unsigned char * p) 120 #else 121 int 122 isonum_733 (p) 123 unsigned char * p; 124 #endif 125 { 126 return (isonum_731 (p)); 127 } 128 129 FILE * in_image = NULL; 130 131 #ifndef USE_SCG 132 /* 133 * Don't define readsecs if mkisofs is linked with 134 * the SCSI library. 135 * readsecs() will be implemented as SCSI command in this case. 136 * 137 * Use global var in_image directly in readsecs() 138 * the SCSI equivalent will not use a FILE* for I/O. 139 * 140 * The main point of this pointless abstraction is that Solaris won't let 141 * you read 2K sectors from the cdrom driver. The fact that 99.9% of the 142 * discs out there have a 2K sectorsize doesn't seem to matter that much. 143 * Anyways, this allows the use of a scsi-generics type of interface on 144 * Solaris. 145 */ 146 #ifdef __STDC__ 147 static int 148 readsecs(int startsecno, void *buffer, int sectorcount) 149 #else 150 static int 151 readsecs(startsecno, buffer, sectorcount) 152 int startsecno; 153 void *buffer; 154 int sectorcount; 155 #endif 156 { 157 int f = fileno(in_image); 158 159 if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) { 160 fprintf(stderr," Seek error on old image\n"); 161 exit(10); 162 } 163 return (read(f, buffer, sectorcount * SECTOR_SIZE)); 164 } 165 #endif 166 167 /* 168 * Parse the RR attributes so we can find the file name. 169 */ 170 static int 171 FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) 172 { 173 int cont_extent, cont_offset, cont_size; 174 char name_buf[256]; 175 176 cont_extent = cont_offset = cont_size = 0; 177 178 while(len >= 4){ 179 if(pnt[3] != 1) { 180 fprintf(stderr,"**BAD RRVERSION"); 181 return -1; 182 }; 183 if(strncmp((char *) pnt, "NM", 2) == 0) { 184 strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); 185 name_buf[pnt[2] - 5] = 0; 186 dpnt->name = strdup(name_buf); 187 dpnt->got_rr_name = 1; 188 return 0; 189 } 190 191 if(strncmp((char *) pnt, "CE", 2) == 0) { 192 cont_extent = isonum_733(pnt+4); 193 cont_offset = isonum_733(pnt+12); 194 cont_size = isonum_733(pnt+20); 195 }; 196 197 len -= pnt[2]; 198 pnt += pnt[2]; 199 if(len <= 3 && cont_extent) { 200 unsigned char sector[SECTOR_SIZE]; 201 readsecs(cont_extent, sector, 1); 202 parse_rr(§or[cont_offset], cont_size, dpnt); 203 }; 204 }; 205 206 /* Fall back to the iso name if no RR name found */ 207 if (dpnt->name == NULL) { 208 char *cp; 209 210 strcpy(name_buf, dpnt->isorec.name); 211 cp = strchr(name_buf, ';'); 212 if (cp != NULL) { 213 *cp = '\0'; 214 } 215 216 dpnt->name = strdup(name_buf); 217 } 218 219 return 0; 220 } /* parse_rr */ 221 222 223 static int 224 FDECL4(check_rr_dates, struct directory_entry *, dpnt, 225 struct directory_entry *, current, 226 struct stat *, statbuf, 227 struct stat *,lstatbuf) 228 { 229 int cont_extent, cont_offset, cont_size; 230 int offset; 231 unsigned char * pnt; 232 int len; 233 int same_file; 234 int same_file_type; 235 mode_t mode; 236 char time_buf[7]; 237 238 239 cont_extent = cont_offset = cont_size = 0; 240 same_file = 1; 241 same_file_type = 1; 242 243 pnt = dpnt->rr_attributes; 244 len = dpnt->rr_attr_size; 245 /* 246 * We basically need to parse the rr attributes again, and 247 * dig out the dates and file types. 248 */ 249 while(len >= 4){ 250 if(pnt[3] != 1) { 251 fprintf(stderr,"**BAD RRVERSION"); 252 return -1; 253 }; 254 255 /* 256 * If we have POSIX file modes, make sure that the file type 257 * is the same. If it isn't, then we must always 258 * write the new file. 259 */ 260 if(strncmp((char *) pnt, "PX", 2) == 0) { 261 mode = isonum_733(pnt + 4); 262 if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) ) 263 { 264 same_file_type = 0; 265 same_file = 0; 266 } 267 } 268 269 if(strncmp((char *) pnt, "TF", 2) == 0) { 270 offset = 5; 271 if( pnt[4] & TF_CREATE ) 272 { 273 iso9660_date((char *) time_buf, lstatbuf->st_ctime); 274 if(memcmp(time_buf, pnt+offset, 7) == 0) 275 same_file = 0; 276 offset += 7; 277 } 278 if( pnt[4] & TF_MODIFY ) 279 { 280 iso9660_date((char *) time_buf, lstatbuf->st_mtime); 281 if(memcmp(time_buf, pnt+offset, 7) == 0) 282 same_file = 0; 283 offset += 7; 284 } 285 } 286 287 if(strncmp((char *) pnt, "CE", 2) == 0) { 288 cont_extent = isonum_733(pnt+4); 289 cont_offset = isonum_733(pnt+12); 290 cont_size = isonum_733(pnt+20); 291 }; 292 293 len -= pnt[2]; 294 pnt += pnt[2]; 295 if(len <= 3 && cont_extent) { 296 unsigned char sector[SECTOR_SIZE]; 297 298 readsecs(cont_extent, sector, 1); 299 parse_rr(§or[cont_offset], cont_size, dpnt); 300 }; 301 }; 302 303 /* 304 * If we have the same fundamental file type, then it is clearly 305 * safe to reuse the TRANS.TBL entry. 306 */ 307 if( same_file_type ) 308 { 309 current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 310 } 311 312 return same_file; 313 } 314 315 struct directory_entry ** 316 FDECL2(read_merging_directory, struct iso_directory_record *, mrootp, 317 int *, nent) 318 { 319 unsigned char * cpnt; 320 unsigned char * cpnt1; 321 char * dirbuff; 322 int i; 323 struct iso_directory_record * idr; 324 int len; 325 struct directory_entry **pnt; 326 int rlen; 327 struct directory_entry **rtn; 328 int seen_rockridge; 329 unsigned char * tt_buf; 330 int tt_extent; 331 int tt_size; 332 333 static int warning_given = 0; 334 335 /* 336 * First, allocate a buffer large enough to read in the entire 337 * directory. 338 */ 339 dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size)); 340 341 readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff, 342 isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE); 343 344 /* 345 * Next look over the directory, and count up how many entries we 346 * have. 347 */ 348 len = isonum_733((unsigned char *)mrootp->size); 349 i = 0; 350 *nent = 0; 351 while(i < len ) 352 { 353 idr = (struct iso_directory_record *) &dirbuff[i]; 354 if(idr->length[0] == 0) 355 { 356 i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); 357 continue; 358 } 359 (*nent)++; 360 i += idr->length[0]; 361 } 362 363 /* 364 * Now allocate the buffer which will hold the array we are 365 * about to return. 366 */ 367 rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); 368 369 /* 370 * Finally, scan the directory one last time, and pick out the 371 * relevant bits of information, and store it in the relevant 372 * bits of the structure. 373 */ 374 i = 0; 375 pnt = rtn; 376 tt_extent = 0; 377 seen_rockridge = 0; 378 tt_size = 0; 379 while(i < len ) 380 { 381 idr = (struct iso_directory_record *) &dirbuff[i]; 382 if(idr->length[0] == 0) 383 { 384 i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); 385 continue; 386 } 387 *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); 388 (*pnt)->next = NULL; 389 (*pnt)->isorec = *idr; 390 (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent); 391 (*pnt)->size = isonum_733((unsigned char *)idr->size); 392 (*pnt)->priority = 0; 393 (*pnt)->name = NULL; 394 (*pnt)->got_rr_name = 0; 395 (*pnt)->table = NULL; 396 (*pnt)->whole_name = NULL; 397 (*pnt)->filedir = NULL; 398 (*pnt)->parent_rec = NULL; 399 /* 400 * Set this information so that we correctly cache previous 401 * session bits of information. 402 */ 403 (*pnt)->inode = (*pnt)->starting_block; 404 (*pnt)->dev = PREV_SESS_DEV; 405 (*pnt)->rr_attributes = NULL; 406 (*pnt)->rr_attr_size = 0; 407 (*pnt)->total_rr_attr_size = 0; 408 (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY; 409 410 /* 411 * Check for and parse any RR attributes for the file. 412 * All we are really looking for here is the original name 413 * of the file. 414 */ 415 rlen = idr->length[0] & 0xff; 416 cpnt = (unsigned char *) idr; 417 418 rlen -= sizeof(struct iso_directory_record); 419 cpnt += sizeof(struct iso_directory_record); 420 421 rlen += sizeof(idr->name); 422 cpnt -= sizeof(idr->name); 423 424 rlen -= idr->name_len[0]; 425 cpnt += idr->name_len[0]; 426 427 if((idr->name_len[0] & 1) == 0){ 428 cpnt++; 429 rlen--; 430 }; 431 432 if( rlen != 0 ) 433 { 434 (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; 435 (*pnt)->rr_attributes = e_malloc(rlen); 436 memcpy((*pnt)->rr_attributes, cpnt, rlen); 437 seen_rockridge = 1; 438 } 439 440 /* 441 * Now zero out the remainder of the name field. 442 */ 443 cpnt = (unsigned char *) &(*pnt)->isorec.name; 444 cpnt += idr->name_len[0]; 445 memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); 446 447 parse_rr((*pnt)->rr_attributes, rlen, *pnt); 448 449 if( ((*pnt)->isorec.name_len[0] == 1) 450 && ( ((*pnt)->isorec.name[0] == 0) 451 || ((*pnt)->isorec.name[0] == 1)) ) 452 { 453 if( (*pnt)->name != NULL ) 454 { 455 free((*pnt)->name); 456 } 457 if( (*pnt)->whole_name != NULL ) 458 { 459 free((*pnt)->whole_name); 460 } 461 if( (*pnt)->isorec.name[0] == 0 ) 462 { 463 (*pnt)->name = strdup("."); 464 } 465 else 466 { 467 (*pnt)->name = strdup(".."); 468 } 469 } 470 471 #ifdef DEBUG 472 fprintf(stderr, "got DE name: %s\n", (*pnt)->name); 473 #endif 474 475 #ifdef APPLE_HYB 476 if( strncmp(idr->name, trans_tbl, strlen(trans_tbl)) == 0) 477 #else 478 if( strncmp(idr->name, "TRANS.TBL", 9) == 0) 479 #endif /* APPLE_HYB */ 480 { 481 if( (*pnt)->name != NULL ) 482 { 483 free((*pnt)->name); 484 } 485 if( (*pnt)->whole_name != NULL ) 486 { 487 free((*pnt)->whole_name); 488 } 489 (*pnt)->name = strdup("<translation table>"); 490 tt_extent = isonum_733((unsigned char *)idr->extent); 491 tt_size = isonum_733((unsigned char *)idr->size); 492 } 493 494 pnt++; 495 i += idr->length[0]; 496 } 497 498 /* 499 * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it 500 * to get the filenames of the files. Also, save the table info, just 501 * in case we need to use it. 502 */ 503 if( tt_extent != 0 && tt_size != 0 ) 504 { 505 tt_buf = (unsigned char *) e_malloc(tt_size); 506 readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE); 507 508 /* 509 * Loop through the file, examine each entry, and attempt to 510 * attach it to the correct entry. 511 */ 512 cpnt = tt_buf; 513 cpnt1 = tt_buf; 514 while( cpnt - tt_buf < tt_size ) 515 { 516 while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; 517 *cpnt1 = '\0'; 518 519 for(pnt = rtn, i = 0; i <*nent; i++, pnt++) 520 { 521 rlen = isonum_711((*pnt)->isorec.name_len); 522 if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, 523 rlen) == 0 524 && cpnt[2+rlen] == ' ') 525 { 526 (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33); 527 sprintf((*pnt)->table, "%c\t%s\n", 528 *cpnt, cpnt+37); 529 if( !(*pnt)->got_rr_name ) 530 { 531 if ((*pnt)->name != NULL) { 532 free((*pnt)->name); 533 } 534 (*pnt)->name = strdup((char *) cpnt+37); 535 } 536 break; 537 } 538 } 539 cpnt = cpnt1 + 1; 540 cpnt1 = cpnt; 541 } 542 543 free(tt_buf); 544 } 545 else if( !seen_rockridge && !warning_given ) 546 { 547 /* 548 * Warn the user that iso (8.3) names were used because neither 549 * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found. 550 */ 551 fprintf(stderr,"Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) \n"); 552 fprintf(stderr,"name translations were found on previous session.\n"); 553 fprintf(stderr,"ISO (8.3) file names have been used instead.\n"); 554 warning_given = 1; 555 } 556 557 if( dirbuff != NULL ) 558 { 559 free(dirbuff); 560 } 561 562 return rtn; 563 } /* read_merging_directory */ 564 565 /* 566 * Free any associated data related to the structures. 567 */ 568 int 569 FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len ) 570 { 571 int i; 572 struct directory_entry **p; 573 574 p = ptr; 575 for(i=0; i<len; i++, p++) 576 { 577 /* 578 * If the tree-handling code decided that it needed an entry, 579 * it will have removed it from the list. Thus we must allow 580 * for null pointers here. 581 */ 582 if( *p == NULL ) 583 { 584 continue; 585 } 586 587 if( (*p)->name != NULL ) 588 { 589 free((*p)->name); 590 } 591 592 if( (*p)->whole_name != NULL ) 593 { 594 free((*p)->whole_name); 595 } 596 597 if( (*p)->rr_attributes != NULL ) 598 { 599 free((*p)->rr_attributes); 600 } 601 602 if( (*p)->table != NULL ) 603 { 604 free((*p)->table); 605 } 606 607 free(*p); 608 609 } 610 611 free(ptr); 612 return 0; 613 } 614 615 /* 616 * Search the list to see if we have any entries from the previous 617 * session that match this entry. If so, copy the extent number 618 * over so we don't bother to write it out to the new session. 619 */ 620 621 int 622 FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len, 623 struct directory_entry *, curr_entry, 624 struct stat *, statbuf, struct stat *, lstatbuf, 625 struct directory_entry **, odpnt) 626 { 627 int i; 628 629 for( i=0; i < len; i++ ) 630 { 631 if( ptr[i] == NULL ) 632 { 633 continue; 634 } 635 636 #if 0 637 if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 638 && ptr[i]->name[0] == '\0' ) 639 { 640 continue; 641 } 642 if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 643 && ptr[i]->name[0] == 1) 644 { 645 continue; 646 } 647 #else 648 if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 ) 649 { 650 continue; 651 } 652 if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 ) 653 { 654 continue; 655 } 656 #endif 657 658 if( ptr[i]->name != NULL 659 && strcmp(ptr[i]->name, curr_entry->name) != 0 ) 660 { 661 continue; 662 } 663 664 /* 665 * We know that the files have the same name. If they also have 666 * the same file type (i.e. file, dir, block, etc), then we 667 * can safely reuse the TRANS.TBL entry for this file. 668 * The check_rr_dates function will do this for us. 669 * 670 * Verify that the file type and dates are consistent. 671 * If not, we probably have a different file, and we need 672 * to write it out again. 673 */ 674 if( (ptr[i]->rr_attributes != NULL) 675 && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) 676 { 677 goto found_it; 678 } 679 680 681 /* 682 * Verify size and timestamp. If rock ridge is in use, we need 683 * to compare dates from RR too. Directories are special, we 684 * calculate their size later. 685 */ 686 if( (curr_entry->isorec.flags[0] & 2) == 0 687 && ptr[i]->size != curr_entry->size ) 688 { 689 goto found_it; 690 } 691 692 if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) 693 { 694 goto found_it; 695 } 696 697 /* 698 * Never ever reuse directory extents. See comments in 699 * tree.c for an explaination of why this must be the case. 700 */ 701 if( (curr_entry->isorec.flags[0] & 2) != 0 ) 702 { 703 goto found_it; 704 } 705 706 memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); 707 curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 708 goto found_it; 709 } 710 return 0; 711 712 found_it: 713 if( odpnt != NULL ) 714 { 715 *odpnt = ptr[i]; 716 } 717 else 718 { 719 free(ptr[i]); 720 } 721 ptr[i] = NULL; 722 return 0; 723 } 724 725 /* 726 * merge_isofs: Scan an existing image, and return a pointer 727 * to the root directory for this image. 728 */ 729 struct iso_directory_record * FDECL1(merge_isofs, char *, path) 730 { 731 char buffer[SECTOR_SIZE]; 732 int file_addr; 733 int i; 734 struct iso_primary_descriptor * pri = NULL; 735 struct iso_directory_record * rootp; 736 struct iso_volume_descriptor * vdp; 737 738 /* 739 * Start by opening up the image and searching for the volume header. 740 * Ultimately, we need to search for volume headers in multiple places 741 * because we might be starting with a multisession image. 742 * FIXME(eric). 743 */ 744 745 #ifndef USE_SCG 746 in_image = fopen(path, "rb"); 747 if( in_image == NULL ) 748 { 749 return NULL; 750 } 751 #else 752 if (strchr(path, '/')) { 753 in_image = fopen(path, "rb"); 754 if( in_image == NULL ) { 755 return NULL; 756 } 757 } else { 758 if (scsidev_open(path) < 0) 759 return NULL; 760 } 761 #endif 762 763 get_session_start(&file_addr); 764 765 for(i = 0; i< 100; i++) 766 { 767 if (readsecs(file_addr/SECTOR_SIZE, &buffer, 768 sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer)) 769 { 770 fprintf(stderr," Read error on old image %s\n", path); 771 exit(10); 772 } 773 774 vdp = (struct iso_volume_descriptor *)buffer; 775 776 if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) 777 && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) ) 778 { 779 break; 780 } 781 file_addr += SECTOR_SIZE; 782 } 783 784 if( i == 100 ) 785 { 786 return NULL; 787 } 788 789 pri = (struct iso_primary_descriptor *)vdp; 790 791 /* 792 * Check the blocksize of the image to make sure it is compatible. 793 */ 794 if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE) 795 || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) ) 796 { 797 return NULL; 798 } 799 800 /* 801 * Get the location and size of the root directory. 802 */ 803 rootp = calloc(1, sizeof(struct iso_directory_record)); 804 805 memcpy(rootp, pri->root_directory_record, sizeof(pri->root_directory_record)); 806 807 return rootp; 808 } 809 810 void FDECL3(merge_remaining_entries, struct directory *, this_dir, 811 struct directory_entry **, pnt, 812 int, n_orig) 813 { 814 int i; 815 struct directory_entry * s_entry; 816 unsigned int ttbl_extent = 0; 817 unsigned int ttbl_index = 0; 818 char whole_path[1024]; 819 820 /* 821 * Whatever is leftover in the list needs to get merged back 822 * into the directory. 823 */ 824 for( i=0; i < n_orig; i++ ) 825 { 826 if( pnt[i] == NULL ) 827 { 828 continue; 829 } 830 831 if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL) 832 { 833 /* 834 * Set the name for this directory. 835 */ 836 strcpy(whole_path, this_dir->de_name); 837 strcat(whole_path, SPATH_SEPARATOR); 838 strcat(whole_path, pnt[i]->name); 839 840 pnt[i]->whole_name = strdup(whole_path); 841 } 842 843 if( pnt[i]->name != NULL 844 && strcmp(pnt[i]->name, "<translation table>") == 0 ) 845 { 846 ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent); 847 ttbl_index = i; 848 continue; 849 } 850 /* 851 * Skip directories for now - these need to be treated 852 * differently. 853 */ 854 if( (pnt[i]->isorec.flags[0] & 2) != 0 ) 855 { 856 /* 857 * FIXME - we need to insert this directory into the 858 * tree, so that the path tables we generate will 859 * be correct. 860 */ 861 if( (strcmp(pnt[i]->name, ".") == 0) 862 || (strcmp(pnt[i]->name, "..") == 0) ) 863 { 864 free(pnt[i]); 865 pnt[i] = NULL; 866 continue; 867 } 868 else 869 { 870 merge_old_directory_into_tree(pnt[i], this_dir); 871 } 872 } 873 pnt[i]->next = this_dir->contents; 874 pnt[i]->filedir = this_dir; 875 this_dir->contents = pnt[i]; 876 pnt[i] = NULL; 877 } 878 879 880 /* 881 * If we don't have an entry for the translation table, then 882 * don't bother trying to copy the starting extent over. 883 * Note that it is possible that if we are copying the entire 884 * directory, the entry for the translation table will have already 885 * been inserted into the linked list and removed from the old 886 * entries list, in which case we want to leave the extent number 887 * as it was before. 888 */ 889 if( ttbl_extent == 0 ) 890 { 891 return; 892 } 893 894 /* 895 * Finally, check the directory we are creating to see whether 896 * there are any new entries in it. If there are not, we can 897 * reuse the same translation table. 898 */ 899 for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 900 { 901 /* 902 * Don't care about '.' or '..'. They are never in the table 903 * anyways. 904 */ 905 if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 ) 906 { 907 continue; 908 } 909 if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 ) 910 { 911 continue; 912 } 913 if( strcmp(s_entry->name, "<translation table>") == 0) 914 { 915 continue; 916 } 917 if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 ) 918 { 919 return; 920 } 921 } 922 923 /* 924 * Locate the translation table, and re-use the same extent. 925 * It isn't clear that there should ever be one in there already 926 * so for now we try and muddle through the best we can. 927 */ 928 for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 929 { 930 if( strcmp(s_entry->name, "<translation table>") == 0) 931 { 932 fprintf(stderr,"Should never get here\n"); 933 set_733(s_entry->isorec.extent, ttbl_extent); 934 return; 935 } 936 } 937 938 pnt[ttbl_index]->next = this_dir->contents; 939 pnt[ttbl_index]->filedir = this_dir; 940 this_dir->contents = pnt[ttbl_index]; 941 pnt[ttbl_index] = NULL; 942 } 943 944 945 /* 946 * Here we have a case of a directory that has completely disappeared from 947 * the face of the earth on the tree we are mastering from. Go through and 948 * merge it into the tree, as well as everything beneath it. 949 * 950 * Note that if a directory has been moved for some reason, this will 951 * incorrectly pick it up and attempt to merge it back into the old 952 * location. FIXME(eric). 953 */ 954 static int 955 FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, 956 struct directory *, parent) 957 { 958 struct directory_entry **contents = NULL; 959 int i; 960 int n_orig; 961 struct directory * this_dir, *next_brother; 962 char whole_path[1024]; 963 964 this_dir = (struct directory *) e_malloc(sizeof(struct directory)); 965 memset(this_dir, 0, sizeof(struct directory)); 966 this_dir->next = NULL; 967 this_dir->subdir = NULL; 968 this_dir->self = dpnt; 969 this_dir->contents = NULL; 970 this_dir->size = 0; 971 this_dir->extent = 0; 972 this_dir->depth = parent->depth + 1; 973 this_dir->parent = parent; 974 if(!parent->subdir) 975 parent->subdir = this_dir; 976 else { 977 next_brother = parent->subdir; 978 while(next_brother->next) next_brother = next_brother->next; 979 next_brother->next = this_dir; 980 } 981 982 /* 983 * Set the name for this directory. 984 */ 985 strcpy(whole_path, parent->de_name); 986 strcat(whole_path, SPATH_SEPARATOR); 987 strcat(whole_path, dpnt->name); 988 this_dir->de_name = strdup(whole_path); 989 this_dir->whole_name = strdup(whole_path); 990 991 /* 992 * Now fill this directory using information from the previous 993 * session. 994 */ 995 contents = read_merging_directory(&dpnt->isorec, &n_orig); 996 /* 997 * Start by simply copying the '.', '..' and non-directory 998 * entries to this directory. Technically we could let 999 * merge_remaining_entries handle this, but it gets rather confused 1000 * by the '.' and '..' entries. 1001 */ 1002 for(i=0; i < n_orig; i ++ ) 1003 { 1004 /* 1005 * We can always reuse the TRANS.TBL in this particular case. 1006 */ 1007 contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; 1008 1009 if( ((contents[i]->isorec.flags[0] & 2) != 0) 1010 && (i >= 2) ) 1011 { 1012 continue; 1013 } 1014 1015 /* 1016 * If we have a directory, don't reuse the extent number. 1017 */ 1018 if( (contents[i]->isorec.flags[0] & 2) != 0 ) 1019 { 1020 memset(contents[i]->isorec.extent, 0, 8); 1021 1022 if( strcmp(contents[i]->name, ".") == 0 ) 1023 this_dir->dir_flags |= DIR_HAS_DOT; 1024 1025 if( strcmp(contents[i]->name, "..") == 0 ) 1026 this_dir->dir_flags |= DIR_HAS_DOTDOT; 1027 } 1028 1029 /* 1030 * Set the whole name for this file. 1031 */ 1032 strcpy(whole_path, this_dir->whole_name); 1033 strcat(whole_path, SPATH_SEPARATOR); 1034 strcat(whole_path, contents[i]->name); 1035 1036 contents[i]->whole_name = strdup(whole_path); 1037 1038 contents[i]->next = this_dir->contents; 1039 contents[i]->filedir = this_dir; 1040 this_dir->contents = contents[i]; 1041 contents[i] = NULL; 1042 } 1043 1044 /* 1045 * Zero the extent number for ourselves. 1046 */ 1047 memset(dpnt->isorec.extent, 0, 8); 1048 1049 /* 1050 * Anything that is left are other subdirectories that need to be merged. 1051 */ 1052 merge_remaining_entries(this_dir, contents, n_orig); 1053 free_mdinfo(contents, n_orig); 1054 #if 0 1055 /* 1056 * This is no longer required. The post-scan sort will handle 1057 * all of this for us. 1058 */ 1059 sort_n_finish(this_dir); 1060 #endif 1061 1062 return 0; 1063 } 1064 1065 1066 char * cdwrite_data = NULL; 1067 1068 int 1069 FDECL1(get_session_start, int *, file_addr) 1070 { 1071 char * pnt; 1072 1073 #ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS 1074 /* 1075 * FIXME(eric). We need to coordinate with cdwrite to obtain 1076 * the parameters. For now, we assume we are writing the 2nd session, 1077 * so we start from the session that starts at 0. 1078 */ 1079 1080 *file_addr = (16 << 11); 1081 1082 /* 1083 * We need to coordinate with cdwrite to get the next writable address 1084 * from the device. Here is where we use it. 1085 */ 1086 session_start = last_extent = last_extent_written = cdwrite_result(); 1087 1088 #else 1089 1090 if( cdwrite_data == NULL ) 1091 { 1092 fprintf(stderr,"Special parameters for cdwrite not specified with -C\n"); 1093 exit(1); 1094 } 1095 1096 /* 1097 * Next try and find the ',' in there which delimits the two numbers. 1098 */ 1099 pnt = strchr(cdwrite_data, ','); 1100 if( pnt == NULL ) 1101 { 1102 fprintf(stderr, "Malformed cdwrite parameters\n"); 1103 exit(1); 1104 } 1105 1106 *pnt = '\0'; 1107 if (file_addr != NULL) { 1108 *file_addr = atol(cdwrite_data) * SECTOR_SIZE; 1109 } 1110 pnt++; 1111 1112 session_start = last_extent = last_extent_written = atol(pnt); 1113 1114 pnt--; 1115 *pnt = ','; 1116 1117 #endif 1118 return 0; 1119 } 1120 1121 /* 1122 * This function scans the directory tree, looking for files, and it makes 1123 * note of everything that is found. We also begin to construct the ISO9660 1124 * directory entries, so that we can determine how large each directory is. 1125 */ 1126 1127 int 1128 FDECL2(merge_previous_session,struct directory *, this_dir, 1129 struct iso_directory_record *, mrootp) 1130 { 1131 struct directory_entry **orig_contents = NULL; 1132 struct directory_entry * odpnt = NULL; 1133 int n_orig; 1134 struct directory_entry * s_entry; 1135 int status, lstatus; 1136 struct stat statbuf, lstatbuf; 1137 1138 /* 1139 * Parse the same directory in the image that we are merging 1140 * for multisession stuff. 1141 */ 1142 orig_contents = read_merging_directory(mrootp, &n_orig); 1143 if( orig_contents == NULL ) 1144 { 1145 return 0; 1146 } 1147 1148 1149 /* Now we scan the directory itself, and look at what is inside of it. */ 1150 1151 for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) 1152 { 1153 status = stat_filter(s_entry->whole_name, &statbuf); 1154 lstatus = lstat_filter(s_entry->whole_name, &lstatbuf); 1155 1156 /* 1157 * We always should create an entirely new directory tree whenever 1158 * we generate a new session, unless there were *no* changes whatsoever 1159 * to any of the directories, in which case it would be kind of pointless 1160 * to generate a new session. 1161 * 1162 * I believe it is possible to rigorously prove that any change anywhere 1163 * in the filesystem will force the entire tree to be regenerated 1164 * because the modified directory will get a new extent number. Since 1165 * each subdirectory of the changed directory has a '..' entry, all of 1166 * them will need to be rewritten too, and since the parent directory 1167 * of the modified directory will have an extent pointer to the directory 1168 * it too will need to be rewritten. Thus we will never be able to reuse 1169 * any directory information when writing new sessions. 1170 * 1171 * We still check the previous session so we can mark off the equivalent 1172 * entry in the list we got from the original disc, however. 1173 */ 1174 1175 /* 1176 * The check_prev_session function looks for an identical entry in 1177 * the previous session. If we see it, then we copy the extent 1178 * number to s_entry, and cross it off the list. 1179 */ 1180 check_prev_session(orig_contents, n_orig, s_entry, 1181 &statbuf, &lstatbuf, &odpnt); 1182 1183 if(S_ISDIR(statbuf.st_mode) && odpnt != NULL) 1184 { 1185 int dflag; 1186 1187 if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) 1188 { 1189 struct directory * child; 1190 1191 child = find_or_create_directory(this_dir, 1192 s_entry->whole_name, 1193 s_entry, 1); 1194 dflag = merge_previous_session(child, 1195 &odpnt->isorec); 1196 /* If unable to scan directory, mark this as a non-directory */ 1197 if(!dflag) 1198 lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; 1199 free(odpnt); 1200 odpnt = NULL; 1201 } 1202 } 1203 } 1204 1205 /* 1206 * Whatever is left over, are things which are no longer in the tree 1207 * on disk. We need to also merge these into the tree. 1208 */ 1209 merge_remaining_entries(this_dir, orig_contents, n_orig); 1210 free_mdinfo(orig_contents, n_orig); 1211 1212 return 1; 1213 } 1214 1215