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

📄 find.c

📁 从大量的wince源代码中剥离出的fat文件系统源代码.移植性非常高. 里面带有source i.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
        if (psh->sh_pstm == NULL)
            goto exit;

        if (len == 0) {

            // The caller must be trying to find '\\'.  That's normally
            // a no-no.  FAT_FindFirstFileW makes an exception, but it makes
            // no sense internally, because the root is never contained by
            // another directory stream.

            dwError = ERROR_FILE_NOT_FOUND;
            goto exit;
        }

        psh->sh_pos = 0;
        psh->sh_cwPattern = (WORD)len;
        memcpy(psh->sh_awcPattern, pwsName, len*sizeof(WCHAR));
        psh->sh_awcPattern[len] = 0;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        dwError = ERROR_INVALID_PARAMETER;
        goto exit;
    }

    dwError = FindNext(psh, pdi, pfd);

  exit:
    if (dwError == ERROR_FILE_NOT_FOUND && (flName & (NAME_FILE|NAME_DIR)) == NAME_DIR)
        dwError = ERROR_PATH_NOT_FOUND;

    if (dwError)
        SetLastError(dwError);

    if (!pdi) {
        if (psh->sh_pstm) {
            CloseStream(psh->sh_pstm);
            psh->sh_pstm = NULL;
        }
    }
    return psh->sh_pstm;
}


/*  MatchNext - worker for FindNext
 *
 *  ENTRY
 *      psh - pointer to SHANDLE structure
 *      len - length of current name
 *      pws - pointer to current name
 *      pde - pointer to DIRENTRY to read from if match
 *
 *  EXIT
 *      TRUE if (another) file was found, FALSE if not
 */

__inline BOOL MatchNext(PSHANDLE psh, PWSTR pws, int len, PDIRENTRY pde)
{
    int fMask = psh->sh_flags & SHF_BYMASK;

    // Check the match criteria, and then check for that kind of match

    ASSERT(fMask);              // make sure flags are set to something

    if (psh->sh_pstm->s_cwPath + max(3,psh->sh_pstm->s_pvol->v_cwsHostRoot) + len + 2 > MAX_PATH)
        return FALSE;

    return(
        fMask == SHF_BYNAME &&
        MatchesWildcard(psh->sh_cwPattern, psh->sh_awcPattern, len, pws)
      ||
        fMask == SHF_BYORD &&
        (DWORD)(psh->sh_h) == psh->sh_pos/sizeof(DIRENTRY)
      ||
        fMask == SHF_BYCLUS &&
        (DWORD)(psh->sh_h) == GETDIRENTRYCLUSTER(psh->sh_pstm->s_pvol, pde)
    );
}


/*  CopyTimes - worker for FindNext
 *
 *  ENTRY
 *      pfd - pointer to WIN32_FIND_DATAW structure
 *      pde - pointer to DIRENTRY containing timestamps to transfer
 *
 *  EXIT
 *      None
 */

__inline void CopyTimes(PWIN32_FIND_DATAW pfd, PDIRENTRY pde)
{
    // DOSTimeToFileTime can fail because it doesn't range-check any of
    // the date/time values in the directory entry;  it just pulls them apart
    // and calls SystemTimeToFileTime, which won't initialize the FILETIME
    // structure if there's an error.  So we preset all the FILETIMEs to zero,
    // because that's what the Win32 API dictates when a time is unknown/not
    // supported.

    memset(&pfd->ftCreationTime, 0, sizeof(pfd->ftCreationTime) +
                                    sizeof(pfd->ftLastAccessTime) +
                                    sizeof(pfd->ftLastWriteTime));

    DOSTimeToFileTime(pde->de_createdDate,
                      pde->de_createdTime,
                      pde->de_createdTimeMsec, &pfd->ftCreationTime);

    DOSTimeToFileTime(pde->de_date, pde->de_time, 0, &pfd->ftLastWriteTime);

    DOSTimeToFileTime(pde->de_lastAccessDate, 0, 0, &pfd->ftLastAccessTime);
}


