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