cvolumeimpdrv98.cpp

来自「PGP8.0源码 请认真阅读您的文件包然后写出其具体功能」· C++ 代码 · 共 874 行 · 第 1/2 页

CPP
874
字号
			PGPUInt8	locksUp 	= 0;
			PGPUInt8	locksDown	= 0;

			if (curLock != lockLevel)
			{
				switch (curLock)
				{
				case LockLevel1:
					switch (lockLevel)
					{
					case LockLevelNone:
						locksDown = 1;
						break;
					case LockLevel2:
						locksUp = 1;
						break;
					case LockLevel3:
						locksUp = 2;
						break;
					default:
						pgpAssert(FALSE);
						break;
					}
					break;

				case LockLevel2:
					switch (lockLevel)
					{
					case LockLevelNone:
						locksDown = 2;
						break;
					case LockLevel1:
						locksDown = 1;
						break;
					case LockLevel3:
						locksUp = 1;
						break;
					default:
						pgpAssert(FALSE);
						break;
					}
					break;

				case LockLevel3:
					switch (lockLevel)
					{
					case LockLevelNone:
						locksDown = 3;
						break;
					case LockLevel1:
						locksDown = 2;
						break;
					case LockLevel2:
						locksDown = 1;
						break;
					default:
						pgpAssert(FALSE);
						break;
					}
					break;

				default:
					pgpAssert(FALSE);
					break;
				}
			}

			// If we need to get locks, we do that here.
			while (error.IsntError() && (locksUp != 0))
			{
				PGPUInt16	lockValue;

				locksUp--;

				if (curLock == LockLevel1)
				{
					curLock = LockLevel2;
					lockValue = 2;
				}
				else
				{
					curLock = LockLevel3;
					lockValue = 3;
				}

				regs.eax	= 0x440D;		// function 440D
				regs.ebx	= (lockValue << 8) + drive + 1; // get lock
				regs.ecx	= 0x084A;		// code 4A (Lock Volume)
				regs.edx	= 0;			// > L1s expect zero here
				regs.flags	= 0x0001;		// carry set if error

				Exec_VxD_Int(0x21, &regs);

				if (regs.flags & 0x0001)
				{
					error.pgpErr = kPGPError_VolumeOpFailed;
					error.err = regs.eax;
				}
			}

			// If we need to release locks, we do that here.
			while (error.IsntError() && (locksDown !=0))
			{
				locksDown--;

				if (curLock == LockLevel3)
					curLock = LockLevel2;
				else if (curLock == LockLevel2)
					curLock = LockLevel1;
				else if (curLock == LockLevel1)
					curLock = LockLevelNone;

				regs.eax	= 0x440D;		// function 440D
				regs.ebx	= drive + 1;	// decrement lock level
				regs.ecx	= 0x086A;		// code 6A (Unlock Volume)
				regs.flags	= 0x0001;		// carry set if error

				Exec_VxD_Int(0x21, &regs);

				if (regs.flags & 0x0001)
				{
					error.pgpErr = kPGPError_VolumeOpFailed;
					error.err = regs.eax;
				}
			}
		}
	}

	UDebug::DebugOut("PGPdisk: Lock on drive %u is now %d", drive, lockLevel);

	return error;
}

CComboError
CVolumeImpDrv98::AcquireFormatLock()
{
	pgpAssert(IsMounted());

	CComboError	error;

	// Make sure we aren't already locked;
	LockLevel	lockLevel;
	error = GetLockLevel(lockLevel);

	if (error.IsntError())
	{
		if (lockLevel != LockLevelNone)
			error.pgpErr = kPGPError_VolumeOpFailed;
	}

	// First get a 'normal' level-0 lock.
	if (error.IsntError())
	{
		PGPUInt8	drive		= UString::LetterToNumber(mRoot[0]);
		PGPUInt32	locksTaken	= 0;
		VxdIntRegs	regs;

		regs.eax	= 0x440D;				// function 440D
		regs.ebx	= 0x0000 + drive + 1;	// L0 lock
		regs.ecx	= 0x084A;				// (Lock Volume)
		regs.edx	= 0;					// must be 0
		regs.flags	= 0x0001;				// carry set if error

		Exec_VxD_Int(0x21, &regs);

		if (regs.flags & 0x0001)
		{
			error.pgpErr = kPGPError_VolumeOpFailed;
			error.err = regs.eax;
		}
		else
		{
			locksTaken++;
		}

		// Now get a 'more restrictive' level-0 lock.
		if (error.IsntError())
		{
			regs.eax	= 0x440D;				// function 440D
			regs.ebx	= 0x0000 + drive + 1;	// L0 lock
			regs.ecx	= 0x084A;				// (Lock Volume)
			regs.edx	= 4;					// must be 4
			regs.flags	= 0x0001;				// carry set if error

			Exec_VxD_Int(0x21, &regs);

			if (regs.flags & 0x0001)
			{
				error.pgpErr = kPGPError_VolumeOpFailed;
				error.err = regs.eax;
			}
			else
			{
				locksTaken++;
			}
		}

		// Undo what we did on error.
		if (error.IsError())
		{
			while (locksTaken-- > 0)
			{
				regs.eax	= 0x440D;		// function 440D
				regs.ebx	= drive + 1;	// decrement lock level
				regs.ecx	= 0x086A;		// code 6A (Unlock Volume)
				regs.flags	= 0x0001;		// carry flag set on error

				Exec_VxD_Int(0x21, &regs);
			}
		}
	}

	return error;
}

CComboError
CVolumeImpDrv98::ReleaseFormatLock()
{
	pgpAssert(IsLockedForFormat());

	CComboError	error;

	// Make sure we aren't already locked;
	LockLevel	lockLevel;
	error = GetLockLevel(lockLevel);

	if (error.IsntError())
	{
		if (lockLevel != LockLevel0MR)
			error.pgpErr = kPGPError_VolumeOpFailed;
	}

	// Release locks.
	PGPUInt8	drive		= UString::LetterToNumber(mRoot[0]);
	PGPUInt32	locksTaken	= 2;

	while (error.IsntError() && (locksTaken-- > 0))
	{
		VxdIntRegs	regs;

		regs.eax	= 0x440D;		// function 440D
		regs.ebx	= drive + 1;	// decrement lock level
		regs.ecx	= 0x086A;		// code 6A (Unlock Volume)
		regs.flags	= 0x0001;		// carry flag set on error

		Exec_VxD_Int(0x21, &regs);

		if (regs.flags & 0x0001)
		{
			error.pgpErr = kPGPError_VolumeOpFailed;
			error.err = regs.eax;
		}
	}

	return error;
}

CComboError
CVolumeImpDrv98::FillInBlockInfo()
{
	CComboError	error;

	if (error.IsntError())
	{
		mBlockSize = static_cast<PGPUInt32>(mDcb.CalcBlockSizeFromShift());
		mTotalBlocks = mDcb.SectorCount();
	}

	return error;
}

void
CVolumeImpDrv98::InitDcb(
	PGPUInt8	drive,
	PGPUInt64	totalBlocks,
	PGPUInt32	blockSize,
	PGPBoolean	readOnly)
{
	PGPUInt32	secsPerTrack, tracksPerCyl;
	PGPUInt64	cylinders;

	UFileSys::CalcFakeFatGeom(blockSize, tracksPerCyl, cylinders,
		secsPerTrack);

	mDcb.PhysicalDcb()	= static_cast<PDCB>(mDcb);
	mDcb.Drive()		= drive;
	mDcb.TsdFlags()		= DCB_TSD_NO_USER_INT13 | DCB_TSD_BAD_MBR;
	mDcb.DeviceFlags()	= DCB_DEV_LOGICAL;

	mDcb.BlockShift()		= UMath::SimpleLog2(blockSize);
	mDcb.PartitionType()	= FileSys::kBigFat16PartId;
	mDcb.DeviceType()		= DCB_type_disk;
	mDcb.UserDrive()		= 0xffff;

	mDcb.MaxTransferLength()	= FileSys::kMaxHeads*FileSys::kMaxSpt*
		FileSys::kMaxCyls;
	mDcb.SectorCount()			= totalBlocks;
	mDcb.BlockSize()			= blockSize;
	mDcb.Heads()				= tracksPerCyl;
	mDcb.Cylinders()			= static_cast<PGPUInt32>(cylinders);
	mDcb.Spt()					= secsPerTrack;

	mDcb.PortSpecific()		= reinterpret_cast<PGPUInt32>(this);
	mDcb.BusType()			= DCB_BUS_ESDI;
	mDcb.BddDeviceSubtype()	= BDT_Fixed_Disk;
	mDcb.BddFlags()			= BDF_VERSION_002;

	mDcb.BddSectorCount()	= totalBlocks;
	mDcb.BddBlockSize()		= blockSize;
	mDcb.BddHeads()			= tracksPerCyl;
	mDcb.BddCylinders()		= static_cast<PGPUInt32>(cylinders);
	mDcb.BddSpt()			= secsPerTrack;

	strncpy(mDcb.VendorId(), kDcbVendorId, strlen(kDcbVendorId));
	strncpy(mDcb.ProductId(), kDcbProductId, strlen(kDcbProductId));
	strncpy(mDcb.RevLevel(), kDcbRevLevel, strlen(kDcbRevLevel));

	if (CVolume::kUseRemovableFlag)
	{
		mDcb.DeviceFlags() |= DCB_DEV_REMOVABLE;
		mDcb.BddFlags() |= BDF_Removable;
	}

	if (!readOnly)
	{
		mDcb.DeviceFlags() |= DCB_DEV_WRITEABLE;
		mDcb.BddFlags() |= BDF_Writeable;
	}
}

CComboError
CVolumeImpDrv98::DiskAccess(
	PGPUInt16	func,
	void		*buf,
	PGPUInt64	pos,
	PGPUInt32	nBlocks) const
{
	pgpAssert(IsMounted());
	pgpAssert((func == IOR_READ) || (func == IOR_WRITE));
	pgpAssertAddrValid(buf, VoidAlign);

	CComboError	error;

	// 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.

	PVRP	pVrp	= mDcb.Vrp();

	if (IsNull(pVrp))
		error.pgpErr = kPGPError_VolumeOpFailed;

	if (error.IsntError())
	{
		CIop	iop;

		// Create our IOP/IOR.
		error = iop.Create(pVrp, ISP_M_FL_INTERRUPT_TIME);

		if (error.IsntError())
		{
			// Fill in the IOP/IOR.
			iop.Func()		= func;			// IOR_READ or IOR_WRITE
			iop.Flags()		|= IORF_HIGH_PRIORITY			// high priority
							| IORF_LOGICAL_START_SECTOR		// in partition
							| IORF_SYNC_COMMAND;			// synchronous

			iop.StartAddress()	= pos;
			iop.TransferCount()	= nBlocks;
			iop.Buffer()		= buf;
			iop.ReqVolHandle()	= pVrp;
			iop.Drive()			= UString::LetterToNumber(mRoot[0]);

			// Ask the system to massage the IOP.
			if (!iop.DoIlbCriteria())
			{
				UDebug::DebugOut("PGPdisk: IlbIoCriteria in "
					"CVolumeImpDrv98::DiskAccess failed!");
			}

			UDebug::DebugOut("PGPdisk: Before volume access IOR %X func %u "
				"pos %u nBlocks %u drive %u", &iop.Ior(), func,
				UMath::GetLowDWord(pos), nBlocks,
				UString::LetterToNumber(mRoot[0]));

			// Call down the IOP.
			iop.SendCommand(mDcb);

			UDebug::DebugOut("PGPdisk: After volume access IOR %X",
				&iop.Ior());

			if (iop.IsStatusError())
			{
				if (func == IOR_READ)
				{
					error.pgpErr = kPGPError_ReadFailed;
					error.err = iop.GetErrorAsWin32();
				}
				else
				{
					error.pgpErr = kPGPError_WriteFailed;
					error.err = iop.GetErrorAsWin32();
				}
			}

			iop.Destroy();
		}
	}

	return error;
}

void
CVolumeImpDrv98::DispatchIopAux(CIop& iop)
{
	mDispatchFunc(iop, mRefPtr);
}

void
CVolumeImpDrv98::DispatchIopStub(PIOP pIop)
{
	CIop	iop(pIop);
	CDcb	dcb(reinterpret_cast<PDCB>(iop.OriginalDcb()));

	CVolumeImpDrv98	*pImp	= reinterpret_cast<CVolumeImpDrv98 *>(
		dcb.PortSpecific());

	pgpAssertAddrValid(pImp, CVolumeImpDrv98);
	pImp->DispatchIopAux(iop);
}

void
CVolumeImpDrv98::DispatchIop(PIOP pIop)
{
	// Get around a MSVC5 compiler bug (involving the stack and IOS).
	DispatchIopStub(pIop);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?