📄 find.c
字号:
}
// CloneDirCluster succeeded
ASSERT( blkNew == pstmDir->s_pbufCur->b_blk );
}
/* NOTE: blkNew will now be the blk of the current buffer,
* so this loop should only come again if there is
* another change in blocks (which there shouldn't be)
*/
}
}
#endif
do {
if( !ISLFNDIRENTRY( pde ))
goto lfndone;
if(( dwError = ModifyStreamBuffer( pstmDir, pde, sizeof( DIRENTRY ))) != ERROR_SUCCESS )
goto lfndone;
pde->de_name[ 0 ] = DIRFREE;
// TEST_BREAK
PWR_BREAK_NOTIFY(24);
} while( pdi->di_posLFN += sizeof( DIRENTRY ), ++pde < pdeEnd );
}
lfndone:
;
}
dwError = WriteAndReleaseStreamBuffers(pstmDir);
#ifdef TFAT
// WriteAndReleaseStreamBuffers may not commit buffer if file is not write-through
if (pvol->v_fTfat) {
CommitStreamBuffers (pstmDir);
}
#endif
// Now kill all the cluster entries associated with this file.
// We enter the FAT's critical section even though we're just freeing
// clusters, because in the process, we could alter the FAT stream's
// current buffer, and that could mess up someone else accessing the FAT.
if (dwError == ERROR_SUCCESS && pdi->di_clusEntry != UNKNOWN_CLUSTER) {
DWORD dwData = FREE_CLUSTER;
#ifdef DEBUG
#ifdef FATUI
if (ZONE_PROMPTS) {
int i;
FATUIDATA fui;
fui.dwSize = sizeof(fui);
fui.dwFlags = FATUI_YES | FATUI_NO | FATUI_CANCEL | FATUI_DEBUGMESSAGE;
fui.idsEvent = (UINT)TEXTW("Preparing to delete clusters for '%1!.11hs!'.\r\n\r\nSelect Yes to delete, No to mark bad, or Cancel to leave allocated.");
fui.idsEventCaption = IDS_FATUI_WARNING;
fui.cuiParams = 1;
fui.auiParams[0].dwType = UIPARAM_VALUE;
fui.auiParams[0].dwValue = (DWORD)achName;
i = FATUIEvent(hFATFS, pvol->v_pwsHostRoot+1, &fui);
if (i == FATUI_CANCEL)
goto exit;
if (i == FATUI_NO)
dwData = FAT32_BAD;
}
#endif
#endif
#ifdef TFAT
if (!pvol->v_fTfat)
#endif
{
while (pdi->di_clusEntry >= DATA_CLUSTER && !ISEOF(pvol, pdi->di_clusEntry)) {
FreeClustersOnDisk(pvol, pdi->di_clusEntry, 1);
if (dwError = PACK(pvol, pdi->di_clusEntry, dwData, &pdi->di_clusEntry))
break;
}
}
#ifdef TFAT
if (pvol->v_fTfat)
// TFAT - don't delete the cluster, freeze it instead
{
DWORD clusFirst = NO_CLUSTER, clusNext = pdi->di_clusEntry, clusEnd;
// Get the last cluster in the chain
dwError = ERROR_SUCCESS;
while (!dwError && clusNext >= DATA_CLUSTER && !ISEOF(pvol, clusNext))
{
if (NO_CLUSTER == clusFirst)
clusFirst = clusNext;
clusEnd = clusNext;
// get next cluster
dwError = UNPACK( pvol, clusNext, &clusNext);
}
if (NO_CLUSTER != clusFirst){
FreezeClusters (pvol, clusFirst, clusEnd);
}
}
#endif
WriteAndReleaseStreamBuffers(pvol->v_pstmFAT);
}
exit:
UnlockFAT(pvol);
return dwError;
}
/* FindFirst - find the directory stream containing the specified file
*
* ENTRY
* pvol - pointer to VOLUME
* pwsPath - pointer to pathname
* psh - pointer to SHANDLE (required)
* pdi - pointer to DIRINFO (optional, NULL if not needed)
* pfd - pointer to WIN32_FIND_DATAW structure (required)
* 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)
*
* Additionally, psh->sh_flags must be set appropriately. At a minimum,
* it must contain SHF_BYNAME, but can also contain SHF_WILD, SHF_DOTDOT,
* and SHF_CREATE.
*
* EXIT
* If successful, it will return the attributes of the file from
* the file's DIRENTRY, and if a pdi was supplied, it will be filled
* in and current stream buffer left held.
*
* If not successful, the attributes will be set to INVALID_ATTR,
* and the current stream buffer will not held.
*
* Finally, if the stream didn't exist, or no pdi was supplied, no
* stream will be returned. Otherwise, the directory stream containing
* the specified file will be returned.
*/
PDSTREAM FindFirst(PVOLUME pvol, PCWSTR pwsPath, PSHANDLE psh, PDIRINFO pdi, PWIN32_FIND_DATAW pfd, int flName, DWORD clusFail)
{
PWSTR pwsName;
DWORD len;
DWORD dwError = ERROR_SUCCESS;
psh->sh_pstm = NULL;
__try {
pfd->dwFileAttributes = INVALID_ATTR;
psh->sh_pstm = OpenPath(pvol, pwsPath, &pwsName, &len, flName, clusFail);
if (psh->sh_pstm == NULL) {
if (ERROR_ALREADY_EXISTS == GetLastError()) {
SetLastError(ERROR_PATH_NOT_FOUND);
}
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;
if (len > MAX_PATH)
return FALSE;
return(
fMask == SHF_BYNAME &&
MatchesWildcardMask(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(psh->sh_pstm->s_pvol, di.di_achOEM, psh->sh_awcPattern, psh->sh_cwPattern, psh->sh_pstm->s_pvol->v_nCodePage);
// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -