📄 disk.c
字号:
dwError = Sg.sr_status;
error:
DEBUGMSGW(ZONE_ERRORS && dwError,(DBGTEXTW("FATFS!ReadWriteDisk(%s, sector %d) failed (%d)\n"), cmd == DISK_IOCTL_READ? TEXTW("READ") : TEXTW("WRITE"), sector, dwError));
// If the I/O was successful, or we got an unrecoverable error like
// ERROR_NOT_READY (driver has disabled itself) or ERROR_BAD_UNIT (card
// has been removed), or we've retried enough already, then get out.
if (dwError == ERROR_SUCCESS ||
dwError == ERROR_NOT_READY ||
dwError == ERROR_BAD_UNIT ||
cRetry-- == 0)
break;
DEBUGMSG(ZONE_DISKIO || ZONE_ERRORS,(DBGTEXT("FATFS!ReadWriteDisk: retrying...\n")));
} while (TRUE);
if (dwError) {
// To be safe, any disk I/O error will set VOLF_UNCERTAIN. This will
// prevent us from making unsafe assumptions later (like whether the disk
// is formatted or not). VOLF_UNCERTAIN is cleared every time a volume
// is created or remounted/recycled (in OpenVolume).
if (pvol)
pvol->v_flags |= VOLF_UNCERTAIN;
}
#ifdef DEBUG
else if (cmd == DISK_IOCTL_READ && ZONE_READVERIFY && pvol) {
PBYTE pbTmp;
ALLOCA(pbTmp, pdi->di_bytes_per_sect+2);
if (pbTmp) {
while (cSectors--) {
DEBUGMSG(ZONE_DISKIO,(DBGTEXT("FATFS!ReadWriteDisk: verifying read from sector %d\n"), Sg.sr_start));
memset(pbTmp, 'J', pdi->di_bytes_per_sect+2);
Sg.sr_num_sec = 1;
Sg.sr_sglist[0].sb_len = pdi->di_bytes_per_sect;
Sg.sr_sglist[0].sb_buf = pbTmp+1;
if (FSDMGR_DiskIoControl((HDSK)hdsk,
(pdi->di_flags & DISK_INFO_FLAGS_FATFS_NEW_IOCTLS) ? IOCTL_DISK_READ : DISK_IOCTL_READ,
&Sg, sizeof(Sg),
NULL, 0, &k, NULL) == FALSE) {
dwError = GetLastError();
DEBUGMSG(ZONE_DISKIO || ZONE_ERRORS,(DBGTEXT("FATFS!ReadWriteDisk(READ, sector %d) failed (%d)\n"), Sg.sr_start, dwError));
}
else {
if (memcmp(pvBuffer, pbTmp+1, pdi->di_bytes_per_sect) != 0) {
dwError = ERROR_GEN_FAILURE;
DEBUGMSGW(ZONE_DISKIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ReadWriteDisk(VERIFY, sector %d) failed\n"), Sg.sr_start));
}
if (pbTmp[0] != 'J' || pbTmp[pdi->di_bytes_per_sect+1] != 'J') {
dwError = ERROR_GEN_FAILURE;
DEBUGMSGW(ZONE_DISKIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ReadWriteDisk(BOUNDSCHECK, sector %d) failed\n"), Sg.sr_start));
}
}
Sg.sr_start++;
(PBYTE)pvBuffer += pdi->di_bytes_per_sect;
}
}
}
#endif
else if (cmd == DISK_IOCTL_WRITE) {
#ifdef DEBUG
creqWrite++; // keep track of total write requests and sectors written
csecWrite += cSectors;
#endif
// If the operation was successful, and it was a WRITE, then set the
// modified flag in the associated VOLUME structure (if there is one). We
// use this flag to avoid a full unmount/remount cycle after a scan or format
// if no changes were actually made.
if (pvol) {
pvol->v_flags |= VOLF_MODIFIED;
// Also on writes, if we still have outstanding reads-after-writes to do, do them now;
// note that we only support this feature on non-simulated volumes.
if ((pvol->v_bVerifyCount || ZONE_WRITEVERIFY) && !(pdi->di_flags & DISK_INFO_FLAGS_FATFS_SIMULATED)) {
PBYTE pbTmp;
ALLOCA(pbTmp, pdi->di_bytes_per_sect);
if (pbTmp) {
cRetry = 1; while (cSectors--) {
reverify:
DEBUGMSG(pvol->v_bVerifyCount || ZONE_DISKIO,(DBGTEXT("FATFS!ReadWriteDisk: verifying write to sector %d\n"), Sg.sr_start));
memset(pbTmp, 'J', pdi->di_bytes_per_sect);
Sg.sr_num_sec = 1;
Sg.sr_sglist[0].sb_len = pdi->di_bytes_per_sect;
Sg.sr_sglist[0].sb_buf = pbTmp;
if (FSDMGR_DiskIoControl((HDSK)hdsk,
(pdi->di_flags & DISK_INFO_FLAGS_FATFS_NEW_IOCTLS) ? IOCTL_DISK_READ : DISK_IOCTL_READ,
&Sg, sizeof(Sg),
NULL, 0, &k, NULL) == FALSE) {
dwError = GetLastError();
DEBUGMSG(pvol->v_bVerifyCount || ZONE_DISKIO || ZONE_ERRORS,(DBGTEXT("FATFS!ReadWriteDisk(READ, sector %d) failed (%d)\n"), Sg.sr_start, dwError));
}
else {
if (memcmp(pvBuffer, pbTmp, pdi->di_bytes_per_sect) != 0) {
dwError = ERROR_GEN_FAILURE;
DEBUGMSGW(pvol->v_bVerifyCount || ZONE_DISKIO || ZONE_ERRORS,(DBGTEXTW("FATFS!ReadWriteDisk(VERIFY, sector %d) failed\n"), Sg.sr_start));
}
}
if (dwError) {
FATUIDATA fui;
DWORD dwVolFlags;
// Setting some bit (like VOLF_LOCKED) that will prevent most
// any other call from entering FATFS while the following dialog is
// active is very important, because this thread is temporarily
// leaving our control, so it could re-enter FATFS and screw up the
// state of any streams we've currently got locked (since critical
// sections only protect our state from *other* threads, not from
// ourselves).
dwVolFlags = pvol->v_flags;
pvol->v_flags |= VOLF_LOCKED;
fui.dwSize = sizeof(fui);
fui.dwFlags = FATUI_YES | FATUI_NO;
fui.idsEvent = IDS_FATUI_WRITEVERIFY_WARNING;
fui.idsEventCaption = IDS_FATUI_WARNING;
fui.cuiParams = 2;
fui.auiParams[0].dwType = UIPARAM_VALUE;
fui.auiParams[0].dwValue = Sg.sr_start;
fui.auiParams[1].dwType = UIPARAM_VALUE;
fui.auiParams[1].dwValue = dwError;
#ifdef FATUI
k = FATUIEvent(hFATFS, pvol->v_pwsHostRoot? pvol->v_pwsHostRoot+1 : NULL, &fui);
#else
k = FATUI_YES;
#endif
pvol->v_flags = (pvol->v_flags & ~VOLF_LOCKED) | (dwVolFlags & VOLF_LOCKED);
if (k == FATUI_YES) {
dwError = ERROR_SUCCESS;
if (cRetry-- == 0)
goto exit; // leave the verify count alone in this case
goto reverify;
}
break; // just report 1 error per multi-sector write
}
Sg.sr_start++;
(PBYTE)pvBuffer += pdi->di_bytes_per_sect;
}
}
// As long as there were no verify errors, go ahead and reduce the verify count
if (!dwError && pvol->v_bVerifyCount > 0 && pvol->v_bVerifyCount < 255)
pvol->v_bVerifyCount--;
}
}
}
exit:
DEBUGMSG(ZONE_DISKIO,(DBGTEXT("FATFS!ReadWriteDisk returned 0x%x\n"), dwError));
return dwError;
}
/* NamePartitionInfo - Assign a name to a PARTINFO structure
*
* ENTRY
* ppi -> PARTINFO structure
* pwsName -> name to be assigned
*
* EXIT
* ERROR_SUCCESS if successful, or a non-zero error code
*/
DWORD NamePartitionInfo(PPARTINFO ppi, PWSTR pwsName)
{
if (ppi->pi_pwsName) {
DEBUGFREE((wcslen(ppi->pi_pwsName) + 1) * sizeof(WCHAR));
LocalFree(ppi->pi_pwsName);
ppi->pi_pwsName = NULL;
}
if (pwsName && *pwsName) {
int cbName = (wcslen(pwsName) + 1) * sizeof(WCHAR);
if (cbName > MAXVOLUMENAME * sizeof(WCHAR))
return ERROR_INVALID_PARAMETER;
ppi->pi_pwsName = (PWSTR)LocalAlloc(LPTR, cbName);
if (!ppi->pi_pwsName)
return ERROR_NOT_ENOUGH_MEMORY;
DEBUGALLOC(cbName);
memcpy(ppi->pi_pwsName, pwsName, cbName);
}
return ERROR_SUCCESS;
}
/* InsertPartitionInfo - Insert a PARTINFO structure into the specified list, in sector order
*
* ENTRY
* pdlPartInfo -> doubly-linked PARTINFO list
* ppiNew -> PARTINFO structure
*
* EXIT
* None
*/
void InsertPartitionInfo(PPI_DLINK pdlPartInfo, PPARTINFO ppiNew)
{
PPI_DLINK pdlPrev = pdlPartInfo;
PPARTINFO ppi = pdlPartInfo->ppiNext;
while (ppi != (PPARTINFO)pdlPartInfo) {
if (ppiNew->pi_secAbsolute < ppi->pi_secAbsolute) {
ASSERT(ppiNew->pi_secAbsolute + ppiNew->pi_PartEntry.Part_TotalSectors <= ppi->pi_secAbsolute);
break;
}
ASSERT(ppi->pi_secAbsolute + ppi->pi_PartEntry.Part_TotalSectors <= ppiNew->pi_secAbsolute);
pdlPrev = &ppi->pi_dlPartitions;
ppi = ppi->pi_dlPartitions.ppiNext;
}
AddItem((PDLINK)pdlPrev, (PDLINK)&ppiNew->pi_dlPartitions);
}
/* FindPartitionInfo - Allocate a PARTINFO structure and link it to a DSK structure
*
* ENTRY
* pdlPartInfo -> doubly-linked PARTINFO list
* secPartition == first sector of partition
* ppiParent -> parent PARTINFO structure, NULL if no parent
*
* EXIT
* Pointer to a PARTINFO structure, NULL if not found
*/
PPI FindPartitionInfo(PPI_DLINK pdlPartInfo, DWORD secPartition, PPARTINFO ppiParent)
{
PPARTINFO ppi, ppiChild;
ppi = pdlPartInfo->ppiNext;
while (ppi != (PPARTINFO)pdlPartInfo) {
if ((PDLINK)&ppi->pi_dlChildren != (PDLINK)ppi->pi_dlChildren.ppiNext) {
if (ppiChild = FindPartitionInfo(&ppi->pi_dlChildren, secPartition, ppiParent))
return ppiChild;
}
if (ppi->pi_secAbsolute == secPartition && ppi->pi_ppiParent == ppiParent)
return ppi;
ppi = ppi->pi_dlPartitions.ppiNext;
}
return NULL;
}
/* AllocPartitionInfo - Allocate a PARTINFO structure and link it to a DSK structure
*
* ENTRY
* pdsk -> DSK structure
* secPartTable == sector of partition table
* idxPartTable == index of partition table entry in partition table
* ppe -> partition table entry
* secPartition == first sector of partition
* ppiParent -> parent PARTINFO structure, NULL if no parent
* pbSector -> contents of first sector of partition, NULL if not provided
*
* EXIT
* Pointer to a PARTINFO structure
*/
PPI AllocPartitionInfo(PDSK pdsk, DWORD secPartTable, int idxPartTable, PPARTENTRY ppe, DWORD secPartition, PPARTINFO ppiParent, PBYTE pbSector)
{
PPARTINFO ppi;
PWSTR pwsName = NULL;
// See if info on this partition already exists...
if (ppi = FindPartitionInfo(&pdsk->d_dlPartitions, secPartition, ppiParent)) {
ASSERT(ppi->pi_secPartTable == secPartTable &&
ppi->pi_idxPartTable == (WORD)idxPartTable &&
ppi->pi_PartEntry.Part_TotalSectors == ppe->Part_TotalSectors);
return ppi;
}
// If this partition has a name associated with it, that name will be located
// at OFFSETVOLUMENAME in pbSector, will begin with a non-NULL character, will be padded
// with NULLs, and will be preceded by BOOTSECVOLUMESIG at offset OFFSETVOLUMESIG.
if (pbSector &&
*(PDWORD)(pbSector+OFFSETVOLUMESIG) == BOOTSECVOLUMESIG &&
*(PDWORD)(pbSector+OFFSETVOLUMENAME) != 0 && *(PDWORD)(pbSector+OFFSETTRLSIG-4) == 0) {
pwsName = (PWCHAR)(pbSector+OFFSETVOLUMENAME);
}
ppi = (PPARTINFO)LocalAlloc(LPTR, sizeof(PARTINFO));
if (!ppi)
DEBUGMSG(ZONE_INIT || ZONE_ERRORS,(DBGTEXT("FATFS!AllocPartitionInfo: out of memory!\n")));
else {
DEBUGALLOC(sizeof(PARTINFO));
InitList((PDLINK)&ppi->pi_dlChildren);
ppi->pi_dwSig = BOOTSECVOLUMESIG;
ppi->pi_pdsk = pdsk;
ppi->pi_secPartTable = secPartTable;
ppi->pi_idxPartTable = (WORD)idxPartTable;
ppi->pi_PartEntry = *ppe;
ppi->pi_secAbsolute = secPartition;
NamePartitionInfo(ppi, pwsName);
if (!ppiParent) {
InsertPartitionInfo(&pdsk->d_dlPartitions, ppi);
}
else {
InsertPartitionInfo(&ppiParent->pi_dlChildren, ppi);
ppi->pi_ppiParent = ppiParent;
}
}
DEBUGMSG(ZONE_DISKIO,(DBGTEXT("FATFS!AllocPartitionInfo(0x%08x): parent=0x%08x, sectbl=%x, secpart=%x, sectotal=%x\n"), ppi, ppiParent, secPartTable, secPartition, ppe->Part_TotalSectors));
return ppi;
}
/* WalkPartitionInfo
*
* ENTRY
* pdlPartInfo -> doubly-linked PARTINFO list
* secStart == beginning of partitioned range
* csecTotal == size of partitioned range, in sectors
* pps -> PARTSRCH structure
*
* EXIT
* TRUE if desired search criteria satisfied, FALSE if not; in the latter
* case, pps->ps_csecFound must be examined to determine whether or not even
* the minimum criteria could be satisfied.
*/
BOOL WalkPartitionInfo(PPI_DLINK pdlPartInfo, DWORD secStart, DWORD csecTotal, PPARTSRCH pps)
{
DWORD secEnd, csecGap;
PPARTINFO ppi = pdlPartInfo->ppiNext;
// Handle the empty PARTINFO list case here...
if (ppi == (PPARTINFO)pdlPartInfo) {
if (csecTotal >= pps->ps_csecDesired ||
csecTotal >= pps->ps_csecMinimum && csecTotal > pps->ps_csecFound) {
pps->ps_pdlFound = pdlPartInfo;
pps->ps_ppiFound = NULL;
pps->ps_csecFound = csecTotal;
}
pps->ps_csecTotalFound += csecTotal;
return (csecTotal >= pps->ps_csecDesired);
}
// Handle the non-empty PARTINFO list case here...
secEnd = secStart + csecTotal;
while (ppi != (PPARTINFO)pdlPartInfo) {
if ((PDLINK)&ppi->pi_dlChildren != (PDLINK)ppi->pi_dlChildren.ppiNext) {
if (WalkPartitionInfo(&ppi->pi_dlChildren, ppi->pi_secAbsolute, ppi->pi_PartEntry.Part_TotalSectors, pps))
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -