fat.c revision 125485
150476Speter/* 215903Swosch * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 315903Swosch * Copyright (c) 1995 Martin Husemann 415903Swosch * 515903Swosch * Redistribution and use in source and binary forms, with or without 615903Swosch * modification, are permitted provided that the following conditions 715903Swosch * are met: 815903Swosch * 1. Redistributions of source code must retain the above copyright 915903Swosch * notice, this list of conditions and the following disclaimer. 1015903Swosch * 2. Redistributions in binary form must reproduce the above copyright 1115903Swosch * notice, this list of conditions and the following disclaimer in the 1215903Swosch * documentation and/or other materials provided with the distribution. 1315903Swosch * 3. All advertising materials mentioning features or use of this software 14139761Skrion * must display the following acknowledgement: 1534678Sbde * This product includes software developed by Martin Husemann 1623546Swosch * and Wolfgang Solfrank. 1723546Swosch * 4. Neither the name of the University nor the names of its contributors 1823546Swosch * may be used to endorse or promote products derived from this software 1939161Sobrien * without specific prior written permission. 2015903Swosch * 2139161Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2215903Swosch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2315903Swosch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2415903Swosch * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2515903Swosch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2615903Swosch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2715903Swosch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2815903Swosch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2932216Swosch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3032216Swosch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3132216Swosch */ 3232216Swosch 33218525Skeramida 34218525Skeramida#include <sys/cdefs.h> 3515903Swosch#ifndef lint 3615903Swosch__RCSID("$NetBSD: fat.c,v 1.12 2000/10/10 20:24:52 is Exp $"); 3715903Swoschstatic const char rcsid[] = 3815903Swosch "$FreeBSD: head/sbin/fsck_msdosfs/fat.c 125485 2004-02-05 15:18:18Z bde $"; 39119057Sobrien#endif /* not lint */ 4015903Swosch 4115903Swosch#include <stdlib.h> 4215903Swosch#include <string.h> 4315903Swosch#include <ctype.h> 4415903Swosch#include <stdio.h> 4515903Swosch#include <unistd.h> 46251512Semaste 47251512Semaste#include "ext.h" 48251512Semaste#include "fsutil.h" 49251512Semaste 50251512Semastestatic int checkclnum(struct bootblock *, int, cl_t, cl_t *); 5115903Swoschstatic int clustdiffer(cl_t, cl_t *, cl_t *, int); 5265501Sobrienstatic int tryclear(struct bootblock *, struct fatEntry *, cl_t, cl_t *); 5315903Swoschstatic int _readfat(int, struct bootblock *, int, u_char **); 54186894Sbz 5515903Swosch/*- 56186894Sbz * The first 2 FAT entries contain pseudo-cluster numbers with the following 5715903Swosch * layout: 5853033Sphantom * 5915903Swosch * 31...... ........ ........ .......0 6015903Swosch * rrrr1111 11111111 11111111 mmmmmmmm FAT32 entry 0 6115903Swosch * rrrrsh11 11111111 11111111 11111xxx FAT32 entry 1 6215903Swosch * 6315903Swosch * 11111111 mmmmmmmm FAT16 entry 0 6439161Sobrien * sh111111 11111xxx FAT16 entry 1 6515903Swosch * 6639161Sobrien * r = reserved 6715903Swosch * m = BPB media ID byte 6815903Swosch * s = clean flag (1 = dismounted; 0 = still mounted) 6915903Swosch * h = hard error flag (1 = ok; 0 = I/O error) 7015903Swosch * x = any value ok 71223596Sse */ 72223596Sse 73223596Sseint 74223596Ssecheckdirty(int fs, struct bootblock *boot) 75223596Sse{ 76223596Sse off_t off; 77223596Sse u_char *buffer; 78223596Sse int ret = 0; 79223596Sse 8015903Swosch if (boot->ClustMask != CLUST16_MASK && boot->ClustMask != CLUST32_MASK) 8115903Swosch return 0; 8215903Swosch 8315903Swosch off = boot->ResSectors; 8415903Swosch off *= boot->BytesPerSec; 8515903Swosch 8615903Swosch buffer = malloc(boot->BytesPerSec); 8715903Swosch if (buffer == NULL) { 8815903Swosch perror("No space for FAT"); 8915903Swosch return 1; 9015903Swosch } 9115903Swosch 9215903Swosch if (lseek(fs, off, SEEK_SET) != off) { 9315903Swosch perror("Unable to read FAT"); 9415903Swosch goto err; 9515903Swosch } 9615903Swosch 9715903Swosch if (read(fs, buffer, boot->BytesPerSec) != boot->BytesPerSec) { 9815903Swosch perror("Unable to read FAT"); 9915903Swosch goto err; 10015903Swosch } 10115903Swosch 10215903Swosch /* 10315903Swosch * If we don't understand the FAT, then the file system must be 10415903Swosch * assumed to be unclean. 10515903Swosch */ 10615903Swosch if (buffer[0] != boot->Media || buffer[1] != 0xff) 10715903Swosch goto err; 10815903Swosch if (boot->ClustMask == CLUST16_MASK) { 10915903Swosch if ((buffer[2] & 0xf8) != 0xf8 || (buffer[3] & 0x3f) != 0x3f) 11090627Sphantom goto err; 11115903Swosch } else { 11290626Sphantom if (buffer[2] != 0xff || (buffer[3] & 0x0f) != 0x0f 11315903Swosch || (buffer[4] & 0xf8) != 0xf8 || buffer[5] != 0xff 11490626Sphantom || buffer[6] != 0xff || (buffer[7] & 0x03) != 0x03) 11515903Swosch goto err; 11661462Sghelmer } 11715903Swosch 11832216Swosch /* 11915903Swosch * Now check the actual clean flag (and the no-error flag). 12094982Sru */ 12194982Sru if (boot->ClustMask == CLUST16_MASK) { 12294982Sru if ((buffer[3] & 0xc0) == 0xc0) 123164411Sru ret = 1; 124156813Sru } else { 125248751Semaste if ((buffer[7] & 0x0c) == 0x0c) 126156836Sru ret = 1; 127156836Sru } 128164411Sru 129156813Sruerr: 13014968Swosch free(buffer); 13139161Sobrien return ret; 13239161Sobrien} 13314573Swosch 13414968Swosch/* 13514573Swosch * Check a cluster number for valid value 136111853Sru */ 137111853Srustatic int 138111853Srucheckclnum(struct bootblock *boot, int fat, cl_t cl, cl_t *next) 13965501Sobrien{ 140111853Sru if (*next >= (CLUST_RSRVD&boot->ClustMask)) 14148204Sjmg *next |= ~boot->ClustMask; 14248204Sjmg if (*next == CLUST_FREE) { 14348204Sjmg boot->NumFree++; 14448204Sjmg return FSOK; 14514573Swosch } 14632226Ssteve if (*next == CLUST_BAD) { 14732226Ssteve boot->NumBad++; 148218525Skeramida return FSOK; 14914573Swosch } 15014573Swosch if (*next < CLUST_FIRST 15114968Swosch || (*next >= boot->NumClusters && *next < CLUST_EOFS)) { 15214968Swosch pwarn("Cluster %u in FAT %d continues with %s cluster number %u\n", 15314968Swosch cl, fat, 15414573Swosch *next < CLUST_RSRVD ? "out of range" : "reserved", 155251512Semaste *next&boot->ClustMask); 156251512Semaste if (ask(0, "Truncate")) { 15714968Swosch *next = CLUST_EOF; 158251512Semaste return FSFATMOD; 15914968Swosch } 16014968Swosch return FSERROR; 16139161Sobrien } 16239161Sobrien return FSOK; 16314968Swosch} 16414968Swosch 165223596Sse/* 166223596Sse * Read a FAT from disk. Returns 1 if successful, 0 otherwise. 167223596Sse */ 168223596Ssestatic int 169223596Sse_readfat(int fs, struct bootblock *boot, int no, u_char **buffer) 17014968Swosch{ 17114968Swosch off_t off; 17214968Swosch 17314968Swosch *buffer = malloc(boot->FATsecs * boot->BytesPerSec); 17414968Swosch if (*buffer == NULL) { 17514968Swosch perror("No space for FAT"); 17614968Swosch return 0; 17714968Swosch } 17814968Swosch 17914968Swosch off = boot->ResSectors + no * boot->FATsecs; 18014968Swosch off *= boot->BytesPerSec; 18114968Swosch 18214968Swosch if (lseek(fs, off, SEEK_SET) != off) { 18314968Swosch perror("Unable to read FAT"); 18414968Swosch goto err; 18514968Swosch } 18690626Sphantom 18790626Sphantom if (read(fs, *buffer, boot->FATsecs * boot->BytesPerSec) 18861462Sghelmer != boot->FATsecs * boot->BytesPerSec) { 18914968Swosch perror("Unable to read FAT"); 19032216Swosch goto err; 19132216Swosch } 192245752Sbrooks 193245752Sbrooks return 1; 194245752Sbrooks 195245752Sbrooks err: 196245752Sbrooks free(*buffer); 197245752Sbrooks return 0; 198245752Sbrooks} 199245752Sbrooks 200245752Sbrooks/* 20114968Swosch * Read a FAT and decode it into internal format 202125494Sru */ 203125494Sruint 204125494Srureadfat(int fs, struct bootblock *boot, int no, struct fatEntry **fp) 205125494Sru{ 20634678Sbde struct fatEntry *fat; 20723546Swosch u_char *buffer, *p; 20894982Sru cl_t cl; 209164411Sru int ret = FSOK; 210156813Sru 211156813Sru boot->NumFree = boot->NumBad = 0; 212156813Sru 213156813Sru if (!_readfat(fs, boot, no, &buffer)) 214156813Sru return FSFATAL; 215156813Sru 216156813Sru fat = calloc(boot->NumClusters, sizeof(struct fatEntry)); 217156813Sru if (fat == NULL) { 218156813Sru perror("No space for FAT"); 219156813Sru free(buffer); 220156813Sru return FSFATAL; 221156813Sru } 222156813Sru 223228158Sfjoe if (buffer[0] != boot->Media 224251512Semaste || buffer[1] != 0xff || buffer[2] != 0xff 225172832Sru || (boot->ClustMask == CLUST16_MASK && buffer[3] != 0xff) 226156869Sru || (boot->ClustMask == CLUST32_MASK 227156869Sru && ((buffer[3]&0x0f) != 0x0f 228156813Sru || buffer[4] != 0xff || buffer[5] != 0xff 229228120Sfjoe || buffer[6] != 0xff || (buffer[7]&0x0f) != 0x0f))) { 230228120Sfjoe 231228120Sfjoe /* Windows 95 OSR2 (and possibly any later) changes 232156813Sru * the FAT signature to 0xXXffff7f for FAT16 and to 233156813Sru * 0xXXffff0fffffff07 for FAT32 upon boot, to know that the 234156813Sru * file system is dirty if it doesn't reboot cleanly. 235156813Sru * Check this special condition before errorring out. 236156813Sru */ 237156813Sru if (buffer[0] == boot->Media && buffer[1] == 0xff 238156813Sru && buffer[2] == 0xff 239156813Sru && ((boot->ClustMask == CLUST16_MASK && buffer[3] == 0x7f) 240156813Sru || (boot->ClustMask == CLUST32_MASK 241156813Sru && buffer[3] == 0x0f && buffer[4] == 0xff 242156813Sru && buffer[5] == 0xff && buffer[6] == 0xff 243220359Simp && buffer[7] == 0x07))) 244183242Ssam ret |= FSDIRTY; 245156813Sru else { 246183242Ssam /* just some odd byte sequence in FAT */ 247183242Ssam 248253396Sandrew switch (boot->ClustMask) { 249162210Simp case CLUST32_MASK: 250183242Ssam pwarn("%s (%02x%02x%02x%02x%02x%02x%02x%02x)\n", 251241823Smarcel "FAT starts with odd byte sequence", 252156813Sru buffer[0], buffer[1], buffer[2], buffer[3], 253156813Sru buffer[4], buffer[5], buffer[6], buffer[7]); 254156813Sru break; 255156813Sru case CLUST16_MASK: 256156813Sru pwarn("%s (%02x%02x%02x%02x)\n", 257156813Sru "FAT starts with odd byte sequence", 258156813Sru buffer[0], buffer[1], buffer[2], buffer[3]); 259156813Sru break; 260156813Sru default: 261156813Sru pwarn("%s (%02x%02x%02x)\n", 262222090Simp "FAT starts with odd byte sequence", 263156813Sru buffer[0], buffer[1], buffer[2]); 264250699Ssjg break; 265156813Sru } 266179815Sdougb 267183242Ssam 268166255Sdelphij if (ask(1, "Correct")) 269156813Sru ret |= FSFIXFAT; 270229319Srwatson } 271163861Sjb } 272156813Sru switch (boot->ClustMask) { 273250659Sbrooks case CLUST32_MASK: 274156813Sru p = buffer + 8; 275183242Ssam break; 276156813Sru case CLUST16_MASK: 277156813Sru p = buffer + 4; 278156813Sru break; 279235654Smarcel default: 280156813Sru p = buffer + 3; 281183242Ssam break; 282250658Sbrooks } 283156813Sru for (cl = CLUST_FIRST; cl < boot->NumClusters;) { 284156813Sru switch (boot->ClustMask) { 285183242Ssam case CLUST32_MASK: 286156813Sru fat[cl].next = p[0] + (p[1] << 8) 287222090Simp + (p[2] << 16) + (p[3] << 24); 288156813Sru fat[cl].next &= boot->ClustMask; 289156813Sru ret |= checkclnum(boot, no, cl, &fat[cl].next); 290156813Sru cl++; 291156813Sru p += 4; 292220359Simp break; 293156813Sru case CLUST16_MASK: 294156813Sru fat[cl].next = p[0] + (p[1] << 8); 295221266Sbz ret |= checkclnum(boot, no, cl, &fat[cl].next); 296156813Sru cl++; 297156813Sru p += 2; 298172832Sru break; 299156813Sru default: 300183242Ssam fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff; 301156813Sru ret |= checkclnum(boot, no, cl, &fat[cl].next); 302183242Ssam cl++; 303240404Sobrien if (cl >= boot->NumClusters) 304156813Sru break; 305222185Simp fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff; 306170644Ssepotvin ret |= checkclnum(boot, no, cl, &fat[cl].next); 307246827Sdes cl++; 308183242Ssam p += 3; 309157115Sru break; 310156813Sru } 311156813Sru } 312156813Sru 313183242Ssam free(buffer); 314156813Sru *fp = fat; 315235655Smarcel return ret; 316183242Ssam} 317156813Sru 318183242Ssam/* 319156813Sru * Get type of reserved cluster 320183242Ssam */ 321156813Sruchar * 322183242Ssamrsrvdcltype(cl_t cl) 323156813Sru{ 324156813Sru if (cl == CLUST_FREE) 325156813Sru return "free"; 326158115Sume if (cl < CLUST_BAD) 327183242Ssam return "reserved"; 328156813Sru if (cl > CLUST_BAD) 329156813Sru return "as EOF"; 330156813Sru return "bad"; 331245606Seadler} 332156813Sru 333238010Sglebiusstatic int 334183242Ssamclustdiffer(cl_t cl, cl_t *cp1, cl_t *cp2, int fatnum) 335183242Ssam{ 336183242Ssam if (*cp1 == CLUST_FREE || *cp1 >= CLUST_RSRVD) { 337183242Ssam if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) { 338228196Sfjoe if ((*cp1 != CLUST_FREE && *cp1 < CLUST_BAD 339183242Ssam && *cp2 != CLUST_FREE && *cp2 < CLUST_BAD) 340156813Sru || (*cp1 > CLUST_BAD && *cp2 > CLUST_BAD)) { 341156813Sru pwarn("Cluster %u is marked %s with different indicators, ", 342156813Sru cl, rsrvdcltype(*cp1)); 343183242Ssam if (ask(1, "fix")) { 344156813Sru *cp2 = *cp1; 345156813Sru return FSFATMOD; 346156813Sru } 347244527Semaste return FSFATAL; 348244527Semaste } 349244527Semaste pwarn("Cluster %u is marked %s in FAT 0, %s in FAT %d\n", 350169724Skan cl, rsrvdcltype(*cp1), rsrvdcltype(*cp2), fatnum); 351251886Speter if (ask(0, "use FAT 0's entry")) { 352169524Sdeischen *cp2 = *cp1; 353156813Sru return FSFATMOD; 354244527Semaste } 355156813Sru if (ask(0, "use FAT %d's entry", fatnum)) { 356183242Ssam *cp1 = *cp2; 357183242Ssam return FSFATMOD; 358156813Sru } 359156813Sru return FSFATAL; 360223209Sed } 361183242Ssam pwarn("Cluster %u is marked %s in FAT 0, but continues with cluster %u in FAT %d\n", 362168409Spjd cl, rsrvdcltype(*cp1), *cp2, fatnum); 363175617Sru if (ask(0, "Use continuation from FAT %d", fatnum)) { 364175617Sru *cp1 = *cp2; 365220359Simp return FSFATMOD; 366220359Simp } 367220359Simp if (ask(0, "Use mark from FAT 0")) { 368220359Simp *cp2 = *cp1; 369220359Simp return FSFATMOD; 370220359Simp } 371220359Simp return FSFATAL; 372238438Sdteske } 373244527Semaste if (*cp2 == CLUST_FREE || *cp2 >= CLUST_RSRVD) { 374231057Sdim pwarn("Cluster %u continues with cluster %u in FAT 0, but is marked %s in FAT %d\n", 375228158Sfjoe cl, *cp1, rsrvdcltype(*cp2), fatnum); 376251512Semaste if (ask(0, "Use continuation from FAT 0")) { 377253689Spfg *cp2 = *cp1; 378245803Stheraven return FSFATMOD; 379220359Simp } 380220359Simp if (ask(0, "Use mark from FAT %d", fatnum)) { 381237612Sobrien *cp1 = *cp2; 382246827Sdes return FSFATMOD; 383245241Sbrooks } 384235537Sgber return FSERROR; 385234782Skib } 386245527Sbz pwarn("Cluster %u continues with cluster %u in FAT 0, but with cluster %u in FAT %d\n", 387251886Speter cl, *cp1, *cp2, fatnum); 388253546Sglebius if (ask(0, "Use continuation from FAT 0")) { 389253546Sglebius *cp2 = *cp1; 390220359Simp return FSFATMOD; 391220359Simp } 392220359Simp if (ask(0, "Use continuation from FAT %d", fatnum)) { 393220359Simp *cp1 = *cp2; 394220359Simp return FSFATMOD; 395220359Simp } 396221726Sru return FSERROR; 397220359Simp} 398220359Simp 399220359Simp/* 400220359Simp * Compare two FAT copies in memory. Resolve any conflicts and merge them 401220359Simp * into the first one. 402220359Simp */ 403220359Simpint 404246354Sandrewcomparefat(struct bootblock *boot, struct fatEntry *first, 405235133Sdim struct fatEntry *second, int fatnum) 406246259Sdim{ 407246354Sandrew cl_t cl; 408246354Sandrew int ret = FSOK; 409246354Sandrew 410246354Sandrew for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) 411220359Simp if (first[cl].next != second[cl].next) 412246259Sdim ret |= clustdiffer(cl, &first[cl].next, &second[cl].next, fatnum); 413220359Simp return ret; 414248856Sandrew} 415248856Sandrew 416248856Sandrewvoid 417242624Sbrooksclearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head) 418242624Sbrooks{ 419242624Sbrooks cl_t p, q; 420242624Sbrooks 421227775Snwhitehorn for (p = head; p >= CLUST_FIRST && p < boot->NumClusters; p = q) { 422227775Snwhitehorn if (fat[p].head != head) 423220359Simp break; 424220359Simp q = fat[p].next; 425220359Simp fat[p].next = fat[p].head = CLUST_FREE; 426220359Simp fat[p].length = 0; 427220359Simp } 428220359Simp} 429220359Simp 430220359Simpint 431220359Simptryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc) 432220359Simp{ 433156813Sru if (ask(0, "Clear chain starting at %u", head)) { 434156813Sru clearchain(boot, fat, head); 435156813Sru return FSFATMOD; 436156813Sru } else if (ask(0, "Truncate")) { 437156813Sru *trunc = CLUST_EOF; 438156813Sru return FSFATMOD; 439156813Sru } else 440156813Sru return FSERROR; 441156813Sru} 442156813Sru 443156813Sru/* 444156813Sru * Check a complete FAT in-memory for crosslinks 445220359Simp */ 446156813Sruint 447156813Srucheckfat(struct bootblock *boot, struct fatEntry *fat) 448156813Sru{ 449156813Sru cl_t head, p, h, n; 450220359Simp u_int len; 451156813Sru int ret = 0; 452156813Sru int conf; 453156813Sru 454156813Sru /* 455156813Sru * pass 1: figure out the cluster chains. 456156813Sru */ 457156813Sru for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 458156813Sru /* find next untravelled chain */ 459156813Sru if (fat[head].head != 0 /* cluster already belongs to some chain */ 460156813Sru || fat[head].next == CLUST_FREE 461156813Sru || fat[head].next == CLUST_BAD) 462156813Sru continue; /* skip it. */ 463220359Simp 464156813Sru /* follow the chain and mark all clusters on the way */ 465156813Sru for (len = 0, p = head; 466156813Sru p >= CLUST_FIRST && p < boot->NumClusters; 467172571Sru p = fat[p].next) { 468156813Sru fat[p].head = head; 469172571Sru len++; 470172571Sru } 471172571Sru 472172571Sru /* the head record gets the length */ 473177714Sru fat[head].length = fat[head].next == CLUST_FREE ? 0 : len; 474172571Sru } 475172571Sru 476172571Sru /* 477156813Sru * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because 478156813Sru * we didn't know the real start of the chain then - would have treated partial 479156813Sru * chains as interlinked with their main chain) 480156813Sru */ 481156813Sru for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 482156813Sru /* find next untravelled chain */ 483156813Sru if (fat[head].head != head) 484156813Sru continue; 485156813Sru 486156813Sru /* follow the chain to its end (hopefully) */ 487246827Sdes for (p = head; 488246827Sdes (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters; 489246827Sdes p = n) 490246827Sdes if (fat[n].head != head) 491246833Sdes break; 492246827Sdes if (n >= CLUST_EOFS) 493246827Sdes continue; 494246827Sdes 495157378Sphk if (n == CLUST_FREE || n >= CLUST_RSRVD) { 496157378Sphk pwarn("Cluster chain starting at %u ends with cluster marked %s\n", 497157378Sphk head, rsrvdcltype(n)); 498157378Sphk ret |= tryclear(boot, fat, head, &fat[p].next); 499230972Srmh continue; 500230972Srmh } 501230972Srmh if (n < CLUST_FIRST || n >= boot->NumClusters) { 502230972Srmh pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n", 503230972Srmh head, n); 504168409Spjd ret |= tryclear(boot, fat, head, &fat[p].next); 505168409Spjd continue; 506228158Sfjoe } 507168409Spjd pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n", 508168409Spjd head, fat[n].head, n); 509156813Sru conf = tryclear(boot, fat, head, &fat[p].next); 510156813Sru if (ask(0, "Clear chain starting at %u", h = fat[n].head)) { 511156813Sru if (conf == FSERROR) { 512156813Sru /* 513156813Sru * Transfer the common chain to the one not cleared above. 514156813Sru */ 515220401Suqs for (p = n; 516220401Suqs p >= CLUST_FIRST && p < boot->NumClusters; 517220401Suqs p = fat[p].next) { 518220401Suqs if (h != fat[p].head) { 519220401Suqs /* 520183242Ssam * Have to reexamine this chain. 521183242Ssam */ 522183242Ssam head--; 523183242Ssam break; 524183242Ssam } 525202440Santoine fat[p].head = head; 526202440Santoine } 527202440Santoine } 528202440Santoine clearchain(boot, fat, h); 529202440Santoine conf |= FSFATMOD; 530156813Sru } 531156813Sru ret |= conf; 532156813Sru } 533156813Sru 534156813Sru return ret; 535156813Sru} 536156813Sru 537156813Sru/* 538156813Sru * Write out FATs encoding them from the internal format 539183242Ssam */ 540183242Ssamint 541183242Ssamwritefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat) 542183242Ssam{ 543156813Sru u_char *buffer, *p; 544222090Simp cl_t cl; 545208964Srdivacky int i; 546222090Simp u_int32_t fatsz; 547156813Sru off_t off; 548156813Sru int ret = FSOK; 549156813Sru 550232322Sdim buffer = malloc(fatsz = boot->FATsecs * boot->BytesPerSec); 551246131Sdim if (buffer == NULL) { 552246259Sdim perror("No space for FAT"); 553232322Sdim return FSFATAL; 554232322Sdim } 555232322Sdim memset(buffer, 0, fatsz); 556156813Sru boot->NumFree = 0; 557156813Sru p = buffer; 558156813Sru if (correct_fat) { 559156813Sru *p++ = (u_char)boot->Media; 560156813Sru *p++ = 0xff; 561156813Sru *p++ = 0xff; 562156813Sru switch (boot->ClustMask) { 563156813Sru case CLUST16_MASK: 564156813Sru *p++ = 0xff; 565166255Sdelphij break; 566156813Sru case CLUST32_MASK: 567221266Sbz *p++ = 0x0f; 568156813Sru *p++ = 0xff; 569156813Sru *p++ = 0xff; 570156813Sru *p++ = 0xff; 571170644Ssepotvin *p++ = 0x0f; 572183242Ssam break; 573183242Ssam } 574183242Ssam } else { 575156813Sru /* use same FAT signature as the old FAT has */ 576156813Sru int count; 577156813Sru u_char *old_fat; 578156813Sru 579156813Sru switch (boot->ClustMask) { 580156813Sru case CLUST32_MASK: 581156813Sru count = 8; 582156813Sru break; 583156813Sru case CLUST16_MASK: 584156813Sru count = 4; 585156813Sru break; 586156813Sru default: 587174548Sru count = 3; 588174548Sru break; 589174548Sru } 590174548Sru 591174548Sru if (!_readfat(fs, boot, boot->ValidFat >= 0 ? boot->ValidFat :0, 592208320Sjkim &old_fat)) { 593208320Sjkim free(buffer); 594174548Sru return FSFATAL; 595174548Sru } 596174548Sru 597174548Sru memcpy(p, old_fat, count); 598174548Sru free(old_fat); 599174548Sru p += count; 600174548Sru } 601174548Sru 602174548Sru for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) { 603174548Sru switch (boot->ClustMask) { 604174548Sru case CLUST32_MASK: 605174548Sru if (fat[cl].next == CLUST_FREE) 606174548Sru boot->NumFree++; 607174548Sru *p++ = (u_char)fat[cl].next; 608174548Sru *p++ = (u_char)(fat[cl].next >> 8); 609240966Sbrooks *p++ = (u_char)(fat[cl].next >> 16); 610240966Sbrooks *p &= 0xf0; 611240966Sbrooks *p++ |= (fat[cl].next >> 24)&0x0f; 612240966Sbrooks break; 613240966Sbrooks case CLUST16_MASK: 614240966Sbrooks if (fat[cl].next == CLUST_FREE) 615240966Sbrooks boot->NumFree++; 616240966Sbrooks *p++ = (u_char)fat[cl].next; 617240966Sbrooks *p++ = (u_char)(fat[cl].next >> 8); 618240966Sbrooks break; 619240966Sbrooks default: 620240966Sbrooks if (fat[cl].next == CLUST_FREE) 621240966Sbrooks boot->NumFree++; 622240966Sbrooks if (cl + 1 < boot->NumClusters 623240966Sbrooks && fat[cl + 1].next == CLUST_FREE) 624240966Sbrooks boot->NumFree++; 625240966Sbrooks *p++ = (u_char)fat[cl].next; 626240966Sbrooks *p++ = (u_char)((fat[cl].next >> 8) & 0xf) 627240966Sbrooks |(u_char)(fat[cl+1].next << 4); 628240966Sbrooks *p++ = (u_char)(fat[++cl].next >> 4); 629240966Sbrooks break; 630240966Sbrooks } 631240966Sbrooks } 632240966Sbrooks for (i = 0; i < boot->FATs; i++) { 633240966Sbrooks off = boot->ResSectors + i * boot->FATsecs; 634240966Sbrooks off *= boot->BytesPerSec; 635240966Sbrooks if (lseek(fs, off, SEEK_SET) != off 636228158Sfjoe || write(fs, buffer, fatsz) != fatsz) { 637228158Sfjoe perror("Unable to write FAT"); 638243393Ssjg ret = FSFATAL; /* Return immediately? XXX */ 639228158Sfjoe } 640228158Sfjoe } 641228158Sfjoe free(buffer); 642228158Sfjoe return ret; 643228158Sfjoe} 644237612Sobrien 645243392Ssjg/* 646237612Sobrien * Check a complete in-memory FAT for lost cluster chains 647243392Ssjg */ 648243392Ssjgint 649243392Ssjgchecklost(int dosfs, struct bootblock *boot, struct fatEntry *fat) 650237612Sobrien{ 651237612Sobrien cl_t head; 652243392Ssjg int mod = FSOK; 653237612Sobrien int ret; 654237612Sobrien 655237612Sobrien for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 656237612Sobrien /* find next untravelled chain */ 657237612Sobrien if (fat[head].head != head 658164411Sru || fat[head].next == CLUST_FREE 659156813Sru || (fat[head].next >= CLUST_RSRVD 660144893Sharti && fat[head].next < CLUST_EOFS) 661 || (fat[head].flags & FAT_USED)) 662 continue; 663 664 pwarn("Lost cluster chain at cluster %u\n%d Cluster(s) lost\n", 665 head, fat[head].length); 666 mod |= ret = reconnect(dosfs, boot, fat, head); 667 if (mod & FSFATAL) 668 break; 669 if (ret == FSERROR && ask(0, "Clear")) { 670 clearchain(boot, fat, head); 671 mod |= FSFATMOD; 672 } 673 } 674 finishlf(); 675 676 if (boot->FSInfo) { 677 ret = 0; 678 if (boot->FSFree != boot->NumFree) { 679 pwarn("Free space in FSInfo block (%d) not correct (%d)\n", 680 boot->FSFree, boot->NumFree); 681 if (ask(1, "fix")) { 682 boot->FSFree = boot->NumFree; 683 ret = 1; 684 } 685 } 686 if (boot->NumFree && fat[boot->FSNext].next != CLUST_FREE) { 687 pwarn("Next free cluster in FSInfo block (%u) not free\n", 688 boot->FSNext); 689 if (ask(1, "fix")) 690 for (head = CLUST_FIRST; head < boot->NumClusters; head++) 691 if (fat[head].next == CLUST_FREE) { 692 boot->FSNext = head; 693 ret = 1; 694 break; 695 } 696 } 697 if (ret) 698 mod |= writefsinfo(dosfs, boot); 699 } 700 701 return mod; 702} 703