/*++ 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 #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); }