📄 find.c
字号:
// This LFN sequence has TOO MANY entries, which also
// means it won't fit in a MAX_PATH buffer. We could
// treat the sequence like orphaned LFN entries, but
// that seems a rather risky proposition, since we may be
// talking directory corruption here. Safer to just ignore
// them and rely on SCANDSKW to fix things up. -JTP
goto resetall;
}
if (!(di.di_flags & DIRINFO_OEM) && di.di_cdeNeed > 1 && seqLFN != di.di_cdeNeed-1) {
// Optimization: this LFN sequence does not have the requisite
// number of entries, so it can't possibly be a match.
goto resetall;
}
chksum = plde->lde_chksum;
// If this LFN sequence has the wrong OEM chksum, it might simply
// be due to charset differences between the system where the OEM name
// was originally created and the current system, so unlike previous
// releases, we will no longer bail out and 'goto resetall'; we will
// instead continue to collect all the LFN chunks and do the full name
// comparison. In other words, we are no longer dependent on the
// accuracy of the OEM version of the name (as computed by UniToOEMName). -JTP
DEBUGMSGW(di.di_cdeNeed == 1 && chksum != di.di_chksum && ZONE_APIS && ZONE_ERRORS,(DBGTEXTW("FATFS!FindNext: lfn chksum (%x) doesn't match OEM chksum (%x) for '%.11hs'\n"), chksum, di.di_chksum, di.di_achOEM));
// Remember this LFN's starting position
di.di_posLFN = di.di_pos;
cwComp = di.di_cwTail;
pwsComp = di.di_pwsTail;
pwsBuff = &pfd->cFileName[LDE_NAME_LEN*LN_MAX_ORD_NUM];
*--pwsBuff = 0; // guarantee a NULL-terminator
// If this LFN contains the max number of LFNDIRENTRYs,
// we have to scoot pwsBuff up one WCHAR and reduce the
// amount of the final memcpy (of lde_name3) by one WCHAR,
// to insure that the NULL-terminator above is preserved.
if (seqLFN == LN_MAX_ORD_NUM) {
pwsBuff++;
cbName3 -= sizeof(WCHAR);
}
}
// Skip LFN entries we're not interested in
else if (seqLFN == -1) {
goto resetall;
}
// Recover LFN entries that are inconsistent
else if (seqLFN != plde->lde_ord || chksum != plde->lde_chksum) {
// All preceding LFN entries are deemed bogus/recoverable.
// If they can be merged with the free count, do it, otherwise
// leave them recorded as unrecoverable.
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!FindNext: LFN sequence (0x%x vs. 0x%x) or LFN chksum (0x%x vs. 0x%x) error\n"), seqLFN, plde->lde_ord, chksum, plde->lde_chksum));
di.di_posOrphan = di.di_posLFN;
di.di_cdeOrphan = (di.di_pos - di.di_posLFN)/sizeof(LFNDIRENTRY);
if (di.di_posFree + di.di_cdeFree * sizeof(LFNDIRENTRY) == di.di_posLFN) {
di.di_cdeFree += di.di_cdeOrphan;
di.di_cdeOrphan = 0;
}
goto resetall;
}
if (di.di_cdeFree < di.di_cdeNeed)
di.di_cdeFree = 0;
// LFN directory entry in sequence. Copy the name entry by
// entry into a scratch buffer to be matched when all of the
// entries in the name have been processed.
pwsBuff -= LDE_NAME_LEN;
memcpy(pwsBuff, plde->lde_name1, sizeof(plde->lde_name1));
memcpy(pwsBuff+LDE_LEN1, plde->lde_name2, sizeof(plde->lde_name2));
memcpy(pwsBuff+LDE_LEN1+LDE_LEN2, plde->lde_name3, cbName3);
// If we can compare individual pieces, do it now
if (fComp) {
// We perform a quick comparison on the first
// character past the end of the LFN (if one exists)
// and if that character isn't a NULL, then this
// entry isn't a match; otherwise, compare entire piece.
if (cwComp != LDE_NAME_LEN && pwsBuff[cwComp] != 0 ||
_wcsnicmp(pwsBuff, pwsComp, cwComp) != 0) {
goto resetlfn;
}
pwsComp -= LDE_NAME_LEN;
}
--seqLFN;
continue;
}
// Check for a "normal" directory entry.
if ((di.di_pde->de_attr & ATTR_DIR_MASK) != ATTR_VOLUME_ID) {
int len;
if (!(psh->sh_flags & SHF_DOTDOT) &&
(*(PDWORD)di.di_pde->de_name == 0x2020202e ||
*(PDWORD)di.di_pde->de_name == 0x20202e2e)) {
goto resetall;
}
// Normal directory entry. If preceeding LFN
// directory entries matched, handle this entry
// as a match. Otherwise, if the name is 8.3
// compatible, then try to match the 8.3 OEM name
// contained in this entry.
if (seqLFN == 0) {
if (chksum == ChkSumName(di.di_pde->de_name)) {
len = wcslen(pwsBuff);
// We processed all the LFN chunks for the current entry,
// (since seqLFN is now 0), so if fComp is TRUE, that means
// we compared every chunk as we went, and they must have
// all matched, so let's just 'goto match'
if (fComp)
goto match;
// If cdeNeed == -1, we're dealing with wildcards *or* a
// a non-name-based search, so we have to explicitly check
// for a match.
if (di.di_cdeNeed == -1)
goto checkmatch;
// Well, we must be performing a name-based search, and since
// we didn't compare the LFN chunks as we went, we did at least
// collect them all in pwsBuff, so let's see if the full LFN
// matches....
//
// Note: we didn't *always* used to do this, which meant that we
// always fell into the "normal directory entry" case below, which
// which only compared the OEM forms of the filenames; normally,
// that was sufficient, but in cases where the OEM name was created
// on a system with different charset mappings, that comparison could
// fail. We should rely on the 8.3 OEM name IFF there are no LFN
// entries -- and in this case, there *is*.... -JTP
if (len == psh->sh_cwPattern && _wcsnicmp(pwsBuff, psh->sh_awcPattern, len) == 0)
goto match;
}
else {
// All preceding LFN entries are deemed bogus/recoverable.
// If they can be merged with the free count, do it, otherwise
// leave them recorded as unrecoverable.
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!FindNext: LFN chksum (0x%x vs. 0x%x) error\n"), chksum, ChkSumName(di.di_pde->de_name)));
di.di_posOrphan = di.di_posLFN;
di.di_cdeOrphan = (di.di_pos - di.di_posLFN)/sizeof(LFNDIRENTRY);
if (di.di_posFree + di.di_cdeFree * sizeof(LFNDIRENTRY) != di.di_posLFN) {
di.di_cdeFree = 0;
} else {
di.di_cdeFree += di.di_cdeOrphan;
di.di_cdeOrphan = 0;
}
// We used to bail at this point (goto checkshort), but the right
// thing to do is just treat the current DIRENTRY as a short-name only.
seqLFN = -1;
}
}
// Normal directory entry, and either there were no preceding LFN
// entries, or there were but we couldn't make use of them.
if (di.di_cdeNeed == -1 ||
(di.di_flags & DIRINFO_OEM) &&
memcmp(di.di_pde->de_name,
di.di_achOEM,
sizeof(di.di_pde->de_name)) == 0) {
// If seqLFN == 0, then the preceding LFN entries probably
// provide better name information, so use the OEM name only if
// we have to.
if (seqLFN != 0) {
pwsBuff = pfd->cFileName;
len = OEMToUniName(pwsBuff, di.di_pde->de_name);
}
if (di.di_flags & DIRINFO_OEM)
goto match;
else
goto checkmatch;
}
goto checkshort;
checkmatch:
// Resync the SHANDLE pos with DIRINFO pos, for MatchNext
psh->sh_pos = di.di_pos;
if (MatchNext(psh, pwsBuff, len, di.di_pde)) {
match:
SETSID(&di.di_sid, di.di_pos, pstmDir->s_clusFirst);
pfd->dwOID = OIDFROMSID(pstmDir->s_pvol, &di.di_sid);
pfd->dwFileAttributes = di.di_pde->de_attr;
if (pfd->dwFileAttributes == 0)
pfd->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
pfd->nFileSizeHigh = 0;
pfd->nFileSizeLow = di.di_pde->de_size;
// If the name was built up from a series of LFN entries,
// it may need to be slid down to the start of pfd->cFilename
// (since we built it up from the top down).
if (pwsBuff != pfd->cFileName) {
memcpy(pfd->cFileName, pwsBuff, len*sizeof(WCHAR));
pfd->cFileName[len] = 0;
}
// If the caller passed us a DIRINFO, then leave the
// the stream buffer held and let him have the address
// of the DIRENTRY (di.di_pde). We do not need to advance
// the search position or fill in the entire WIN32_FIND_DATAW
// for such callers.
if (pdi) {
di.di_clusEntry =
GETDIRENTRYCLUSTER(pstmDir->s_pvol, di.di_pde);
if (di.di_clusEntry == NO_CLUSTER)
di.di_clusEntry = UNKNOWN_CLUSTER;
di.di_cwName = len;
goto norelease;
}
// We don't need to waste time converting/copying all the
// file times for certain types of searches (eg, SHF_BYCLUS
// or SHF_DOTDOT).
if ((psh->sh_flags & SHF_BYMASK) != SHF_BYCLUS && !(psh->sh_flags & SHF_DOTDOT))
CopyTimes(pfd, di.di_pde);
di.di_pde = NULL;
psh->sh_pos = di.di_pos + sizeof(DIRENTRY);
goto release;
}
// We just can't seem to do anything with this
// directory entry. Well, if the caller may need to
// create a new LFN entry, determine if the current
// entry conflicts with any of the possible short names
// we can generate.
checkshort:
if (pdwShortNameBitArray)
CheckNumericTail(&di, pdwShortNameBitArray);
}
resetall:
if (di.di_cdeFree < di.di_cdeNeed)
di.di_cdeFree = 0;
resetlfn:
seqLFN = -1; // reset LFN match sequence #
di.di_posLFN = INVALID_POS;
} while ((di.di_pos += sizeof(DIRENTRY)), ++di.di_pde < pdeEnd);
} __except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
di.di_pde = NULL;
}
}
release:
ReleaseStreamBuffer(pstmDir, FALSE);
norelease:
if (pdi) {
// Before copying the DIRINFO structure, see if the caller was
// searching on behalf of a CREATE, and try to generate a non-existent
// short name that he can use to perform the creation.
if (pdwShortNameBitArray)
GenerateNumericTail(&di, pdwShortNameBitArray);
*pdi = di;
}
if (dwError)
psh->sh_pos = INVALID_POS;
return dwError;
}
void CreateDirEntry(PDSTREAM pstmDir, PDIRENTRY pde, PDIRENTRY pdeClone, BYTE bAttr, DWORD clusFirst)
{
FILETIME ft;
SYSTEMTIME st;
if (pdeClone) {
*pde = *pdeClone;
return;
}
memset(pde->de_name, ' ', sizeof(pde->de_name));
memset(&pde->de_attr, 0, sizeof(DIRENTRY)-sizeof(pde->de_name));
pde->de_attr = bAttr;
if (clusFirst != UNKNOWN_CLUSTER && clusFirst >= DATA_CLUSTER)
SETDIRENTRYCLUSTER(pstmDir->s_pvol, pde, clusFirst);
GetSystemTimeAsFileTime(&ft);
// Directories don't really benefit from creation and access
// timestamps, but we'll set them anyway. MS-DOS only sets access
// and modified dates, but Win95's VFAT sets all three, so so will we.
FileTimeToDOSTime(&ft,
&pde->de_createdDate,
&pde->de_createdTime,
&pde->de_createdTimeMsec);
FileTimeToDOSTime(&ft, &pde->de_date, &pde->de_time, NULL);
// This is simpler than truncating the local system time to midnight,
// converting it to a local file time, then converting it to a non-local
// file time, then calling FileTimeToDOSTime, which turns around and
// undoes most of that.
GetLocalTime(&st);
DEBUGMSG(ZONE_STREAMS,(DBGTEXT("FATFS!CreateDirEntry: local file system ACCESS time: y=%d,m=%d,d=%d,h=%d,m=%d,s=%d\n"), st.wYear, st.wMonth, st.wDay, 0, 0, 0));
pde->de_lastAccessDate = ((st.wYear-1980) << 9) | (st.wMonth << 5) | (st.wDay);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -