mirror of https://github.com/lianthony/NT4.0
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
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);
|
|
}
|