Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1241 lines
33 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
dllflopy.c
Abstract:
This module implements floppy disk related functions.
Author:
Ofer Porat (oferp) 6-21-93
Revision History:
--*/
#include "os2dll.h"
#include "os2dev.h"
#include "os2err.h"
#include <ntdddisk.h>
#include "os2flopy.h"
//
// Some constants
//
#define MAX_FLOPPY_DRIVES 5 // limit on number of floppy drives in system
#define MAX_GEOMETRIES_PER_DRIVE 6 // limit on number of different geometries for a single drive
#define SHORT_BPB_LENGTH 25 // length of initial DOS-like section of BPB
#define LONG_BPB_LENGTH 36 // length of total OS/2 BPB
#define BOOT_SECTOR_BPB_OFFSET 11 // offset of short BPB in a floppy's boot sector
//
// Data type definitions
//
//
// The following structure is used to hold per-floppy-drive information:
// 1) IsDeviceBpbValid asserts the validity of DeviceBpb which is used to
// hold the recommended BPB for the device.
// 2) IsMediaBpbValid asserts the validity of the following fields, which
// are considered a unit:
// a) MediaBpb -- BPB for the current media in drive
// b) MediaType -- NT Media Type based on MediaBpb
// c) TrueMediaGeometry -- contains the true media dimensions in case MediaBpb
// is a fake BPB given by the user.
//
typedef struct _OD2_FLOPPYDISK_INFORMATION {
BOOLEAN IsDeviceBpbValid;
BOOLEAN IsMediaBpbValid;
MEDIA_TYPE MediaType;
DISK_GEOMETRY TrueMediaGeometry;
BIOSPARAMETERBLOCK DeviceBpb;
BIOSPARAMETERBLOCK MediaBpb;
} OD2_FLOPPYDISK_INFORMATION, *POD2_FLOPPYDISK_INFORMATION;
#if 0
//
// This structure is used to read the object name for floppy drives in
// order to determine their number. It's large enough to contain
// L"\\Device\\Floppy" plus some spare
//
//
// Disabled, see below in Od2IdentifyDiskDrive()
//
typedef struct _X_OBJECT_NAME_INFORMATION {
OBJECT_NAME_INFORMATION i;
WCHAR n[20];
} X_OBJECT_NAME_INFORMATION, *PX_OBJECT_NAME_INFORMATION;
#endif
//
// Global variables
//
//
// The following table holds default short BPBs for the common
// drive types.
//
static BIOSPARAMETERBLOCK Od2StdBpb[8] = {
{512, 1, 1, 2, 112, 1*8*40, 0xFE, 1, 8, 1, 0, 0}, // 160KB 5.25"
{512, 1, 1, 2, 112, 1*9*40, 0xFC, 2, 9, 1, 0, 0}, // 180KB 5.25"
{512, 2, 1, 2, 112, 2*8*40, 0xFF, 1, 8, 2, 0, 0}, // 320KB 5.25"
{512, 2, 1, 2, 112, 2*9*40, 0xFD, 2, 9, 2, 0, 0}, // 360KB 5.25"
{512, 1, 1, 2, 224, 2*15*80, 0xF9, 7, 15, 2, 0, 0}, // 1.2MB 5.25"
{512, 2, 1, 2, 112, 2*9*80, 0xF9, 3, 9, 2, 0, 0}, // 720KB 3.5"
{512, 1, 1, 2, 224, 2*18*80, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB 3.5"
{512, 2, 1, 2, 240, 2*36*80, 0xF0, 9, 36, 2, 0, 0} // 2.88MB 3.5"
};
//
// The following resource lock protects Od2DiskBlocks & Od2Geometries
//
static RTL_RESOURCE Od2DisksLock;
#define AcquireDisksLockExclusive() (VOID) RtlAcquireResourceExclusive(&Od2DisksLock, TRUE)
#define AcquireDisksLockShared() (VOID) RtlAcquireResourceShared(&Od2DisksLock, TRUE)
#define ReleaseDisksLockExclusive() (VOID) RtlReleaseResource(&Od2DisksLock)
#define ReleaseDisksLockShared() (VOID) RtlReleaseResource(&Od2DisksLock)
#define ConvertDisksLockExclusiveToShared() (VOID) RtlConvertExclusiveToShared(&Od2DisksLock)
#define ConvertDisksLockSharedToExclusive() (VOID) RtlConvertSharedToExclusive(&Od2DisksLock)
//
// Od2Geometries is used for reading in geometries from drives
//
static DISK_GEOMETRY Od2Geometries[MAX_GEOMETRIES_PER_DRIVE];
//
// Od2DiskBlocks holds the floppy disk information for the system.
//
static OD2_FLOPPYDISK_INFORMATION Od2DiskBlocks[MAX_FLOPPY_DRIVES];
//
// Code comes next
//
APIRET
Od2IdentifyDiskDrive(
IN HANDLE NtHandle,
IN PULONG pDriveNumberPermanentStorageLocation,
OUT PULONG pDriveNumber
)
{
// X_OBJECT_NAME_INFORMATION ObjectName;
FILE_FS_DEVICE_INFORMATION FsDeviceInfoBuffer;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
ULONG DriveNumber;
//
// Initially it was intended that the drive number be discovered by
// using NtQueryObject() to find the object name which should be
// something like \Device\Floppy0, and from this it's possible to
// tell the drive number.
//
// It turns out however that NT does not have a name for a drive
// opened in this fashion (\os2ss\drives\a:). So, instead, DosOpen()
// was modified to put the drive letter which it knows about in
// *pDriveNumberPermanentStorageLocation. It sets the high bit on.
// During the first time, this routine checks to see that it's actually
// a floppy drive. After this it sets the high bit off, and later on it
// only uses the drive number it has already figured out in DosOpen().
//
DriveNumber = *pDriveNumberPermanentStorageLocation;
if (DriveNumber != (ULONG) NULL &&
DriveNumber <= MAX_FLOPPY_DRIVES) {
*pDriveNumber = DriveNumber - 1;
return(NO_ERROR);
}
Status = NtQueryVolumeInformationFile(NtHandle,
&IoStatus,
&FsDeviceInfoBuffer,
sizeof(FsDeviceInfoBuffer),
FileFsDeviceInformation
);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2IdentifyDiskDrive: unable to NtQueryVolumeInfo, Status == %lx\n",
Status));
}
#endif
return(Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
}
if (FsDeviceInfoBuffer.DeviceType != FILE_DEVICE_DISK ||
!(FsDeviceInfoBuffer.Characteristics & FILE_DEVICE_IS_MOUNTED)) {
return(ERROR_INVALID_HANDLE);
}
//
// currently we support only floppy drives ...
//
if (!(FsDeviceInfoBuffer.Characteristics & FILE_FLOPPY_DISKETTE)) {
return(ERROR_NOT_SUPPORTED);
}
#if 1
//
// This is the altername code -- it just leaves the drive number
// obtained from DosOpen()
//
DriveNumber &= 0x7fffffff;
if (DriveNumber != (ULONG) NULL &&
DriveNumber <= MAX_FLOPPY_DRIVES) {
*pDriveNumber = DriveNumber - 1;
*pDriveNumberPermanentStorageLocation = DriveNumber;
return(NO_ERROR);
} else {
//
// Drive obtained from DosOpen() is not good.
// return an error
//
return(ERROR_INVALID_DRIVE);
}
#else
//
// This is the code that should have worked -- get the drive name from NT
//
Status = NtQueryObject(NtHandle,
ObjectNameInformation,
&ObjectName,
sizeof(ObjectName),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2IdentifyDiskDrive: unable to NtQueryObject, Status == %lx\n",
Status));
}
#endif
if (Status == STATUS_BUFFER_OVERFLOW) {
return(ERROR_INVALID_DRIVE);
} else {
return(Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_DRIVE));
}
}
if (ObjectName.i.Name.Length != 30 ||
RtlCompareMemory(ObjectName.i.Name.Buffer, L"\\Device\\Floppy", 28) != 28) {
return(ERROR_INVALID_DRIVE);
}
DriveNumber = (ULONG) (ObjectName.n[14] - L'0');
*pDriveNumber = DriveNumber;
*pDriveNumberPermanentStorageLocation = DriveNumber + 1;
return(NO_ERROR);
#endif
}
VOID
Od2DetermineMediaType(
OUT PMEDIA_TYPE pMediaType,
IN PBIOSPARAMETERBLOCK pBPB
)
{
MEDIA_TYPE MediaType = Unknown;
switch (pBPB->bDeviceType) {
case DEVTYPE_35:
case DEVTYPE_UNKNOWN:
if (RtlCompareMemory(pBPB, &Od2StdBpb[6], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F3_1Pt44_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[5], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F3_720_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[7], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F3_2Pt88_512;
break;
}
break;
case DEVTYPE_48TPI:
case DEVTYPE_96TPI:
if (RtlCompareMemory(pBPB, &Od2StdBpb[4], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F5_1Pt2_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[3], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F5_360_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[2], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F5_320_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[1], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F5_180_512;
break;
}
if (RtlCompareMemory(pBPB, &Od2StdBpb[0], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
MediaType = F5_160_512;
break;
}
break;
case DEVTYPE_FIXED:
MediaType = FixedMedia;
break;
case DEVTYPE_TAPE:
MediaType = RemovableMedia;
break;
}
*pMediaType = MediaType;
}
VOID
Od2ComputeTrueGeometry(
IN HANDLE NtHandle,
IN BOOLEAN EnforceFakeGeometry,
OUT PDISK_GEOMETRY pTrueGeometry,
IN PBIOSPARAMETERBLOCK pFakeBpb,
IN MEDIA_TYPE FakeMediaType
)
{
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
if (!EnforceFakeGeometry) {
Status = NtDeviceIoControlFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
pTrueGeometry,
sizeof(DISK_GEOMETRY));
if (NT_SUCCESS(Status) && IoStatus.Information >= sizeof(DISK_GEOMETRY)) {
return;
}
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ComputeTrueGeometry: unable to get true geometry (using fake), Status == %lx\n",
Status));
}
#endif
}
pTrueGeometry->MediaType = FakeMediaType;
pTrueGeometry->Cylinders = RtlConvertUlongToLargeInteger((ULONG) pFakeBpb->cCylinders);
pTrueGeometry->TracksPerCylinder = (ULONG) pFakeBpb->cHeads;
pTrueGeometry->SectorsPerTrack = (ULONG) pFakeBpb->usSectorsPerTrack;
pTrueGeometry->BytesPerSector = (ULONG) pFakeBpb->usBytesPerSector;
}
APIRET
Od2AcquireDeviceBPB(
IN ULONG DriveNumber,
IN HANDLE NtHandle,
IN BOOLEAN Validate,
IN BOOLEAN UseDefault,
IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL
)
{
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
APIRET RetCode = NO_ERROR;
PBOOLEAN pIsValid;
MEDIA_TYPE MediaType;
ULONG GeometryIndex;
LONG StdBpbIndex;
POD2_FLOPPYDISK_INFORMATION DiskInfo;
PBIOSPARAMETERBLOCK pBPB;
if (DriveNumber >= MAX_FLOPPY_DRIVES) {
return(ERROR_INVALID_DRIVE);
}
DiskInfo = &Od2DiskBlocks[DriveNumber];
pBPB = &DiskInfo->DeviceBpb;
pIsValid = &DiskInfo->IsDeviceBpbValid;
if (Validate) {
AcquireDisksLockShared();
if (*pIsValid) {
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
ReleaseDisksLockShared();
return(NO_ERROR);
}
ConvertDisksLockSharedToExclusive();
if (*pIsValid) {
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
ReleaseDisksLockExclusive();
return(NO_ERROR);
}
} else {
AcquireDisksLockExclusive();
}
*pIsValid = FALSE;
if (!UseDefault) {
RtlMoveMemory(pBPB, pBpb, sizeof(BIOSPARAMETERBLOCK));
Od2DetermineMediaType(
&MediaType,
pBPB
);
if (MediaType == Unknown) {
RetCode = ERROR_INVALID_DATA;
} else {
*pIsValid = TRUE;
}
goto Cleanup;
}
Status = NtDeviceIoControlFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_MEDIA_TYPES,
NULL,
0,
Od2Geometries,
sizeof(Od2Geometries));
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireDeviceBPB: unable to NtDeviceIoCtl, Status == %lx\n",
Status));
}
#endif
RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
goto Cleanup;
}
if (IoStatus.Information < sizeof(DISK_GEOMETRY)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireDeviceBPB: NtDeviceIoCtl returned short length = %lx\n",
IoStatus.Information));
}
#endif
RetCode = ERROR_INVALID_DRIVE;
goto Cleanup;
}
if (Status == STATUS_BUFFER_OVERFLOW) {
GeometryIndex = MAX_GEOMETRIES_PER_DRIVE - 1;
} else {
GeometryIndex = (IoStatus.Information / sizeof(DISK_GEOMETRY)) - 1;
}
MediaType = Od2Geometries[GeometryIndex].MediaType;
if (MediaType == FixedMedia ||
MediaType == Unknown) {
pBPB->fsDeviceAttr = 0x1; // non-removable, no media change detect
} else if (MediaType == RemovableMedia) {
pBPB->fsDeviceAttr = 0x0; // removable, no media change detect
} else {
pBPB->fsDeviceAttr = 0x2; // removable, yes media change detect
}
pBPB->cCylinders = (USHORT) Od2Geometries[GeometryIndex].Cylinders.LowPart;
StdBpbIndex = -1L;
switch (MediaType) {
case F5_1Pt2_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
StdBpbIndex = 4L;
break;
case F5_360_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
StdBpbIndex = 3L;
break;
case F5_320_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
StdBpbIndex = 2L;
break;
case F5_320_1024:
pBPB->bDeviceType = DEVTYPE_96TPI;
break;
case F5_180_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
StdBpbIndex = 1L;
break;
case F5_160_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
StdBpbIndex = 0L;
break;
case F3_1Pt44_512:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
StdBpbIndex = 6L;
break;
case F3_720_512:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
StdBpbIndex = 5L;
break;
case F3_20Pt8_512:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
break;
case F3_2Pt88_512:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
StdBpbIndex = 7L;
break;
case FixedMedia:
pBPB->bDeviceType = DEVTYPE_FIXED;
break;
case RemovableMedia:
pBPB->bDeviceType = DEVTYPE_TAPE;
break;
default:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
break;
}
if (StdBpbIndex == -1L) {
//
// unrecognized device type
//
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireDeviceBPB: recommended BPB asked for unknown dev type = %lx\n",
MediaType));
}
#endif
RetCode = ERROR_INVALID_DRIVE;
goto Cleanup;
}
RtlMoveMemory(pBPB, &Od2StdBpb[StdBpbIndex], SHORT_BPB_LENGTH);
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
*pIsValid = TRUE;
Cleanup:
ReleaseDisksLockExclusive();
return(RetCode);
}
APIRET
Od2AcquireMediaBPB(
IN ULONG DriveNumber,
IN HANDLE NtHandle,
IN BOOLEAN Validate,
IN BOOLEAN UseDefault,
IN BOOLEAN EnforceFakeGeometry,
IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL,
OUT PMEDIA_TYPE pMediaType OPTIONAL,
OUT PDISK_GEOMETRY pTrueMediaGeometry OPTIONAL
)
{
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
APIRET RetCode = NO_ERROR;
PBOOLEAN pIsValid;
LARGE_INTEGER BootSecOffset;
PBYTE BootSecBuffer;
POD2_FLOPPYDISK_INFORMATION DiskInfo;
PBIOSPARAMETERBLOCK pBPB;
PDISK_GEOMETRY pTrueGeometry;
if (DriveNumber >= MAX_FLOPPY_DRIVES) {
return(ERROR_INVALID_DRIVE);
}
DiskInfo = &Od2DiskBlocks[DriveNumber];
pBPB = &DiskInfo->MediaBpb;
pIsValid = &DiskInfo->IsMediaBpbValid;
pTrueGeometry = &DiskInfo->TrueMediaGeometry;
if (Validate) {
if (!EnforceFakeGeometry) {
AcquireDisksLockShared();
if (*pIsValid) {
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
if (ARGUMENT_PRESENT(pMediaType)) {
*pMediaType = DiskInfo->MediaType;
}
if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
}
ReleaseDisksLockShared();
return(NO_ERROR);
}
ConvertDisksLockSharedToExclusive();
} else {
AcquireDisksLockExclusive();
}
if (*pIsValid) {
if (EnforceFakeGeometry) {
Od2ComputeTrueGeometry(
NtHandle,
TRUE,
pTrueGeometry,
pBPB,
DiskInfo->MediaType);
}
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
if (ARGUMENT_PRESENT(pMediaType)) {
*pMediaType = DiskInfo->MediaType;
}
if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
}
ReleaseDisksLockExclusive();
return(NO_ERROR);
}
} else {
AcquireDisksLockExclusive();
}
*pIsValid = FALSE;
if (!UseDefault) {
RtlMoveMemory(pBPB, pBpb, sizeof(BIOSPARAMETERBLOCK));
Od2DetermineMediaType(
&DiskInfo->MediaType,
pBPB
);
if (DiskInfo->MediaType == Unknown) {
RetCode = ERROR_INVALID_DATA;
} else {
Od2ComputeTrueGeometry(
NtHandle,
EnforceFakeGeometry,
pTrueGeometry,
pBPB,
DiskInfo->MediaType);
if (ARGUMENT_PRESENT(pMediaType)) {
*pMediaType = DiskInfo->MediaType;
}
if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
}
*pIsValid = TRUE;
}
goto Cleanup;
}
Status = NtDeviceIoControlFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
Od2Geometries,
sizeof(Od2Geometries));
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireMediaBPB: unable to NtDeviceIoCtl, Status == %lx\n",
Status));
}
#endif
RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
goto Cleanup;
}
if (IoStatus.Information < sizeof(DISK_GEOMETRY)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireMediaBPB: NtDeviceIoCtl returned short length = %lx\n",
IoStatus.Information));
}
#endif
RetCode = ERROR_INVALID_DRIVE;
goto Cleanup;
}
DiskInfo->MediaType = Od2Geometries[0].MediaType;
RtlMoveMemory(pTrueGeometry, Od2Geometries, sizeof(DISK_GEOMETRY));
if (DiskInfo->MediaType == FixedMedia ||
DiskInfo->MediaType == Unknown) {
pBPB->fsDeviceAttr = 0x1; // non-removable, no media change detect
} else if (DiskInfo->MediaType == RemovableMedia) {
pBPB->fsDeviceAttr = 0x0; // removable, no media change detect
} else {
pBPB->fsDeviceAttr = 0x2; // removable, yes media change detect
}
pBPB->cCylinders = (USHORT) Od2Geometries[0].Cylinders.LowPart;
switch (DiskInfo->MediaType) {
case F5_1Pt2_512:
case F5_360_512:
case F5_320_512:
case F5_320_1024:
case F5_180_512:
case F5_160_512:
pBPB->bDeviceType = DEVTYPE_96TPI;
break;
case F3_1Pt44_512:
case F3_720_512:
case F3_20Pt8_512:
case F3_2Pt88_512:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
break;
case FixedMedia:
pBPB->bDeviceType = DEVTYPE_FIXED;
break;
case RemovableMedia:
pBPB->bDeviceType = DEVTYPE_TAPE;
break;
default:
pBPB->bDeviceType = DEVTYPE_UNKNOWN;
break;
}
//
// Get BPB for current media
// by reading it off the disk
//
BootSecOffset.HighPart = BootSecOffset.LowPart = 0L;
BootSecBuffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, Od2Geometries[0].BytesPerSector);
if (BootSecBuffer == NULL) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireMediaBPB: unable to alloc buffer for boot sector\n"));
}
#endif
RetCode = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Status = NtReadFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
BootSecBuffer,
Od2Geometries[0].BytesPerSector,
&BootSecOffset,
NULL);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireMediaBPB: unable to NtReadFile, Status = %lx\n", Status));
}
#endif
RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY);
RtlFreeHeap(Od2Heap, 0, BootSecBuffer);
goto Cleanup;
}
//
// check validity of boot sector
//
if ((IoStatus.Information >= 36) &&
(BootSecBuffer[0] == 0x69 || BootSecBuffer[0] == 0xE9 ||
(BootSecBuffer[0] == 0xEB && BootSecBuffer[2] == 0x90)) &&
((BootSecBuffer[21] & 0xF0) == 0xF0)) {
RtlMoveMemory(pBPB, BootSecBuffer + BOOT_SECTOR_BPB_OFFSET, SHORT_BPB_LENGTH);
if (ARGUMENT_PRESENT(pBpb)) {
RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
}
if (ARGUMENT_PRESENT(pMediaType)) {
*pMediaType = DiskInfo->MediaType;
}
if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
}
*pIsValid = TRUE;
} else {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2AcquireMediaBPB: unable to recognize boot sector\n"));
}
#endif
RetCode = ERROR_INVALID_DRIVE;
}
RtlFreeHeap(Od2Heap, 0, BootSecBuffer);
Cleanup:
ReleaseDisksLockExclusive();
return(RetCode);
}
ULONG
Od2ComputeDiskOffset(
IN PBIOSPARAMETERBLOCK pBpb,
IN PDISK_GEOMETRY pTrueGeometry,
IN ULONG Head,
IN ULONG Cylinder,
IN ULONG Sector
)
{
ULONG TrackOffset, SectorOffset, ByteOffset;
if (Head >= (ULONG) pBpb->cHeads ||
Sector >= (ULONG) pBpb->usSectorsPerTrack ||
Cylinder >= (ULONG) pBpb->cCylinders) {
return((ULONG) -1); // invalid parameter given
}
TrackOffset = Head +
Cylinder *
pTrueGeometry->TracksPerCylinder;
SectorOffset = Sector +
TrackOffset *
pTrueGeometry->SectorsPerTrack;
ByteOffset = (SectorOffset + pBpb->cHiddenSectors) *
pTrueGeometry->BytesPerSector;
return(ByteOffset);
}
APIRET
Od2ReadWriteVerifyTrack(
IN HANDLE NtHandle,
IN ULONG Command,
IN PTRACKLAYOUT TrackLayout,
IN PBYTE pData OPTIONAL,
IN ULONG CountSectors,
IN PBIOSPARAMETERBLOCK pBpb,
IN PDISK_GEOMETRY pTrueGeometry
)
{
IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER BigByteOffset;
NTSTATUS Status;
PBYTE Buffer;
ULONG ByteOffset;
ULONG ByteLength;
ULONG Sector;
if (Command >= TRACK_CMD_LIMIT) {
return(ERROR_NOT_SUPPORTED);
}
if (TrackLayout->bCommand == 1) {
if ((ULONG) TrackLayout->usFirstSector + CountSectors > (ULONG) pBpb->usSectorsPerTrack) {
return(ERROR_SECTOR_NOT_FOUND);
}
ByteLength = CountSectors * (ULONG) pBpb->usBytesPerSector;
ByteOffset = Od2ComputeDiskOffset(
pBpb,
pTrueGeometry,
(ULONG) TrackLayout->usHead,
(ULONG) TrackLayout->usCylinder,
(ULONG) TrackLayout->usFirstSector);
if (ByteOffset == (ULONG) -1) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: Invalid sector location given (1)\n"));
}
#endif
return(ERROR_INVALID_PARAMETER);
}
BigByteOffset = RtlConvertUlongToLargeInteger(ByteOffset);
if (Command == VERIFY_TRACK_CMD) {
Buffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, ByteLength);
if (Buffer == NULL) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: Unable to allocate memory for track verification (1)\n"));
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
} else {
Buffer = pData;
}
if (Command == WRITE_TRACK_CMD) {
Status = NtWriteFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
Buffer,
ByteLength,
&BigByteOffset,
NULL);
} else {
Status = NtReadFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
Buffer,
ByteLength,
&BigByteOffset,
NULL);
}
if (Command == VERIFY_TRACK_CMD) {
RtlFreeHeap(Od2Heap, 0, Buffer);
}
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (1) failed, Status = %lx\n", Status));
}
#endif
return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
}
if (IoStatus.Information != ByteLength) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (1) partial read/write, Wanted = %lx, Actual = %lx\n",
ByteOffset, IoStatus.Information));
}
#endif
return(ERROR_NOT_READY); // Bogus return code
}
} else {
//
// We have a sector list, write it sector by sector
//
ULONG i,j;
ByteLength = (ULONG) pBpb->usBytesPerSector;
if (Command == VERIFY_TRACK_CMD) {
Buffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, ByteLength);
if (Buffer == NULL) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: Unable to allocate memory for track verification (2)\n"));
}
#endif
return(ERROR_NOT_ENOUGH_MEMORY);
}
} else {
Buffer = pData;
}
for (i = 0, j = (ULONG) TrackLayout->usFirstSector;
i < CountSectors;
i++, j++) {
Sector = ((ULONG) TrackLayout->TrackTable[j].usSectorNumber) - 1;
ByteOffset = Od2ComputeDiskOffset(
pBpb,
pTrueGeometry,
(ULONG) TrackLayout->usHead,
(ULONG) TrackLayout->usCylinder,
Sector);
if (ByteOffset == (ULONG) -1) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: Invalid sector location given (2), table position = %ld\n", j));
}
#endif
if (Command == VERIFY_TRACK_CMD) {
RtlFreeHeap(Od2Heap, 0, Buffer);
}
return(ERROR_INVALID_PARAMETER);
}
BigByteOffset = RtlConvertUlongToLargeInteger(ByteOffset);
if (Command == WRITE_TRACK_CMD) {
Status = NtWriteFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
Buffer,
ByteLength,
&BigByteOffset,
NULL);
} else {
Status = NtReadFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
Buffer,
ByteLength,
&BigByteOffset,
NULL);
}
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (2) failed, Status = %lx\n", Status));
}
#endif
if (Command == VERIFY_TRACK_CMD) {
RtlFreeHeap(Od2Heap, 0, Buffer);
}
return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
}
if (IoStatus.Information != ByteLength) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (2) partial read/write, Wanted = %lx, Actual = %lx\n",
ByteOffset, IoStatus.Information));
}
#endif
if (Command == VERIFY_TRACK_CMD) {
RtlFreeHeap(Od2Heap, 0, Buffer);
}
return(ERROR_NOT_READY); // Bogus return code
}
Buffer += ByteLength;
}
if (Command == VERIFY_TRACK_CMD) {
RtlFreeHeap(Od2Heap, 0, Buffer);
}
}
return(NO_ERROR);
}
APIRET
Od2FormatTrack(
IN HANDLE NtHandle,
IN PTRACKFORMAT TrackFormat,
IN ULONG CountSectors,
IN BYTE FormatSectorSizeType,
IN PBIOSPARAMETERBLOCK pBpb,
IN MEDIA_TYPE MediaType
)
{
FORMAT_PARAMETERS FormP;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
//
// Check that user's parameters don't contradict BPB
//
if (FormatSectorSizeType > 0x3 ||
(((USHORT)128) << FormatSectorSizeType) != pBpb->usBytesPerSector ||
CountSectors != (ULONG) pBpb->usSectorsPerTrack ||
(ULONG) TrackFormat->usHead >= (ULONG) pBpb->cHeads ||
(ULONG) TrackFormat->usCylinder >= (ULONG) pBpb->cCylinders) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2FormatTrack: Format parameters given contradict BPB\n"));
}
#endif
return(ERROR_INVALID_PARAMETER);
}
FormP.MediaType = MediaType;
FormP.StartCylinderNumber = (ULONG) TrackFormat->usCylinder;
FormP.EndCylinderNumber = (ULONG) TrackFormat->usCylinder;
FormP.StartHeadNumber = (ULONG) TrackFormat->usHead;
FormP.EndHeadNumber = (ULONG) TrackFormat->usHead;
Status = NtDeviceIoControlFile(
NtHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_FORMAT_TRACKS,
&FormP,
sizeof(FormP),
NULL,
0);
if (!NT_SUCCESS(Status)) {
#if DBG
IF_OD2_DEBUG( FILESYS ) {
KdPrint(("Od2FormatTrack: NtDeviceIoControlFile failed, Status = %lx\n", Status));
}
#endif
return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
}
return(NO_ERROR);
}
VOID
Od2DiskIOInitialize(
VOID
)
{
RtlInitializeResource(&Od2DisksLock);
}
VOID
Od2DiskIOTerminate(
VOID
)
{
RtlDeleteResource(&Od2DisksLock);
}