📄 disk.c
字号:
}
else {
csecGap = ppi->pi_secAbsolute - secStart;
ASSERT((int)csecGap >= 0);
if (csecGap >= pps->ps_csecDesired ||
csecGap >= pps->ps_csecMinimum && csecGap > pps->ps_csecFound) {
pps->ps_pdlFound = pdlPartInfo;
pps->ps_ppiFound = ppi;
pps->ps_csecFound = csecGap;
}
pps->ps_csecTotalFound += csecGap;
if (csecGap >= pps->ps_csecDesired)
return TRUE;
}
secStart = ppi->pi_secAbsolute + ppi->pi_PartEntry.Part_TotalSectors;
ppi = ppi->pi_dlPartitions.ppiNext;
}
// Check for any gap past the end of the list...
csecGap = secEnd - secStart;
ASSERT((int)csecGap >= 0);
if (csecGap >= pps->ps_csecDesired ||
csecGap >= pps->ps_csecMinimum && csecGap > pps->ps_csecFound) {
pps->ps_pdlFound = pdlPartInfo;
pps->ps_ppiFound = ppi;
pps->ps_csecFound = csecGap;
}
pps->ps_csecTotalFound += csecGap;
if (csecGap >= pps->ps_csecDesired)
return TRUE;
return FALSE;
}
/* RefreshPartitionInfo
*
* ENTRY
* pdsk -> DSK structure
*
* EXIT
* Partition information cached in the DSK structure is updated
* (eg, d_csec_Unused, d_csecTotalUnused). Total unused sectors
* could be updated on the fly as we create/destroy PARTINFO structures,
* but the largest unused chunk cannot be determined until all partition
* mounting is complete.
*/
void RefreshPartitionInfo(PDSK pdsk)
{
PARTSRCH ps;
memset(&ps, 0, sizeof(ps));
ps.ps_csecMinimum = ps.ps_csecDesired = 0xffffffff;
WalkPartitionInfo(&pdsk->d_dlPartitions, 0, pdsk->d_diActive.di_total_sectors, &ps);
pdsk->d_csecUnused = ps.ps_csecFound;
pdsk->d_csecTotalUnused = ps.ps_csecTotalFound;
}
/* FreePartitionInfo - Free all PARTINFO structures associated with a DSK structure
*
* ENTRY
* pdlPartInfo -> head of a partition list
*
* EXIT
* None
*/
void FreePartitionInfo(PPI_DLINK pdlPartInfo)
{
PPARTINFO ppi = pdlPartInfo->ppiNext;
while (ppi != (PPARTINFO)pdlPartInfo) {
FreePartitionInfo(&ppi->pi_dlChildren);
RemoveItem((PDLINK)&ppi->pi_dlPartitions);
// If this partition info is associated with a volume, kill that association now
if (ppi->pi_pvol) {
ppi->pi_pvol->v_ppi = NULL;
//ppi->pi_pvol = NULL;
}
NamePartitionInfo(ppi, NULL); // free the name, if any
ppi->pi_dwSig = 0; // zap the signature, to avoid being spoofed elsewhere
DEBUGFREE(sizeof(PARTINFO));
VERIFYNULL(LocalFree((HLOCAL)ppi));
ppi = pdlPartInfo->ppiNext;
continue;
}
}
PDSK FindDisk(HANDLE hdsk, PCWSTR pwsDisk, PDISK_INFO pdi)
{
DWORD cwDisk;
PDSK pdsk = dlDisks.pdskNext;
ASSERT(OWNCRITICALSECTION(&csFATFS));
cwDisk = 0;
if (pwsDisk)
cwDisk = wcslen(pwsDisk)+1;
while (pdsk && (pdsk != (PDSK)&dlDisks)) {
if (pdsk->d_hdsk == hdsk) {
if (pdi)
ASSERT(memcmp(&pdsk->d_diActive, pdi, sizeof(*pdi)) == 0);
goto exit;
}
if (pdi && (pdsk->d_flags & DSKF_FROZEN)) {
if (memcmp(&pdsk->d_diActive, pdi, sizeof(*pdi)) == 0) {
pdsk->d_flags |= DSKF_REMOUNTED;
DEBUGMSG(ZONE_INIT,(DBGTEXT("FATFS!FindDisk: remounting frozen disk...\n")));
goto init2;
}
}
pdsk = pdsk->d_dlOpenDisks.pdskNext;
}
if (!pdi) {
pdsk = NULL;
goto exit;
}
pdsk = (PDSK)LocalAlloc(LPTR, sizeof(DSK)-sizeof(pdsk->d_wsName) + cwDisk*sizeof(pwsDisk[0]));
if (!pdsk)
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!FindDisk: out of memory!\n")));
else {
DEBUGALLOC(sizeof(DSK)-sizeof(pdsk->d_wsName) + cwDisk*sizeof(pwsDisk[0]));
AddItem((PDLINK)&dlDisks, (PDLINK)&pdsk->d_dlOpenDisks);
InitList((PDLINK)&pdsk->d_dlPartitions);
pdsk->d_diActive = *pdi;
init2:
pdsk->d_cwName = cwDisk;
wcsncpy(pdsk->d_wsName, pwsDisk, cwDisk);
}
exit:
return pdsk;
}
/* MountDisk - Find and mount all volumes on specified disk
*
* ENTRY
* hdsk - handle to disk device containing one or more FAT volumes
* pwsDisk -> name of disk device, NULL if unknown
* flVol - initial volume flags (currently, only VOLF_READONLY is copied)
*
* EXIT
* Pointer to DSK structure, NULL if error (eg, out of memory,
* unusable disk, etc)
*
* NOTES
* In the 1.0 release, if the disk appeared to be a hard disk, I mounted
* only the active DOS partition, and if there was *no* active partition,
* then I mounted only the *first* DOS partition. In the current release,
* I mount *all* DOS partitions, including "Extended DOS Partitions".
*/
PDSK MountDisk(HANDLE hdsk, PCWSTR pwsDisk, DWORD flVol)
{
DWORD dwError;
DISK_INFO di;
PBYTE pbSector;
PDSK pdsk = NULL;
if (GetDiskInfo(hdsk, &di) != ERROR_SUCCESS || di.di_bytes_per_sect == 0) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!MountDisk: no valid disk info (%d)\n"), GetLastError()));
di.di_total_sectors = SetFilePointer(hdsk, 0, NULL, FILE_END);
if (di.di_total_sectors == 0xFFFFFFFF || di.di_total_sectors < DEFAULT_SECTOR_SIZE)
return NULL;
di.di_total_sectors /= DEFAULT_SECTOR_SIZE;
di.di_bytes_per_sect = DEFAULT_SECTOR_SIZE;
di.di_cylinders = 1;
di.di_heads = 1;
di.di_sectors = di.di_total_sectors;
di.di_flags = DISK_INFO_FLAG_CHS_UNCERTAIN | DISK_INFO_FLAGS_FATFS_SIMULATED;
}
else {
// Make sure our special "simulated" flag is never set by the driver
DEBUGMSG((di.di_flags & DISK_INFO_FLAGS_FATFS_SIMULATED),(DBGTEXT("FATFS!MountDisk: driver is setting reserved bit(s)!\n")));
di.di_flags &= ~DISK_INFO_FLAGS_FATFS_SIMULATED;
}
if (di.di_total_sectors < 16) {
return NULL;
}
// We ZEROINIT the memory so that if the ReadWriteDisk call fails
// (perhaps because the media is completely unreadable/unusable at this
// point), MountVolume won't be spoofed by bogus data in the sector buffer;
// even though MountVolume won't actually mount anything in that case, it
// will at least register a volume name that can be subsequently used in
// format requests.
pbSector = (PBYTE)LocalAlloc(LPTR, di.di_bytes_per_sect);
if (!pbSector) {
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!MountDisk: out of memory, aborting mount\n")));
return NULL;
}
DEBUGALLOC(di.di_bytes_per_sect);
dwError = ReadWriteDisk(NULL, hdsk, DISK_IOCTL_READ, &di, 0, 1, pbSector);
DEBUGMSG(ZONE_ERRORS && dwError,(DBGTEXT("FATFS!MountDisk: error reading MBR (%d)\n"), dwError));
EnterCriticalSection(&csFATFS);
// This is a logical point to assume that we're actually going
// to succeed in mounting one or more volumes, so let's allocate
// and initialize a DSK structure for the entire disk (which may
// contain 0 or more volumes).
pdsk = FindDisk(hdsk, pwsDisk, &di);
if (!pdsk)
goto exit;
pdsk->d_hdsk = hdsk;
pdsk->d_flags &= ~DSKF_FROZEN;
// Since we're mounting non-partitioned media, HiddenSectors should be zero
if (((PBIGFATBOOTSEC)pbSector)->bgbsBPB.oldBPB.BPB_HiddenSectors != 0) {
DEBUGMSGW(ZONE_ERRORS,(DBGTEXTW("FATFS!MountDisk: BPB_HiddenSectors(%d) != 0\n"), ((PBIGFATBOOTSEC)pbSector)->bgbsBPB.oldBPB.BPB_HiddenSectors));
((PBIGFATBOOTSEC)pbSector)->bgbsBPB.oldBPB.BPB_HiddenSectors = 0;
}
pdsk->pVol = MountVolume(pdsk, (PBIGFATBOOTSEC *)&pbSector, NULL, flVol);
// If we allocated a DSK structure but we never allocated any VOLUMEs
// to go along with it, then free the DSK structure, using UnmountDisk.
exit:
if (pdsk && !(pdsk->d_flags & (DSKF_REMOUNTED | DSKF_RECYCLED)) && !pdsk->pVol) {
pdsk->d_hdsk = INVALID_HANDLE_VALUE; // prevent UnmountDisk from trying to close the disk
UnmountDisk(pdsk, FALSE);
pdsk = NULL;
}
if (pdsk)
RefreshPartitionInfo(pdsk);
LeaveCriticalSection(&csFATFS);
DEBUGFREE(di.di_bytes_per_sect);
VERIFYNULL(LocalFree((HLOCAL)pbSector));
return pdsk;
}
/* UnmountDisk - Unmount all volumes on specified disk
*
* ENTRY
* pdsk -> DSK structure
* fFrozen == TRUE to unmount frozen volumes only;
* this is used when we're notified that all file system devices
* are ON, so we no longer want to retain frozen volumes that no
* longer have any open files or dirty data.
*
* EXIT
* TRUE if all volumes on disk were unmounted, FALSE if not; if all
* VOLUMEs are automatically freed, then the DSK is freed as well.
*/
BOOL UnmountDisk(PDSK pdsk, BOOL fFrozen)
{
PVOLUME pvol=pdsk->pVol;
BOOL fSuccess = TRUE;
DEBUGMSGW(ZONE_INIT,(DBGTEXTW("FATFS!UnmountDisk: unmounting %s volumes on disk %s\n"), fFrozen? TEXTW("frozen") : TEXTW("all"), pdsk->d_wsName));
EnterCriticalSection(&csFATFS);
if (pvol) {
ASSERT(pvol->v_pdsk == pdsk);
fSuccess = UnmountVolume(pvol, fFrozen);
}
// If we're going to free the DSK structure, or the disk
// is going away anyway, then close the disk handle as well.
if (fSuccess || !fFrozen) {
if (pdsk->d_hdsk != INVALID_HANDLE_VALUE) {
DEBUGFREE(DEBUGALLOC_HANDLE);
CloseHandle(pdsk->d_hdsk);
pdsk->d_hdsk = INVALID_HANDLE_VALUE;
}
pdsk->d_flags |= DSKF_FROZEN;
pdsk->d_flags &= ~(DSKF_REMOUNTED | DSKF_RECYCLED);
}
if (fSuccess) {
FreePartitionInfo(&pdsk->d_dlPartitions);
RemoveItem((PDLINK)&pdsk->d_dlOpenDisks);
DEBUGFREE(sizeof(DSK)-sizeof(pdsk->d_wsName) + pdsk->d_cwName*sizeof(pdsk->d_wsName[0]));
VERIFYNULL(LocalFree((HLOCAL)pdsk));
}
LeaveCriticalSection(&csFATFS);
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!UnmountDisk returned %d\n"), fSuccess));
return fSuccess;
}
/* UnmountAllDisks - Unmount all disks
*
* ENTRY
* fFrozen == TRUE to unmount frozen volumes only; this is used when
* we are notified that all file system devices are ON, so we no longer
* want to retain frozen volumes that no longer have any open files or
* dirty data.
*
* EXIT
* The number of disk devices actually unmounted.
*/
DWORD UnmountAllDisks(BOOL fFrozen)
{
DWORD cDisks = 0;
if (dlDisks.pdskNext != (PDSK)&dlDisks) {
PDSK pdsk;
EnterCriticalSection(&csFATFS);
pdsk = dlDisks.pdskNext;
while (pdsk != (PDSK)&dlDisks) {
if (UnmountDisk(pdsk, fFrozen)) {
cDisks++;
// Since UnmountDisk was successful, the DSK was
// removed from the list and freed, so start at the top
// of the list again.
pdsk = dlDisks.pdskNext;
continue;
}
pdsk = pdsk->d_dlOpenDisks.pdskNext;
}
LeaveCriticalSection(&csFATFS);
}
return cDisks;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -