📄 volume.c
字号:
//对pdsk->pVol是否为null进行验证,如果为真,即未挂在分区,则分配并初始化相关的临界区变量
//条件为假则置flag为VOLF_REMOUNTED,表示某个分区被重新的mount
PVOLUME FindVolume(PDSK pdsk, PBIGFATBOOTSEC pbgbs)
{
PBIGFATBPB pbpb = &pbgbs->bgbsBPB;
PVOLUME pvol = pdsk->pVol;
ASSERT(OWNCRITICALSECTION(&csFATFS));
if (!pvol) {
//为挂载任何分区
pvol = (PVOLUME)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(VOLUME));
if (pvol) {
pvol->v_hVol = 0;
}
} else {
pvol->v_flags |= VOLF_REMOUNTED;
return pvol;
}
if (!pvol)
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!FindVolume: out of memory!\r\n")));
else {
DEBUGALLOC(sizeof(VOLUME));
InitializeCriticalSection(&pvol->v_cs);
DEBUGALLOC(DEBUGALLOC_CS);
InitializeCriticalSection(&pvol->v_csStms);
DEBUGALLOC(DEBUGALLOC_CS);
#ifdef PATH_CACHING
InitList((PDLINK)&pvol->v_dlCaches);
InitializeCriticalSection(&pvol->v_csCaches);
DEBUGALLOC(DEBUGALLOC_CS);
#endif
InitList((PDLINK)&pvol->v_dlOpenStreams);
pvol->v_pdsk = pdsk;
pvol->v_volID = INVALID_AFS;
}
return pvol;
}
/* TestVolume - Test a VOLUME's validity
*
* ENTRY
* pvol - pointer to VOLUME
* ppbgbs - pointer to address of PBR (partition boot record) for volume
*
* EXIT
* ERROR_SUCCESS, else VOLUME's INVALID bit set if any errors encountered
*/
DWORD TestVolume(PVOLUME pvol, PBIGFATBOOTSEC *ppbgbs)
{
DWORD cbSecOrig;
DWORD dwError = ERROR_SUCCESS;
PDSK pdsk = pvol->v_pdsk;
PBIGFATBOOTSEC pbgbs = *ppbgbs;
if (pvol->v_flags & VOLF_INVALID)
return dwError;
// Make sure other key BPB values are in sync with the driver (ie, sector
// size), assuming driver info was provided.
cbSecOrig = pdsk->d_diActive.di_bytes_per_sect;
if (cbSecOrig != pbgbs->bgbsBPB.oldBPB.BPB_BytesPerSector) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,
(DBGTEXT("FATFS!TestVolume: forcing driver sector size (%d) to match BPB (%d)\r\n"),
cbSecOrig, pbgbs->bgbsBPB.oldBPB.BPB_BytesPerSector));
pdsk->d_diActive.di_bytes_per_sect = pbgbs->bgbsBPB.oldBPB.BPB_BytesPerSector;
if (SetDiskInfo(pdsk->d_hdsk, &pdsk->d_diActive) == ERROR_SUCCESS) {
pvol->v_flags |= VOLF_MODDISKINFO;
if (pdsk->d_diActive.di_bytes_per_sect > cbSecOrig) {
PVOID pTemp;
pTemp = LocalReAlloc((HLOCAL)pbgbs, pdsk->d_diActive.di_bytes_per_sect, LMEM_MOVEABLE);
if (pTemp) {
pbgbs = pTemp;
} else {
DEBUGCHK(0);
return ERROR_OUTOFMEMORY;
}
if (pbgbs) {
DEBUGALLOC(pdsk->d_diActive.di_bytes_per_sect - cbSecOrig);
*ppbgbs = pbgbs; // update the caller's buffer address, too
}
else {
dwError = GetLastError();
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: out of memory, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= (VOLF_INVALID|VOLF_UNCERTAIN);
goto exit;
}
}
}
else {
// If SetDiskInfo returned an error, then revert to the
// size originally reported, but continue trying to mount.
pdsk->d_diActive.di_bytes_per_sect = cbSecOrig;
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: SetDiskInfo call to driver failed (%d)\r\n"), GetLastError()));
}
}
// Perform some trial reads now (first sector of first FAT, first
// sector of second FAT if one exists, and anything else we think of).
// We will clear VOLF_INVALID only on success. NOTE that we can now reuse
// the sector containing the BPB; we've extracted everything we needed
// from it.
#ifdef FAT32
// 对dbr的相关内容进行 有效性验证
if (pvol->v_flags & VOLF_32BIT_FAT) {
PBIGFATBOOTFSINFO pFSInfo;
dwError = ReadWriteDisk(pvol,
pdsk->d_hdsk,
READ_DISK_CMD,
&pdsk->d_diActive,
pvol->v_secVolBias + 1,
1,
pbgbs,
TRUE);
if (dwError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: ReadWriteDisk failed on extended boot sector (%d)\r\n"), dwError));
pvol->v_flags |= (VOLF_INVALID|VOLF_UNCERTAIN);
goto exit;
}
if (*(PDWORD)((PBYTE)pbgbs + 0) != SECONDBOOTSECSIG
||
*(PDWORD)((PBYTE)pbgbs + OFFSETTRLSIG) != BOOTSECTRAILSIG)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: error verifying extended boot sector, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= VOLF_INVALID;
goto exit;
}
// If secFSInfo happens to be 1 (which is typical), then there's no need
// to perform another read, since it's the same sector we just read (above).
if (pvol->v_secFSInfo != 1) {
dwError = ReadWriteDisk(pvol,
pdsk->d_hdsk,
READ_DISK_CMD,
&pdsk->d_diActive,
pvol->v_secVolBias + pvol->v_secFSInfo,
1,
pbgbs,
TRUE);
}
if (dwError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: ReadWriteDisk failed on FS info sector (%d)\r\n"), dwError));
pvol->v_flags |= (VOLF_INVALID|VOLF_UNCERTAIN);
goto exit;
}
if (*(PDWORD)((PBYTE)pbgbs + 0) != SECONDBOOTSECSIG
||
*(PDWORD)((PBYTE)pbgbs + OFFSETTRLSIG) != BOOTSECTRAILSIG
||
(pFSInfo = (PBIGFATBOOTFSINFO)((PBYTE)pbgbs + OFFSETFSINFOFRMSECSTRT))->bfFSInf_Sig != FSINFOSIG)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: error verifying FS info sector, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= VOLF_INVALID;
goto exit;
}
// Don't use the FSInfo values since we will not update them (they are legacy from Win 9x).
#if 0
if (pFSInfo->bfFSInf_free_clus_cnt < pvol->v_clusMax &&
pFSInfo->bfFSInf_next_free_clus <= pvol->v_clusMax) {
pvol->v_cclusFree = pFSInfo->bfFSInf_free_clus_cnt;
pvol->v_clusAlloc = pFSInfo->bfFSInf_next_free_clus;
}
else {
// Note that if the FSInfo fields are simply UNKNOWN_CLUSTER, then my assumption
// is that they simply haven't been initialized yet (as opposed to being truly bogus).
DEBUGMSG((ZONE_INIT || ZONE_ERRORS) &&
pFSInfo->bfFSInf_free_clus_cnt != UNKNOWN_CLUSTER &&
pFSInfo->bfFSInf_next_free_clus != UNKNOWN_CLUSTER, (DBGTEXT("FATFS!TestVolume: FS info data suspicious (%x,%x), ignoring...\r\n"), pFSInfo->bfFSInf_free_clus_cnt, pFSInfo->bfFSInf_next_free_clus));
}
#endif
}
#endif // FAT32
dwError = ReadWriteDisk(pvol,
pdsk->d_hdsk,
READ_DISK_CMD,
&pdsk->d_diActive,
pvol->v_secBlkBias + 0,
1,
pbgbs,
FALSE);
if (dwError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: ReadWriteDisk failed on first FAT (%d)\r\n"), dwError));
pvol->v_flags |= (VOLF_INVALID|VOLF_UNCERTAIN);
goto exit;
}
// 判断是否是有效的fat表
if (!ValidateFATSector(pvol, pbgbs))
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: error reading first FAT, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= VOLF_INVALID;
goto exit;
}
if (pvol->v_flags & VOLF_BACKUP_FAT) {
dwError = ReadWriteDisk(pvol,
pdsk->d_hdsk,
READ_DISK_CMD,
&pdsk->d_diActive,
pvol->v_secBlkBias + pvol->v_csecFAT,
1,
pbgbs,
FALSE);
if (dwError != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: ReadWriteDisk failed on backup FAT (%d)\r\n"), dwError));
pvol->v_flags |= (VOLF_INVALID|VOLF_UNCERTAIN);
goto exit;
}
if (!ValidateFATSector(pvol, pbgbs))
{
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: error reading backup FAT, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= VOLF_INVALID;
goto exit;
}
}
// Verify we can read the last sector in the last cluster of the volume too...
#if 0
dwError = ReadWriteDisk(pvol,
pdsk->d_hdsk,
READ_DISK_CMD,
&pdsk->d_diActive,
CLUSTERTOSECTOR(pvol, pvol->v_clusMax) +
(1 << pvol->v_log2csecClus) - 1,
1,
pbgbs);
if (dwError != ERROR_SUCCESS)
{
DEBUGMSGBREAK(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!TestVolume: error reading last sector, volume deemed invalid (%d)\r\n"), dwError));
pvol->v_flags |= VOLF_INVALID;
goto exit;
}
#endif
// If we modified the drive parameters but the volume isn't valid anyway, restore the default parameters.
exit:
if ((pvol->v_flags & (VOLF_MODDISKINFO | VOLF_INVALID)) == (VOLF_MODDISKINFO | VOLF_INVALID)) {
pvol->v_flags &= ~VOLF_MODDISKINFO;
pdsk->d_diActive.di_bytes_per_sect = cbSecOrig;
SetDiskInfo(pdsk->d_hdsk, &pdsk->d_diActive);
}
return dwError;
}
/* RefreshVolume - Refresh a VOLUME's handles
*
* ENTRY
* pvol - pointer to VOLUME
*
* EXIT
* Stream handles are restored, provided the volume is valid AND
* the streams appear to be in the same state we left them.
*/
void RefreshVolume(PVOLUME pvol)
{
PDSTREAM pstm, pstmEnd;
if (!(pvol->v_flags & (VOLF_REMOUNTED | VOLF_RECYCLED)))
return;
ASSERT(OWNCRITICALSECTION(&pvol->v_cs));
// Walk the open stream list, regenerate each stream, then walk the
// open handle list for each successfully regenerated stream, and clear
// the unmounted bit for each open handle.
// First, make sure the VISITED bit is clear in every stream currently
// open on this volume.
EnterCriticalSection(&pvol->v_csStms);
pstm = pvol->v_dlOpenStreams.pstmNext;
pstmEnd = (PDSTREAM)&pvol->v_dlOpenStreams;
while (pstm != pstmEnd) {
pstm->s_flags &= ~STF_VISITED;
pstm = pstm->s_dlOpenStreams.pstmNext;
}
// Now find the next unvisited stream. Note that every iteration of the
// loop starts with the volume critical section held.
restart:
pstm = pvol->v_dlOpenStreams.pstmNext;
while (pstm != pstmEnd) {
if (pstm->s_flags & STF_VISITED) {
pstm = pstm->s_dlOpenStreams.pstmNext;
continue;
}
pstm->s_flags |= STF_VISITED;
// Add a ref to insure that the stream can't go away once we
// let go of the volume's critical section.
pstm->s_refs++;
LeaveCriticalSection(&pvol->v_csStms);
EnterCriticalSection(&pstm->s_cs);
// Find/read the block containing this stream's DIRENTRY, unless
// it's a VOLUME-based stream, in which case we'll just automatically
// remount it.
ASSERT(pstm->s_pvol == pvol);
// Volume handles are always remounted, regardless
if (pstm->s_flags & STF_VOLUME)
pstm->s_flags &= ~STF_UNMOUNTED;
if ((pstm->s_flags & STF_UNMOUNTED) && !(pvol->v_flags & VOLF_INVALID)) {
PBUF pbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -