?? volume.c
字號:
void UnlockVolume(PVOLUME pvol)
{
// pvol->v_flags &= ~VOLF_LOCKED;
// return;
// We need to clear the volume's lock flag first, because if
// MountDisk decides to try to format it, it will need to be able
// to (re)lock the volume.
ASSERT(pvol->v_flags & VOLF_LOCKED);
pvol->v_flags &= ~VOLF_LOCKED;
if (pvol->v_flags & VOLF_MODIFIED) {
DWORD dwOldFlags;
HANDLE hdsk = pvol->v_pdsk->d_hdsk;
// Reinvigorate our data structures since it appears that the disk
// could have been significantly modified.
EnterCriticalSection(&csFATFS);
// Since the unmount/remount can cause the REMOUNTED or RECYCLED bits
// to be set, and since this could be called *within* an earlier mount,
// we don't want to lose the original bits for that earlier mount.
dwOldFlags = pvol->v_flags;
// We set the RETAIN bit, so that we don't have to worry about
// UnmountVolume freeing the current VOLUME structure. It will be
// reset by UnmountVolume as soon as CloseVolume has completed.
// (I used to set the FROZEN bit instead, but that doesn't get reset
// until much later -- when the volume is reopened by OpenVolume -- and
// it prevents legitimate ReadVolume/WriteVolume calls from working -JTP)
pvol->v_flags |= VOLF_RETAIN;
UnmountVolume(pvol, FALSE);
// When UnmountVolume called CloseVolume, CloseVolume froze the volume
// and set v_bMediaDesc to MAX_VOLUMES. We set it to zero now to insure
// that we will re-use the volume without delay.
pvol->v_bMediaDesc = 0;
if (pvol->v_flags & VOLF_FROZEN) {
pvol->v_pdsk->pVol = pvol;
pvol->v_flags &= ~VOLF_FROZEN;
}
//#if 0
#ifndef DEBUG
MountDisk(hdsk, NULL, pvol->v_flags);
#else
VERIFYTRUE(MountDisk(hdsk, NULL, pvol->v_flags));
#endif
//#endif
// IMPORTANT NOTE: If the VOLF_FROZEN bit is *not* clear, then it's
// possible that MountDisk (which calls MountVolume) may have recycled
// the *wrong* volume (or allocated a completely new one), which means
// that we may have just leaked a VOLUME; at the very least, it probably
// means our current pvol pointer is stale.
// TODO: Yadhug
// ASSERT(!(pvol->v_flags & VOLF_FROZEN));
// Restore the REMOUNTED and RECYCLED bits to their former glory
pvol->v_flags &= ~(VOLF_REMOUNTED | VOLF_RECYCLED);
pvol->v_flags |= dwOldFlags & (VOLF_REMOUNTED | VOLF_RECYCLED);
LeaveCriticalSection(&csFATFS);
#if 0
if (pvol->v_volID > INVALID_AFS) {
DEREGISTERAFS(pvol);
pvol->v_volID = REGISTERAFS(pvol, pvol->v_volID);
}
#endif
}
}
/* OpenVolume - Allocate a VOLUME structure and validate volume
*
* ENTRY
* pdsk -> DSK structure
* ppi -> partition info, if any
* ppbgbs - pointer to address of PBR (partition boot record) for volume
* pstmParent - pointer to parent stream (only if MiniFAT volume)
*
* EXIT
* pointer to new VOLUME structure, or NULL if we couldn't make one
*/
PVOLUME OpenVolume(PDSK pdsk, PPARTINFO ppi, PBIGFATBOOTSEC *ppbgbs, PDSTREAM pstmParent)
{
PVOLUME pvol;
ASSERT(pdsk->d_hdsk != INVALID_HANDLE_VALUE);
EnterCriticalSection(&csFATFS);
// Find a reusable VOLUME or allocate a new one.
pvol = FindVolume(pdsk, *ppbgbs);
if (!pvol)
goto exit;
EnterCriticalSection(&pvol->v_cs);
pvol->v_ppi = ppi; // record the associated partition info (NULL if non-partitioned)
if (ppi) // and associate the volume with the partition info, if any exists
ppi->pi_pvol = pvol;
pvol->v_flags &= ~(VOLF_FROZEN | VOLF_UNCERTAIN | VOLF_DIRTY_WARN);
// Initialize the rest of the VOLUME structure now. This doesn't perform
// any I/O, and will return an error only if there is a problem allocating
// memory for either the FAT or root directory streams.
if (!InitVolume(pvol, *ppbgbs)) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!OpenVolume: InitVolume failed, volume not opened!\n")));
CloseVolume(pvol, NULL);
pvol = NULL;
goto exit;
}
// Now make sure the volume is valid. This will set the INVALID bit if
// it isn't, but we will still register/mount the volume so that it can be
// made valid (ie, formatted) later.
TestVolume(pvol, ppbgbs);
exit:
LeaveCriticalSection(&csFATFS);
return pvol;
}
/* CloseVolume - Free a VOLUME structure (if no open handles)
*
* ENTRY
* pvol - pointer to VOLUME
* pwsVolName - pointer to volume name buffer (assumed to be MAX_PATH)
*
* EXIT
* TRUE if freed, FALSE if not. If not freed, then at a minimum,
* the disk handle is invalidated and the volume is marked FROZEN.
*
* NOTES
* The volume's critical section should be held by the caller,
* and is the caller's responsibility to unhold if this returns FALSE
* (ie, volume not freed).
*/
BOOL CloseVolume(PVOLUME pvol, PWSTR pwsVolName)
{
BOOL fSuccess = TRUE;
PDSTREAM pstm, pstmEnd;
PFHANDLE pfh, pfhEnd;
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!CloseVolume(0x%x)\n"), pvol));
ASSERT(pvol);
ASSERT(OWNCRITICALSECTION(&csFATFS));
ASSERT(OWNCRITICALSECTION(&pvol->v_cs));
#ifdef PATH_CACHING
// We destroy the path cache first, releasing any streams
// that it may have been holding onto, so that our assertion
// checks below don't give us false fits.
PathCacheDestroyAll(pvol);
#endif
// Walk the open stream list, and for each open stream, walk
// the open handle list, and for each open handle, mark it as
// unmounted. Streams with no open handles are immediately
// closed; the only streams that should fall into that category
// are the special streams for the FAT and root directory.
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;
}
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);
// Try to commit the stream before we unmount it, because we may
// never be able to remount this stream again, and CommitStream
// will refuse to commit a stream that's unmounted (and rightly so).
CommitStream(pstm, TRUE);
pfh = pstm->s_dlOpenHandles.pfhNext;
pfhEnd = (PFHANDLE)&pstm->s_dlOpenHandles;
if (pfh == pfhEnd) {
if (pstm->s_refs == 2) {
if (pstm == pvol->v_pstmFAT) {
pstm->s_refs--;
pvol->v_pstmFAT = NULL;
}
else if (pstm == pvol->v_pstmRoot) {
pstm->s_refs--;
pvol->v_pstmRoot = NULL;
}
}
}
else {
// An open handle exists, so we won't be able to free the volume.
fSuccess = FALSE;
// Note that we print # of refs less 1, because one of the
// refs is temporary (ie, it has been added by this function).
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!CloseVolume: stream %.11hs still open (%d refs)\n"), pstm->s_achOEM, pstm->s_refs-1));
// Since a stream's current buffer should be neither manipulated
// nor held after the release of its critical section, and since we
// own that critical section now, assert that the current buffer
// is no longer held; this means that the current buffer pointer
// serves only as a "cache hint" now, and since we are about to call
// FreeBufferPool, we need to invalidate that hint now, too.
ASSERT(!(pstm->s_flags & STF_BUFCURHELD));
pstm->s_pbufCur = NULL;
while (pfh != pfhEnd) {
pfh->fh_flags |= FHF_UNMOUNTED;
pfh = pfh->fh_dlOpenHandles.pfhNext;
}
}
pstm->s_flags |= STF_UNMOUNTED;
CloseStream(pstm);
EnterCriticalSection(&pvol->v_csStms);
goto restart;
}
LeaveCriticalSection(&pvol->v_csStms);
// Free any other memory associated with the volume. The only
// memory remaining (if ANY) should be the VOLUME structure and one
// or more open streams hanging off it. Also, before the registered name
// of the volume goes away, save a copy if the caller wants it (like for
// error reporting or something....) We start at "+1" to avoid copying
// the leading backslash.
if (pwsVolName) {
*pwsVolName = '\0';
if (pvol->v_pwsHostRoot)
wcscpy(pwsVolName, pvol->v_pwsHostRoot+1);
}
if (!(pvol->v_flags & VOLF_FORMATTING))
DeregisterVolume(pvol);
if (!FreeBufferPool(pvol))
fSuccess = FALSE;
// If this volume is associated with partition information, kill that association now
if (pvol->v_ppi) {
pvol->v_ppi->pi_pvol = NULL;
pvol->v_ppi = NULL;
}
if (fSuccess) {
// If we already tried once to close this volume and failed,
// leave it allocated but frozen until the volume is remounted
// or recycled, lest we mess up volume bookkeeping in
// external components.
fSuccess = !(pvol->v_flags & (VOLF_FROZEN | VOLF_RETAIN));
if (fSuccess) {
#ifdef PATH_CACHING
DEBUGFREE(DEBUGALLOC_CS);
DeleteCriticalSection(&pvol->v_csCaches);
#endif
DEBUGFREE(DEBUGALLOC_CS);
DeleteCriticalSection(&pvol->v_csStms);
DEBUGFREE(DEBUGALLOC_CS);
LeaveCriticalSection(&pvol->v_cs); // DeleteCriticalSection is picky about this...
DeleteCriticalSection(&pvol->v_cs);
DEBUGFREE(sizeof(VOLUME));
VERIFYNULL(LocalFree((HLOCAL)pvol));
}
else {
DEBUGMSGW(ZONE_INIT,(DBGTEXTW("FATFS!CloseVolume: retaining volume 0x%08x (%s)\n"), pvol, pvol->v_flags & VOLF_FROZEN? TEXTW("previously frozen") : TEXTW("following power cycle")));
if (!(pvol->v_flags & VOLF_FROZEN)) {
pvol->v_bMediaDesc = MAX_VOLUMES;
pvol->v_flags |= VOLF_FROZEN;
}
}
}
else {
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!CloseVolume: retaining volume 0x%08x (open files add/or dirty buffers)\n"), pvol));
if (!(pvol->v_flags & VOLF_FROZEN)) {
pvol->v_bMediaDesc = MAX_VOLUMES; // overload bMediaDesc as a recycle skip count
pvol->v_flags |= VOLF_FROZEN;
}
}
#ifdef DISK_CACHING
pvol->v_CacheSize = 0;
if (pvol->v_pFATCacheBuffer) {
VirtualFree( pvol->v_pFATCacheBuffer, 0, MEM_RELEASE);
pvol->v_pFATCacheBuffer = NULL;
}
if (pvol->v_pFATCacheLookup) {
HeapFree( GetProcessHeap(), 0, pvol->v_pFATCacheLookup);
pvol->v_pFATCacheLookup = NULL;
}
#endif
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!CloseVolume returned 0x%x\n"), fSuccess));
return fSuccess;
}
/* QueryVolumeParameters - Query volume parameters
*
* ENTRY
* pvol - pointer VOLUME structure
* pdevpb - pointer to DOS-style device parameter block
* fVolume - TRUE to return volume info, FALSE for device info
*
* EXIT
* ERROR_SUCCESS if successful, error code if not
*/
void QueryVolumeParameters(PVOLUME pvol, PDEVPB pdevpb, BOOL fVolume)
{
// Caller wants a DEVPB. Give him a close approximation of one.
memset(pdevpb, 0, sizeof(DEVPB));
#ifdef OLD_CODE
// In order to allow invalid volumes inside valid partitions
// to be reformatted, I'm going to leave fVolume alone now. -JTP
if (pvol->v_flags & VOLF_INVALID)
fVolume = FALSE;
#endif
// We'll use this bMediaType field to tell the caller what
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -