📄 scan.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
scan.c
Abstract:
This file contains routines for scanning volumes for inconsistencies.
Revision History:
--*/
#include "fatfs.h"
#define LOSTCLUS_PARENT 0x10000000 // start (potentially) of some lost cluster chain
#define LOSTCLUS_CHILD 0x20000000 // referred to by another child or parent
#define LOSTCLUS_MODIFIED 0x80000000
#define LOSTCLUS_FLAGS (LOSTCLUS_PARENT | LOSTCLUS_CHILD | LOSTCLUS_MODIFIED)
typedef struct _LOSTCLUS {
DWORD dwIndex;
DWORD dwData;
struct _LOSTCLUS *plcNext;
} LOSTCLUS, *PLOSTCLUS;
int ScanLostClusters(PVOLUME pvol, PDWORD pdwClusArray, PLOSTCLUS plc, int cLostClusters)
{
int i, j, k;
DWORD dwClus;
int cLostChains = 0;
for (i=0, j=0, dwClus=DATA_CLUSTER; dwClus <= pvol->v_clusMax && j < cLostClusters; i++,dwClus++) {
DWORD dwData;
DWORD dwError = UNPACK(pvol, dwClus, &dwData);
if (dwError) {
DEBUGMSG(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXT("FATFS!ScanLostClusters: error reading cluster %d (%d)\n"), dwClus, dwError));
break;
}
if (!TestBitArray(pdwClusArray, i)) {
if (dwData != FREE_CLUSTER) {
if (dwData == (pvol->v_clusEOF | 0xF))
dwData = UNKNOWN_CLUSTER;
// Make sure the dwIndex fields never get these flag bits set "accidentally"
ASSERT(!(dwClus & LOSTCLUS_FLAGS));
plc[j].dwIndex = dwClus;
plc[j].dwData = dwData;
plc[j].plcNext = NULL;
j++;
}
}
}
ASSERT(j == cLostClusters);
// OK, now we're ready to identify all the chains. For every lost cluster,
// if it has a child, then that child better be lost too, or we must truncate
// that cluster's chain immediately. Normally, its child *will* also be lost;
// we will keep marking all the lost clusters in that chain as LOSTCLUS_CHILD,
// until we reach the end of the chain or we had to truncate it.
for (i=0; i<cLostClusters; i++) {
DWORD dwNext;
if (plc[i].dwIndex & LOSTCLUS_CHILD)
continue; // already visited in the context of some other lost cluster's chain
ASSERT(!(plc[i].dwIndex & LOSTCLUS_PARENT));
plc[i].dwIndex |= LOSTCLUS_PARENT;
k = i;
dwNext = plc[i].dwData;
while (dwNext) {
j = 0;
if (dwNext > pvol->v_clusMax) {
// We are either at the natural end of a cluster chain,
// or we've encountered a too-large cluster number; if
// the latter, then we need to properly truncate the chain.
if (dwNext == UNKNOWN_CLUSTER)
break; // the entry is OK as-is
goto truncate;
}
for (; j<cLostClusters; j++) {
DWORD dwCur = plc[j].dwIndex;
if (dwNext == (dwCur & ~LOSTCLUS_FLAGS)) {
if (dwCur & LOSTCLUS_CHILD)
goto truncate;
plc[j].dwIndex |= LOSTCLUS_CHILD;
plc[k].plcNext = &plc[j];
if (dwCur & LOSTCLUS_PARENT) {
plc[j].dwIndex &= ~LOSTCLUS_PARENT;
dwNext = 0;
break;
}
dwNext = plc[j].dwData;
break;
}
}
// If we couldn't find the next lost cluster, truncate the current
// lost cluster chain
if (j == cLostClusters) {
truncate:
plc[k].dwIndex |= LOSTCLUS_MODIFIED;
plc[k].dwData = UNKNOWN_CLUSTER;
break;
}
k = j;
}
}
// One more pass through the lost cluster array looking for LOSTCLUS_PARENT flags
// will tell us how many total lost chains there are.
for (i=0; i<cLostClusters; i++) {
if (plc[i].dwIndex & LOSTCLUS_PARENT)
cLostChains++;
}
return cLostChains;
}
DWORD FreeLostClusters(PVOLUME pvol, PLOSTCLUS plc, int cLostClusters)
{
int i;
DWORD dwError = ERROR_SUCCESS;
// Simply zap all the clusters in the LOSTCLUS array...
for (i=0; i<cLostClusters; i++) {
dwError = PACK(pvol, plc[i].dwIndex & ~LOSTCLUS_FLAGS, FREE_CLUSTER, NULL);
if (dwError)
break;
}
return dwError;
}
DWORD ReclaimLostClusters(PVOLUME pvol, PLOSTCLUS plc, int cLostClusters, int cLostChains)
{
int i, j, k;
PLOSTCLUS plcCur;
DWORD dwError = ERROR_SUCCESS;
// WARNING: If you change this template string, make sure that
// wsFileName is still large enough to hold the result from wsprintf! -JTP
static CONST WCHAR awcTemplate[] = TEXTW("FILE%04d.CHK");
// For each chain, we want to create a FILEnnnn.CHK file, and hook all the clusters
// in that chain onto that file.
for (i=1,k=1; i<=cLostChains && !dwError; i++) {
PDSTREAM pstm;
do {
WCHAR wsFileName[OEMNAMESIZE+2];
int flName = NAME_FILE | NAME_NEW | NAME_CREATE;
// Each time we build a name, we also auto-increment the "nnnn" part
wsprintf(wsFileName, awcTemplate, k++);
pstm = OpenName((PDSTREAM)pvol, wsFileName, 0, &flName);
} while (!pstm && GetLastError() == ERROR_FILE_EXISTS && k <= 999);
if (pstm) {
DWORD dwNewSize = 0;
ASSERT(pstm->s_clusFirst == UNKNOWN_CLUSTER);
// Find the beginning of some lost cluster chain, and start threading the
// clusters on that chain onto this file.
for (j=0; j<cLostClusters; j++) {
if (plc[j].dwIndex & LOSTCLUS_PARENT)
break;
}
ASSERT(j<cLostClusters); // we should always find a parent
plcCur = &plc[j];
// we don't want to find this parent again
plcCur->dwIndex &= ~LOSTCLUS_PARENT;
while (plcCur) {
DWORD dwClus = plcCur->dwIndex & ~LOSTCLUS_FLAGS;
if (pstm->s_clusFirst == UNKNOWN_CLUSTER) {
pstm->s_clusFirst = dwClus;
pstm->s_flags |= STF_DIRTY | STF_DIRTY_CLUS;
}
if (plcCur->dwIndex & LOSTCLUS_MODIFIED) {
dwError = PACK(pvol, dwClus, plcCur->dwData, NULL);
if (dwError)
break; }
dwNewSize += pvol->v_cbClus;
plcCur = plcCur->plcNext;
ASSERT(plcCur == NULL || plcCur->dwIndex & LOSTCLUS_CHILD);
}
// Commit and close the new entry
if (dwNewSize > 0) {
pstm->s_size = dwNewSize;
pstm->s_flags |= STF_DIRTY;
}
CloseStream(pstm);
}
else
dwError = GetLastError();
}
return dwError;
}
DWORD ModifyCluster(PDSTREAM pstmDir, PDIRENTRY pde, DWORD dwClus)
{
DWORD dwError = ERROR_SUCCESS;
if (dwClus < DATA_CLUSTER || dwClus == UNKNOWN_CLUSTER)
dwClus = NO_CLUSTER;
if (pde->de_clusFirst != LOWORD(dwClus))
dwError = ModifyStreamBuffer(pstmDir, &pde->de_clusFirst, sizeof(pde->de_clusFirst));
if (!dwError) {
pde->de_clusFirst = LOWORD(dwClus);
if (pde->de_clusFirstHigh != HIWORD(dwClus))
dwError = ModifyStreamBuffer(pstmDir, &pde->de_clusFirstHigh, sizeof(pde->de_clusFirstHigh));
if (!dwError)
pde->de_clusFirstHigh = HIWORD(dwClus);
}
return dwError;
}
/* ScanDirectory - Scan a directory (on a volume) for inconsistencies
*
* ENTRY
* psd - pointer to SCANDATA
* pstmDir - pointer to DSTREAM
* pdiPrev - pointer to previous DIRINFO, if any
* pfdPrev - pointer to previous WIN32_FIND_DATAW, if any
*
* EXIT
* ERROR_SUCCESS if successful, error code if not
*/
DWORD ScanDirectory(PSCANDATA psd, PDSTREAM pstmDir, PDIRINFO pdiPrev, PWIN32_FIND_DATAW pfdPrev)
{
int iFix;
PWSTR pwsEnd;
PSHANDLE psh;
DWORD dwError;
DIRINFO di;
PVOLUME pvol = psd->sd_pvol;
PWIN32_FIND_DATAW pfd = NULL;
DEBUGMSGW(ZONE_LOGIO,(DBGTEXTW("FATFS!ScanDirectory(\"%s\")\n"), psd->sd_wsPath));
pwsEnd = psd->sd_wsPath + wcslen(psd->sd_wsPath);
if (!pstmDir) {
if (pstmDir = OpenRoot(pvol)) {
#ifdef FAT32
// Handle clusters in the root directory of a FAT32 volume
DWORD dwClus = pvol->v_pstmRoot->s_clusFirst, dwData;
while (dwClus >= DATA_CLUSTER && !ISEOF(pvol, dwClus)) {
ASSERT(pvol->v_flags & VOLF_32BIT_FAT);
ASSERT(!TestBitArray(psd->sd_pdwClusArray, dwClus-DATA_CLUSTER));
dwError = UNPACK(pvol, dwClus, &dwData);
if (dwError) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"<ROOT>\" error reading cluster %d (%d)\n"), dwClus, dwError));
goto exit;
}
else if (dwData == FREE_CLUSTER) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"<ROOT>\" cluster %d points to bogus cluster %d\n"), dwClus, dwData));
dwError = ERROR_INVALID_DATA;
goto exit;
}
SetBitArray(psd->sd_pdwClusArray, dwClus-DATA_CLUSTER);
dwClus = dwData;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -