📄 scan.c
字号:
}
}
if (!pstmDir) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
// The pattern we will search for in the current stream is always "*"
ALLOCA(psh, sizeof(SHANDLE)-ARRAYSIZE(psh->sh_awcPattern)*sizeof(WCHAR)+2*sizeof(WCHAR));
if (!psh) {
psd->sd_flags |= SCANDATA_TOODEEP;
dwError = ERROR_OUTOFMEMORY;
goto exit;
}
memset(psh, 0, sizeof(SHANDLE)-ARRAYSIZE(psh->sh_awcPattern)*sizeof(WCHAR)+2*sizeof(WCHAR));
psh->sh_pstm = pstmDir;
psh->sh_flags = SHF_BYNAME | SHF_WILD; psh->sh_cwPattern = 1;
psh->sh_awcPattern[0] = '*';
pfd = LocalAlloc(LPTR, sizeof(WIN32_FIND_DATAW));
if (!pfd) {
psd->sd_flags |= SCANDATA_TOODEEP;
dwError = ERROR_OUTOFMEMORY;
goto exit;
}
DEBUGALLOC(sizeof(WIN32_FIND_DATAW));
do {
int i;
BOOL fBadDirent = FALSE;
DWORD dwClus, dwData, cClus;
iFix = FATUI_NO;
dwError = FindNext(psh, &di, pfd);
if (dwError) {
if (dwError == ERROR_FILE_NOT_FOUND) {
dwError = ERROR_SUCCESS; // eventually running out of files is to be expected
goto exit;
}
if (dwError == ERROR_BAD_UNIT || dwError == ERROR_GEN_FAILURE || dwError == ERROR_NOT_READY || dwError == ERROR_READ_FAULT) {
dwError = SCAN_CANCELLED; // abort scan if we get any "driver errors"
goto exit;
}
if (dwError != ERROR_FILE_CORRUPT || pdiPrev == NULL || pfdPrev == NULL)
goto exit; // unknown or uncorrectable error
// When FindNext() returns ERROR_FILE_CORRUPT, it's telling us that
// that one or both of the cluster numbers in the "dot" and "dotdot" entries
// are inconsistent. If the user elects to correct them, we'll try searching
// the directory again.
iFix = psd->sd_pfnScanFix(psd, pdiPrev, pfdPrev, SCANERR_DIR_BADCLUS|SCANERR_REPAIRABLE);
if (iFix != FATUI_YES) {
if (iFix == FATUI_CANCEL)
dwError = SCAN_CANCELLED;
goto exit;
}
if (dwError = ReadStream(pstmDir, 0, &di.di_pde, NULL))
goto exit;
if (dwError = ModifyCluster(pstmDir, di.di_pde, pstmDir->s_clusFirst))
goto exit;
di.di_pde++;
if (dwError = ModifyCluster(pstmDir, di.di_pde, pstmDir->s_sid.sid_clusDir))
goto exit;
if (dwError = CommitStreamBuffers(pstmDir))
goto exit;
psh->sh_pos = 0;
continue; // try that FindNext() call again now
}
psd->sd_cFiles++;
DEBUGMSG(ZONE_LOGIO,(DBGTEXT("FATFS!ScanDirectory: '%.11hs', clus=%d\n"), di.di_pde->de_name, di.di_clusEntry));
// We call GETDIRENTRYCLUSTER again to catch the "NO_CLUSTER" case, because even though
// FindNext() called it and saved the result in di_clusEntry, FindNext *also* maps
// NO_CLUSTER to UNKNOWN_CLUSTER to reduce the number of different "invalid cluster" values
// other callers must deal with. Unfortunately, *we* need to deal with it.
dwClus = di.di_clusEntry;
if (GETDIRENTRYCLUSTER(pvol, di.di_pde) == NO_CLUSTER)
dwClus = NO_CLUSTER;
for (i=0; i<sizeof(di.di_pde->de_name); i++) {
if (di.di_pde->de_name[i] < ' ' /* || di.di_pde->de_name[i] > 0x7F */ ) {
DEBUGMSG(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXT("FATFS!ScanDirectory: '%.11hs' contains invalid char at %d: %02x\n"), di.di_pde->de_name, i, di.di_pde->de_name[i]));
fBadDirent = TRUE;
}
}
if (di.di_clusEntry == UNKNOWN_CLUSTER && (di.di_pde->de_attr & ATTR_DIRECTORY)) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" contains bogus directory cluster %d\n"), pfd->cFileName, dwClus));
fBadDirent = TRUE;
}
if (dwClus > pvol->v_clusMax) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" contains invalid cluster %d\n"), pfd->cFileName, dwClus));
fBadDirent = TRUE;
}
if (dwClus) {
if (UNPACK(pvol, dwClus, &dwData) != ERROR_SUCCESS || dwData == FREE_CLUSTER) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" contains bogus cluster %d [0x%x]\n"), pfd->cFileName, dwClus, dwData));
fBadDirent = TRUE;
}
}
if (fBadDirent) {
iFix = psd->sd_pfnScanFix(psd, &di, pfd, SCANERR_DIR_BADDATA|SCANERR_REPAIRABLE);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
goto exit;
}
if (iFix == FATUI_YES || iFix == FATUI_DELETE) { // repair and delete are the same thing in this case...
// We set di_clusEntry to UNKNOWN_CLUSTER to prevent DestroyName from
// reclaiming any of the (potentially bogus) clusters referenced by the
// afflicted DIRENTRY.
di.di_clusEntry = UNKNOWN_CLUSTER;
if (dwError = DestroyName(pstmDir, &di))
goto exit;
goto next; // nothing more to do with this (now deleted) DIRENTRY
}
// If we're still here, then the user simply told us not to modify this DIRENTRY.
}
// Walk all the clusters of the DIRENTRY we just found...
cClus = 0;
while (dwClus >= DATA_CLUSTER && !ISEOF(pvol, dwClus)) {
if (TestBitArray(psd->sd_pdwClusArray, dwClus-DATA_CLUSTER)) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" cross-linked on cluster %d (after %d clusters)\n"), pfd->cFileName, dwClus, cClus));
iFix = psd->sd_pfnScanFix(psd, &di, pfd, SCANERR_FAT_CROSSLINK);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
goto exit;
}
break; // no point in examining the rest of the chain...
}
dwError = UNPACK(pvol, dwClus, &dwData);
if (dwError) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" error reading cluster %d (%d)\n"), pfd->cFileName, dwClus, dwError));
}
else if (dwData == FREE_CLUSTER) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" cluster %d points to bogus cluster %d\n"), pfd->cFileName, dwClus, dwData));
dwError = ERROR_INVALID_DATA;
}
if (dwError) {
iFix = psd->sd_pfnScanFix(psd, &di, pfd, SCANERR_DIR_BADCLUS|SCANERR_REPAIRABLE);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
goto exit;
}
if (iFix == FATUI_YES) {
if (cClus == 0) {
// The cluster chain must be truncated inside the DIRENTRY
if (dwError = ModifyCluster(pstmDir, di.di_pde, NO_CLUSTER))
goto exit;
if (dwError = CommitStreamBuffers(pstmDir))
goto exit;
dwClus = NO_CLUSTER;
di.di_clusEntry = UNKNOWN_CLUSTER;
}
else {
// The cluster chain must be truncated outside the DIRENTRY
PACK(pvol, dwClus, UNKNOWN_CLUSTER, NULL); }
}
else if (iFix == FATUI_DELETE) {
if (dwError = DestroyName(pstmDir, &di))
goto exit;
}
break; // in any case, no point in examining the rest of the chain...
}
SetBitArray(psd->sd_pdwClusArray, dwClus-DATA_CLUSTER);
dwClus = dwData;
cClus++;
DEBUGMSG(ZONE_LOGIO && ZONE_CLUSTERS,(DBGTEXT("FATFS!ScanDirectory: '%.11hs', next=%d\n"), di.di_pde->de_name, dwClus));
}
if (di.di_pde->de_attr & ATTR_DIRECTORY) {
PDSTREAM pstmSubDir;
// Whenever we hit this limit, we set a flag that disables free cluster
// checking (otherwise we would report a bunch of unvisited clusters as lost).
if (psd->sd_cLevels == MAX_PATH/2) {
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ScanDirectory: hit nesting limit!\n")));
psd->sd_flags |= SCANDATA_TOODEEP;
goto next;
}
// Since the DIRENTRY is a directory, traverse into it
pstmSubDir = OpenStream(pvol,
di.di_clusEntry,
&di.di_sid,
pstmDir, &di, OPENSTREAM_CREATE);
if (pstmSubDir) {
*pwsEnd = '\\';
wcscpy(pwsEnd+1, pfd->cFileName);
// Note that since FindNext() succeeded, it held onto a buffer for us;
// we need to release that buffer now, otherwise the deepest tree structure
// we can scan will be equal to the number of buffers in our pool.
ReleaseStreamBuffer(pstmDir, FALSE);
DEBUGONLY(di.di_pde = NULL);
psd->sd_cLevels++;
dwError = ScanDirectory(psd, pstmSubDir, &di, pfd);
psd->sd_cLevels--;
// Note that ScanDirectory always closes the pstm we pass to it, so
// we do not need to explicitly call CloseStream() for pstmSubDir.
// A corollary is that pstmSubDir is now invalid, so we will explicitly
// invalidate it in DEBUG builds.
DEBUGONLY(pstmSubDir = NULL);
if (dwError == SCAN_CANCELLED)
goto exit;
if (dwError) {
iFix = psd->sd_pfnScanFix(psd, &di, pfd, SCANERR_DIR_BADDATA|SCANERR_REPAIRABLE);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
goto exit;
}
if (iFix == FATUI_YES || iFix == FATUI_DELETE) { // repair and delete are the same thing in this case...
// Since we released buffer above, with the hope/expectation that
// we would no longer need it, we were proven wrong, so before we can
// call DestroyName, we must refetch a buffer containing the afflicted
// DIRENTRY.
if (dwError = ReadStream(pstmDir, di.di_pos, &di.di_pde, NULL))
goto exit;
// We could set di_clusEntry to UNKNOWN_CLUSTER to prevent DestroyName from
// reclaiming any of the (potentially bogus) clusters referenced by the
// afflicted DIRENTRY, but more often than not, they aren't really bogus. -JTP
// di.di_clusEntry = UNKNOWN_CLUSTER;
if (dwError = DestroyName(pstmDir, &di))
goto exit;
goto next; // nothing more to do with this (now deleted) DIRENTRY
}
}
}
}
else {
// Since the DIRENTRY is a file, make sure the size field in the DIRENTRY
// is consistent with the number of clusters currently assigned to it; this
// isn't done for directory DIRENTRYs because FAT file systems do not normally
// either update or rely on sizes, time-stamps, etc, for directories.
DWORD cbMax = cClus * pvol->v_cbClus;
DWORD cbMin = cbMax - (cbMax? (pvol->v_cbClus - 1) : 0);
if (di.di_pde->de_size < cbMin || di.di_pde->de_size > cbMax) {
DEBUGMSGW(ZONE_LOGIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ScanDirectory: \"%s\" size %d inconsistent with %d total clusters\n"), pfd->cFileName, di.di_pde->de_size, cClus));
// If iFix is FATUI_YES, the user already said "yes" to repair an earlier error
// in this file, so let's just go ahead and repair this error too...
if (iFix != FATUI_YES) {
iFix = psd->sd_pfnScanFix(psd, &di, pfd, SCANERR_DIR_BADSIZE|SCANERR_REPAIRABLE);
if (iFix == FATUI_CANCEL) {
dwError = SCAN_CANCELLED;
goto exit;
}
}
if (iFix == FATUI_YES) {
if (dwError = ModifyStreamBuffer(pstmDir, &di.di_pde->de_size, sizeof(di.di_pde->de_size)))
goto exit;
di.di_pde->de_size = cbMax;
if (dwError = CommitStreamBuffers(pstmDir))
goto exit;
}
else if (iFix == FATUI_DELETE) {
if (dwError = DestroyName(pstmDir, &di))
goto exit;
}
}
}
// FindNext() does not advance the SHANDLE's search position automatically when
// it is asked to fill in a DIRINFO, so we must do it ourselves. Note that it must
// be advanced relative to the entry we just found, NOT the last search position.
next:
psh->sh_pos = di.di_pos + sizeof(DIRENTRY);
} while (TRUE);
exit:
if (pfd) {
DEBUGFREE(sizeof(WIN32_FIND_DATAW));
VERIFYNULL(LocalFree(pfd));
}
if (pstmDir) {
DWORD dw = CloseStream(pstmDir);
if (!dwError)
dwError = dw;
}
DEBUGONLY(*pwsEnd = '\0');
DEBUGMSGW(ZONE_LOGIO,(DBGTEXTW("FATFS!ScanDirectory(\"%s\") returned %d\n"), psd->sd_wsPath, dwError));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -