⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scan.c

📁 从大量的wince源代码中剥离出的fat文件系统源代码.移植性非常高. 里面带有source i.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
        }
    }

    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 + -