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

📄 find.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// 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:

    find.c

Abstract:

    This file contains the FAT file system FindFirst/FindNext/FindClose
    routines.

Revision History:

--*/

#include "fatfs.h"


HANDLE FAT_FindFirstFileW(PVOLUME pvol, HANDLE hProc, PCWSTR pwsFileSpec, PWIN32_FIND_DATAW pfd)
{
    DWORD len;
    PCWSTR pwsName;
    PSHANDLE psh = NULL;
    PDSTREAM pstm = NULL;
    DWORD dwError = ERROR_SUCCESS;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_FindFirstFileW(%d chars: %s)\r\n"), wcslen(pwsFileSpec), pwsFileSpec));

    if (!FATEnter(NULL, LOGID_NONE))
        return INVALID_HANDLE_VALUE;

    if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_WRITELOCKED)) {
        dwError = ERROR_ACCESS_DENIED;
        goto exit;
    }

    __try {
        pstm = OpenPath(pvol, pwsFileSpec, &pwsName, &len, NAME_DIR, UNKNOWN_CLUSTER);
        if (!pstm) {
            DEBUGONLY(dwError = GetLastError());
            goto abort;
        }

        // Perform a wildcard simplification up front...

        if (len == 3 && wcscmp(pwsName, TEXTW("*.*")) == 0)
            len = 1;

        psh = (PSHANDLE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(SHANDLE)+(len+1-ARRAYSIZE(psh->sh_awcPattern))*sizeof(WCHAR));
        if (!psh) {
            dwError = ERROR_OUTOFMEMORY;
            goto exit;
        }

        DEBUGALLOC(psh->sh_cbAlloc = sizeof(SHANDLE)+(len+1-ARRAYSIZE(psh->sh_awcPattern))*sizeof(WCHAR));

        AddItem((PDLINK)&pstm->s_dlOpenHandles, (PDLINK)&psh->sh_dlOpenHandles);
        psh->sh_pstm = pstm;
        psh->sh_flags = SHF_BYNAME | SHF_WILD;
        psh->sh_cwPattern = (WORD)len;
        memcpy(psh->sh_awcPattern, pwsName, len*sizeof(WCHAR));

        if (len == 0) {

            // The caller must be trying to find '\\'.  That's normally
            // a no-no, but in this case we'll do our best to pretend that
            // it worked, because our root directory is not a root directory
            // in the host file system;  it's treated like another folder.

            memset(pfd, 0, sizeof(*pfd));

            pfd->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
#ifdef UNDER_CE
            // NT does not have OID defined        
            pfd->dwOID = OIDFROMSID(pvol, NULL);
#endif
            wcscpy(pfd->cFileName, pwsFileSpec);

            // Prevent the caller from searching any further with this pattern

            psh->sh_pos = INVALID_POS;
        }
        else {
            dwError = FindNext(psh, NULL, pfd);
            if (dwError == ERROR_FILE_NOT_FOUND)
                dwError = ERROR_NO_MORE_FILES;            
            if (dwError)
                goto exit;
        }

        if (!(hFind = FSDMGR_CreateSearchHandle(pvol->v_hVol, hProc, (PSEARCH)psh))) {
            hFind = INVALID_HANDLE_VALUE;
            dwError = ERROR_OUTOFMEMORY;
            goto exit;
        }

        psh->sh_h = hFind;
        psh->sh_hProc = hProc;

        // Don't be disturbed by this LeaveCriticalSection call inside the
        // try/except block;  if an exception occurs, dwError will be set, and
        // so we'll call CloseStream below, which again takes care of leaving
        // (and freeing) the stream as appropriate.

        // We don't want to call CloseStream in the success path, because the
        // stream needs to be left open for as long as the search handle exists.

        LeaveCriticalSection(&pstm->s_cs);

    } __except (EXCEPTION_EXECUTE_HANDLER) {
        dwError = ERROR_INVALID_PARAMETER;
    }

  exit:
    if (dwError) {
        if (psh) {
            RemoveItem((PDLINK)&psh->sh_dlOpenHandles);
            DEBUGFREE(psh->sh_cbAlloc);
            VERIFYTRUE(HeapFree(hHeap, 0, (HLOCAL)psh));
#ifdef DEBUG
            psh = NULL;
#endif
        }
        CloseStream(pstm);
        SetLastError(dwError);
    }

  abort:
    FATExit(pvol, LOGID_NONE);

    DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && hFind == INVALID_HANDLE_VALUE,
                        (DBGTEXTW("FATFS!FAT_FindFirstFileW(0x%08x,%-.64s) returned 0x%x \"%s\" (%d)\r\n"),
                         psh, pwsFileSpec, hFind, hFind != INVALID_HANDLE_VALUE? pfd->cFileName : TEXTW(""), dwError));

    return hFind;
}


