1 /* fat.c - Read/write access to the FAT 2 3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch> 4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> 5 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch> 6 7 This program is free software: you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 20 The complete text of the GNU General Public License 21 can be found in /usr/share/common-licenses/GPL-3 file. 22 */ 23 24 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998 25 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */ 26 27 #include "vfatlib.h" 28 29 #define NDEBUG 30 #include <debug.h> 31 32 33 /** 34 * Fetch the FAT entry for a specified cluster. 35 * 36 * @param[out] entry Cluster to which cluster of interest is linked 37 * @param[in] fat FAT table for the partition 38 * @param[in] cluster Cluster of interest 39 * @param[in] fs Information from the FAT boot sectors (bits per FAT entry) 40 */ 41 void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs) 42 { 43 unsigned char *ptr; 44 45 if (cluster > fs->data_clusters + 1) { 46 die("Internal error: cluster out of range in get_fat() (%lu > %lu).", 47 (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1)); 48 } 49 50 switch (fs->fat_bits) { 51 case 12: 52 ptr = &((unsigned char *)fat)[cluster * 3 / 2]; 53 entry->value = 0xfff & (cluster & 1 ? (ptr[0] >> 4) | (ptr[1] << 4) : 54 (ptr[0] | ptr[1] << 8)); 55 break; 56 case 16: 57 entry->value = le16toh(((unsigned short *)fat)[cluster]); 58 break; 59 case 32: 60 /* According to M$, the high 4 bits of a FAT32 entry are reserved and 61 * are not part of the cluster number. So we cut them off. */ 62 { 63 uint32_t e = le32toh(((unsigned int *)fat)[cluster]); 64 entry->value = e & 0xfffffff; 65 entry->reserved = e >> 28; 66 } 67 break; 68 default: 69 die("Bad FAT entry size: %d bits.", fs->fat_bits); 70 } 71 } 72 73 /** 74 * Build a bookkeeping structure from the partition's FAT table. 75 * If the partition has multiple FATs and they don't agree, try to pick a winner, 76 * and queue a command to overwrite the loser. 77 * One error that is fixed here is a cluster that links to something out of range. 78 * 79 * @param[inout] fs Information about the filesystem 80 */ 81 void read_fat(DOS_FS * fs) 82 { 83 int eff_size, alloc_size; 84 uint32_t i; 85 void *first, *second = NULL; 86 int first_ok, second_ok; 87 uint32_t total_num_clusters; 88 89 /* Clean up from previous pass */ 90 if (fs->fat) 91 free(fs->fat); 92 if (fs->cluster_owner) 93 free(fs->cluster_owner); 94 fs->fat = NULL; 95 fs->cluster_owner = NULL; 96 97 total_num_clusters = fs->data_clusters + 2; 98 eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL; 99 100 if (fs->fat_bits != 12) 101 alloc_size = eff_size; 102 else 103 /* round up to an even number of FAT entries to avoid special 104 * casing the last entry in get_fat() */ 105 alloc_size = (total_num_clusters * 12 + 23) / 24 * 3; 106 107 first = alloc(alloc_size); 108 fs_read(fs->fat_start, eff_size, first); 109 if (fs->nfats > 1) { 110 second = alloc(alloc_size); 111 fs_read(fs->fat_start + fs->fat_size, eff_size, second); 112 } 113 if (second && memcmp(first, second, eff_size) != 0) { 114 FAT_ENTRY first_media, second_media; 115 get_fat(&first_media, first, 0, fs); 116 get_fat(&second_media, second, 0, fs); 117 first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); 118 second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); 119 if (first_ok && !second_ok) { 120 printf("FATs differ - using first FAT.\n"); 121 fs_write(fs->fat_start + fs->fat_size, eff_size, first); 122 } 123 if (!first_ok && second_ok) { 124 printf("FATs differ - using second FAT.\n"); 125 fs_write(fs->fat_start, eff_size, second); 126 memcpy(first, second, eff_size); 127 } 128 if (first_ok && second_ok) { 129 if (interactive) { 130 printf("FATs differ but appear to be intact. Use which FAT ?\n" 131 "1) Use first FAT\n2) Use second FAT\n"); 132 if (get_key("12", "?") == '1') { 133 fs_write(fs->fat_start + fs->fat_size, eff_size, first); 134 } else { 135 fs_write(fs->fat_start, eff_size, second); 136 memcpy(first, second, eff_size); 137 } 138 } else { 139 printf("FATs differ but appear to be intact. Using first " 140 "FAT.\n"); 141 fs_write(fs->fat_start + fs->fat_size, eff_size, first); 142 } 143 } 144 if (!first_ok && !second_ok) { 145 printf("Both FATs appear to be corrupt. Giving up.\n"); 146 exit(1); 147 } 148 } 149 if (second) { 150 free(second); 151 } 152 fs->fat = (unsigned char *)first; 153 154 fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *)); 155 memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *))); 156 157 /* Truncate any cluster chains that link to something out of range */ 158 for (i = 2; i < fs->data_clusters + 2; i++) { 159 FAT_ENTRY curEntry; 160 get_fat(&curEntry, fs->fat, i, fs); 161 if (curEntry.value == 1) { 162 printf("Cluster %ld out of range (1). Setting to EOF.\n", 163 (long)(i - 2)); 164 set_fat(fs, i, -1); 165 } 166 if (curEntry.value >= fs->data_clusters + 2 && 167 (curEntry.value < FAT_MIN_BAD(fs))) { 168 printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n", 169 (long)(i - 2), (long)curEntry.value, 170 (long)(fs->data_clusters + 2 - 1)); 171 set_fat(fs, i, -1); 172 } 173 } 174 } 175 176 /** 177 * Update the FAT entry for a specified cluster 178 * (i.e., change the cluster it links to). 179 * Queue a command to write out this change. 180 * 181 * @param[in,out] fs Information about the filesystem 182 * @param[in] cluster Cluster to change 183 * @param[in] new Cluster to link to 184 * Special values: 185 * 0 == free cluster 186 * -1 == end-of-chain 187 * -2 == bad cluster 188 */ 189 void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new) 190 { 191 unsigned char *data = NULL; 192 int size; 193 off_t offs; 194 195 if (cluster > fs->data_clusters + 1) { 196 die("Internal error: cluster out of range in set_fat() (%lu > %lu).", 197 (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1)); 198 } 199 200 if (new == -1) 201 new = FAT_EOF(fs); 202 else if ((long)new == -2) 203 new = FAT_BAD(fs); 204 else if (new > fs->data_clusters + 1) { 205 die("Internal error: new cluster out of range in set_fat() (%lu > %lu).", 206 (unsigned long)new, (unsigned long)(fs->data_clusters + 1)); 207 } 208 209 switch (fs->fat_bits) { 210 case 12: 211 data = fs->fat + cluster * 3 / 2; 212 offs = fs->fat_start + cluster * 3 / 2; 213 if (cluster & 1) { 214 FAT_ENTRY prevEntry; 215 get_fat(&prevEntry, fs->fat, cluster - 1, fs); 216 data[0] = ((new & 0xf) << 4) | (prevEntry.value >> 8); 217 data[1] = new >> 4; 218 } else { 219 FAT_ENTRY subseqEntry; 220 if (cluster != fs->data_clusters + 1) 221 get_fat(&subseqEntry, fs->fat, cluster + 1, fs); 222 else 223 subseqEntry.value = 0; 224 data[0] = new & 0xff; 225 data[1] = (new >> 8) | ((0xff & subseqEntry.value) << 4); 226 } 227 size = 2; 228 break; 229 case 16: 230 data = fs->fat + cluster * 2; 231 offs = fs->fat_start + cluster * 2; 232 *(unsigned short *)data = htole16(new); 233 size = 2; 234 break; 235 case 32: 236 { 237 FAT_ENTRY curEntry; 238 get_fat(&curEntry, fs->fat, cluster, fs); 239 240 data = fs->fat + cluster * 4; 241 offs = fs->fat_start + cluster * 4; 242 /* According to M$, the high 4 bits of a FAT32 entry are reserved and 243 * are not part of the cluster number. So we never touch them. */ 244 *(uint32_t *)data = htole32((new & 0xfffffff) | 245 (curEntry.reserved << 28)); 246 size = 4; 247 } 248 break; 249 default: 250 die("Bad FAT entry size: %d bits.", fs->fat_bits); 251 } 252 fs_write(offs, size, data); 253 if (fs->nfats > 1) { 254 fs_write(offs + fs->fat_size, size, data); 255 } 256 } 257 258 int bad_cluster(DOS_FS * fs, uint32_t cluster) 259 { 260 FAT_ENTRY curEntry; 261 get_fat(&curEntry, fs->fat, cluster, fs); 262 263 return FAT_IS_BAD(fs, curEntry.value); 264 } 265 266 /** 267 * Get the cluster to which the specified cluster is linked. 268 * If the linked cluster is marked bad, abort. 269 * 270 * @param[in] fs Information about the filesystem 271 * @param[in] cluster Cluster to follow 272 * 273 * @return -1 'cluster' is at the end of the chain 274 * @return Other values Next cluster in this chain 275 */ 276 uint32_t next_cluster(DOS_FS * fs, uint32_t cluster) 277 { 278 uint32_t value; 279 FAT_ENTRY curEntry; 280 281 get_fat(&curEntry, fs->fat, cluster, fs); 282 283 value = curEntry.value; 284 if (FAT_IS_BAD(fs, value)) 285 die("Internal error: next_cluster on bad cluster"); 286 return FAT_IS_EOF(fs, value) ? -1 : value; 287 } 288 289 off_t cluster_start(DOS_FS * fs, uint32_t cluster) 290 { 291 return fs->data_start + ((off_t)cluster - 2) * (uint64_t)fs->cluster_size; 292 } 293 294 /** 295 * Update internal bookkeeping to show that the specified cluster belongs 296 * to the specified dentry. 297 * 298 * @param[in,out] fs Information about the filesystem 299 * @param[in] cluster Cluster being assigned 300 * @param[in] owner Information on dentry that owns this cluster 301 * (may be NULL) 302 */ 303 void set_owner(DOS_FS * fs, uint32_t cluster, DOS_FILE * owner) 304 { 305 if (fs->cluster_owner == NULL) 306 die("Internal error: attempt to set owner in non-existent table"); 307 308 if (owner && fs->cluster_owner[cluster] 309 && (fs->cluster_owner[cluster] != owner)) 310 die("Internal error: attempt to change file owner"); 311 fs->cluster_owner[cluster] = owner; 312 } 313 314 DOS_FILE *get_owner(DOS_FS * fs, uint32_t cluster) 315 { 316 if (fs->cluster_owner == NULL) 317 return NULL; 318 else 319 return fs->cluster_owner[cluster]; 320 } 321 322 void fix_bad(DOS_FS * fs) 323 { 324 uint32_t i; 325 326 if (verbose) 327 printf("Checking for bad clusters.\n"); 328 for (i = 2; i < fs->data_clusters + 2; i++) { 329 FAT_ENTRY curEntry; 330 get_fat(&curEntry, fs->fat, i, fs); 331 332 if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value)) 333 if (!fs_test(cluster_start(fs, i), fs->cluster_size)) { 334 printf("Cluster %lu is unreadable.\n", (unsigned long)i); 335 set_fat(fs, i, -2); 336 } 337 } 338 } 339 340 void reclaim_free(DOS_FS * fs) 341 { 342 int reclaimed; 343 uint32_t i; 344 345 if (verbose) 346 printf("Checking for unused clusters.\n"); 347 reclaimed = 0; 348 for (i = 2; i < fs->data_clusters + 2; i++) { 349 FAT_ENTRY curEntry; 350 get_fat(&curEntry, fs->fat, i, fs); 351 352 if (!get_owner(fs, i) && curEntry.value && 353 !FAT_IS_BAD(fs, curEntry.value) && rw) { 354 set_fat(fs, i, 0); 355 reclaimed++; 356 } 357 } 358 if (reclaimed) 359 printf("Reclaimed %d unused cluster%s (%llu bytes).\n", (int)reclaimed, 360 reclaimed == 1 ? "" : "s", 361 (unsigned long long)reclaimed * fs->cluster_size); 362 } 363 364 /** 365 * Assign the specified owner to all orphan chains (except cycles). 366 * Break cross-links between orphan chains. 367 * 368 * @param[in,out] fs Information about the filesystem 369 * @param[in] owner dentry to be assigned ownership of orphans 370 * @param[in,out] num_refs For each orphan cluster [index], how many 371 * clusters link to it. 372 * @param[in] start_cluster Where to start scanning for orphans 373 */ 374 static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs, 375 uint32_t start_cluster) 376 { 377 int prev; 378 uint32_t i, walk; 379 380 if (start_cluster == 0) 381 start_cluster = 2; 382 383 for (i = start_cluster; i < fs->data_clusters + 2; i++) { 384 FAT_ENTRY curEntry; 385 get_fat(&curEntry, fs->fat, i, fs); 386 387 /* If the current entry is the head of an un-owned chain... */ 388 if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) && 389 !get_owner(fs, i) && !num_refs[i]) { 390 prev = 0; 391 /* Walk the chain, claiming ownership as we go */ 392 for (walk = i; walk != -1; walk = next_cluster(fs, walk)) { 393 if (!get_owner(fs, walk)) { 394 set_owner(fs, walk, owner); 395 } else { 396 /* We've run into cross-links between orphaned chains, 397 * or a cycle with a tail. 398 * Terminate this orphan chain (break the link) 399 */ 400 set_fat(fs, prev, -1); 401 402 /* This is not necessary because 'walk' is owned and thus 403 * will never become the head of a chain (the only case 404 * that would matter during reclaim to files). 405 * It's easier to decrement than to prove that it's 406 * unnecessary. 407 */ 408 num_refs[walk]--; 409 break; 410 } 411 prev = walk; 412 } 413 } 414 } 415 } 416 417 /** 418 * Recover orphan chains to files, handling any cycles or cross-links. 419 * 420 * @param[in,out] fs Information about the filesystem 421 */ 422 void reclaim_file(DOS_FS * fs) 423 { 424 DOS_FILE orphan; 425 int reclaimed, files; 426 int changed = 0; 427 uint32_t i, next, walk; 428 uint32_t *num_refs = NULL; /* Only for orphaned clusters */ 429 uint32_t total_num_clusters; 430 431 if (verbose) 432 printf("Reclaiming unconnected clusters.\n"); 433 434 total_num_clusters = fs->data_clusters + 2; 435 num_refs = alloc(total_num_clusters * sizeof(uint32_t)); 436 memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t))); 437 438 /* Guarantee that all orphan chains (except cycles) end cleanly 439 * with an end-of-chain mark. 440 */ 441 442 for (i = 2; i < total_num_clusters; i++) { 443 FAT_ENTRY curEntry; 444 get_fat(&curEntry, fs->fat, i, fs); 445 446 next = curEntry.value; 447 if (!get_owner(fs, i) && next && next < fs->data_clusters + 2) { 448 /* Cluster is linked, but not owned (orphan) */ 449 FAT_ENTRY nextEntry; 450 get_fat(&nextEntry, fs->fat, next, fs); 451 452 /* Mark it end-of-chain if it links into an owned cluster, 453 * a free cluster, or a bad cluster. 454 */ 455 if (get_owner(fs, next) || !nextEntry.value || 456 FAT_IS_BAD(fs, nextEntry.value)) 457 set_fat(fs, i, -1); 458 else 459 num_refs[next]++; 460 } 461 } 462 463 /* Scan until all the orphans are accounted for, 464 * and all cycles and cross-links are broken 465 */ 466 do { 467 tag_free(fs, &orphan, num_refs, changed); 468 changed = 0; 469 470 /* Any unaccounted-for orphans must be part of a cycle */ 471 for (i = 2; i < total_num_clusters; i++) { 472 FAT_ENTRY curEntry; 473 get_fat(&curEntry, fs->fat, i, fs); 474 475 if (curEntry.value && !FAT_IS_BAD(fs, curEntry.value) && 476 !get_owner(fs, i)) { 477 if (!num_refs[curEntry.value]--) 478 die("Internal error: num_refs going below zero"); 479 set_fat(fs, i, -1); 480 changed = curEntry.value; 481 printf("Broke cycle at cluster %lu in free chain.\n", (unsigned long)i); 482 483 /* If we've created a new chain head, 484 * tag_free() can claim it 485 */ 486 if (num_refs[curEntry.value] == 0) 487 break; 488 } 489 } 490 } 491 while (changed); 492 493 if (rw) { 494 /* Now we can start recovery */ 495 files = reclaimed = 0; 496 for (i = 2; i < total_num_clusters; i++) 497 /* If this cluster is the head of an orphan chain... */ 498 if (get_owner(fs, i) == &orphan && !num_refs[i]) { 499 DIR_ENT de; 500 off_t offset; 501 files++; 502 offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC"); 503 de.start = htole16(i & 0xffff); 504 if (fs->fat_bits == 32) 505 de.starthi = htole16(i >> 16); 506 for (walk = i; walk > 0 && walk != -1; 507 walk = next_cluster(fs, walk)) { 508 de.size = htole32(le32toh(de.size) + fs->cluster_size); 509 reclaimed++; 510 } 511 fs_write(offset, sizeof(DIR_ENT), &de); 512 } 513 if (reclaimed) 514 printf("Reclaimed %d unused cluster%s (%llu bytes) in %d chain%s.\n", 515 reclaimed, reclaimed == 1 ? "" : "s", 516 (unsigned long long)reclaimed * fs->cluster_size, files, 517 files == 1 ? "" : "s"); 518 } 519 520 free(num_refs); 521 } 522 523 uint32_t update_free(DOS_FS * fs) 524 { 525 uint32_t i; 526 uint32_t free = 0; 527 int do_set = 0; 528 529 for (i = 2; i < fs->data_clusters + 2; i++) { 530 FAT_ENTRY curEntry; 531 get_fat(&curEntry, fs->fat, i, fs); 532 533 if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value)) 534 ++free; 535 } 536 537 if (!fs->fsinfo_start) 538 return free; 539 540 if (verbose) 541 printf("Checking free cluster summary.\n"); 542 if (fs->free_clusters != 0xFFFFFFFF) { 543 if (free != fs->free_clusters) { 544 printf("Free cluster summary wrong (%ld vs. really %ld)\n", 545 (long)fs->free_clusters, (long)free); 546 if (interactive) 547 printf("1) Correct\n2) Don't correct\n"); 548 else if (rw) 549 printf(" Auto-correcting.\n"); 550 if ((!interactive && rw) || (interactive && get_key("12", "?") == '1')) 551 do_set = 1; 552 } 553 } else { 554 printf("Free cluster summary uninitialized (should be %ld)\n", (long)free); 555 if (rw) { 556 if (interactive) 557 printf("1) Set it\n2) Leave it uninitialized\n"); 558 else 559 printf(" Auto-setting.\n"); 560 if (!interactive || get_key("12", "?") == '1') 561 do_set = 1; 562 } 563 } 564 565 if (do_set) { 566 uint32_t le_free = htole32(free); 567 fs->free_clusters = free; 568 fs_write(fs->fsinfo_start + offsetof(struct info_sector, free_clusters), 569 sizeof(le_free), &le_free); 570 } 571 572 return free; 573 } 574