1/* 2 * Copyright (c) 2000,2005-2007,2010-2011 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 25 * Copyright (c) 1995 Martin Husemann 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. All advertising materials mentioning features or use of this software 36 * must display the following acknowledgement: 37 * This product includes software developed by Martin Husemann 38 * and Wolfgang Solfrank. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 56#include <sys/cdefs.h> 57 58#include <stdlib.h> 59#include <string.h> 60#include <ctype.h> 61#include <stdint.h> 62#include <stdio.h> 63#include <unistd.h> 64 65#include <sys/param.h> 66 67#include "ext.h" 68#include "fsutil.h" 69 70/* 71 * The following value should be a multiple of the sector size in bytes. The 72 * Microsoft supported sector sizes are 512, 1024, 2048, and 4096, which means 73 * this should be a multiple of 4096. It should also be a minimum of 6K so 74 * that a maximal FAT12 FAT can fit in a single chunk (so the code doesn't 75 * have to handle a FAT entry crossing a chunk boundary). It should be 76 * large enough to make the I/O efficient, without occupying too much memory. 77 */ 78#define FAT_CHUNK_SIZE (64*1024) 79 80 81ssize_t deblock_read(int d, void *buf, size_t nbytes); 82ssize_t deblock_write(int d, void *buf, size_t nbytes); 83 84static cl_t fat32_get(cl_t cluster); 85static int fat32_set(cl_t cluster, cl_t value); 86static cl_t fat16_get(cl_t cluster); 87static int fat16_set(cl_t cluster, cl_t value); 88static cl_t fat12_get(cl_t cluster); 89static int fat12_set(cl_t cluster, cl_t value); 90 91cl_t (*fat_get)(cl_t cluster); 92int (*fat_set)(cl_t cluster, cl_t value); 93 94static int gFS; /* File descriptor to read/write the volume */ 95static struct bootblock *gBoot; 96static size_t gUseMapBytes; 97static size_t gNumCacheBlocks; 98 99/* 100 * A cached FAT sector. 101 */ 102struct fat_cache_block { 103 unsigned int dirty:1; 104 unsigned int chunk:31; 105 struct fat_cache_block *next; /* LRU list */ 106 uint8_t * buffer; 107 uint32_t length; /* Size of this block, in bytes */ 108}; 109enum { FAT_CHUNK_MAX = 0x7FFFFFFF }; 110 111static uint8_t *fat_cache_buffers; 112static struct fat_cache_block *fat_cache; 113static struct fat_cache_block *fat_cache_mru; 114 115/* 116 * Initialize the FAT structures and cache. 117 * 118 * Should we use a global, or return a structure to be passed 119 * back into other routines? 120 */ 121int fat_init(int fs, struct bootblock *boot) 122{ 123 int mod = 0; 124 int i; 125 cl_t temp; 126 cl_t value; 127 128 /* 129 * We can get called multiple times if a first 130 * repair didn't work. Be prepared to re-use 131 * or free/reallocate memory. 132 */ 133 fat_uninit(); 134 135 gFS = fs; 136 gBoot = boot; 137 138 /* 139 * Point fat_get and fat_set to the appropriate routine for the volume's 140 * FAT type. (Virtual functions in C) 141 */ 142 switch (boot->ClustMask) 143 { 144 case CLUST12_MASK: 145 fat_get = fat12_get; 146 fat_set = fat12_set; 147 break; 148 case CLUST16_MASK: 149 fat_get = fat16_get; 150 fat_set = fat16_set; 151 break; 152 case CLUST32_MASK: 153 fat_get = fat32_get; 154 fat_set = fat32_set; 155 break; 156 default: 157 pfatal("Unknown cluster mask (0x%08X)\n", boot->ClustMask); 158 return FSFATAL; 159 } 160 161 if (initUseMap(boot)) 162 return FSFATAL; 163 164 /* 165 * Allocate space for the FAT cache structures 166 * 167 * If maxmem is set, limit the FAT bitmap plus buffers to that amount 168 * of memory. TODO: If the entire FAT plus bitmap would fit in less 169 * than maxmem bytes, just allocate as much as actually needed for the 170 * entire FAT. 171 * 172 * If maxmem is not set, allocate enough to cache the entire FAT. 173 * TODO: Should we use a smaller number of bigger blocks to minimize the 174 * overhead of finding a cache block? 175 */ 176 if (maxmem) 177 { 178 gNumCacheBlocks = (maxmem-gUseMapBytes)/FAT_CHUNK_SIZE; 179 } 180 else 181 { 182 gNumCacheBlocks = (boot->FATsecs*boot->BytesPerSec+FAT_CHUNK_SIZE-1)/FAT_CHUNK_SIZE; 183 } 184 fat_cache = calloc(gNumCacheBlocks, sizeof(struct fat_cache_block)); 185 if (fat_cache == NULL) 186 { 187 freeUseMap(); 188 perr("No memory for FAT cache headers\n"); 189 return FSFATAL; 190 } 191 fat_cache_buffers = calloc(gNumCacheBlocks, FAT_CHUNK_SIZE); 192 if (fat_cache_buffers == NULL) 193 { 194 free(fat_cache); 195 fat_cache = NULL; 196 freeUseMap(); 197 perr("No memory for FAT cache buffers\n"); 198 return FSFATAL; 199 } 200 201 /* 202 * Initialize the FAT cache buffers and buffer headers 203 */ 204 for (i=0; i<gNumCacheBlocks; ++i) 205 { 206 fat_cache[i].dirty = 0; 207 fat_cache[i].chunk = FAT_CHUNK_MAX; 208 fat_cache[i].buffer = fat_cache_buffers + i * FAT_CHUNK_SIZE; 209 if (i != gNumCacheBlocks-1) 210 fat_cache[i].next = &fat_cache[i+1]; 211 } 212 fat_cache_mru = &fat_cache[0]; 213 214 /* 215 * Check the first (index 0) entry of the FAT. The low byte should be 216 * the same as boot->Media. All other bits should be set. Note that we 217 * can't rely on fat_get() sign extending the value for us, since 0xF0 218 * is a valid media type, and is less than CLUST_RSRVD, so won't get 219 * sign extended. 220 */ 221 value = fat_get(0); 222 if (value == CLUST_ERROR) 223 return FSFATAL; 224 value &= boot->ClustMask; 225 temp = boot->ClustMask & (0xFFFFFF00+boot->Media); 226 if (value != temp) 227 { 228 pwarn("FAT[0] is incorrect (is 0x%X; should be 0x%X)\n", value, temp); 229 if (ask(1, "Correct")) 230 { 231 mod = fat_set(0, temp); 232 if (!mod) 233 mod = FSFATMOD; 234 } 235 else 236 { 237 mod = FSERROR; 238 } 239 } 240 241 /* 242 * Check the second (index 1) entry of the FAT. It should be set to an 243 * end of file mark. For FAT16 and FAT32, the upper two bits may be cleared 244 * to indicate "volume dirty" and "hard errors"; for FAT12, it must always 245 * be an EOF value. 246 * 247 * Also check the "clean" bit. If it is not set (i.e., the volume is dirty), 248 * set the FSDIRTY status. 249 */ 250 value = fat_get(1); 251 if (value == CLUST_ERROR) 252 return FSFATAL; 253 switch (boot->ClustMask) 254 { 255 case CLUST16_MASK: 256 if ((value & 0x8000) == 0) 257 mod |= FSDIRTY; 258 break; 259 case CLUST32_MASK: 260 if ((value & 0x08000000) == 0) 261 mod |= FSDIRTY; 262 break; 263 default: 264 break; 265 } 266 /* 267 * Figure out how many bits of the FAT[1] entry to compare. FAT16 and 268 * FAT32 use the upper two bits as flags, so we don't want to compare 269 * them. The >>2 part below leaves temp set to the cluster mask, but 270 * with the upper two bits zeroed. (Note that the cluster mask has 271 * the lower N bits set.) FAT12 has no flags, and uses all 12 bits. 272 * 273 * The second if statement then compares the significant bits (i.e. not 274 * the flags) of the fetched value with the same bits of the expected 275 * value (CLUST_EOFS). 276 */ 277 if (boot->ClustMask == CLUST12_MASK) 278 temp = boot->ClustMask; 279 else 280 temp = boot->ClustMask >> 2; 281 if ((value & temp) < (CLUST_EOFS & temp)) 282 { 283 pwarn("FAT[1] is incorrect\n"); 284 if (ask(1, "Correct")) 285 { 286 /* 287 * Set the lower bits of FAT[1] to all ones (i.e. the 288 * value in temp), but preserving the flags from the 289 * FAT[1] entry (in the upper two significant bits of 290 * value). 291 */ 292 i = fat_set(1, value | temp); 293 if (i) 294 mod |= i; 295 else 296 mod |= FSFATMOD; 297 } 298 else 299 { 300 mod |= FSERROR; 301 } 302 } 303 304 return mod; 305} 306 307 308/* 309 * Find the FAT cache block associated with the given cluster. If not found, 310 * try to find an unused cache block. Otherwise, recycle the least recently 311 * used block (writing it out first if it was dirty). Move the found cache 312 * block to the head of the most recently used list. 313 * 314 * Returns NULL on I/O error 315 */ 316static struct fat_cache_block * 317fat_cache_find(uint32_t offset) 318{ 319 struct fat_cache_block *found; 320 struct fat_cache_block *prev; 321 uint32_t chunk; 322 uint32_t length; 323 324 /* Figure out which chunk we're looking for */ 325 chunk = offset / FAT_CHUNK_SIZE; 326 length = (gBoot->FATsecs * gBoot->BytesPerSec) - (chunk * FAT_CHUNK_SIZE); 327 if (length > FAT_CHUNK_SIZE) 328 length = FAT_CHUNK_SIZE; 329 330 /* Find the matching buffer, else LRU buffer */ 331 prev = NULL; 332 found = fat_cache_mru; 333 while (found->chunk != chunk && found->next != NULL) 334 { 335 prev = found; 336 found = found->next; 337 } 338 339 /* 340 * If we didn't find the desired sector in the cache, recycle 341 * the least recently used buffer. 342 */ 343 if (found->chunk != chunk) 344 { 345 int activeFAT; 346 off_t io_offset; 347 348 activeFAT = gBoot->ValidFat >= 0 ? gBoot->ValidFat : 0; 349 350 if (found->dirty) 351 { 352// fprintf(stderr, "Writing FAT sector %u\n", found->sector); 353 354 /* Byte offset of start of active FAT */ 355 io_offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec; 356 357 /* Byte offset of current chunk */ 358 io_offset += found->chunk * FAT_CHUNK_SIZE; 359 360 if (lseek(gFS, io_offset, SEEK_SET) != io_offset) 361 { 362 perr("Unable to seek FAT"); 363 return NULL; 364 } 365 if (deblock_write(gFS, found->buffer, found->length) != found->length) 366 { 367 perr("Unable to write FAT"); 368 return NULL; 369 } 370 371 found->dirty = 0; 372 } 373 374 /* Figure out where the desired chunk is on disk */ 375 found->chunk = chunk; 376 found->length = length; 377 378 /* Byte offset of start of active FAT */ 379 io_offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec; 380 381 /* Byte offset of desired chunk */ 382 io_offset += chunk * FAT_CHUNK_SIZE; 383 384 /* Read in the sector */ 385// fprintf(stderr, "Reading FAT sector %u\n", found->sector); 386 if (lseek(gFS, io_offset, SEEK_SET) != io_offset) 387 { 388 perr("Unable to seek FAT"); 389 return NULL; 390 } 391 if (deblock_read(gFS, found->buffer, length) != length) 392 { 393 perr("Unable to read FAT"); 394 return NULL; 395 } 396 } 397 398 /* 399 * Move the found buffer to the head of the MRU list. 400 */ 401 if (found != fat_cache_mru) 402 { 403 if (prev) 404 prev->next = found->next; 405 found->next = fat_cache_mru; 406 fat_cache_mru = found; 407 } 408 409 return found; 410} 411 412 413void fat_uninit(void) 414{ 415 if (fat_cache != NULL) 416 { 417 free(fat_cache); 418 fat_cache = NULL; 419 } 420 if (fat_cache_buffers != NULL) 421 { 422 free(fat_cache_buffers); 423 fat_cache_buffers = NULL; 424 } 425 freeUseMap(); 426} 427 428 429/* 430 * Returns the entry for cluster @cluster in @*value. 431 * The function result is the error, if any. 432 */ 433static cl_t fat32_get(cl_t cluster) 434{ 435 struct fat_cache_block *block; 436 uint8_t *p; 437 cl_t value; 438 439 if (cluster >= gBoot->NumClusters) 440 { 441 fprintf(stderr, "fat32_get: invalid cluster (%u)\n", cluster); 442 return CLUST_ERROR; 443 } 444 445 block = fat_cache_find(cluster*4); 446 if (block == NULL) 447 return CLUST_ERROR; 448 449 /* Point to the @cluster'th entry. */ 450 p = block->buffer + (cluster * 4) % FAT_CHUNK_SIZE; 451 452 /* Extract the raw value, ignoring the reserved bits. */ 453 value = (p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24)) & CLUST32_MASK; 454 455 /* Sign extended the special values for consistency. */ 456 if (value >= (CLUST_RSRVD & CLUST32_MASK)) 457 value |= ~CLUST32_MASK; 458 459 return value; 460} 461 462static cl_t fat16_get(cl_t cluster) 463{ 464 struct fat_cache_block *block; 465 uint8_t *p; 466 cl_t value; 467 468 if (cluster >= gBoot->NumClusters) 469 { 470 fprintf(stderr, "fat16_get: invalid cluster (%u)\n", cluster); 471 return CLUST_ERROR; 472 } 473 474 block = fat_cache_find(cluster*2); 475 if (block == NULL) 476 return CLUST_ERROR; 477 478 /* Point to the @cluster'th entry. */ 479 p = block->buffer + (cluster * 2) % FAT_CHUNK_SIZE; 480 481 /* Extract the value. */ 482 value = p[0] + (p[1] << 8); 483 484 /* Sign extended the special values for consistency. */ 485 if (value >= (CLUST_RSRVD & CLUST16_MASK)) 486 value |= ~CLUST16_MASK; 487 488 return value; 489} 490 491static cl_t fat12_get(cl_t cluster) 492{ 493 struct fat_cache_block *block; 494 uint8_t *p; 495 cl_t value; 496 497 if (cluster >= gBoot->NumClusters) 498 { 499 fprintf(stderr, "fat16_get: invalid cluster (%u)\n", cluster); 500 return CLUST_ERROR; 501 } 502 503 block = fat_cache_find(cluster + cluster/2); 504 if (block == NULL) 505 return CLUST_ERROR; 506 507 /* Point to the @cluster'th entry. */ 508 p = block->buffer + (cluster + cluster/2) % FAT_CHUNK_SIZE; 509 510 /* Extract the value. */ 511 value = p[0] + (p[1] << 8); 512 if (cluster & 1) 513 value >>= 4; 514 else 515 value &= 0x0FFF; 516 517 /* Sign extended the special values for consistency. */ 518 if (value >= (CLUST_RSRVD & CLUST12_MASK)) 519 value |= ~CLUST12_MASK; 520 521 return value; 522} 523 524 525/* 526 * Sets the entry for cluster @cluster to @value. 527 * The function result is the error, if any. 528 * 529 * For now, this is FAT32-only. 530 */ 531static int fat32_set(cl_t cluster, cl_t value) 532{ 533 struct fat_cache_block *block; 534 uint8_t *p; 535 536 if (cluster >= gBoot->NumClusters) 537 { 538 fprintf(stderr, "fat32_set: invalid cluster (%u)\n", cluster); 539 return FSFATAL; 540 } 541 542 block = fat_cache_find(cluster*4); 543 if (block == NULL) 544 return FSFATAL; 545 546 /* Point to the @cluster'th entry in the FAT. */ 547 p = block->buffer + (cluster * 4) % FAT_CHUNK_SIZE; 548 549 /* Store the value, preserving the reserved bits. */ 550 *p++ = (uint8_t) value; 551 *p++ = (uint8_t) (value >> 8); 552 *p++ = (uint8_t) (value >> 16); 553 *p &= 0xF0; 554 *p |= (value >> 24) & 0x0F; 555 556 /* Update the use map. */ 557 if (value == CLUST_FREE) 558 markFree(cluster); 559 else 560 markUsed(cluster); 561 562 /* Remember that this block has been changed. */ 563 block->dirty = 1; 564 565 return 0; 566} 567 568static int fat16_set(cl_t cluster, cl_t value) 569{ 570 struct fat_cache_block *block; 571 uint8_t *p; 572 573 if (cluster >= gBoot->NumClusters) 574 { 575 fprintf(stderr, "fat16_set: invalid cluster (%u)\n", cluster); 576 return FSFATAL; 577 } 578 579 block = fat_cache_find(cluster*2); 580 if (block == NULL) 581 return FSFATAL; 582 583 /* Point to the @cluster'th entry in the FAT. */ 584 p = block->buffer + (cluster * 2) % FAT_CHUNK_SIZE; 585 586 /* Store the value. */ 587 *p++ = (uint8_t) value; 588 *p = (uint8_t) (value >> 8); 589 590 /* Update the use map. */ 591 if (value == CLUST_FREE) 592 markFree(cluster); 593 else 594 markUsed(cluster); 595 596 /* Remember that this block has been changed. */ 597 block->dirty = 1; 598 599 return 0; 600} 601 602static int fat12_set(cl_t cluster, cl_t value) 603{ 604 struct fat_cache_block *block; 605 uint8_t *p; 606 607 if (cluster >= gBoot->NumClusters) 608 { 609 fprintf(stderr, "fat16_set: invalid cluster (%u)\n", cluster); 610 return FSFATAL; 611 } 612 613 block = fat_cache_find(cluster + cluster/2); 614 if (block == NULL) 615 return FSFATAL; 616 617 /* Point to the @cluster'th entry in the FAT. */ 618 p = block->buffer + (cluster + cluster/2) % FAT_CHUNK_SIZE; 619 620 /* Mix the new value with other nibble. */ 621 if (cluster & 1) 622 value = (value << 4) | (p[0] & 0x0F); 623 else 624 value |= (p[1] & 0xF0) << 8; 625 *p++ = (uint8_t) value; 626 *p = (uint8_t) (value >> 8); 627 628 /* Update the use map. */ 629 if (value == CLUST_FREE) 630 markFree(cluster); 631 else 632 markUsed(cluster); 633 634 /* Remember that this block has been changed. */ 635 block->dirty = 1; 636 637 return 0; 638} 639 640 641/* 642 * If the FAT has been modified, write it back to disk. 643 */ 644int fat_flush(void) 645{ 646 int i; 647 int activeFAT; 648 off_t offset; 649 650 activeFAT = gBoot->ValidFat >= 0 ? gBoot->ValidFat : 0; 651 652 for (i=0; i<gNumCacheBlocks; ++i) 653 { 654 if (fat_cache[i].dirty) 655 { 656 /* Byte offset of start of active FAT */ 657 offset = (gBoot->ResSectors + activeFAT * gBoot->FATsecs) * gBoot->BytesPerSec; 658 659 /* Byte offset of current chunk */ 660 offset += fat_cache[i].chunk * FAT_CHUNK_SIZE; 661 662// fprintf(stderr, "Flushing FAT sector %u\n", fat_cache[i].sector); 663 if (lseek(gFS, offset, SEEK_SET) != offset) 664 { 665 perr("Unable to seek FAT"); 666 return FSFATAL; 667 } 668 if (deblock_write(gFS, fat_cache[i].buffer, fat_cache[i].length) != fat_cache[i].length) 669 { 670 perr("Unable to write FAT"); 671 return FSFATAL; 672 } 673 674 fat_cache[i].dirty = 0; 675 } 676 } 677 678 return 0; 679} 680 681 682/* 683 * Mark all unreferenced clusters as CLUST_FREE. Also calculate 684 * the number of free clusters. 685 */ 686int fat_free_unused(void) 687{ 688 int err = 0; 689 cl_t cluster, value; 690 cl_t count = 0; 691 int fix=0; 692 693 for (cluster = CLUST_FIRST; cluster < gBoot->NumClusters; ++cluster) 694 { 695 value = fat_get(cluster); 696 if (value == CLUST_ERROR) 697 break; 698 if (!isUsed(cluster)) 699 { 700 if (value == CLUST_BAD) 701 { 702 gBoot->NumBad++; 703 } 704 else if (value == CLUST_FREE) 705 { 706 gBoot->NumFree++; 707 } 708 else 709 { 710 if (count == 0) 711 { 712 pwarn("Found orphan cluster(s)\n"); 713 fix = ask(1, "Fix"); 714 } 715 ++count; 716 if (fix) 717 { 718 err = fat_set(cluster, CLUST_FREE); 719 if (err) 720 break; 721 gBoot->NumFree++; 722 } 723 } 724 } 725 } 726 727 if (count) 728 { 729 if (fix) 730 { 731 pwarn("Marked %u clusters as free\n", count); 732 err |= FSFATMOD; 733 } 734 else 735 { 736 pwarn("Found %u orphaned clusters\n", count); 737 err |= FSERROR; 738 } 739 } 740 741 /* 742 * Check the FSInfo sector. 743 * 744 * NOTE: Since the values there are merely "hints", we don't return a 745 * non-zero exit status if the values are unexpected. 746 */ 747 if (gBoot->FSInfo) { 748 fix = 0; 749 if (gBoot->FSFree != gBoot->NumFree) { 750 pwarn("Free space in FSInfo block (%d) not correct (%d)\n", 751 gBoot->FSFree, gBoot->NumFree); 752 if (ask(1, "Fix")) { 753 gBoot->FSFree = gBoot->NumFree; 754 fix = 1; 755 } 756 } 757 if (fix) 758 err |= writefsinfo(gFS, gBoot); 759 } 760 761 return err; 762} 763 764 765/* 766 * Determine whether a volume is dirty, without reading the entire FAT. 767 */ 768int isdirty(int fs, struct bootblock *boot, int fat) 769{ 770 int result; 771 u_char *buffer; 772 off_t offset; 773 774 result = 1; /* In case of error, assume volume was dirty */ 775 776 /* FAT12 volumes don't have a "clean" bit, so always assume they are dirty */ 777 if (boot->ClustMask == CLUST12_MASK) 778 return 1; 779 780 buffer = malloc(boot->BytesPerSec); 781 if (buffer == NULL) { 782 perr("No space for FAT sector"); 783 return 1; /* Assume it was dirty */ 784 } 785 786 offset = boot->ResSectors + fat * boot->FATsecs; 787 offset *= boot->BytesPerSec; 788 789 if (lseek(fs, offset, SEEK_SET) != offset) { 790 perr("Unable to read FAT"); 791 goto ERROR; 792 } 793 794 if (deblock_read(fs, buffer, boot->BytesPerSec) != boot->BytesPerSec) { 795 perr("Unable to read FAT"); 796 goto ERROR; 797 } 798 799 switch (boot->ClustMask) { 800 case CLUST32_MASK: 801 /* FAT32 uses bit 27 of FAT[1] */ 802 if ((buffer[7] & 0x08) != 0) 803 result = 0; /* It's clean */ 804 break; 805 case CLUST16_MASK: 806 /* FAT16 uses bit 15 of FAT[1] */ 807 if ((buffer[3] & 0x80) != 0) 808 result = 0; /* It's clean */ 809 break; 810 } 811 812ERROR: 813 free(buffer); 814 return result; 815} 816 817 818/* 819 * Mark a FAT16 or FAT32 volume "clean." Ignored for FAT12. 820 */ 821int fat_mark_clean(void) 822{ 823 cl_t value; 824 825 /* 826 * FAT12 does not have a "dirty" bit, so do nothing. 827 */ 828 if (gBoot->ClustMask == CLUST12_MASK) 829 return 0; 830 831 value = fat_get(1); 832 if (value == CLUST_ERROR) 833 return FSERROR; 834 835 if (gBoot->ClustMask == CLUST16_MASK) 836 value |= 0x8000; 837 else 838 value |= 0x08000000; 839 return fat_set(1, value); 840} 841 842 843/* 844 * Get type of reserved cluster 845 */ 846char * 847rsrvdcltype(cl) 848 cl_t cl; 849{ 850 if (cl == CLUST_FREE) 851 return "free"; 852 if (cl < CLUST_BAD) 853 return "reserved"; 854 if (cl > CLUST_BAD) 855 return "as EOF"; 856 return "bad"; 857} 858 859#define DEBLOCK_SIZE (MAXPHYSIO>>2) 860ssize_t deblock_read(int d, void *buf, size_t nbytes) { 861 ssize_t totbytes = 0, readbytes; 862 char *b = buf; 863 864 while (nbytes > 0) { 865 size_t rbytes = nbytes < DEBLOCK_SIZE? nbytes : DEBLOCK_SIZE; 866 readbytes = read(d, b, rbytes); 867 if (readbytes < 0) 868 return readbytes; 869 else if (readbytes == 0) 870 break; 871 else { 872 nbytes-=readbytes; 873 totbytes += readbytes; 874 b += readbytes; 875 } 876 } 877 878 return totbytes; 879} 880 881ssize_t deblock_write(int d, void *buf, size_t nbytes) { 882 ssize_t totbytes = 0, writebytes; 883 char *b = buf; 884 885 while (nbytes > 0) { 886 size_t wbytes = nbytes < DEBLOCK_SIZE ? nbytes : DEBLOCK_SIZE; 887 writebytes = write(d, b, wbytes); 888 if (writebytes < 0) 889 return writebytes; 890 else if (writebytes == 0) 891 break; 892 else { 893 nbytes-=writebytes; 894 totbytes += writebytes; 895 b += writebytes; 896 } 897 } 898 899 return totbytes; 900} 901 902 903/*====================================================================== 904 Cluster Use Map Routines 905 906 These routines keep track of which clusters have been referenced 907 (by a directory entry). 908 909 Right now, the implementation is a simple bitmap. But it could be 910 replaced with something else (list of allocated ranges, etc.). 911======================================================================*/ 912 913static uint32_t *useMap = NULL; 914 915int initUseMap(struct bootblock *boot) 916{ 917 /* Round up clusters to a multiple of 32 */ 918 cl_t clusters = (boot->NumClusters + 31) & ~31; 919 if (useMap != NULL) 920 free(useMap); 921 gUseMapBytes = clusters/8; 922 if (maxmem != 0 && maxmem < (gUseMapBytes + FAT_CHUNK_SIZE)) 923 { 924 pfatal("Cannot allocate %zd bytes for usemap (maxmem=%zd, clusters=%d)\n" 925 "maxmem must be at least %zd\n", 926 gUseMapBytes, maxmem, clusters, gUseMapBytes + FAT_CHUNK_SIZE); 927 useMap = NULL; 928 } 929 else 930 { 931 useMap = calloc(clusters/32, sizeof(uint32_t)); 932 } 933 return useMap==NULL; 934} 935 936void freeUseMap(void) 937{ 938 if (useMap == NULL) 939 free(useMap); 940 useMap = NULL; 941} 942 943int isUsed(cl_t cluster) 944{ 945 return (useMap[cluster/32] >> cluster%32) & 1; 946} 947 948int markUsed(cl_t cluster) 949{ 950 int error = 0; 951 cl_t index = cluster / 32; 952 uint32_t mask = 1 << (cluster % 32); 953 954 if (useMap[index] & mask) 955 error = 1; 956 else 957 useMap[index] |= mask; 958 959 return error; 960} 961 962int markFree(cl_t cluster) 963{ 964 int error = 0; 965 cl_t index = cluster / 32; 966 uint32_t mask = 1 << (cluster % 32); 967 968 if (useMap[index] & mask) 969 useMap[index] &= ~mask; 970 else 971 error = 1; 972 973 return error; 974} 975