/*  FindNext - worker for FindFirstFileW, FindNextFileW, etc.
 *
 *  Callers need to supply a WIN32_FIND_DATAW structure even if they're
 *  not interested in "find data".  This is because the search may involve
 *  comparisons against LFN directory entries, which have to be built a piece
 *  at a time, and a wildcard comparison cannot be performed until the entire
 *  name has been built.  NON-wildcard searches can perform their comparisons
 *  a piece at a time, and don't necessarily need the MAX_PATH buffer that
 *  WIN32_FIND_DATAW provides us, but using the same buffer strategy in both
 *  cases yields better code.
 *
 *  ENTRY
 *      psh - pointer to SHANDLE structure
 *      pdi - pointer to DIRINFO (optional, NULL if not needed)
 *      pfd - pointer to user's WIN32_FIND_DATAW structure (required)
 *
 *  EXIT
 *      0 if successful, error code if not
 *
 *  On success, most of the fields in the WIN32_FIND_DATAW structure are filled
 *  in (eg, dwFileAttributes, nFileSizeHigh, nFileSizeLow, cFileName, and some
 *  CE-specific fields like dwOID).  Some are only filled in depending on the
 *  type of search however, like all the FILETIME fields (eg, ftCreationTime,
 *  ftLastAccessTime, ftLastWriteTime).  For example, SHF_BYCLUS searches, which
 *  are only used and supported internally, don't care about those fields, so we
 *  don't waste time filling them in.
 */

