1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999,2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 /* 29 * fsck_pcfs -- routines for manipulating clusters. 30 */ 31 #include <stdio.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <libintl.h> 36 #include <errno.h> 37 #include <sys/dktp/fdisk.h> 38 #include <sys/fs/pc_fs.h> 39 #include <sys/fs/pc_dir.h> 40 #include <sys/fs/pc_label.h> 41 #include "pcfs_common.h" 42 #include "fsck_pcfs.h" 43 44 extern ClusterContents TheRootDir; 45 extern off64_t FirstClusterOffset; 46 extern off64_t PartitionOffset; 47 extern int32_t BytesPerCluster; 48 extern int32_t TotalClusters; 49 extern int32_t LastCluster; 50 extern int32_t RootDirSize; 51 extern int32_t FATSize; 52 extern bpb_t TheBIOSParameterBlock; 53 extern short FATEntrySize; 54 extern int RootDirModified; 55 extern int OkayToRelink; 56 extern int ReadOnly; 57 extern int IsFAT32; 58 extern int Verbose; 59 60 static struct pcdir BlankPCDIR; 61 static CachedCluster *ClusterCache; 62 static ClusterInfo **InUse; 63 static int32_t ReservedClusterCount; 64 static int32_t AllocedClusterCount; 65 static int32_t FreeClusterCount; 66 static int32_t BadClusterCount; 67 68 /* 69 * Internal statistics 70 */ 71 static int32_t CachedClusterCount; 72 73 int32_t HiddenClusterCount; 74 int32_t FileClusterCount; 75 int32_t DirClusterCount; 76 int32_t HiddenFileCount; 77 int32_t FileCount; 78 int32_t DirCount; 79 80 static int32_t orphanSizeLookup(int32_t clusterNum); 81 82 static void 83 freeNameInfo(int32_t clusterNum) 84 { 85 /* silent failure for bogus clusters */ 86 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 87 return; 88 if (InUse[clusterNum - FIRST_CLUSTER]->path != NULL) { 89 if (InUse[clusterNum - FIRST_CLUSTER]->path->references > 1) { 90 InUse[clusterNum - FIRST_CLUSTER]->path->references--; 91 } else { 92 free(InUse[clusterNum - FIRST_CLUSTER]->path->fullName); 93 free(InUse[clusterNum - FIRST_CLUSTER]->path); 94 } 95 InUse[clusterNum - FIRST_CLUSTER]->path = NULL; 96 } 97 } 98 99 static void 100 printOrphanPath(int32_t clusterNum) 101 { 102 /* silent failure for bogus clusters */ 103 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 104 return; 105 if (InUse[clusterNum - FIRST_CLUSTER]->path != NULL) { 106 (void) printf(gettext("\nOrphaned allocation units originally " 107 "allocated to:\n")); 108 (void) printf("%s\n", 109 InUse[clusterNum - FIRST_CLUSTER]->path->fullName); 110 freeNameInfo(clusterNum); 111 } else { 112 (void) printf(gettext("\nOrphaned allocation units originally " 113 "allocated to an unknown file or directory:\n")); 114 (void) printf(gettext("Orphaned chain begins with allocation " 115 "unit %d.\n"), clusterNum); 116 } 117 } 118 119 static void 120 printOrphanSize(int32_t clusterNum) 121 { 122 int32_t size = orphanSizeLookup(clusterNum); 123 124 if (size > 0) { 125 (void) printf(gettext("%d bytes in the orphaned chain of " 126 "allocation units.\n"), size); 127 if (Verbose) { 128 (void) printf(gettext("[Starting at allocation " 129 "unit %d]\n"), clusterNum); 130 } 131 } 132 } 133 134 static void 135 printOrphanInfo(int32_t clusterNum) 136 { 137 printOrphanPath(clusterNum); 138 printOrphanSize(clusterNum); 139 } 140 141 static int 142 askAboutFreeing(int32_t clusterNum) 143 { 144 /* 145 * If it is not OkayToRelink, we haven't already printed the size 146 * of the orphaned chain. 147 */ 148 if (!OkayToRelink) 149 printOrphanInfo(clusterNum); 150 /* 151 * If we are in preen mode, preenBail won't return. 152 */ 153 preenBail("Need user confirmation to free orphaned chain.\n"); 154 155 (void) printf( 156 gettext("Free the allocation units in the orphaned chain ? " 157 "(y/n) ")); 158 return (yes()); 159 } 160 161 static int 162 askAboutRelink(int32_t clusterNum) 163 { 164 /* 165 * Display the size of the chain for the user to consider. 166 */ 167 printOrphanInfo(clusterNum); 168 /* 169 * If we are in preen mode, preenBail won't return. 170 */ 171 preenBail("Need user confirmation to re-link orphaned chain.\n"); 172 173 (void) printf(gettext("Re-link orphaned chain into file system ? " 174 "(y/n) ")); 175 176 return (yes()); 177 } 178 179 static int 180 isHidden(int32_t clusterNum) 181 { 182 /* silent failure for bogus clusters */ 183 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 184 return (0); 185 186 if (InUse[clusterNum - FIRST_CLUSTER] == NULL) 187 return (0); 188 189 return (InUse[clusterNum - FIRST_CLUSTER]->flags & CLINFO_HIDDEN); 190 } 191 192 static int 193 isInUse(int32_t clusterNum) 194 { 195 /* silent failure for bogus clusters */ 196 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 197 return (0); 198 199 return ((InUse[clusterNum - FIRST_CLUSTER] != NULL) && 200 (InUse[clusterNum - FIRST_CLUSTER]->dirent != NULL)); 201 } 202 203 /* 204 * Caller's may request that we cache the data from a readCluster. 205 * The xxxClusterxxxCachexxx routines handle looking for cached data 206 * or initially caching the data. 207 * 208 * XXX - facilitate releasing cached data for low memory situations. 209 */ 210 static CachedCluster * 211 findClusterCacheEntry(int32_t clusterNum) 212 { 213 CachedCluster *loop = ClusterCache; 214 215 while (loop != NULL) { 216 if (loop->clusterNum == clusterNum) 217 return (loop); 218 loop = loop->next; 219 } 220 return (NULL); 221 } 222 223 static uchar_t * 224 findClusterDataInTheCache(int32_t clusterNum) 225 { 226 CachedCluster *loop = ClusterCache; 227 228 while (loop) { 229 if (loop->clusterNum == clusterNum) 230 return (loop->clusterData.bytes); 231 loop = loop->next; 232 } 233 return (NULL); 234 } 235 236 static uchar_t * 237 addToCache(int32_t clusterNum, uchar_t *buf, int32_t *datasize) 238 { 239 CachedCluster *new; 240 uchar_t *cp; 241 242 if ((new = (CachedCluster *)malloc(sizeof (CachedCluster))) == NULL) { 243 perror(gettext("No memory for cached cluster info")); 244 return (buf); 245 } 246 new->clusterNum = clusterNum; 247 new->modified = 0; 248 249 if ((cp = (uchar_t *)calloc(1, BytesPerCluster)) == NULL) { 250 perror(gettext("No memory for cached copy of cluster")); 251 free(new); 252 return (buf); 253 } 254 (void) memcpy(cp, buf, *datasize); 255 new->clusterData.bytes = cp; 256 257 if (Verbose) { 258 (void) fprintf(stderr, 259 gettext("Allocation unit %d cached.\n"), clusterNum); 260 } 261 if (ClusterCache == NULL) { 262 ClusterCache = new; 263 new->next = NULL; 264 } else if (new->clusterNum < ClusterCache->clusterNum) { 265 new->next = ClusterCache; 266 ClusterCache = new; 267 } else { 268 CachedCluster *loop = ClusterCache; 269 CachedCluster *trailer = NULL; 270 271 while (loop && new->clusterNum > loop->clusterNum) { 272 trailer = loop; 273 loop = loop->next; 274 } 275 trailer->next = new; 276 if (loop) { 277 new->next = loop; 278 } else { 279 new->next = NULL; 280 } 281 } 282 CachedClusterCount++; 283 return (new->clusterData.bytes); 284 } 285 286 static int 287 seekCluster(int fd, int32_t clusterNum) 288 { 289 off64_t seekto; 290 int saveError; 291 292 seekto = FirstClusterOffset + 293 ((off64_t)clusterNum - FIRST_CLUSTER) * BytesPerCluster; 294 if (lseek64(fd, seekto, SEEK_SET) != seekto) { 295 saveError = errno; 296 (void) fprintf(stderr, 297 gettext("Seek to Allocation unit #%d failed: "), 298 clusterNum); 299 (void) fprintf(stderr, strerror(saveError)); 300 (void) fprintf(stderr, "\n"); 301 return (0); 302 } 303 return (1); 304 } 305 306 /* 307 * getcluster 308 * Get cluster bytes off the disk. We always read those bytes into 309 * the same static buffer. If the caller wants its own copy of the 310 * data it'll have to make its own copy. We'll return all the data 311 * read, even if it's short of a full cluster. This is for future use 312 * when we might want to relocate any salvagable data from bad clusters. 313 */ 314 static int 315 getCluster(int fd, int32_t clusterNum, uchar_t **data, int32_t *datasize) 316 { 317 static uchar_t *clusterBuffer = NULL; 318 int saveError; 319 int try; 320 321 *datasize = 0; 322 *data = NULL; 323 324 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 325 return (RDCLUST_BADINPUT); 326 327 if (clusterBuffer == NULL && 328 (clusterBuffer = (uchar_t *)malloc(BytesPerCluster)) == NULL) { 329 perror(gettext("No memory for a cluster data buffer")); 330 return (RDCLUST_MEMERR); 331 } 332 333 for (try = 0; try < RDCLUST_MAX_RETRY; try++) { 334 if (!seekCluster(fd, clusterNum)) 335 return (RDCLUST_FAIL); 336 if ((*datasize = read(fd, clusterBuffer, BytesPerCluster)) == 337 BytesPerCluster) { 338 *data = clusterBuffer; 339 return (RDCLUST_GOOD); 340 } 341 } 342 if (*datasize >= 0) { 343 *data = clusterBuffer; 344 (void) fprintf(stderr, 345 gettext("Short read of allocation unit #%d\n"), clusterNum); 346 } else { 347 saveError = errno; 348 (void) fprintf(stderr, "Allocation unit %d:", clusterNum); 349 (void) fprintf(stderr, strerror(saveError)); 350 (void) fprintf(stderr, "\n"); 351 } 352 return (RDCLUST_FAIL); 353 } 354 355 static void 356 writeCachedCluster(int fd, CachedCluster *clustInfo) 357 { 358 ssize_t bytesWritten; 359 360 if (ReadOnly) 361 return; 362 363 if (Verbose) 364 (void) fprintf(stderr, 365 gettext("Allocation unit %d modified.\n"), 366 clustInfo->clusterNum); 367 368 if (seekCluster(fd, clustInfo->clusterNum) == 0) 369 return; 370 371 if ((bytesWritten = write(fd, clustInfo->clusterData.bytes, 372 BytesPerCluster)) != BytesPerCluster) { 373 if (bytesWritten < 0) { 374 perror(gettext("Failed to write modified " 375 "allocation unit")); 376 } else { 377 (void) fprintf(stderr, 378 gettext("Short write of allocation unit %d\n"), 379 clustInfo->clusterNum); 380 } 381 (void) close(fd); 382 exit(13); 383 } 384 } 385 386 /* 387 * It's cheaper to allocate a lot at a time; malloc overhead pushes 388 * you over the brink much more quickly if you don't. 389 * This numbers seems to be a fair trade-off between reduced malloc overhead 390 * and additional overhead by over-allocating. 391 */ 392 393 #define CHUNKSIZE 1024 394 395 static ClusterInfo *pool; 396 397 static ClusterInfo * 398 newClusterInfo(void) 399 { 400 401 ClusterInfo *ret; 402 403 if (pool == NULL) { 404 int i; 405 406 pool = (ClusterInfo *)malloc(sizeof (ClusterInfo) * CHUNKSIZE); 407 408 if (pool == NULL) { 409 perror( 410 gettext("Out of memory for cluster information")); 411 exit(9); 412 } 413 414 for (i = 0; i < CHUNKSIZE - 1; i++) 415 pool[i].nextfree = &pool[i+1]; 416 417 pool[CHUNKSIZE-1].nextfree = NULL; 418 } 419 ret = pool; 420 pool = pool->nextfree; 421 422 memset(ret, 0, sizeof (*ret)); 423 424 return (ret); 425 } 426 427 /* Should be called with verified arguments */ 428 429 static ClusterInfo * 430 cloneClusterInfo(int32_t clusterNum) 431 { 432 ClusterInfo *cl = InUse[clusterNum - FIRST_CLUSTER]; 433 434 if (cl->refcnt > 1) { 435 ClusterInfo *newCl = newClusterInfo(); 436 cl->refcnt--; 437 *newCl = *cl; 438 newCl->refcnt = 1; 439 if (newCl->path) 440 newCl->path->references++; 441 InUse[clusterNum - FIRST_CLUSTER] = newCl; 442 } 443 return (InUse[clusterNum - FIRST_CLUSTER]); 444 } 445 446 static void 447 updateFlags(int32_t clusterNum, int newflags) 448 { 449 ClusterInfo *cl = InUse[clusterNum - FIRST_CLUSTER]; 450 451 if (cl->flags != newflags && cl->refcnt > 1) 452 cl = cloneClusterInfo(clusterNum); 453 454 cl->flags = newflags; 455 } 456 457 static void 458 freeClusterInfo(ClusterInfo *old) 459 { 460 if (--old->refcnt <= 0) { 461 if (old->path && --old->path->references <= 0) { 462 free(old->path->fullName); 463 free(old->path); 464 } 465 old->nextfree = pool; 466 pool = old; 467 } 468 } 469 470 /* 471 * Allocate entries in our sparse array of cluster information. 472 * Returns non-zero if the structure already has been allocated 473 * (for those keeping score at home). 474 * 475 * The template parameter, if non-NULL, is used to facilitate sharing 476 * the ClusterInfo nodes for the clusters belonging to the same file. 477 * The first call to allocInUse for a new file should have *template 478 * set to 0; on return, *template then points to the newly allocated 479 * ClusterInfo. Second and further calls keep the same value 480 * in *template and that ClusterInfo ndoe is then used for all 481 * entries in the file. Code that modifies the ClusterInfo nodes 482 * should take care proper sharing semantics are maintained (i.e., 483 * copy-on-write using cloneClusterInfo()) 484 * 485 * The ClusterInfo used in the template is guaranted to be in use in 486 * at least one other cluster as we never return a value if we didn't 487 * set it first. So we can overwrite it without the possibility of a leak. 488 */ 489 static int 490 allocInUse(int32_t clusterNum, ClusterInfo **template) 491 { 492 ClusterInfo *newCl; 493 494 if (InUse[clusterNum - FIRST_CLUSTER] != NULL) 495 return (CLINFO_PREVIOUSLY_ALLOCED); 496 497 if (template != NULL && *template != NULL) 498 newCl = *template; 499 else { 500 newCl = newClusterInfo(); 501 if (template) 502 *template = newCl; 503 } 504 505 InUse[clusterNum - FIRST_CLUSTER] = newCl; 506 newCl->refcnt++; 507 508 return (CLINFO_NEWLY_ALLOCED); 509 } 510 511 static void 512 markFree(int32_t clusterNum) 513 { 514 /* silent failure for bogus clusters */ 515 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 516 return; 517 518 if (InUse[clusterNum - FIRST_CLUSTER]) { 519 if (InUse[clusterNum - FIRST_CLUSTER]->saved) 520 free(InUse[clusterNum - FIRST_CLUSTER]->saved); 521 freeClusterInfo(InUse[clusterNum - FIRST_CLUSTER]); 522 InUse[clusterNum - FIRST_CLUSTER] = NULL; 523 } 524 } 525 526 static void 527 markOrphan(int fd, int32_t clusterNum, struct pcdir *dp) 528 { 529 /* silent failure for bogus clusters */ 530 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 531 return; 532 533 (void) markInUse(fd, clusterNum, dp, NULL, 0, VISIBLE, NULL); 534 if (InUse[clusterNum - FIRST_CLUSTER] != NULL) 535 updateFlags(clusterNum, 536 InUse[clusterNum - FIRST_CLUSTER]->flags | CLINFO_ORPHAN); 537 } 538 539 static void 540 markBad(int32_t clusterNum, uchar_t *recovered, int32_t recoveredLen) 541 { 542 /* silent failure for bogus clusters */ 543 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 544 return; 545 546 (void) allocInUse(clusterNum, NULL); 547 548 if (recoveredLen) { 549 (void) cloneClusterInfo(clusterNum); 550 InUse[clusterNum - FIRST_CLUSTER]->saved = recovered; 551 } 552 updateFlags(clusterNum, 553 InUse[clusterNum - FIRST_CLUSTER]->flags | CLINFO_BAD); 554 555 BadClusterCount++; 556 if (Verbose) 557 (void) fprintf(stderr, 558 gettext("Allocation unit %d marked bad.\n"), clusterNum); 559 } 560 561 static void 562 clearOrphan(int32_t c) 563 { 564 /* silent failure for bogus clusters */ 565 if (c < FIRST_CLUSTER || c > LastCluster) 566 return; 567 if (InUse[c - FIRST_CLUSTER] != NULL) 568 updateFlags(c, 569 InUse[c - FIRST_CLUSTER]->flags & ~CLINFO_ORPHAN); 570 } 571 572 static void 573 clearInUse(int32_t c) 574 { 575 ClusterInfo **clp; 576 577 /* silent failure for bogus clusters */ 578 if (c < FIRST_CLUSTER || c > LastCluster) 579 return; 580 581 clp = &InUse[c - FIRST_CLUSTER]; 582 if (*clp != NULL) { 583 freeClusterInfo(*clp); 584 *clp = NULL; 585 } 586 } 587 588 static void 589 clearAllClusters_InUse() 590 { 591 int32_t cc; 592 for (cc = FIRST_CLUSTER; cc < LastCluster; cc++) { 593 clearInUse(cc); 594 } 595 } 596 597 static void 598 makeUseTable(void) 599 { 600 if (InUse != NULL) { 601 clearAllClusters_InUse(); 602 return; 603 } 604 if ((InUse = (ClusterInfo **) 605 calloc(TotalClusters, sizeof (ClusterInfo *))) == NULL) { 606 perror(gettext("No memory for internal table")); 607 exit(9); 608 } 609 } 610 611 static void 612 countClusters(void) 613 { 614 int32_t c; 615 616 BadClusterCount = HiddenClusterCount = 617 AllocedClusterCount = FreeClusterCount = 0; 618 619 for (c = FIRST_CLUSTER; c < LastCluster; c++) { 620 if (badInFAT(c)) { 621 BadClusterCount++; 622 } else if (isMarkedBad(c)) { 623 /* 624 * This catches the bad sectors found 625 * during thorough verify that have never been 626 * allocated to a file. Without this check, we 627 * count these guys as free. 628 */ 629 BadClusterCount++; 630 markBadInFAT(c); 631 } else if (isHidden(c)) { 632 HiddenClusterCount++; 633 } else if (isInUse(c)) { 634 AllocedClusterCount++; 635 } else { 636 FreeClusterCount++; 637 } 638 } 639 } 640 641 /* 642 * summarizeFAT 643 * Mark orphans without directory entries as allocated. 644 * XXX - these chains should be reclaimed! 645 * XXX - merge this routine with countClusters (same loop, duh.) 646 */ 647 static void 648 summarizeFAT(int fd) 649 { 650 int32_t c; 651 ClusterInfo *tmpl = NULL; 652 653 for (c = FIRST_CLUSTER; c < LastCluster; c++) { 654 if (!freeInFAT(c) && !badInFAT(c) && !reservedInFAT(c) && 655 !isInUse(c)) { 656 (void) markInUse(fd, c, &BlankPCDIR, NULL, 0, VISIBLE, 657 &tmpl); 658 } 659 } 660 } 661 662 static void 663 getReadyToSearch(int fd) 664 { 665 getFAT(fd); 666 if (!IsFAT32) 667 getRootDirectory(fd); 668 } 669 670 671 static char PathName[MAXPATHLEN]; 672 673 static void 674 summarize(int fd, int includeFAT) 675 { 676 struct pcdir *ignorep1, *ignorep2 = NULL; 677 int32_t ignore32; 678 char ignore; 679 int pathlen; 680 681 ReservedClusterCount = 0; 682 AllocedClusterCount = 0; 683 HiddenClusterCount = 0; 684 FileClusterCount = 0; 685 FreeClusterCount = 0; 686 DirClusterCount = 0; 687 BadClusterCount = 0; 688 HiddenFileCount = 0; 689 FileCount = 0; 690 DirCount = 0; 691 ignorep1 = ignorep2 = NULL; 692 ignore = '\0'; 693 694 PathName[0] = '\0'; 695 pathlen = 0; 696 697 getReadyToSearch(fd); 698 /* 699 * Traverse the full meta-data tree to talley what clusters 700 * are in use. The root directory is an area outside of the 701 * file space on FAT12 and FAT16 file systems. On FAT32 file 702 * systems, the root directory is in a file area cluster just 703 * like any other directory. 704 */ 705 if (!IsFAT32) { 706 traverseFromRoot(fd, 0, PCFS_VISIT_SUBDIRS, PCFS_TRAVERSE_ALL, 707 ignore, &ignorep1, &ignore32, &ignorep2, PathName, 708 &pathlen); 709 } else { 710 DirCount++; 711 traverseDir(fd, TheBIOSParameterBlock.bpb32.root_dir_clust, 712 0, PCFS_VISIT_SUBDIRS, PCFS_TRAVERSE_ALL, ignore, 713 &ignorep1, &ignore32, &ignorep2, PathName, &pathlen); 714 } 715 716 if (includeFAT) 717 summarizeFAT(fd); 718 countClusters(); 719 } 720 721 int 722 isMarkedBad(int32_t clusterNum) 723 { 724 /* silent failure for bogus clusters */ 725 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 726 return (0); 727 728 if (InUse[clusterNum - FIRST_CLUSTER] == NULL) 729 return (0); 730 731 return (InUse[clusterNum - FIRST_CLUSTER]->flags & CLINFO_BAD); 732 } 733 734 static int 735 isMarkedOrphan(int32_t clusterNum) 736 { 737 /* silent failure for bogus clusters */ 738 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 739 return (0); 740 741 if (InUse[clusterNum - FIRST_CLUSTER] == NULL) 742 return (0); 743 744 return (InUse[clusterNum - FIRST_CLUSTER]->flags & CLINFO_ORPHAN); 745 } 746 747 static void 748 orphanChain(int fd, int32_t c, struct pcdir *ndp) 749 { 750 ClusterInfo *tmpl = NULL; 751 752 /* silent failure for bogus clusters */ 753 if (c < FIRST_CLUSTER || c > LastCluster) 754 return; 755 clearInUse(c); 756 markOrphan(fd, c, ndp); 757 c = nextInChain(c); 758 while (c != 0) { 759 clearInUse(c); 760 clearOrphan(c); 761 (void) markInUse(fd, c, ndp, NULL, 0, VISIBLE, &tmpl); 762 c = nextInChain(c); 763 } 764 } 765 766 static int32_t 767 findAFreeCluster(int32_t startAt) 768 { 769 int32_t look = startAt; 770 771 for (;;) { 772 if (freeInFAT(look)) { 773 break; 774 } 775 if (look == LastCluster) 776 look = FIRST_CLUSTER; 777 else 778 look++; 779 if (look == startAt) 780 break; 781 } 782 if (look != startAt) 783 return (look); 784 else 785 return (0); 786 } 787 788 static void 789 setEndOfDirectory(struct pcdir *dp) 790 { 791 dp->pcd_filename[0] = PCD_UNUSED; 792 } 793 794 static void 795 emergencyEndOfDirectory(int fd, int32_t secondToLast) 796 { 797 ClusterContents dirdata; 798 int32_t dirdatasize = 0; 799 800 if (readCluster(fd, secondToLast, &(dirdata.bytes), &dirdatasize, 801 RDCLUST_DO_CACHE) != RDCLUST_GOOD) { 802 (void) fprintf(stderr, 803 gettext("Unable to read allocation unit %d.\n"), 804 secondToLast); 805 (void) fprintf(stderr, 806 gettext("Cannot allocate a new allocation unit to hold an" 807 " end-of-directory marker.\nCannot access allocation unit" 808 " to overwrite existing directory entry with\nthe marker." 809 " Needed directory truncation has failed. Giving up.\n")); 810 (void) close(fd); 811 exit(11); 812 } 813 setEndOfDirectory(dirdata.dirp); 814 markClusterModified(secondToLast); 815 } 816 817 static void 818 makeNewEndOfDirectory(struct pcdir *entry, int32_t secondToLast, 819 int32_t newCluster, ClusterContents *newData) 820 { 821 setEndOfDirectory(newData->dirp); 822 markClusterModified(newCluster); 823 /* 824 * There are two scenarios. One is that we truncated the 825 * directory in the very beginning. The other is that we 826 * truncated it in the middle or at the end. In the first 827 * scenario, the secondToLast argument is not a valid cluster 828 * (it's zero), and so we actually need to change the start 829 * cluster for the directory to this new start cluster. In 830 * the second scenario, the secondToLast cluster we received 831 * as an argument needs to be pointed at the new end of 832 * directory. 833 */ 834 if (secondToLast == 0) { 835 updateDirEnt_Start(entry, newCluster); 836 } else { 837 writeFATEntry(secondToLast, newCluster); 838 } 839 markLastInFAT(newCluster); 840 } 841 842 static void 843 createNewEndOfDirectory(int fd, struct pcdir *entry, int32_t secondToLast) 844 { 845 ClusterContents dirdata; 846 int32_t dirdatasize = 0; 847 int32_t freeCluster; 848 849 if (((freeCluster = findAFreeCluster(secondToLast)) != 0)) { 850 if (readCluster(fd, freeCluster, &(dirdata.bytes), 851 &dirdatasize, RDCLUST_DO_CACHE) == RDCLUST_GOOD) { 852 if (Verbose) { 853 (void) fprintf(stderr, 854 gettext("Grabbed allocation unit #%d " 855 "for truncated\ndirectory's new end " 856 "of directory.\n"), freeCluster); 857 } 858 makeNewEndOfDirectory(entry, secondToLast, 859 freeCluster, &dirdata); 860 return; 861 } 862 } 863 if (secondToLast == 0) { 864 if (freeCluster == 0) { 865 (void) fprintf(stderr, gettext("File system full.\n")); 866 } else { 867 (void) fprintf(stderr, 868 gettext("Unable to read allocation unit %d.\n"), 869 freeCluster); 870 } 871 (void) fprintf(stderr, 872 gettext("Cannot allocate a new allocation unit to hold " 873 "an end-of-directory marker.\nNo existing directory " 874 "entries can be overwritten with the marker,\n" 875 "the only unit allocated to the directory is " 876 "inaccessible.\nNeeded directory truncation has failed. " 877 "Giving up.\n")); 878 (void) close(fd); 879 exit(11); 880 } 881 emergencyEndOfDirectory(fd, secondToLast); 882 } 883 884 /* 885 * truncAtCluster 886 * Given a directory entry and a cluster number, search through 887 * the cluster chain for the entry and make the cluster previous 888 * to the given cluster in the chain the last cluster in the file. 889 * The number of orphaned bytes is returned. For a chain that's 890 * a directory we need to do some special handling, since we'll be 891 * getting rid of the end of directory notice by truncating. 892 */ 893 static int64_t 894 truncAtCluster(int fd, struct pcdir *entry, int32_t cluster) 895 { 896 uint32_t oldSize, newSize; 897 int32_t prev, count, follow; 898 int dir = (entry->pcd_attr & PCA_DIR); 899 900 prev = 0; count = 0; 901 follow = extractStartCluster(entry); 902 while (follow != cluster && follow >= FIRST_CLUSTER && 903 follow <= LastCluster) { 904 prev = follow; 905 count++; 906 follow = nextInChain(follow); 907 } 908 if (follow != cluster) { 909 /* 910 * We didn't find the cluster they wanted to trunc at 911 * anywhere in the entry's chain. So we'll leave the 912 * entry alone, and return a negative value so they 913 * can know something is wrong. 914 */ 915 return (-1); 916 } 917 if (Verbose) { 918 (void) fprintf(stderr, 919 gettext("Chain truncation at unit #%d\n"), cluster); 920 } 921 if (!dir) { 922 oldSize = extractSize(entry); 923 newSize = count * 924 TheBIOSParameterBlock.bpb.sectors_per_cluster * 925 TheBIOSParameterBlock.bpb.bytes_per_sector; 926 if (newSize == 0) 927 updateDirEnt_Start(entry, 0); 928 } else { 929 newSize = 0; 930 } 931 updateDirEnt_Size(entry, newSize); 932 if (dir) { 933 createNewEndOfDirectory(fd, entry, prev); 934 } else if (prev != 0) { 935 markLastInFAT(prev); 936 } 937 if (dir) { 938 /* 939 * We don't really know what the size of a directory is 940 * but it is important for us to know if this truncation 941 * results in an orphan with any size. The value we 942 * return from this routine for a normal file is the 943 * number of bytes left in the chain. For a directory 944 * we can't be exact, and the caller doesn't really 945 * expect us to be. For a directory the caller only 946 * cares if there are zero bytes left or more than 947 * zero bytes left. We'll return 1 to indicate 948 * more than zero. 949 */ 950 if ((follow = nextInChain(follow)) != 0) 951 return (1); 952 else 953 return (0); 954 } 955 /* 956 * newSize should always be smaller than the old one, since 957 * we are decreasing the number of clusters allocated to the file. 958 */ 959 return ((int64_t)oldSize - (int64_t)newSize); 960 } 961 962 static struct pcdir * 963 updateOrphanedChainMetadata(int fd, struct pcdir *dp, int32_t endCluster, 964 int isBad) 965 { 966 struct pcdir *ndp = NULL; 967 int64_t remainder; 968 char *newName = NULL; 969 int chosenName; 970 int dir = (dp->pcd_attr & PCA_DIR); 971 972 /* 973 * If the truncation fails, (which ought not to happen), 974 * there's no need to go any further, we just return 975 * a null value for the new directory entry pointer. 976 */ 977 remainder = truncAtCluster(fd, dp, endCluster); 978 if (remainder < 0) 979 return (ndp); 980 if (!dir && isBad) { 981 /* 982 * Subtract out the bad cluster from the remaining size 983 * We always assume the cluster being deleted from the 984 * file is full size, but that might not be the case 985 * for the last cluster of the file, so that is why 986 * we check for negative remainder value. 987 */ 988 remainder -= TheBIOSParameterBlock.bpb.sectors_per_cluster * 989 TheBIOSParameterBlock.bpb.bytes_per_sector; 990 if (remainder < 0) 991 remainder = 0; 992 } 993 /* 994 * Build a new directory entry for the rest of the chain. 995 * Later, if the user okays it, we'll link this entry into the 996 * root directory. The new entry will start out as a 997 * copy of the truncated entry. 998 */ 999 if ((remainder != 0) && 1000 ((newName = nextAvailableCHKName(&chosenName)) != NULL) && 1001 ((ndp = newDirEnt(dp)) != NULL)) { 1002 if (Verbose) { 1003 if (dir) 1004 (void) fprintf(stderr, 1005 gettext("Orphaned directory chain.\n")); 1006 else 1007 (void) fprintf(stderr, 1008 gettext("Orphaned chain, %u bytes.\n"), 1009 (uint32_t)remainder); 1010 } 1011 if (!dir) 1012 updateDirEnt_Size(ndp, (uint32_t)remainder); 1013 if (isBad) 1014 updateDirEnt_Start(ndp, nextInChain(endCluster)); 1015 else 1016 updateDirEnt_Start(ndp, endCluster); 1017 updateDirEnt_Name(ndp, newName); 1018 addEntryToCHKList(chosenName); 1019 } 1020 return (ndp); 1021 } 1022 1023 /* 1024 * splitChain() 1025 * 1026 * split a cluster allocation chain into two cluster chains 1027 * around a given cluster (problemCluster). This results in two 1028 * separate directory entries; the original (dp), and one we hope 1029 * to create and return a pointer to to the caller (*newdp). 1030 * This second entry is the orphan chain, and it may end up in 1031 * the root directory as a FILEnnnn.CHK file. We also return the 1032 * starting cluster of the orphan chain to the caller (*orphanStart). 1033 */ 1034 void 1035 splitChain(int fd, struct pcdir *dp, int32_t problemCluster, 1036 struct pcdir **newdp, int32_t *orphanStart) 1037 { 1038 struct pcdir *ndp = NULL; 1039 int isBad = isMarkedBad(problemCluster); 1040 1041 ndp = updateOrphanedChainMetadata(fd, dp, problemCluster, isBad); 1042 *newdp = ndp; 1043 clearInUse(problemCluster); 1044 if (isBad) { 1045 clearOrphan(problemCluster); 1046 *orphanStart = nextInChain(problemCluster); 1047 orphanChain(fd, *orphanStart, ndp); 1048 markBadInFAT(problemCluster); 1049 } else { 1050 *orphanStart = problemCluster; 1051 orphanChain(fd, problemCluster, ndp); 1052 } 1053 } 1054 1055 /* 1056 * freeOrphan 1057 * 1058 * User has requested that an orphaned cluster chain be freed back 1059 * into the file area. 1060 */ 1061 static void 1062 freeOrphan(int32_t c) 1063 { 1064 int32_t n; 1065 1066 /* 1067 * Free the directory entry we explicitly created for 1068 * the orphaned clusters. 1069 */ 1070 if (InUse[c - FIRST_CLUSTER]->dirent != NULL) 1071 free(InUse[c - FIRST_CLUSTER]->dirent); 1072 /* 1073 * Then mark the clusters themselves as available. 1074 */ 1075 do { 1076 n = nextInChain(c); 1077 markFreeInFAT(c); 1078 markFree(c); 1079 c = n; 1080 } while (c != 0); 1081 } 1082 1083 /* 1084 * Rewrite the InUse field for a cluster chain. Can be used on a partial 1085 * chain if provided with a stopAtCluster. 1086 */ 1087 static void 1088 redoInUse(int fd, int32_t c, struct pcdir *ndp, int32_t stopAtCluster) 1089 { 1090 while (c && c != stopAtCluster) { 1091 clearInUse(c); 1092 (void) markInUse(fd, c, ndp, NULL, 0, VISIBLE, NULL); 1093 c = nextInChain(c); 1094 } 1095 } 1096 1097 static struct pcdir * 1098 orphanDirEntLookup(int32_t clusterNum) 1099 { 1100 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1101 return (NULL); 1102 1103 if (isInUse(clusterNum)) { 1104 return (InUse[clusterNum - FIRST_CLUSTER]->dirent); 1105 } else { 1106 return (NULL); 1107 } 1108 } 1109 1110 static int32_t 1111 orphanSizeLookup(int32_t clusterNum) 1112 { 1113 /* silent failure for bogus clusters */ 1114 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1115 return (-1); 1116 1117 if (isInUse(clusterNum)) { 1118 return (extractSize(InUse[clusterNum - FIRST_CLUSTER]->dirent)); 1119 } else { 1120 return (-1); 1121 } 1122 } 1123 1124 /* 1125 * linkOrphan 1126 * 1127 * User has requested that an orphaned cluster chain be brought back 1128 * into the file system. So we have to make a new directory entry 1129 * in the root directory and point it at the cluster chain. 1130 */ 1131 static void 1132 linkOrphan(int fd, int32_t start) 1133 { 1134 struct pcdir *newEnt = NULL; 1135 struct pcdir *dp; 1136 1137 if ((dp = orphanDirEntLookup(start)) != NULL) { 1138 newEnt = addRootDirEnt(fd, dp); 1139 } else { 1140 (void) printf(gettext("Re-link of orphaned chain failed." 1141 " Allocation units will remain orphaned.\n")); 1142 } 1143 /* 1144 * A cluster isn't really InUse() unless it is referenced, 1145 * so if newEnt is NULL here, we are in effect using markInUse() 1146 * to note that the cluster is NOT in use. 1147 */ 1148 redoInUse(fd, start, newEnt, 0); 1149 } 1150 1151 /* 1152 * relinkCreatedOrphans 1153 * 1154 * While marking clusters as bad, we can create orphan cluster 1155 * chains. Since we were the ones doing the marking, we were able to 1156 * keep track of the orphans we created. Now we want to go through 1157 * all those chains and either get them back into the file system or 1158 * free them depending on the user's input. 1159 */ 1160 static void 1161 relinkCreatedOrphans(int fd) 1162 { 1163 int32_t c; 1164 1165 for (c = FIRST_CLUSTER; c < LastCluster; c++) { 1166 if (isMarkedOrphan(c)) { 1167 if (OkayToRelink && askAboutRelink(c)) { 1168 linkOrphan(fd, c); 1169 } else if (askAboutFreeing(c)) { 1170 freeOrphan(c); 1171 } 1172 clearOrphan(c); 1173 } 1174 } 1175 } 1176 1177 /* 1178 * relinkFATOrphans 1179 * 1180 * We want to find orphans not represented in the meta-data. 1181 * These are chains marked in the FAT as being in use but 1182 * not referenced anywhere by any directory entries. 1183 * We'll go through the whole FAT and mark the first cluster 1184 * in any such chain as an orphan. Then we can just use 1185 * the relinkCreatedOrphans routine to get them back into the 1186 * file system or free'ed depending on the user's input. 1187 */ 1188 static void 1189 relinkFATOrphans(int fd) 1190 { 1191 struct pcdir *ndp = NULL; 1192 int32_t cc, c, n; 1193 int32_t bpc, newSize; 1194 char *newName; 1195 int chosenName; 1196 1197 for (c = FIRST_CLUSTER; c < LastCluster; c++) { 1198 if (freeInFAT(c) || badInFAT(c) || 1199 reservedInFAT(c) || isInUse(c)) 1200 continue; 1201 cc = 1; 1202 n = c; 1203 while (n = nextInChain(n)) 1204 cc++; 1205 bpc = TheBIOSParameterBlock.bpb.sectors_per_cluster * 1206 TheBIOSParameterBlock.bpb.bytes_per_sector; 1207 newSize = cc * bpc; 1208 if (((newName = nextAvailableCHKName(&chosenName)) != NULL) && 1209 ((ndp = newDirEnt(NULL)) != NULL)) { 1210 updateDirEnt_Size(ndp, newSize); 1211 updateDirEnt_Start(ndp, c); 1212 updateDirEnt_Name(ndp, newName); 1213 addEntryToCHKList(chosenName); 1214 } 1215 orphanChain(fd, c, ndp); 1216 } 1217 relinkCreatedOrphans(fd); 1218 } 1219 1220 static void 1221 relinkOrphans(int fd) 1222 { 1223 relinkCreatedOrphans(fd); 1224 relinkFATOrphans(fd); 1225 } 1226 1227 static void 1228 checkForFATLoop(int32_t clusterNum) 1229 { 1230 int32_t prev = clusterNum; 1231 int32_t follow; 1232 1233 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1234 return; 1235 1236 follow = nextInChain(clusterNum); 1237 while (follow != clusterNum && follow >= FIRST_CLUSTER && 1238 follow <= LastCluster) { 1239 prev = follow; 1240 follow = nextInChain(follow); 1241 } 1242 if (follow == clusterNum) { 1243 /* 1244 * We found a loop. Eradicate it by changing 1245 * the last cluster in the loop to be last 1246 * in the chain instead instead of pointing 1247 * back to the first cluster. 1248 */ 1249 markLastInFAT(prev); 1250 } 1251 } 1252 1253 static void 1254 sharedChainError(int fd, int32_t clusterNum, struct pcdir *badEntry) 1255 { 1256 /* 1257 * If we have shared clusters, it is either because the 1258 * cluster somehow got assigned to multiple files and/or 1259 * because of a loop in the cluster chain. In either 1260 * case we want to truncate the offending file at the 1261 * cluster of contention. Then, we will want to run 1262 * through the remainder of the chain. If we find ourselves 1263 * back at the top, we will know there is a loop in the 1264 * FAT we need to remove. 1265 */ 1266 if (Verbose) 1267 (void) fprintf(stderr, 1268 gettext("Truncating chain due to duplicate allocation of " 1269 "unit %d.\n"), clusterNum); 1270 /* 1271 * Note that we don't orphan anything here, because the duplicate 1272 * part of the chain may be part of another valid chain. 1273 */ 1274 (void) truncAtCluster(fd, badEntry, clusterNum); 1275 checkForFATLoop(clusterNum); 1276 } 1277 1278 void 1279 truncChainWithBadCluster(int fd, struct pcdir *dp, int32_t startCluster) 1280 { 1281 struct pcdir *orphanEntry; 1282 int32_t orphanStartCluster; 1283 int32_t c = startCluster; 1284 1285 while (c != 0) { 1286 if (isMarkedBad(c)) { 1287 /* 1288 * splitChain() truncates the current guy and 1289 * then makes an orphan chain out of the remaining 1290 * clusters. When we come back from the split 1291 * we'll want to continue looking for bad clusters 1292 * in the orphan chain. 1293 */ 1294 splitChain(fd, dp, c, 1295 &orphanEntry, &orphanStartCluster); 1296 /* 1297 * There is a chance that we weren't able or weren't 1298 * required to make a directory entry for the 1299 * remaining clusters. In that case we won't go 1300 * on, because we couldn't make any more splits 1301 * anyway. 1302 */ 1303 if (orphanEntry == NULL) 1304 break; 1305 c = orphanStartCluster; 1306 dp = orphanEntry; 1307 continue; 1308 } 1309 c = nextInChain(c); 1310 } 1311 } 1312 1313 int32_t 1314 nextInChain(int32_t currentCluster) 1315 { 1316 int32_t nextCluster; 1317 1318 /* silent failure for bogus clusters */ 1319 if (currentCluster < FIRST_CLUSTER || currentCluster > LastCluster) 1320 return (0); 1321 1322 /* 1323 * Look up FAT entry of next link in cluster chain, 1324 * if this one is the last one return 0 as the next link. 1325 */ 1326 nextCluster = readFATEntry(currentCluster); 1327 if (nextCluster < FIRST_CLUSTER || nextCluster > LastCluster) 1328 return (0); 1329 1330 return (nextCluster); 1331 } 1332 1333 /* 1334 * findImpactedCluster 1335 * 1336 * Called when someone modifies what they believe might be a cached 1337 * cluster entry, but when they only have a directory entry pointer 1338 * and not the cluster number. We have to go dig up what cluster 1339 * they are modifying. 1340 */ 1341 int32_t 1342 findImpactedCluster(struct pcdir *modified) 1343 { 1344 CachedCluster *loop; 1345 /* 1346 * Check to see if it's in the root directory first 1347 */ 1348 if (!IsFAT32 && ((uchar_t *)modified >= TheRootDir.bytes) && 1349 ((uchar_t *)modified < TheRootDir.bytes + RootDirSize)) 1350 return (FAKE_ROOTDIR_CLUST); 1351 1352 loop = ClusterCache; 1353 while (loop) { 1354 if (((uchar_t *)modified >= loop->clusterData.bytes) && 1355 ((uchar_t *)modified < 1356 (loop->clusterData.bytes + BytesPerCluster))) { 1357 return (loop->clusterNum); 1358 } 1359 loop = loop->next; 1360 } 1361 /* 1362 * Guess it wasn't cached after all... 1363 */ 1364 return (0); 1365 } 1366 1367 void 1368 writeClusterMods(int fd) 1369 { 1370 CachedCluster *loop = ClusterCache; 1371 1372 while (loop) { 1373 if (loop->modified) 1374 writeCachedCluster(fd, loop); 1375 loop = loop->next; 1376 } 1377 } 1378 1379 void 1380 squirrelPath(struct nameinfo *pathInfo, int32_t clusterNum) 1381 { 1382 /* silent failure for bogus clusters */ 1383 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1384 return; 1385 if (InUse[clusterNum - FIRST_CLUSTER] == NULL) 1386 return; 1387 InUse[clusterNum - FIRST_CLUSTER]->path = pathInfo; 1388 } 1389 1390 int 1391 markInUse(int fd, int32_t clusterNum, struct pcdir *referencer, struct 1392 pcdir *longRef, int32_t longStartCluster, int isHiddenFile, 1393 ClusterInfo **template) 1394 { 1395 int alreadyMarked; 1396 ClusterInfo *cl; 1397 1398 /* silent failure for bogus clusters */ 1399 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1400 return (CLINFO_NEWLY_ALLOCED); 1401 1402 alreadyMarked = allocInUse(clusterNum, template); 1403 if ((alreadyMarked == CLINFO_PREVIOUSLY_ALLOCED) && 1404 (isInUse(clusterNum))) { 1405 sharedChainError(fd, clusterNum, referencer); 1406 return (CLINFO_PREVIOUSLY_ALLOCED); 1407 } 1408 cl = InUse[clusterNum - FIRST_CLUSTER]; 1409 /* 1410 * If Cl is newly allocated (refcnt <= 1) we must fill in the fields. 1411 * If Cl has different fields, we must clone it. 1412 */ 1413 1414 if (cl->refcnt <= 1 || cl->dirent != referencer || 1415 cl->longent != longRef || 1416 cl->longEntStartClust != longStartCluster) { 1417 if (cl->refcnt > 1) 1418 cl = cloneClusterInfo(clusterNum); 1419 cl->dirent = referencer; 1420 cl->longent = longRef; 1421 cl->longEntStartClust = longStartCluster; 1422 if (isHiddenFile) 1423 cl->flags |= CLINFO_HIDDEN; 1424 1425 /* 1426 * Return cl as the template to use for other clusters in 1427 * this file 1428 */ 1429 if (template) 1430 *template = cl; 1431 } 1432 return (CLINFO_NEWLY_ALLOCED); 1433 } 1434 1435 void 1436 markClusterModified(int32_t clusterNum) 1437 { 1438 CachedCluster *c; 1439 1440 if (clusterNum == FAKE_ROOTDIR_CLUST) { 1441 RootDirModified = 1; 1442 return; 1443 } 1444 1445 /* silent failure for bogus clusters */ 1446 if (clusterNum < FIRST_CLUSTER || clusterNum > LastCluster) 1447 return; 1448 1449 if (c = findClusterCacheEntry(clusterNum)) { 1450 c->modified = 1; 1451 } else { 1452 (void) fprintf(stderr, 1453 gettext("Unexpected internal error: " 1454 "Missing cache entry [%d]\n"), clusterNum); 1455 exit(10); 1456 } 1457 } 1458 1459 /* 1460 * readCluster 1461 * caller wants to read cluster clusterNum. We should return 1462 * a pointer to the read data in "data", and fill in the number 1463 * of bytes read in "datasize". If shouldCache is non-zero 1464 * we should allocate cache space to the cluster, otherwise we 1465 * just return a pointer to a buffer we re-use whenever cacheing 1466 * is not requested. 1467 */ 1468 int 1469 readCluster(int fd, int32_t clusterNum, uchar_t **data, int32_t *datasize, 1470 int shouldCache) 1471 { 1472 uchar_t *newBuf; 1473 int rv; 1474 1475 *data = NULL; 1476 if ((*data = findClusterDataInTheCache(clusterNum)) != NULL) { 1477 *datasize = BytesPerCluster; 1478 return (RDCLUST_GOOD); 1479 } 1480 1481 rv = getCluster(fd, clusterNum, &newBuf, datasize); 1482 if (rv != RDCLUST_GOOD) 1483 return (rv); 1484 1485 /* 1486 * Caller requested we NOT cache the data from this read. 1487 * So, we just return a pointer to the common data buffer. 1488 */ 1489 if (shouldCache == 0) { 1490 *data = newBuf; 1491 return (rv); 1492 } 1493 1494 /* 1495 * Caller requested we cache the data from this read. 1496 * So, if we have some data, add it to the cache by 1497 * copying it out of the common buffer into new storage. 1498 */ 1499 if (*datasize > 0) 1500 *data = addToCache(clusterNum, newBuf, datasize); 1501 return (rv); 1502 } 1503 1504 void 1505 findBadClusters(int fd) 1506 { 1507 int32_t clusterCount; 1508 int32_t datasize; 1509 uchar_t *data; 1510 1511 BadClusterCount = 0; 1512 makeUseTable(); 1513 (void) printf(gettext("** Scanning allocation units\n")); 1514 for (clusterCount = FIRST_CLUSTER; 1515 clusterCount < LastCluster; clusterCount++) { 1516 if (readCluster(fd, clusterCount, 1517 &data, &datasize, RDCLUST_DONT_CACHE) < 0) { 1518 if (Verbose) 1519 (void) fprintf(stderr, 1520 gettext("\nUnreadable allocation unit %d.\n"), 1521 clusterCount); 1522 markBad(clusterCount, data, datasize); 1523 } 1524 /* 1525 * Progress meter, display a '.' for every 1000 clusters 1526 * processed. We don't want to display this when 1527 * we are in verbose mode; verbose mode progress is 1528 * shown by displaying each file name as it is found. 1529 */ 1530 if (!Verbose && clusterCount % 1000 == 0) 1531 (void) printf("."); 1532 } 1533 (void) printf(gettext("..done\n")); 1534 } 1535 1536 void 1537 scanAndFixMetadata(int fd) 1538 { 1539 /* 1540 * First we initialize a few things. 1541 */ 1542 makeUseTable(); 1543 getReadyToSearch(fd); 1544 createCHKNameList(fd); 1545 1546 /* 1547 * Make initial scan, taking into account any effect that 1548 * the bad clusters we may have already discovered have 1549 * on meta-data. We may break up some cluster chains 1550 * during this period. The relinkCreatedOrphans() call 1551 * will then give the user the chance to recover stuff 1552 * we've created. 1553 */ 1554 (void) printf(gettext("** Scanning file system meta-data\n")); 1555 summarize(fd, NO_FAT_IN_SUMMARY); 1556 if (Verbose) 1557 printSummary(stderr); 1558 (void) printf(gettext("** Correcting any meta-data discrepancies\n")); 1559 relinkCreatedOrphans(fd); 1560 1561 /* 1562 * Clear our usage table and go back over everything, this 1563 * time including looking for clusters floating free in the FAT. 1564 * This may include clusters the user chose to free during the 1565 * relink phase. 1566 */ 1567 makeUseTable(); 1568 summarize(fd, INCLUDE_FAT_IN_SUMMARY); 1569 relinkOrphans(fd); 1570 } 1571 1572 void 1573 printSummary(FILE *outDest) 1574 { 1575 (void) fprintf(outDest, 1576 gettext("%llu bytes.\n"), 1577 (uint64_t) 1578 TotalClusters * TheBIOSParameterBlock.bpb.sectors_per_cluster * 1579 TheBIOSParameterBlock.bpb.bytes_per_sector); 1580 (void) fprintf(outDest, 1581 gettext("%llu bytes in bad sectors.\n"), 1582 (uint64_t) 1583 BadClusterCount * TheBIOSParameterBlock.bpb.sectors_per_cluster * 1584 TheBIOSParameterBlock.bpb.bytes_per_sector); 1585 (void) fprintf(outDest, 1586 gettext("%llu bytes in %d directories.\n"), 1587 (uint64_t) 1588 DirClusterCount * TheBIOSParameterBlock.bpb.sectors_per_cluster * 1589 TheBIOSParameterBlock.bpb.bytes_per_sector, DirCount); 1590 if (HiddenClusterCount) { 1591 (void) fprintf(outDest, 1592 gettext("%llu bytes in %d hidden files.\n"), 1593 (uint64_t)HiddenClusterCount * 1594 TheBIOSParameterBlock.bpb.sectors_per_cluster * 1595 TheBIOSParameterBlock.bpb.bytes_per_sector, 1596 HiddenFileCount); 1597 } 1598 (void) fprintf(outDest, 1599 gettext("%llu bytes in %d files.\n"), 1600 (uint64_t) 1601 FileClusterCount * TheBIOSParameterBlock.bpb.sectors_per_cluster * 1602 TheBIOSParameterBlock.bpb.bytes_per_sector, FileCount); 1603 (void) fprintf(outDest, 1604 gettext("%llu bytes free.\n"), (uint64_t)FreeClusterCount * 1605 TheBIOSParameterBlock.bpb.sectors_per_cluster * 1606 TheBIOSParameterBlock.bpb.bytes_per_sector); 1607 (void) fprintf(outDest, 1608 gettext("%d bytes per allocation unit.\n"), 1609 TheBIOSParameterBlock.bpb.sectors_per_cluster * 1610 TheBIOSParameterBlock.bpb.bytes_per_sector); 1611 (void) fprintf(outDest, 1612 gettext("%d total allocation units.\n"), TotalClusters); 1613 if (ReservedClusterCount) 1614 (void) fprintf(outDest, gettext("%d reserved allocation units.\n"), 1615 ReservedClusterCount); 1616 (void) fprintf(outDest, 1617 gettext("%d available allocation units.\n"), FreeClusterCount); 1618 } 1619