BOOL FAT_FindNextFileW(PSHANDLE psh, PWIN32_FIND_DATAW pfd)
{
    PDSTREAM pstm;
    DWORD dwError;

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_FindNextFile(0x%08x,%s)\r\n"), psh, psh->sh_awcPattern));

    if (!FATEnter(NULL, LOGID_NONE))
        return FALSE;

    pstm = psh->sh_pstm;
    ASSERT(pstm);

    __try {

        EnterCriticalSection(&pstm->s_cs);
        dwError = FindNext(psh, NULL, pfd);
        LeaveCriticalSection(&pstm->s_cs);

        if (dwError == ERROR_FILE_NOT_FOUND)
            dwError = ERROR_NO_MORE_FILES;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        dwError = ERROR_INVALID_PARAMETER;
    }

    if (dwError)
        SetLastError(dwError);

    FATExit(pstm->s_pvol, LOGID_NONE);

    DEBUGMSGW(ZONE_APIS /* || ZONE_ERRORS && dwError */,
                        (DBGTEXTW("FATFS!FAT_FindNextFile(0x%08x,%s) returned 0x%x \"%s\" (%d)\r\n"),
                         psh,
                         psh->sh_awcPattern,
                         dwError == ERROR_SUCCESS,
                         dwError == ERROR_SUCCESS? pfd->cFileName : TEXTW(""),
                         dwError));
    return dwError == ERROR_SUCCESS;
}


BOOL FAT_FindClose(PSHANDLE psh)
{
    PDSTREAM pstm;
    PVOLUME  pvol;

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_FindClose(0x%08x,%s)\r\n"), psh, psh->sh_awcPattern));

    if (!FATEnter(NULL, LOGID_NONE))
        return FALSE;

    pstm = psh->sh_pstm;
    ASSERT(pstm);

    pvol = pstm->s_pvol;
    ASSERT (pvol);

    EnterCriticalSection(&pstm->s_cs);
    RemoveItem((PDLINK)&psh->sh_dlOpenHandles);
    CloseStream(pstm);

    DEBUGFREE(psh->sh_cbAlloc);
    VERIFYTRUE(HeapFree(hHeap, 0, (HLOCAL)psh));

    FATExit(pvol, LOGID_NONE);

    DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_FindClose returned TRUE (0)\r\n")));

    return TRUE;
}


/*  OpenRoot - Open stream for the root directory on a volume
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *
 *  EXIT
 *      pointer to the root directory stream, NULL if none;  there may not
 *      be one if the volume hasn't been formatted yet (for example).
 */

PDSTREAM OpenRoot(PVOLUME pvol)
{
    PDSTREAM pstm = pvol->v_pstmRoot;

    if (pstm) {

        if (pstm->s_flags & STF_UNMOUNTED)
            return NULL;

        EnterCriticalSection(&pvol->v_csStms);

        pstm->s_refs++;
        LeaveCriticalSection(&pvol->v_csStms);

        EnterCriticalSection(&pstm->s_cs);
    }
    return pstm;
}