DWORD FindNext(PSHANDLE psh, PDIRINFO pdi, PWIN32_FIND_DATAW pfd)
{

    PDIRENTRY pdeEnd;           // ptr to ending directory entry
    BYTE chksum;                // LFN entry checksum of 8.3 name
    int seqLFN = -1;            // next LFN DIRENTRY seq # expected
    PCWSTR pwsComp;
    PWSTR pwsBuff;
    BOOL fComp = FALSE;
    DIRINFO di;
    DWORD dwError = ERROR_SUCCESS;
    PDSTREAM pstmDir = psh->sh_pstm;
    PDWORD pdwShortNameBitArray = NULL;

    ERRFALSE(sizeof(pfd->cFileName) >= sizeof(WCHAR [LDE_NAME_LEN*LN_MAX_ORD_NUM]));
    ASSERT(pstmDir);
    ASSERT(psh->sh_flags);      // make sure flags are set to something

    ASSERT(OWNCRITICALSECTION(&pstmDir->s_cs));

    memset(&di, 0, sizeof(DIRINFO));

    di.di_pos = psh->sh_pos;
    di.di_posLFN = INVALID_POS;
    di.di_clusEntry = UNKNOWN_CLUSTER;
    di.di_cdeNeed = -1;

    if (psh->sh_pos == INVALID_POS) {
        dwError = ERROR_FILE_NOT_FOUND;
        goto norelease;
    }

    if ((psh->sh_flags & SHF_BYMASK) == SHF_BYNAME) {

        di.di_cdeNeed = UniToOEMName(di.di_achOEM, psh->sh_awcPattern, psh->sh_cwPattern);

        // If the name is invalid (-2), or contains wildcards when wildcards
        // are not allowed, fail immediately.

        if (di.di_cdeNeed == -2 || di.di_cdeNeed == -1 && !(psh->sh_flags & SHF_WILD)) {
            dwError = ERROR_INVALID_NAME;
            goto norelease;
        }

        // If the name is OEM, then force the CREATE flag off.  Otherwise,
        // we'll leave the flag on if the caller turned it on (meaning he
        // wants us to check every normal DIRENTRY for a collision with the
        // short name in achOEM and set it to some name that doesn't conflict).

        if (di.di_cdeNeed >= 1) {

            di.di_flags |= DIRINFO_OEM;
            di.di_chksum = ChkSumName(di.di_achOEM);

            if (di.di_cdeNeed == 1) {
                psh->sh_flags &= ~SHF_CREATE;
            }

            // If the name fits in achOEM but contains lower-case, then cdeNeed
            // is already correct (2), but cwTail and pwsTail still need to be set.

            else if (di.di_cdeNeed == 2) {
                di.di_cwTail = psh->sh_cwPattern;
                di.di_pwsTail = psh->sh_awcPattern;
            }

            // If there's some uncertainty about the charset mapping, then revert to
            // the UNICODE case.

            else {
                ASSERT(di.di_cdeNeed == 3);
                di.di_cdeNeed = 0;
            }
        }

        // If the name is UNICODE (0), then cdeNeed needs to be recomputed,
        // based on the length of the UNICODE name.  Furthermore, unlike the
        // wildcard case, we will be able to compare it piece by piece.
        // pwsTail points to the end-most piece to compare, and cwTail is its
        // length.

        if (di.di_cdeNeed == 0) {
            fComp = TRUE;
            di.di_pwsTail = psh->sh_awcPattern + psh->sh_cwPattern;
            di.di_cdeNeed = ((psh->sh_cwPattern+LDE_NAME_LEN-1)/LDE_NAME_LEN) + 1;
            if ((di.di_cwTail = psh->sh_cwPattern % LDE_NAME_LEN) == 0)
                di.di_cwTail = LDE_NAME_LEN;
            di.di_pwsTail -= di.di_cwTail;
        }

        // Also record the complete length of the name.  If we actually
        // find a match, we will update this field again (since the match
        // might have been based on a short name and we always return
        // long names), but if we don't find a match, this still needs to
        // be set in case the caller wants to create it (via CreateName).

        di.di_cwName = psh->sh_cwPattern;
    }

    // Create a short name conflict bit array if the caller may need
    // to create a new LFN entry.  We must add 1 to MAX_SHORT_NAMES because
    // the set of addressible bits in the array starts with bit 0.

    if (psh->sh_flags & SHF_CREATE) {
        InitNumericTail(&di);
        CreateBitArray(pdwShortNameBitArray, MAX_SHORT_NAMES+1);
    }

    while (!dwError) {

        dwError = ReadStream(pstmDir, di.di_pos, &di.di_pde, &pdeEnd);
        if (dwError) {
            if (dwError == ERROR_HANDLE_EOF) {
                if (di.di_pos == 0) {
                    DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!FindNext: 0-length directory???\n")));
                    dwError = ERROR_INVALID_DATA;
                }
                else
                    dwError = ERROR_FILE_NOT_FOUND;
            }
            else
                DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!FindNext: unexpected error (%d)\n"), dwError));
            di.di_posLFN = INVALID_POS;
            break;
        }

        // Let's do a little more error-checking before we dive in;  in particular,
        // if this is not a root directory, then it must have "dot" and "dotdot" entries
        // at the top, else the directory is corrupt.

        if (!ISROOTDIR(pstmDir) && di.di_pos == 0 && di.di_pde+1 < pdeEnd) {

            DWORD dwClus;

            if (*(PDWORD)di.di_pde->de_name != 0x2020202e ||
                *(PDWORD)(di.di_pde+1)->de_name != 0x20202e2e) {
                DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!FindNext: bogus directory!\n")));
                dwError = ERROR_INVALID_DATA;
                break;
            }

            // NOTE: I'm reserving ERROR_FILE_CORRUPT to indicate "correctable" directory
            // errors.  All the caller has to do is plug in correct cluster values.  See the
            // code in SCAN.C for more details.

            dwClus = GETDIRENTRYCLUSTER(pstmDir->s_pvol, di.di_pde);
            if (dwClus != pstmDir->s_clusFirst) {
                DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!FindNext: bogus '.' cluster (0x%08x instead of 0x%08x)\n"), dwClus, pstmDir->s_clusFirst));
                dwError = ERROR_FILE_CORRUPT;
                break;
            }

            dwClus = GETDIRENTRYCLUSTER(pstmDir->s_pvol, di.di_pde+1);
            if (!ISPARENTROOTDIR(pstmDir) || dwClus != NO_CLUSTER) {
                if (pstmDir->s_sid.sid_clusDir >= DATA_CLUSTER &&
                    pstmDir->s_sid.sid_clusDir != UNKNOWN_CLUSTER && dwClus != pstmDir->s_sid.sid_clusDir) {
                    DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!FindNext: bogus '..' cluster (0x%08x instead of 0x%08x)\n"), dwClus, pstmDir->s_sid.sid_clusDir));
                    dwError = ERROR_FILE_CORRUPT;
                    break;
                }
            }
        }

      __try {

        do {
            // Check for a deleted entry.

            if (di.di_pde->de_name[0] == DIRFREE) {

                // Deleted file entry.  If this is the first one,
                // remember its location.

                if (di.di_cdeFree < di.di_cdeNeed && di.di_cdeFree++ == 0)
                    di.di_posFree = di.di_pos;

                // Reset LFN sequence/position info
                goto resetlfn;
            }

            // Check for an ending entry.

            if (di.di_pde->de_name[0] == DIREND) {

                // Empty file entry.  If this is the first one,
                // remember its location.

                if (di.di_cdeFree < di.di_cdeNeed && di.di_cdeFree++ == 0)
                    di.di_posFree = di.di_pos;

                di.di_posLFN = INVALID_POS;
                dwError = ERROR_FILE_NOT_FOUND;
                goto release;
            }

            // Check for an LFN entry.

            if (ISLFNDIRENTRY(di.di_pde)) {

                int cwComp = LDE_NAME_LEN;
                PLFNDIRENTRY plde = (PLFNDIRENTRY)di.di_pde;
                int cbName3 = sizeof(plde->lde_name3);

                // If lde_flags is not zero, our assumption must be that
                // this is some new kind of LFN entry that we don't fully
                // understand, and must therefore ignore....

                if (plde->lde_flags != 0)
                    goto resetall;

                // Initialization code for initial LFN entry

                if (plde->lde_ord & LN_ORD_LAST_MASK) {

                    seqLFN = plde->lde_ord & ~LN_ORD_LAST_MASK;

                    if (seqLFN > LN_MAX_ORD_NUM) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -