📄 scan.c
字号:
return dwError;
}
/* ScanFixInteractive - Query user regarding scan error and ask to fix
*
* ENTRY
* psd -> SCANDATA
* pdi -> DIRINFO
* pfd -> WIN32_FIND_DATAW
* dwScanErr == one or more SCANERR_* flags
*
* EXIT
* FATUI_NONE, FATUI_YES, FATUI_NO, FATUI_CANCEL or FATUI_DELETE
*/
int ScanFixInteractive(PSCANDATA psd, PDIRINFO pdi, PWIN32_FIND_DATAW pfd, DWORD dwScanErr)
{
CEOIDINFO oi;
FATUIDATA fui;
int i;
// If the caller to ScanVolume passed a pointer to a dwScanErr
// variable, collect all the different error types that were encountered;
// but don't include SCANERR_REPAIRABLE, because that bit is just a signal
// to us as to whether ScanVolume can actually repair the given error.
if (psd->sd_pRefData)
*(PDWORD)psd->sd_pRefData |= (dwScanErr & ~SCANERR_REPAIRABLE);
if (psd->sd_dwScanVol & SCANVOL_UNATTENDED)
return (psd->sd_dwScanVol & SCANVOL_REPAIRALL)? FATUI_YES : FATUI_NO;
#if(IDS_FATUI_SCANERR_UNKNOWN != IDS_FATUI_SCANERR_DIR_BADDATA - 1 || \
SCANERR_DIR_BADCLUS != (1 << (IDS_FATUI_SCANERR_DIR_BADCLUS - IDS_FATUI_SCANERR_DIR_BADDATA)) || \
SCANERR_DIR_BADSIZE != (1 << (IDS_FATUI_SCANERR_DIR_BADSIZE - IDS_FATUI_SCANERR_DIR_BADDATA)) || \
SCANERR_FAT_BADINDEX != (1 << (IDS_FATUI_SCANERR_FAT_BADINDEX - IDS_FATUI_SCANERR_DIR_BADDATA)) || \
SCANERR_FAT_CROSSLINK != (1 << (IDS_FATUI_SCANERR_FAT_CROSSLINK - IDS_FATUI_SCANERR_DIR_BADDATA)) || \
SCANERR_FAT_WASTED != (1 << (IDS_FATUI_SCANERR_FAT_WASTED - IDS_FATUI_SCANERR_DIR_BADDATA)) )
#error SCANERR_* constants are out of sync with IDS_FATUI_* constants
#endif
fui.dwSize = sizeof(fui);
fui.dwFlags = (dwScanErr & SCANERR_REPAIRABLE)? (FATUI_YES | FATUI_NO | FATUI_CANCEL) : (FATUI_CANCEL);
fui.idsEvent = IDS_FATUI_SCANERR_DIR_BADDATA + Log2(dwScanErr & ~SCANERR_REPAIRABLE);
fui.idsEventCaption = IDS_FATUI_ERROR;
fui.auiParams[0].dwType = UIPARAM_STRINGID;
fui.auiParams[0].dwValue = (dwScanErr & SCANERR_REPAIRABLE)? IDS_FATUI_SCANERR_REPAIR : IDS_FATUI_SCANERR_ADVISE;
// In the case of SCANERR_FAT_WASTED, pdi and pfd are not DIRINFO and WIN32_FIND_DATAW pointers;
// pdi is used to pass the number of lost clusters, and pfd is the number of lost chains.
if (fui.idsEvent == IDS_FATUI_SCANERR_FAT_WASTED) {
fui.cuiParams = 4;
fui.auiParams[1].dwType = UIPARAM_VALUE;
fui.auiParams[1].dwValue = (DWORD)pdi;
fui.auiParams[2].dwType = UIPARAM_VALUE;
fui.auiParams[2].dwValue = (DWORD)pfd;
fui.auiParams[3].dwType = UIPARAM_VALUE;
fui.auiParams[3].dwValue = (DWORD)(psd->sd_pvol->v_pwsHostRoot+1);
}
else {
fui.cuiParams = 2;
fui.auiParams[1].dwType = UIPARAM_VALUE;
fui.auiParams[1].dwValue = (DWORD)pfd->cFileName;
if (pdi && GetSIDInfo(psd->sd_pvol, &pdi->di_sid, &oi) == ERROR_SUCCESS) {
int i;
fui.cuiParams = 3;
fui.auiParams[2].dwType = UIPARAM_VALUE;
fui.auiParams[2].dwValue = (DWORD)oi.infFile.szFileName;
for (i=wcslen(oi.infFile.szFileName); --i > 0;) {
if (oi.infFile.szFileName[i] == TEXTW('\\')) {
oi.infFile.szFileName[i] = 0; // chop off the final component in the path
break;
}
}
}
}
#ifdef FATUI
i = FATUIEvent(hFATFS, psd->sd_pvol->v_pwsHostRoot+1, &fui);
#else
i = FATUI_YES;
#endif
return i;
}
BOOL ScanFixDefault(PSCANDATA psd, PDIRINFO pdi, PWIN32_FIND_DATAW pfd, DWORD dwScanErr)
{
int i;
PVOID p;
if (p = psd->sd_pRefData)
((PSCANRESULTS)psd->sd_pRefData)->sr_dwScanErr |= (dwScanErr & ~SCANERR_REPAIRABLE);
if (!(psd->sd_dwScanVol & SCANVOL_UNATTENDED)) {
psd->sd_pRefData = NULL;
i = ScanFixInteractive(psd, pdi, pfd, dwScanErr);
psd->sd_pRefData = p;
return i;
}
return (psd->sd_dwScanVol & SCANVOL_REPAIRALL)? FATUI_YES : FATUI_NO;
}
void ScanNotify(PVOLUME pvol, UINT idsMessage)
{
FATUIDATA fui;
fui.dwSize = sizeof(fui);
fui.dwFlags = FATUI_NONE;
fui.idsEvent = idsMessage;
fui.idsEventCaption = IDS_FATUI_WARNING;
fui.cuiParams = 0;
// Since this is just a notification, we don't care what the FATUIEvent response was...
#ifdef FATUI
FATUIEvent(hFATFS, pvol->v_pwsHostRoot+1, &fui);
#endif
}
/* ScanVolume - Scan a volume for inconsistencies
*
* ENTRY
* pvol - pointer to VOLUME
* dwScanVol - one or more SCANVOL_* flags
* pfnScanFix - pointer to PFNSCANFIX function
* pRefData - pointer to caller-defined data; if pfnScanFix
* is NULL, then the default handler (ScanFixDefault) expects
* pRefData to be either NULL or a pointer to a SCANRESULTS structure.
*
* EXIT
* ERROR_SUCCESS if successful, error code if not, or 0xFFFFFFFF
* if scan was interrupted/cancelled.
*
* NOTES
* There are a very large number of problems that a FAT volume
* can suffer from, but many of them are minor (stuff like non-OEM
* characters in 8.3 names, dates in the future, paths that can't
* be reached by MSDOS-based applications, etc).
*
* What I deem most important: (1) that all files point to valid
* and unique sets of clusters, (2) that all file sizes agree with
* the number of clusters allocated to them, (3) that all other
* clusters are marked free, and (4) that all copies of the FAT are
* in agreement.
*
* To verify (1) and (3), I allocate a bitarray representing all
* the clusters on the volume, and then start walking the directory
* structure, and every cluster chain in that structure, and flag
* every cluster in use. If a cluster is already marked in use,
* then we have a cross-link. Now a limitation of the bitmap is
* that I won't be able to (easily) identify the first file using
* the same clusters, but I can at least list the second file and offer
* to allocate it separate clusters with duplicate contents.
*/
DWORD ScanVolume(PVOLUME pvol, DWORD dwScanVol, PFNSCANFIX pfnScanFix, PVOID pRefData)
{
BOOL iFix;
SCANDATA sd;
DWORD i, dwClus;
DWORD cClusters;
DWORD dwError = ERROR_SUCCESS;
// An invalid volume is generally an unformatted volume; in any case, if the
// volume is known to be invalid, there's no point in scanning it. Similarly, if
// we're already scanning it, no need to do so again.
if (pvol->v_flags & (VOLF_INVALID | VOLF_SCANNING))
goto abort;
DEBUGMSGW(ZONE_LOGIO,(DBGTEXTW("FATFS!ScanVolume(%s) starting...\n"), pvol->v_pwsHostRoot));
dwError = LockVolume(pvol, VOLF_READLOCKED);
if (dwError) {
DEBUGMSG(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXT("FATFS!ScanVolume: unable to lock volume (%d)\n"), dwError));
goto exit;
}
// Set the SCANNING flag to prevent re-entrancy, and clear the MODIFIED flag
// so that if no modifications are made during the scan, UnlockVolume can avoid
// an expensive unmount/remount of the volume.
pvol->v_flags |= VOLF_SCANNING;
pvol->v_flags &= ~VOLF_MODIFIED;
ScanNotify(pvol, IDS_FATUI_SCANSTART_WARNING);
// Initialize the SCANDATA structure and allocate a bitarray for all the clusters on the volume
sd.sd_pvol = pvol;
sd.sd_dwScanVol = dwScanVol;
sd.sd_pfnScanFix = (pfnScanFix? pfnScanFix : ScanFixDefault);
sd.sd_pRefData = pRefData;
ASSERT(pvol->v_clusMax > DATA_CLUSTER);
cClusters = pvol->v_clusMax - DATA_CLUSTER + 1;
CreateBitArray(sd.sd_pdwClusArray, cClusters);
if (!sd.sd_pdwClusArray) {
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto unlockvol;
}
LockFAT(pvol);
sd.sd_cFiles = 0;
sd.sd_cLevels = 0;
sd.sd_flags = SCANDATA_NONE;
sd.sd_wsPath[0] = '\0';
dwError = ScanDirectory(&sd, NULL, NULL, NULL);
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!ScanVolume scanned %d files (%d)\n"), sd.sd_cFiles, dwError));
if (sd.sd_flags & SCANDATA_TOODEEP) {
// This should simply generate the IDS_SCANERR_UNKNOWN message. We
// don't care what the response is, because it's a generic, unrepairable error.
sd.sd_pfnScanFix(&sd, NULL, NULL, 0);
}
else if (dwError != SCAN_CANCELLED) {
// Now make sure that all the clusters in the FAT for which the
// corresponding bit in the bitarray is clear are actually "free",
// and since we're verifying the set of free clusters, we might as well
// take this opportunity to update the cached free cluster count in the
// VOLUME structure too...
int cLostClusters = 0;
dwError = ERROR_SUCCESS;
pvol->v_cclusFree = 0;
for (i=0, dwClus=DATA_CLUSTER; dwClus <= pvol->v_clusMax; i++,dwClus++) {
DWORD dwData;
dwError = UNPACK(pvol, dwClus, &dwData);
if (dwError) {
DEBUGMSG(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXT("FATFS!ScanVolume: error reading cluster %d (%d)\n"), dwClus, dwError));
pvol->v_cclusFree = UNKNOWN_CLUSTER; // if we bail, zap cached free cluster count too
break;
}
if (!TestBitArray(sd.sd_pdwClusArray, i)) {
if (dwData == FREE_CLUSTER)
pvol->v_cclusFree++; // update cached free cluster count
else if (dwData == (pvol->v_clusEOF|0x8)-1) {
SetBitArray(sd.sd_pdwClusArray, i);
DEBUGMSG(ZONE_LOGIO,(DBGTEXT("FATFS!ScanVolume: cluster %d marked bad (0x%x)\n"), dwClus, dwData));
}
else {
cLostClusters++;
// Used to be ZONE_LOGIO || ZONE_ERRORS, but too noisy when card has lots of lost clusters...
DEBUGMSG(ZONE_LOGIO,(DBGTEXT("FATFS!ScanVolume: cluster %d should be free but instead contains %d (0x%x)\n"), dwClus, dwData, dwData));
}
}
else {
// dwData == FREE_CLUSTER suggests a bit-array inconsistency, hence the break -JTP
DEBUGMSGBREAK(ZONE_LOGIO && dwData == FREE_CLUSTER,(DBGTEXT("FATFS!ScanVolume: cluster %d should be used but instead is free\n"), dwClus));
}
}
if (cLostClusters*sizeof(LOSTCLUS) > 32*1024) {
// This should simply generate the IDS_SCANERR_UNKNOWN message. We
// don't care what the response is, because it's a generic, unrepairable error.
sd.sd_pfnScanFix(&sd, NULL, NULL, 0);
dwError = ERROR_OUTOFMEMORY;
cLostClusters = 0;
}
if (cLostClusters) {
PLOSTCLUS plc;
ALLOCA(plc, cLostClusters*sizeof(LOSTCLUS));
if (!plc) {
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ScanVolume: unable to allocate %d bytes to recover lost clusters\n"), cLostClusters*sizeof(LOSTCLUS)));
dwError = ERROR_OUTOFMEMORY;
}
else {
// Identify all the chains now
int cLostChains;
cLostChains = ScanLostClusters(pvol, sd.sd_pdwClusArray, plc, cLostClusters);
// Offer to repair (ie, recover) all the chains
iFix = sd.sd_pfnScanFix(&sd, (PVOID)cLostClusters, (PVOID)cLostChains, SCANERR_FAT_WASTED|SCANERR_REPAIRABLE);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
}
else if (iFix == FATUI_YES) {
dwError = ReclaimLostClusters(pvol, plc, cLostClusters, cLostChains);
}
else if (iFix == FATUI_DELETE) {
dwError = FreeLostClusters(pvol, plc, cLostClusters);
}
}
}
}
// Commit the FAT now, just in case we dirtied any of its buffers...
CommitAndReleaseStreamBuffers(pvol->v_pstmFAT);
UnlockFAT(pvol);
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!ScanVolume scanned %d clusters (%d free)\n"), i, pvol->v_cclusFree));
unlockvol:
ScanNotify(pvol, IDS_FATUI_SCANDONE_WARNING);
UnlockVolume(pvol);
exit:
pvol->v_flags &= ~VOLF_SCANNING;
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!ScanVolume(%s) complete, returned %d\n"), pvol->v_pwsHostRoot, dwError));
abort:
return dwError;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -