📄 volume.cpp
字号:
pgpAssert(Mounted());
pgpAssert(!AttachedToLocalVolume());
hasOpenFiles = lockedDown = FALSE;
if (!isThisEmergency)
{
// Check for open files.
derr = Driver->HasOpenFiles(mDrive, &hasOpenFiles);
if (derr.IsntError())
{
if (hasOpenFiles)
derr = DualErr(kPGDMinorError_FilesOpenOnDrive);
}
if (derr.IsntError())
{
// Flush the volume.
VolFlush(mDrive, NULL);
// Get a lock on the drive.
oldLock = Driver->GetLockLevel(mDrive);
derr = Driver->AcquireLogicalVolLock(mDrive, kLock_L3);
lockedDown = derr.IsntError();
}
}
if (derr.IsntError())
{
// Some people tell me this should be done to prevent hangs. (?)
NotifyVolumeRemoval(GetDrive());
// We make a system call to disassociate the mounted DCB with its
// drive letter, thereby unmounting the volume.
if (!IspDisassociateDcb(GetDrive()))
derr = DualErr(kPGDMinorError_IspDisassocDcbFailed);
}
if (derr.IsntError())
{
CleanUpMountedVars();
}
if (derr.IsError())
{
if (lockedDown)
Driver->AcquireLogicalVolLock(mDrive, oldLock);
}
return derr;
}
// LockVolumeForReadWrite locks the mounted volume for direct read/write
// access.
DualErr
Volume::LockVolumeForReadWrite()
{
DualErr derr;
pgpAssert(Mounted());
pgpAssert(!LockedForReadWrite() && !LockedForFormat());
derr = Driver->AcquireLogicalVolLock(mDrive, kLock_L3);
if (derr.IsntError())
{
mLockState = kLock_ReadWrite;
}
return derr;
}
// LockVolumeForFormat locks the mounted volume for formatting.
DualErr
Volume::LockVolumeForFormat()
{
DualErr derr;
pgpAssert(Mounted());
pgpAssert(!LockedForReadWrite() && !LockedForFormat());
derr = Driver->GetFormatLockOnDrive(mDrive);
if (derr.IsntError())
{
mLockState = kLock_Format;
}
return derr;
}
// UnlockVolume removes any outstanding locks on the volume;
DualErr
Volume::UnlockVolume()
{
DualErr derr;
pgpAssert(Mounted());
pgpAssert(LockedForReadWrite() || LockedForFormat());
if (LockedForReadWrite())
derr = Driver->AcquireLogicalVolLock(mDrive, ::kLock_None);
else
derr = Driver->ReleaseFormatLockOnDrive(mDrive);
if (derr.IsntError())
{
mLockState = kLock_None;
}
return derr;
}
// Read reads 'nBlocks' sectors from the logical mounted volume from sector
// position 'pos'.
DualErr
Volume::Read(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBlocks,
GenericCallbackInfo *upInfo)
{
pgpAssertAddrValid(buf, PGPUInt8);
return DiskAccess(IOR_READ, buf, pos, nBlocks, upInfo);
}
// Write reads 'nBlocks' sectors from the logical mounted volume from sector
// position 'pos'.
DualErr
Volume::Write(
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBlocks,
GenericCallbackInfo *upInfo)
{
pgpAssertAddrValid(buf, PGPUInt8);
return DiskAccess(IOR_WRITE, buf, pos, nBlocks, upInfo);
}
////////////////////////////////////////
// Class Volume private member functions
////////////////////////////////////////
// InitMountedVars initializes some variables that describe a mounted volume
// and/or can be used to perform I/O on that volume.
DualErr
Volume::InitMountedVars(PGPUInt8 drive, PDCB pDcb)
{
DualErr derr;
pgpAssert(IsLegalDriveNumber(drive));
pgpAssert(Unmounted());
pgpAssertAddrValid(pDcb, DCB);
// Allocate a buffer for bootblock and devparam requests.
if (derr.IsntError())
{
derr = GetByteBuffer(ExtractBlockSize(pDcb), (PGPUInt8 **) &mBBlock);
}
if (derr.IsntError())
{
mMountState = kVol_Mounted;
mDrive = drive;
mPDcb = pDcb;
}
return derr;
}
// CleanUpMountedVars cleans up those variables we initialized in
// InitMountedVars.
void
Volume::CleanUpMountedVars()
{
pgpAssert(Mounted());
pgpAssertAddrValid(mBBlock, PGPUInt8);
mMountState = kVol_Unmounted;
FreeByteBuffer(mBBlock);
mDrive = kInvalidDrive;
mBBlock = NULL;
mPDcb = NULL;
}
// DiskAccess performs either an IOR_READ or an IOR_WRITE operation on the
// mounted volume.
DualErr
Volume::DiskAccess(
PGPUInt16 func,
PGPUInt8 *buf,
PGPUInt64 pos,
PGPUInt32 nBlocks,
GenericCallbackInfo *upInfo)
{
DualErr derr;
PIOP pIop;
PIOR pIor;
PGPBoolean useAsync;
PGPUInt16 offset, size;
PVRP pVrp;
pgpAssertAddrValid(buf, PGPUInt8);
pgpAssert((func == IOR_READ) || (func == IOR_WRITE));
// Is this request asynchronous?
useAsync = IsntNull(upInfo);
pgpAssert(Mounted());
pgpAssertAddrValid(mPDcb, DCB);
pgpAssert(!mVolumeReq.isInUse);
// Prepare the request.
mVolumeReq.isInUse = TRUE;
if (useAsync)
{
mVolumeReq.upInfo = upInfo;
mVolumeReq.downInfo.refData[0] = (PGPUInt32) this;
}
// Make sure we check that the VRP field in the DCB exists; the system
// has a habit of nullifying it when an I/O error occurs.
if (!(pVrp = (PVRP) mPDcb->DCB_cmn.DCB_vrp_ptr))
derr = DualErr(kPGDMinorError_InvalidVRP);
// Create our IOP/IOR.
if (derr.IsntError())
{
size = (PGPUInt16) pVrp->VRP_max_req_size +
pVrp->VRP_max_sgd*sizeof(SGD);
offset = (PGPUInt16) pVrp->VRP_delta_to_ior;
pIop = IspCreateIop(size, offset, ISP_M_FL_INTERRUPT_TIME);
if (!pIop)
derr = DualErr(kPGDMinorError_IorAllocationFailed);
}
// Now we fill in the fields of our IOR structure prior to sending the
// I/O request to the IOS subsystem.
if (derr.IsntError())
{
pIor = &pIop->IOP_ior;
pIop->IOP_timer_orig = pIop->IOP_timer = kDefaultIopTimeOut;
mVolumeReq.pIor = pIor;
pIor->IOR_next = NULL; // must be NULL
pIor->IOR_func = func; // IOR_READ or IOR_WRITE
pIor->IOR_status = 0; // result code goes here
pIor->IOR_flags = IORF_VERSION_002 // means we are using IOR
| IORF_HIGH_PRIORITY // high priority
| IORF_LOGICAL_START_SECTOR // in partition
| IORF_DOUBLE_BUFFER; // copy buffer
// We have to set the start address, transfer count, and buffer fields
// with the passed information.
pIor->IOR_start_addr[0] = GetLowDWord(pos); // low sector
pIor->IOR_start_addr[1] = GetHighDWord(pos); // high sector
pIor->IOR_xfer_count = nBlocks; // # secs
pIor->IOR_buffer_ptr = (PGPUInt32) buf; // buffer
pIor->IOR_private_client = kPGPdiskIopMagic; // comes from us
pIor->IOR_req_vol_handle = (PGPUInt32) pVrp; // vrp pointer
pIor->IOR_sgd_lin_phys = (PGPUInt32) (pIor + 1); // SGDs here
pIor->IOR_num_sgds = 0; // system fills in
pIor->IOR_vol_designtr = GetDrive();
// Initialize the callback info.
if (useAsync)
{
pIor->IOR_callback = (CMDCPLT) VolumeCallback;
pIor->IOR_req_req_handle = (PGPUInt32) &mVolumeReq.downInfo;
}
else
{
pIor->IOR_flags |= IORF_SYNC_COMMAND;
pIor->IOR_callback = NULL;
}
// The IlbIoCriteria routine must be run on the IOR in order to let
// the system massage some of the fields in the IOR into a form that
// it likes.
if (!IlbIoCriteria(pIor))
DebugOut("PGPdisk: IlbIoCriteria in DiskAccess failed");
DebugOut(
"PGPdisk: Vol Access IOR %X func %u pos %u nBlocks %u drive %u",
pIor, func, (PGPUInt32) pos, nBlocks, GetDrive());
// Send the request to the IOS for processing synchronously.
__asm push edi
IOS_SendCommand(pIor, mPDcb);
__asm pop edi
DebugOut("PGPdisk: Exiting Vol Access IOR %X", pIor);
}
// If we are sync and called down the IOP we need to cleanup now
// since there is no callback.
if (derr.IsntError())
{
if (!useAsync)
{
derr = CleanUpRequest(); // extract derr from IOR
mVolumeReq.isInUse = FALSE;
}
}
// If an error calling down the IOP, we need to callback if we were
// called async.
if (derr.IsError())
{
if (useAsync)
{
CleanUpRequest();
ScheduleAsyncCallback(derr);
}
}
return derr;
}
// CleanUpRequest performs housekeeping after a request has been completed.
DualErr
Volume::CleanUpRequest()
{
DualErr derr;
PIOR pIor;
pgpAssert(mVolumeReq.isInUse);
pIor = mVolumeReq.pIor;
// Convert possible error value to Windows standard.
if (pIor->IOR_status >= IORS_ERROR_DESIGNTR)
{
if (pIor->IOR_func == IOR_READ)
{
derr = DualErr(kPGDMinorError_IorReadFailure,
IOSMapIORSToI21(pIor->IOR_status));
}
else
{
derr = DualErr(kPGDMinorError_IorWriteFailure,
IOSMapIORSToI21(pIor->IOR_status));
}
}
// De-allocate the IOR if one was allocated.
if (pIor)
{
PGPUInt16 offset;
PVRP pVrp;
pVrp = (PVRP) mPDcb->DCB_cmn.DCB_vrp_ptr;
// Hopefully our volume didn't go away.
if (pVrp)
{
pgpAssertAddrValid(pVrp, VRP);
offset = (PGPUInt16) pVrp->VRP_delta_to_ior;
IspDeallocMem((PGPUInt8 *) pIor - offset);
}
}
return derr;
}
// VolumeCallback is called by the system after it has finished processing
// the IOP we gave it. We extract the address of the Volume object in question
// and pass the callback to it.
void
Volume::VolumeCallback(GenericCallbackInfo *downInfo)
{
Volume *pVol;
pgpAssertAddrValid(downInfo, GenericCallbackInfo);
pVol = (Volume *) downInfo->refData[0];
pgpAssertAddrValid(pVol, Volume);
pVol->VolumeCallbackAux();
}
// VolumeCallbackAux is called by the static callback function
// 'VolumeCallback' so we don't have to type 'pVol' before every reference to
// an object member or method. (Not needed here but coded so we are parallel
// to higher classes such as FatParser and PGPdisk in this regard.)
void
Volume::VolumeCallbackAux()
{
DualErr derr;
pgpAssert(mVolumeReq.isInUse);
// Cleanup.
derr = CleanUpRequest();
// Call up.
ScheduleAsyncCallback(derr);
}
// ScheduleAsyncCallback schedules a windows event that calls our function
// that will call the asynchronous request up.
void
Volume::ScheduleAsyncCallback(DualErr derr)
{
static RestrictedEvent_THUNK callbackThunk;
pgpAssertAddrValid(mVolumeReq.upInfo, GenericCallbackInfo);
mVolumeReq.upInfo->derr = derr;
Call_Restricted_Event(0, NULL, PEF_ALWAYS_SCHED, (PVOID) this,
AsyncExecuteCallback, 0, &callbackThunk);
}
// AsyncExecuteCallback was scheduled by 'ScheduleAsyncCallback' for the
// purpose of calling back up the asynchronous request we received.
VOID __stdcall
Volume::AsyncExecuteCallback(
VMHANDLE hVM,
THREADHANDLE hThread,
PVOID Refdata,
PCLIENT_STRUCT pRegs)
{
Volume *pVol;
pVol = (Volume *) Refdata;
pgpAssertAddrValid(pVol, Volume);
pgpAssert(pVol->mVolumeReq.isInUse);
pVol->mVolumeReq.isInUse = FALSE;
pgpAssertAddrValid(pVol->mVolumeReq.upInfo, GenericCallbackInfo);
pVol->mVolumeReq.upInfo->callback(pVol->mVolumeReq.upInfo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -