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