/*  CloseRoot - Close stream for the root directory on a volume
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *
 *  EXIT
 *      ERROR_SUCCESS (or other error code).  The only time an error
 *      would be reported however is if there were still dirty buffers
 *      associated with the root stream that could not be committed by
 *      this call to CloseStream -- but such an error would have normally
 *      already been reported by an *earlier* call to CloseStream.
 */

DWORD CloseRoot(PVOLUME pvol)
{
    return CloseStream(pvol->v_pstmRoot);
}


/*  OpenPath - Open stream for next-to-last element of a path
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      pwsPath - pointer to path
 *      ppwsTail - address of pointer to last element (returned)
 *      plen - address of length of last element (returned)
 *      flName - zero or more NAME_* flags (eg, NAME_FILE, NAME_DIR)
 *      clusFail - cluster of stream not allowed in path
 *      (normally, this is UNKNOWN_CLUSTER, to perform unrestricted opens)
 *
 *  EXIT
 *      pointer to stream, NULL if error (call GetLastError for error code);
 *      rely on *ppwsTail and *plen only if there is no error.
 *
 *  NOTES
 *      There can be no "last element" if the specified path is the root
 *      directory;  in that case, *plen is set to ZERO.
 */

PDSTREAM OpenPath(PVOLUME pvol, PCWSTR pwsPath, PCWSTR *ppwsTail, int *plen, int flName, DWORD clusFail)
{
    int len = 0;
	int flTmp = 0;
    PCWSTR pws;
    LPTSTR pwsTempPath = NULL, pwsOrig = NULL;
    DWORD dwError = ERROR_SUCCESS;
    PDSTREAM pstm=NULL, pstmPrev = NULL ;

    ASSERT(pwsPath);

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!OpenPath (%s)\r\n"), pwsPath));

    __try {

        // Ignore leading slash
        if (*pwsPath == TEXTW('\\') || *pwsPath == TEXTW('/'))
            ++pwsPath;

        // Ignore empty paths
        if (*pwsPath == 0) {
            SetLastError(ERROR_ALREADY_EXISTS);
            goto exit;
        }

        pstm = OpenRoot(pvol);
        if (!pstm) {
            SetLastError(ERROR_ACCESS_DENIED);
            goto exit;
        }

        pwsTempPath = (LPTSTR)pwsPath;
        
#ifdef TFAT
        // Prepend the hidden directory to the path.  Ignore VOL:
        if (pvol->v_flags & VOLF_TFAT_REDIR_ROOT && _wcsicmp(pwsPath, TEXTW("VOL:")))
        {
            DWORD cbSize = (HIDDEN_TFAT_ROOT_DIR_LEN  + _tcslen(pwsPath) + 2) * sizeof(TCHAR);
            if (!(pwsTempPath = (LPTSTR) HeapAlloc (hHeap, 0 ,cbSize))) {
                goto exit;
            }
            _tcscpy (pwsTempPath, HIDDEN_TFAT_ROOT_DIR);
            _tcscat (pwsTempPath, TEXT("\\"));
            _tcscat (pwsTempPath, pwsPath);            
        }
#endif

        pwsOrig = pwsTempPath;

#ifdef PATH_CACHING
        // If clusFail is set to a specific cluster, we have walk
        // the path the hard way, making sure that no part of the path
        // references that cluster.  Otherwise, we can search the cache.

        if (clusFail == UNKNOWN_CLUSTER) {
            if (pstmPrev = PathCacheSearch(pvol, &pwsTempPath)) {
                CloseStream(pstm);
                pstm = pstmPrev;
            }
        }
#endif
        do {
            // pws points to current element

            pws = pwsTempPath;

            // Find end of current element

            while (*pwsTempPath && *pwsTempPath != TEXTW('\\') && *pwsTempPath != TEXTW('/'))
                ++pwsTempPath;

            // Determine size of current element

            if (len = pwsTempPath - pws) {

                if (len > MAX_LFN_LEN) {
                    dwError = ERROR_FILENAME_EXCED_RANGE;
                    break;
                }

⌨️ 快捷键说明

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