📄 path.c
字号:
// Failed allocation means that optimization is not used
pvol->v_clusterListSize = (pvol->v_clusMax + CLUSTERS_PER_LIST_ENTRY - 1) / CLUSTERS_PER_LIST_ENTRY;
pvol->v_clusterListSize = (pvol->v_clusterListSize + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1);
pvol->v_pFreeClusterList = (LPBYTE)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, pvol->v_clusterListSize);
dwSectorsRead = dwBufferSize >> pvol->v_log2cbSec;
if (ReadVolume (pvol, 0, dwSectorsRead, pFATBuffer) != ERROR_SUCCESS) {
goto exit;
}
// Start looking at the DATA_CLUSTER
// 偏移到真正的数据区开始位置,偏移量为cbFATEntry * DATA_CLUSTER,这些数据都在fat表中
pCurEntry = pFATBuffer + cbFATEntry * DATA_CLUSTER;
pvol->v_cclusFree = 0;
for (dwClus = DATA_CLUSTER; dwClus <= pvol->v_clusMax; dwClus++) {
if ((DWORD)(pCurEntry - pFATBuffer) >= dwBufferSize) {
// We've reached the end of the buffer, read the next chunk of data
DWORD dwSectorsToRead = min (pvol->v_csecFAT - dwSectorsRead, (DWORD)MAX_FREE_SPACE_CHUNK_SIZE >> pvol->v_log2cbSec);
if (ReadVolume (pvol, dwSectorsRead, dwSectorsToRead, pFATBuffer) != ERROR_SUCCESS) {
goto exit;
}
pCurEntry = pFATBuffer;
dwSectorsRead += dwSectorsToRead;
}
if (fFAT16) {
if ((*(PWORD)pCurEntry) == FREE_CLUSTER) {
IncrementFreeClusterCount(pvol, dwClus);
}
} else {
if ((*(PDWORD)pCurEntry) == FREE_CLUSTER) {
IncrementFreeClusterCount(pvol, dwClus);
}
}
pCurEntry += cbFATEntry;
}
fRet = TRUE;
exit:
if (pFATBuffer) {
VirtualFree (pFATBuffer, 0, MEM_RELEASE);
}
return fRet;
}
DWORD CalculateFreeClustersFromBuffers(PVOLUME pvol)
{
DWORD dwClus, dwData;
DWORD dwError = ERROR_SUCCESS;
pvol->v_cclusFree = 0;
for (dwClus=DATA_CLUSTER; dwClus <= pvol->v_clusMax; dwClus++) {
dwError = UNPACK(pvol, dwClus, &dwData);
if (dwError)
break;
if (dwData == FREE_CLUSTER)
pvol->v_cclusFree++;
}
return dwError;
}
BOOL FAT_GetDiskFreeSpaceW(
PVOLUME pvol,
PCWSTR pwsPathName,
PDWORD pSectorsPerCluster,
PDWORD pBytesPerSector,
PDWORD pFreeClusters,
PDWORD pClusters)
{
BOOL fSuccess = FALSE;
DWORD dwError = ERROR_SUCCESS;
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_GetDiskFreeSpace(%s)\r\n"), pwsPathName? pwsPathName : TEXTW("")));
LockFAT(pvol);
if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_WRITELOCKED)) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
// We enter the FAT's critical section even though we're just reading
// the FAT, because in process of reading, we could alter the FAT stream's
// current buffer, and that could mess up someone else accessing the FAT.
if (pvol->v_cclusFree == UNKNOWN_CLUSTER) {
// We currently call FATEnter/FATExit just at this point,
// because it's the only path in this call that might generate any I/O.
if (!FATEnter(NULL, LOGID_NONE))
goto exit;
if (!CalculateFreeClustersInRAM(pvol)) {
// If we couldn't do it in RAM, try it through the FAT buffers.
dwError = CalculateFreeClustersFromBuffers(pvol);
}
FATExit(pvol, LOGID_NONE);
}
__try {
if (!dwError) {
if (pSectorsPerCluster)
*pSectorsPerCluster = (1 << pvol->v_log2csecClus);
if (pBytesPerSector)
*pBytesPerSector = (1 << pvol->v_log2cbSec);
if (pFreeClusters)
*pFreeClusters = pvol->v_cclusFree;
if (pClusters)
*pClusters = pvol->v_clusMax-1;
fSuccess = TRUE;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
exit:
UnlockFAT(pvol);
DEBUGMSG(ZONE_APIS || ZONE_CLUSTERS || ZONE_ERRORS && !fSuccess,(DBGTEXT("FATFS!FAT_GetDiskFreeSpace returned 0x%x (%d), 0x%x clusters free\r\n"), fSuccess, dwError, pvol->v_cclusFree));
if (dwError)
SetLastError(dwError);
return fSuccess;
}
/* GetSIDInfo - Get file information by SID (worker for FAT_OidGetInfo)
*
* ENTRY
* pvol - pointer to VOLUME
* psid - pointer to SID of interest
* poi - pointer to OID information to return
*
* EXIT
* Error code (ERROR_SUCCESS if none). This code was removed from FAT_OidGetInfo
* and put into this worker function, because we cannot tolerate FAT_* entry points
* calling other FAT_* entry points (like FAT_OidGetInfo!), because then we can
* get into situations where an outer call is blocked by an inner call that is in
* turn blocked in FATEnter (because power just went off or something....)
*
* That particular case wasn't a problem in v1.0, because the shell notification
* mechanism was SHELL_MESSAGE_NOTIFICATION, not SHELL_CALLBACK_NOTIFICATION; the latter
* now requires us to provide information while we're still inside the FAT APIs.
*/
DWORD GetSIDInfo(PVOLUME pvol, PDSID psid, CEOIDINFO *poi)
{
SHANDLE sh;
PWSTR pwsCur;
DWORD len, dwError;
BYTE fSearch;
DWORD dwSearch;
DWORD dwNext;
DWORD oidParent;
DWORD clusParent;
DIRINFO di;
WIN32_FIND_DATAW fd;
fSearch = SHF_BYORD;
dwSearch = psid->sid_ordDir;
oidParent = 0;
clusParent = psid->sid_clusDir;
// Assume the OID is valid
dwError = ERROR_SUCCESS;
if (psid->sid_clusDir == UNKNOWN_CLUSTER)
dwError = ERROR_INVALID_PARAMETER;
// Find/create a stream for the object's directory
// NOTE: this form of OpenStream doesn't initialize the stream's name,
// attr, size, parent OID, or path length. However, lower level functions
// we call, like FindNext (which calls ReadStream), don't depend on that
// information, and since we're creating the stream as a PRIVATE stream, no
// one else will either.
while (!dwError && clusParent && (sh.sh_pstm = OpenStream(pvol, clusParent, NULL, NULL, NULL, OPENSTREAM_CREATE|OPENSTREAM_PRIVATE))) {
__try {
dwNext = clusParent;
dwError = ERROR_SUCCESS;
// Prepare to build the full name from the top down
// Find the object's DIRENTRY within that stream now.
// But first, since the directory's "." and ".." entries
// should appear first, let's look for them first. This
// will reduce the amount of oscillation within the stream.
if (!ISROOTDIR(sh.sh_pstm)) {
sh.sh_pos = 0;
sh.sh_flags = SHF_BYNAME | SHF_DOTDOT;
sh.sh_cwPattern = ARRAYSIZE(szDotDot)-1;
memcpy(sh.sh_awcPattern, szDotDot, sizeof(szDotDot));
dwError = FindNext(&sh, &di, &fd);
if (!dwError) {
// Because we supplied a DIRINFO to FindNext,
// the stream buffer did NOT automatically get unheld.
ReleaseStreamBuffer(sh.sh_pstm, FALSE);
clusParent = di.di_clusEntry;
// The absence of a cluster (on non-FAT32 volumes anyway)
// means that this directory's parent is the ROOT.
if (di.di_clusEntry == UNKNOWN_CLUSTER)
clusParent = pvol->v_pstmRoot->s_clusFirst;
}
else {
DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!GetSIDInfo: FindNext(%x) for clusParent 0x%x returned %d\r\n"), sh.sh_flags, dwNext, dwError));
// FindNext already set dwError to something, so let's pass it on;
// this is more important for "driver errors", like ERROR_GEN_FAILURE,
// because those errors will insure that any lengthy scan in-progress
// will get cancelled instead of continuing (see ScanDirectory in scan.c)
// dwError = ERROR_INVALID_PARAMETER;
goto close;
}
}
else
clusParent = NO_CLUSTER;
// OK, now we can go look for the object's DIRENTRY
sh.sh_pos = 0;
sh.sh_flags = fSearch;
sh.sh_h = (HANDLE)dwSearch;
dwError = FindNext(&sh, NULL, &fd);
if (!dwError) {
// The first DIRENTRY search is BYORD because that's
// all the OID tells us. Subsequent DIRENTRY searches are
// BYCLUS because that's all the ".." entries tell us.
// The first (BYORD) search is also the one that gives us
// the attribute, size, etc info we need, so record that now.
if (fSearch == SHF_BYORD) {
poi->infFile.dwAttributes = fd.dwFileAttributes;
poi->infFile.ftLastChanged = fd.ftLastWriteTime;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
poi->wObjType = OBJTYPE_DIRECTORY;
else {
poi->wObjType = OBJTYPE_FILE;
poi->infFile.dwLength = fd.nFileSizeLow;
}
pwsCur = &poi->infFile.szFileName[MAX_PATH-1];
*pwsCur = 0;
}
// If this is the first BYCLUS search (ie, if oidParent
// is still zero), then record this object as the parent.
else if (oidParent == 0)
#ifdef UNDER_CE
// NT does not have OID defined
oidParent = fd.dwOID;
#endif
// fd.cFileName has the name from the object's DIRENTRY
// Ignore the hidden root directory.
if (wcscmp(fd.cFileName, HIDDEN_TFAT_ROOT_DIR) != 0) {
len = wcslen(fd.cFileName);
pwsCur -= len;
}
if (pwsCur > poi->infFile.szFileName) {
if (wcscmp(fd.cFileName, HIDDEN_TFAT_ROOT_DIR) != 0) {
memcpy(pwsCur, fd.cFileName, len*sizeof(WCHAR));
*--pwsCur = TEXTW('\\');
}
if (clusParent) {
// Get ready for next search, since this one is done now
fSearch = SHF_BYCLUS;
dwSearch = dwNext;
}
else if (pvol->v_pwsHostRoot) {
pwsCur -= pvol->v_cwsHostRoot;
if (pwsCur >= poi->infFile.szFileName)
memcpy(pwsCur, pvol->v_pwsHostRoot, pvol->v_cwsHostRoot*sizeof(WCHAR));
else
dwError = ERROR_BUFFER_OVERFLOW;
}
}
else
dwError = ERROR_BUFFER_OVERFLOW;
}
else {
DEBUGMSG(ZONE_ERRORS,(TEXT("FATFS!GetSIDInfo: FindNext(%x) for clusParent 0x%x returned %d\r\n"), sh.sh_flags, dwNext, dwError));
dwError = ERROR_INVALID_PARAMETER;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
close:
CloseStream(sh.sh_pstm);
if (dwError)
break;
}
if (!dwError && !sh.sh_pstm) {
dwError = ERROR_BAD_UNIT; // device must have been removed
}
if (!dwError) {
if (oidParent == 0)
oidParent = OIDFROMSID(pvol, NULL);
__try {
poi->infFile.oidParent = oidParent;
// Slide the completed filename down (if it isn't already)
if (pwsCur != poi->infFile.szFileName)
memcpy(poi->infFile.szFileName, pwsCur, (wcslen(pwsCur)+1)*sizeof(WCHAR));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
}
return dwError;
}
#ifdef SHELL_MESSAGE_NOTIFICATION
#ifndef DEBUG
void PostFileSystemMessage(PVOLUME pvol, UINT uMsg, PDSID psid, PDSID psidParent)
#else
void PostFileSystemMessage(PVOLUME pvol, UINT uMsg, PDSID psid, PDSID psidParent, PWSTR pwsCaller)
#endif
{
if (hwndShellNotify && ZONE_SHELLMSGS) {
PostMessage(hwndShellNotify, uMsg, OIDFROMSID(pvol,psid), OIDFROMSID(pvol,psidParent));
DEBUGMSGW(ZONE_MSGS,(DBGTEXTW("FATFS!%s posted(0x%08x,0x%08x,0x%08x)\r\n"), pwsCaller, uMsg, OIDFROMSID(pvol,psid), OIDFROMSID(pvol,psidParent)));
}
}
#endif // SHELL_MESSAGE_NOTIFICATION
#ifdef SHELL_CALLBACK_NOTIFICATION
#ifndef DEBUG
void CallFileSystemFunction(PVOLUME pvol, DWORD dwSHCNE, PDSID psid, PDSID psidOld, CEOIDINFO *poiOld)
#else
void CallFileSystemFunction(PVOLUME pvol, DWORD dwSHCNE, PDSID psid, PDSID psidOld, CEOIDINFO *poiOld, PWSTR pwsCaller)
#endif
{
if (pfnShell && ZONE_SHELLMSGS) {
DWORD dwError;
CEOIDINFO oi;
FILECHANGEINFO fci;
memset(&oi, 0, sizeof(oi));
DEBUGMSG(ZONE_ERRORS && psid == NULL && psidOld == NULL,(DBGTEXT("FATFS!CallFileSystemFunction(0x%08x,0x%08x): called with invalid PDSIDs\r\n"), pvol, dwSHCNE));
if (psid && (dwError = GetSIDInfo(pvol, psid, &oi))) {
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!CallFileSystemFunction(0x%08x,0x%08x): GetSIDInfo unexpectedly failed (%d)\r\n"), pvol, dwSHCNE, dwError));
return;
}
fci.cbSize = sizeof(fci);
fci.wEventId = dwSHCNE;
fci.uFlags = SHCNF_PATH | SHCNF_FLUSHNOWAIT;
fci.dwItem1 = psid? (DWORD)&oi.infFile.szFileName : 0;
fci.dwItem2 = 0;
fci.dwAttributes = oi.infFile.dwAttributes;
fci.ftModified = oi.infFile.ftLastChanged;
fci.nFileSize = oi.infFile.dwLength;
if (poiOld) {
fci.dwItem2 = fci.dwItem1;
fci.dwItem1 = psidOld? (DWORD)&poiOld->infFile.szFileName : 0;
}
__try {
(*pfnShell)(&fci);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!CallFileSystemFunction(0x%08x,0x%08x): 0x%08x blew up\r\n"), pvol, dwSHCNE, pfnShell));
return;
}
DEBUGMSGW(ZONE_MSGS,(DBGTEXTW("FATFS!%s notified function 0x%08x(0x%08x,\"%s\",\"%s\")\r\n"), pwsCaller, pfnShell, dwSHCNE, fci.dwItem1, fci.dwItem2));
}
}
#endif // SHELL_CALLBACK_NOTIFICATION
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -