📄 find.c
字号:
//
// 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)\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_FILE, 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)LocalAlloc(LPTR, 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;
pfd->dwOID = OIDFROMSID(pvol, NULL);
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)
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);
VERIFYNULL(LocalFree((HLOCAL)psh));
#ifdef DEBUG
psh = NULL;
#endif
}
CloseStream(pstm);
SetLastError(dwError);
}
abort:
FATExit(LOGID_NONE);
DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && hFind == INVALID_HANDLE_VALUE,
(DBGTEXTW("FATFS!FAT_FindFirstFileW(0x%08x,%-.64s) returned 0x%x \"%s\" (%d)\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)\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(LOGID_NONE);
DEBUGMSGW(ZONE_APIS /* || ZONE_ERRORS && dwError */,
(DBGTEXTW("FATFS!FAT_FindNextFile(0x%08x,%s) returned 0x%x \"%s\" (%d)\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;
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_FindClose(0x%08x,%s)\n"), psh, psh->sh_awcPattern));
if (!FATEnter(NULL, LOGID_NONE))
return FALSE;
pstm = psh->sh_pstm;
ASSERT(pstm);
EnterCriticalSection(&pstm->s_cs);
RemoveItem((PDLINK)&psh->sh_dlOpenHandles);
CloseStream(pstm);
DEBUGFREE(psh->sh_cbAlloc);
VERIFYNULL(LocalFree((HLOCAL)psh));
FATExit(LOGID_NONE);
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_FindClose returned TRUE (0)\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, flTmp;
PCWSTR pws, pwsOrig;
DWORD dwError = ERROR_SUCCESS;
PDSTREAM pstm=NULL, pstmPrev = NULL ;
ASSERT(pwsPath);
__try {
// Ignore empty paths
if (*pwsPath == 0)
goto exit;
pstm = OpenRoot(pvol);
if (!pstm) {
SetLastError(ERROR_ACCESS_DENIED);
goto exit;
}
// Ignore leading slash
if (*pwsPath == TEXTW('\\') || *pwsPath == TEXTW('/'))
++pwsPath;
pwsOrig = pwsPath;
#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, &pwsPath)) {
CloseStream(pstm);
pstm = pstmPrev;
}
}
#endif
do {
// pws points to current element
pws = pwsPath;
// Find end of current element
while (*pwsPath && *pwsPath != TEXTW('\\') && *pwsPath != TEXTW('/'))
++pwsPath;
// Determine size of current element
if (len = pwsPath - pws) {
if (len > MAX_LFN_LEN) {
dwError = ERROR_FILENAME_EXCED_RANGE;
break;
}
// If this is the last element, exit. We know that the
// current character is either a NULL or slash. If NULL,
// we're done; if not NULL, then if the character after
// the current slash is NULL *and* the caller is looking
// for a directory, again we're done.
if (*pwsPath == 0)
break;
if (*(pwsPath+1) == 0 && (flName & NAME_DIR))
break;
flTmp = NAME_DIR;
pstm = OpenName(pstmPrev = pstm, pws, len, &flTmp);
ASSERT(!pstm || pstm->s_cwPath > pstmPrev->s_cwPath + 1);
#ifdef DEMAND_PAGING_DEADLOCKS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -