windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/migisol/sectorio.c

817 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
sectorio.c
Abstract:
Routines to perform low-level sector I/O on either Windows NT or
Windows 95.
Author:
Ted Miller (tedm) 1 Nov 1996
Revision History:
--*/
#include "pch.h"
#include <tlhelp32.h>
#define ISOSR2() ISATLEASTOSR2()
#define MALLOC(u) (LocalAlloc (GMEM_FIXED, u))
#define FREE(u) (LocalFree (u))
//
// Define structures for use with Win9x VWIN32.
// Note: alignment must be on 1-byte boundaries for these structures.
//
#include <pshpack1.h>
typedef struct _DIOC_REGISTERS {
DWORD reg_EBX;
DWORD reg_EDX;
DWORD reg_ECX;
DWORD reg_EAX;
DWORD reg_EDI;
DWORD reg_ESI;
DWORD reg_Flags;
} DIOC_REGISTERS;
typedef struct _DIOC_DISKIO {
DWORD StartSector;
WORD SectorCount;
LPBYTE Buffer;
} DIOC_DISKIO;
#include <poppack.h>
//
// Define codes we care about for use with VWIN32
//
#define VWIN32_DIOC_DOS_IOCTL 1
#define VWIN32_DIOC_DOS_INT25 2
#define VWIN32_DIOC_DOS_INT26 3
#define VWIN32_DIOC_DOS_DRIVEINFO 6 // new in OSR2
BOOL
ReadOrWriteSectorsWin9xOriginal(
IN HANDLE VWin32Vxd,
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN OUT LPBYTE Buffer,
IN BOOL Write
)
/*++
Routine Description:
Common routine to read or write sectors on a disk under Windows 95
earlier than OSR2. Uses int25/26.
This routine will fail on Windows NT.
Arguments:
VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
Drive - supplies drive letter of device to be read from or written to.
StartSector - supplies logical sector number of first sector to be
read/written.
SectorCount - supplies number of sectors to be read/written.
SectorSize - supplies the number of bytes in a sector on the drive
to be read from/written to.
Buffer - Supplies or receives data, depending on the value or the Write
parameter.
Write - if 0, then this is a read operastion. If non-0, then this is
a write operation.
Return Value:
Boolean value indicating whether the disk was read/written successfully.
--*/
{
DIOC_REGISTERS RegistersIn,RegistersOut;
DIOC_DISKIO Params;
BOOL b;
DWORD SizeOut;
//
// Set up registers and parameter block.
//
RegistersIn.reg_EAX = (DWORD)(_totupper(Drive) - TEXT('A'));
RegistersIn.reg_EBX = (DWORD)&Params;
RegistersIn.reg_ECX = 0xFFFF;
Params.StartSector = StartSector;
Params.SectorCount = (WORD)SectorCount;
Params.Buffer = Buffer;
//
// Do the real work.
//
b = DeviceIoControl(
VWin32Vxd,
Write ? VWIN32_DIOC_DOS_INT26 : VWIN32_DIOC_DOS_INT25,
&RegistersIn,
sizeof(DIOC_REGISTERS),
&RegistersOut,
sizeof(DIOC_REGISTERS),
&SizeOut,
NULL
);
//
// Check carry flag for failure.
//
if(b && (RegistersOut.reg_Flags & 1)) {
b = FALSE;
}
return(b);
}
BOOL
ReadOrWriteSectorsWin9xOsr2(
IN HANDLE VWin32Vxd,
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN OUT LPBYTE Buffer,
IN BOOL Write
)
/*++
Routine Description:
Common routine to read or write sectors on a disk under Windows 95
OSR2 or later. Uses the new int21 function 7305 (Ext_ABSDiskReadWrite).
This routine will fail on Windows NT and earlier versions of Windows 95.
Arguments:
VWin32Vxd - supplies Win32 handle to VWIN32 VxD.
Drive - supplies drive letter of device to be read from or written to.
StartSector - supplies logical sector number of first sector to be
read/written.
SectorCount - supplies number of sectors to be read/written.
SectorSize - supplies the number of bytes in a sector on the drive
to be read from/written to.
Buffer - Supplies or receives data, depending on the value or the Write
parameter.
Write - if 0, then this is a read operastion. If non-0, then this is
a write operation.
Return Value:
Boolean value indicating whether the disk was read/written successfully.
--*/
{
DIOC_REGISTERS RegistersIn,RegistersOut;
DIOC_DISKIO Params;
BOOL b;
DWORD SizeOut;
//
// Set up registers and parameter block.
//
RegistersIn.reg_EAX = 0x7305;
RegistersIn.reg_EBX = (DWORD)&Params;
RegistersIn.reg_ECX = 0xFFFF;
RegistersIn.reg_EDX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
RegistersIn.reg_ESI = Write ? 1 : 0;
Params.StartSector = StartSector;
Params.SectorCount = (WORD)SectorCount;
Params.Buffer = Buffer;
//
// Do the real work.
//
b = DeviceIoControl(
VWin32Vxd,
VWIN32_DIOC_DOS_DRIVEINFO,
&RegistersIn,
sizeof(DIOC_REGISTERS),
&RegistersOut,
sizeof(DIOC_REGISTERS),
&SizeOut,
NULL
);
//
// Check carry flag for failure.
//
if(b && (RegistersOut.reg_Flags & 1)) {
b = FALSE;
SetLastError (ERROR_IO_DEVICE);
}
return(b);
}
BOOL
LockOrUnlockVolumeWin9x(
IN HANDLE VWin32Vxd,
IN TCHAR Drive,
IN UINT Level,
IN BOOL Lock
)
{
DIOC_REGISTERS RegistersIn,RegistersOut;
BOOL b;
DWORD SizeOut;
BOOL Pass;
Pass = 0;
retry:
//
// ax = generic ioctl code
//
RegistersIn.reg_EAX = 0x440d;
//
// bl = 1-based drive number
// bh = lock level
//
RegistersIn.reg_EBX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
RegistersIn.reg_EBX |= (Level << 8);
//
// cl = lock or unlock volume code
// ch = categoey, 8 on original Win95, 0x48 on OSR2
//
RegistersIn.reg_ECX = Lock ? 0x4a : 0x6a;
RegistersIn.reg_ECX |= ((ISOSR2() && !Pass) ? 0x4800 : 0x800);
//
// dx = permissions
//
// bit 0 controls write operations (0 = disallowed)
// bit 1 controls read operations (0 = allowed)
//
RegistersIn.reg_EDX = 1;
//
// Perform the lock and check carry.
//
b = DeviceIoControl(
VWin32Vxd,
VWIN32_DIOC_DOS_IOCTL,
&RegistersIn,
sizeof(DIOC_REGISTERS),
&RegistersOut,
sizeof(DIOC_REGISTERS),
&SizeOut,
NULL
);
if(b && (RegistersOut.reg_Flags & 1)) {
b = FALSE;
}
//
// If OSR2, try form of call with 8 in ch instead of 48.
//
if(!b && ISOSR2() && !Pass) {
Pass = 1;
goto retry;
}
return(b);
}
BOOL
pGetWin9xLockFlagState (
IN HANDLE VWin32Vxd,
IN TCHAR Drive,
OUT PINT LockStatus
)
{
DIOC_REGISTERS RegistersIn,RegistersOut;
BOOL b;
DWORD SizeOut;
*LockStatus = 0;
//
// ax = generic ioctl code
//
RegistersIn.reg_EAX = 0x440D;
//
// bx = 1-based drive number
//
RegistersIn.reg_EBX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
//
// cx = 0x86C (get lock flag state)
//
RegistersIn.reg_ECX = 0x86C;
//
// Perform the lock and check carry.
//
b = DeviceIoControl(
VWin32Vxd,
VWIN32_DIOC_DOS_IOCTL,
&RegistersIn,
sizeof(DIOC_REGISTERS),
&RegistersOut,
sizeof(DIOC_REGISTERS),
&SizeOut,
NULL
);
if (b) {
if (RegistersOut.reg_Flags & 1) {
b = FALSE;
} else {
*LockStatus = RegistersOut.reg_EAX;
}
}
return b;
}
BOOL
ResetWin9xDisk (
IN HANDLE VWin32Vxd,
IN TCHAR Drive
)
{
DIOC_REGISTERS RegistersIn,RegistersOut;
BOOL b;
DWORD SizeOut;
//
// ax = generic ioctl code
//
RegistersIn.reg_EAX = 0x710d;
//
// cx = 0 (reset & flush disk)
//
RegistersIn.reg_ECX = 0;
//
// dx = 1-based drive number
//
RegistersIn.reg_EDX = (DWORD)(_totupper(Drive) - TEXT('A')) + 1;
//
// Perform the lock and check carry.
//
b = DeviceIoControl(
VWin32Vxd,
VWIN32_DIOC_DOS_IOCTL,
&RegistersIn,
sizeof(DIOC_REGISTERS),
&RegistersOut,
sizeof(DIOC_REGISTERS),
&SizeOut,
NULL
);
if(b && (RegistersOut.reg_Flags & 1)) {
b = FALSE;
}
return b;
}
typedef HANDLE(WINAPI *OPENTHREAD)(DWORD, BOOL, DWORD);
BOOL
pMakeThreadExclusive (
BOOL Lock
)
{
HANDLE h;
THREADENTRY32 e;
DWORD thisThread;
HANDLE threadHandle;
OPENTHREAD openThreadFn;
HMODULE lib;
BOOL result = FALSE;
lib = LoadLibrary (TEXT("kernel32.dll"));
if (!lib) {
goto c0;
}
openThreadFn = (OPENTHREAD) GetProcAddress (lib, "OpenThread");
if (!openThreadFn) {
//
// Must be Win98 or Win98SE -- change thread priority as workaround
//
if (Lock) {
result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
Sleep (0);
} else {
result = SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
}
goto c1;
}
thisThread = GetCurrentThreadId();
h = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
if (h == INVALID_HANDLE_VALUE) {
goto c1;
}
e.dwSize = sizeof (e);
if (Thread32First (h, &e)) {
do {
if (e.th32ThreadID != thisThread) {
threadHandle = openThreadFn (THREAD_SUSPEND_RESUME, FALSE, e.th32ThreadID);
if (threadHandle) {
if (Lock) {
SuspendThread (threadHandle);
} else {
ResumeThread (threadHandle);
}
CloseHandle (threadHandle);
}
}
} while (Thread32Next (h, &e));
}
CloseHandle (h);
result = TRUE;
c1:
FreeLibrary (lib);
c0:
return result;
}
BOOL
ReadOrWriteSectorsWin9x(
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN OUT LPBYTE Buffer,
IN BOOL Write
)
/*++
Routine Description:
Common routine to read or write sectors on a disk under Windows 95.
This routine will fail on Windows NT. After opening the VWIN32
VxD, the routine determines whether to use the original algorithm
or the OSR2 algorithm, and calls the appropriate worker routine.
Arguments:
Drive - supplies drive letter of device to be read from or written to.
StartSector - supplies logical sector number of first sector to be
read/written.
SectorCount - supplies number of sectors to be read/written.
SectorSize - supplies the number of bytes in a sector on the drive
to be read from/written to.
Buffer - Supplies or receives data, depending on the value or the Write
parameter.
Write - if 0, then this is a read operastion. If non-0, then this is
a write operation.
Return Value:
Boolean value indicating whether the disk was read/written successfully.
If failure, last error is set to something meaningful.
--*/
{
HANDLE hVxd;
BOOL b;
DWORD d;
INT level;
INT retry = 100;
//
// This thread must be the exclusive thread in our process
//
pMakeThreadExclusive (TRUE);
//
// Open VWIN32.VXD
//
hVxd = CreateFileA(
"\\\\.\\VWIN32",
Write ? GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(hVxd == INVALID_HANDLE_VALUE) {
d = GetLastError();
b = FALSE;
goto c0;
}
//
// Take out locks. We'll be as unrestrictive as possible.
// The locking stuff is really funky. You have to pass in all kinds of
// different parameters in OSR2 for reasons unknown. Also the
// permissions bits are strangely encoded.
//
if(!LockOrUnlockVolumeWin9x(hVxd,Drive,1,TRUE)) {
d = ERROR_SHARING_VIOLATION;
b = FALSE;
goto c1;
}
if(!LockOrUnlockVolumeWin9x(hVxd,Drive,2,TRUE)) {
d = ERROR_SHARING_VIOLATION;
b = FALSE;
goto c2;
}
//
// Try to get the level 3 lock. Retry if something happened while
// getting the lock. Fail after too many retries.
//
do {
if(!LockOrUnlockVolumeWin9x(hVxd,Drive,3,TRUE)) {
d = ERROR_SHARING_VIOLATION;
b = FALSE;
goto c3;
}
if (!pGetWin9xLockFlagState (hVxd, Drive, &level)) {
// unexpected -- INT 21h call failed
break;
}
if (!level) {
// We successfully got a clean level 3 lock
break;
}
LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
retry--;
} while (retry);
if (!retry) {
d = ERROR_SHARING_VIOLATION;
b = FALSE;
goto c3;
}
//
// Go do it.
//
b = ISOSR2()
? ReadOrWriteSectorsWin9xOsr2(hVxd,Drive,StartSector,SectorCount,Buffer,Write)
: ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
//
// If it failed, and OSR2 routine is being used, fall back to Win95 API. This is a workaround
// for Compaq because they ship OSR2 without the new OSR2 sector API support!
//
if (!b && ISOSR2()) {
b = ReadOrWriteSectorsWin9xOriginal(hVxd,Drive,StartSector,SectorCount,Buffer,Write);
}
d = GetLastError();
LockOrUnlockVolumeWin9x(hVxd,Drive,3,FALSE);
c3:
LockOrUnlockVolumeWin9x(hVxd,Drive,2,FALSE);
c2:
LockOrUnlockVolumeWin9x(hVxd,Drive,1,FALSE);
c1:
CloseHandle(hVxd);
c0:
//
// Resume all threads
//
pMakeThreadExclusive (FALSE);
SetLastError(d);
return(b);
}
BOOL
ReadOrWriteSectors(
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN UINT SectorSize,
IN OUT LPBYTE Buffer,
IN BOOL Write
)
/*++
Routine Description:
Common routine to read or write sectors on a disk. Allocates a properly
aligned buffer and decides whether to call NT- or Win9x-specific
i/o routine.
Arguments:
Drive - supplies drive letter of device to be read from or written to.
StartSector - supplies logical sector number of first sector to be
read/written.
SectorCount - supplies number of sectors to be read/written.
SectorSize - supplies the number of bytes in a sector on the drive
to be read from/written to.
Buffer - Supplies or receives data, depending on the value or the Write
parameter. There are no alignment requirements on ths buffer.
Write - if 0, then this is a read operastion. If non-0, then this is
a write operation.
Return Value:
Boolean value indicating whether the disk was read/written successfully.
Last error is undisturbed from the operation that caused any failure.
--*/
{
LPBYTE AlignedBuffer;
LPBYTE p;
BOOL b;
DWORD d;
//
// Allocate a buffer we will align on a sector boundary.
//
if(AlignedBuffer = MALLOC((SectorCount * SectorSize) + (SectorSize - 1))) {
if(d = (DWORD)AlignedBuffer % SectorSize) {
p = (PUCHAR)((DWORD)AlignedBuffer + (SectorSize - d));
} else {
p = AlignedBuffer;
}
if(Write) {
CopyMemory(p,Buffer,SectorCount*SectorSize);
}
b = ReadOrWriteSectorsWin9x(Drive,StartSector,SectorCount,p,Write);
d = GetLastError();
if(b && !Write) {
CopyMemory(Buffer,p,SectorCount*SectorSize);
}
FREE(AlignedBuffer);
} else {
b = FALSE;
d = ERROR_NOT_ENOUGH_MEMORY;
}
SetLastError(d);
return(b);
}
BOOL
ReadDiskSectors(
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN UINT SectorSize,
OUT LPBYTE Buffer
)
/*++
Routine Description:
Read a set of disk sectors off a disk device.
Arguments:
Drive - supplies drive letter of device to be read from.
StartSector - supplies logical sector number of first sector to be read.
SectorCount - supplies number of sectors to be read.
SectorSize - supplies the number of bytes in a sector on the drive
to be read from.
Buffer - if successful, receives data from the disk. There are no
alignment requirements on ths buffer.
Return Value:
Boolean value indicating whether the disk was read successfully.
--*/
{
return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,FALSE));
}
BOOL
WriteDiskSectors(
IN TCHAR Drive,
IN UINT StartSector,
IN UINT SectorCount,
IN UINT SectorSize,
IN LPBYTE Buffer
)
/*++
Routine Description:
Write data to a set of disk sectors.
Arguments:
Drive - supplies drive letter of device to be written to.
StartSector - supplies logical sector number of first sector to be written.
SectorCount - supplies number of sectors to be written.
SectorSize - supplies the number of bytes in a sector on the drive
to be written to.
Buffer - supplies data to be written. There are no alignment requirements
on ths buffer.
Return Value:
Boolean value indicating whether the disk was successfully written.
--*/
{
return(ReadOrWriteSectors(Drive,StartSector,SectorCount,SectorSize,Buffer,TRUE));
}