492 lines
13 KiB
C
492 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fat_rec.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the mini-file system recognizer for FAT.
|
||
|
||
Author:
|
||
|
||
Darryl E. Havens (darrylh) 8-dec-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode, local to I/O system
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "fs_rec.h"
|
||
#include "fat_rec.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,FatRecFsControl)
|
||
#pragma alloc_text(PAGE,IsFatVolume)
|
||
#pragma alloc_text(PAGE,FatReadBlock)
|
||
#pragma alloc_text(PAGE,UnpackBiosParameterBlock)
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
NTSTATUS
|
||
FatRecFsControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function performs the mount and driver reload functions for this mini-
|
||
file system recognizer driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this driver's device object.
|
||
|
||
Irp - Pointer to the I/O Request Packet (IRP) representing the function to
|
||
be performed.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PDEVICE_OBJECT targetDevice;
|
||
PPACKED_BOOT_SECTOR buffer;
|
||
LARGE_INTEGER byteOffset;
|
||
UNICODE_STRING driverName;
|
||
NTSTATUS extStatus;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Begin by determining what function that is to be performed.
|
||
//
|
||
|
||
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
||
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
switch ( irpSp->MinorFunction ) {
|
||
|
||
case IRP_MN_MOUNT_VOLUME:
|
||
|
||
//
|
||
// Attempt to mount a volume: Determine whether or not the volume in
|
||
// question is a FAT volume and, if so, let the I/O system know that it
|
||
// is by returning a special status code so that this driver can get
|
||
// called back to load the FAT file system.
|
||
//
|
||
|
||
//
|
||
// Begin by making a special case test to determine whether or not this
|
||
// driver has ever recognized a volume as being a FAT volume and the
|
||
// attempt to load the driver failed. If so, then simply complete the
|
||
// request with an error, indicating that the volume is not recognized
|
||
// so that it gets mounted by the RAW file system.
|
||
//
|
||
|
||
status = STATUS_UNRECOGNIZED_VOLUME;
|
||
if (deviceExtension->RealFsLoadFailed || irpSp->Flags) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Attempt to determine whether or not the target volume being mounted
|
||
// is a FAT volume. Note that if an error occurs, and this is a floppy
|
||
// drive, and the error occurred on the actual read from the device,
|
||
// then the FAT file system will actually be loaded to handle the
|
||
// problem since this driver is a place holder and does not need to
|
||
// know all of the protocols for handling floppy errors.
|
||
//
|
||
|
||
targetDevice = irpSp->Parameters.MountVolume.DeviceObject;
|
||
byteOffset.QuadPart = 0;
|
||
|
||
if (FatReadBlock( targetDevice, &byteOffset, 512, &extStatus, &buffer )) {
|
||
if (IsFatVolume( buffer )) {
|
||
status = STATUS_FS_DRIVER_REQUIRED;
|
||
}
|
||
ExFreePool( buffer );
|
||
} else {
|
||
if (!NT_SUCCESS( extStatus )) {
|
||
if (targetDevice->Characteristics & FILE_FLOPPY_DISKETTE) {
|
||
status = STATUS_FS_DRIVER_REQUIRED;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case IRP_MN_LOAD_FILE_SYSTEM:
|
||
|
||
//
|
||
// Attempt to load the FAT file system: A volume has been found that
|
||
// appears to be a FAT volume, so attempt to load the FAT file system.
|
||
// If it successfully loads, then
|
||
//
|
||
|
||
RtlInitUnicodeString( &driverName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Fastfat" );
|
||
status = ZwLoadDriver( &driverName );
|
||
if (!NT_SUCCESS( status )) {
|
||
if (status != STATUS_IMAGE_ALREADY_LOADED) {
|
||
deviceExtension->RealFsLoadFailed = TRUE;
|
||
}
|
||
} else {
|
||
IoUnregisterFileSystem( DeviceObject );
|
||
}
|
||
break;
|
||
|
||
default:
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
}
|
||
|
||
//
|
||
// Finally, complete the request and return the same status code to the
|
||
// caller.
|
||
//
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status;
|
||
}
|
||
|
||
BOOLEAN
|
||
IsFatVolume(
|
||
IN PPACKED_BOOT_SECTOR Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks at the buffer passed in which contains the FAT boot
|
||
sector and determines whether or not it represents an actual FAT boot
|
||
sector.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Pointer to buffer containing potential boot block.
|
||
|
||
Return Value:
|
||
|
||
The function returns TRUE if the buffer contains a recognizable FAT boot
|
||
sector, otherwise it returns FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
BIOS_PARAMETER_BLOCK bios;
|
||
BOOLEAN result;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Begin by unpacking the Bios Parameter Block that is packed in the boot
|
||
// sector so that it can be examined without incurring alignment faults.
|
||
//
|
||
|
||
UnpackBiosParameterBlock( &Buffer->PackedBpb, &bios );
|
||
|
||
//
|
||
// Assume that the sector represents a FAT boot block and then determine
|
||
// whether or not it really does.
|
||
//
|
||
|
||
result = TRUE;
|
||
|
||
if (bios.Sectors) {
|
||
bios.LargeSectors = 0;
|
||
}
|
||
|
||
// FMR Jul.11.1994 NaokiM - Fujitsu -
|
||
// FMR boot sector has 'IPL1' string at the beginnig.
|
||
|
||
if (Buffer->Jump[0] != 0x49 && /* FMR */
|
||
Buffer->Jump[0] != 0xe9 &&
|
||
Buffer->Jump[0] != 0xeb) {
|
||
|
||
result = FALSE;
|
||
|
||
|
||
// FMR Jul.11.1994 NaokiM - Fujitsu -
|
||
// Sector size of FMR partition is 2048.
|
||
|
||
} else if (bios.BytesPerSector != 128 &&
|
||
bios.BytesPerSector != 256 &&
|
||
bios.BytesPerSector != 512 &&
|
||
bios.BytesPerSector != 1024 &&
|
||
bios.BytesPerSector != 2048 && /* FMR */
|
||
bios.BytesPerSector != 4096) {
|
||
|
||
result = FALSE;
|
||
|
||
} else if (bios.SectorsPerCluster != 1 &&
|
||
bios.SectorsPerCluster != 2 &&
|
||
bios.SectorsPerCluster != 4 &&
|
||
bios.SectorsPerCluster != 8 &&
|
||
bios.SectorsPerCluster != 16 &&
|
||
bios.SectorsPerCluster != 32 &&
|
||
bios.SectorsPerCluster != 64 &&
|
||
bios.SectorsPerCluster != 128) {
|
||
|
||
result = FALSE;
|
||
|
||
} else if (!bios.ReservedSectors) {
|
||
|
||
result = FALSE;
|
||
|
||
} else if (!bios.Fats) {
|
||
|
||
result = FALSE;
|
||
|
||
} else if (!bios.RootEntries) {
|
||
|
||
result = FALSE;
|
||
|
||
//
|
||
// Prior to DOS 3.2 might contains value in both of Sectors and
|
||
// Sectors Large.
|
||
//
|
||
} else if (!bios.Sectors && !bios.LargeSectors) {
|
||
|
||
result = FALSE;
|
||
|
||
} else if (!bios.SectorsPerFat) {
|
||
|
||
result = FALSE;
|
||
|
||
// FMR Jul.11.1994 NaokiM - Fujitsu -
|
||
// 1. Media descriptor of FMR partitions is 0xfa.
|
||
// 2. Media descriptor of partitions formated by FMR OS/2 is 0x00.
|
||
// 3. Media descriptor of floppy disks formated by FMR DOS is 0x01.
|
||
|
||
} else if (bios.Media != 0x00 && /* FMR */
|
||
bios.Media != 0x01 && /* FMR */
|
||
bios.Media != 0xf0 &&
|
||
bios.Media != 0xf8 &&
|
||
bios.Media != 0xf9 &&
|
||
bios.Media != 0xfa && /* FMR */
|
||
bios.Media != 0xfb &&
|
||
bios.Media != 0xfc &&
|
||
bios.Media != 0xfd &&
|
||
bios.Media != 0xfe &&
|
||
bios.Media != 0xff) {
|
||
|
||
result = FALSE;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
BOOLEAN
|
||
FatReadBlock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PLARGE_INTEGER ByteOffset,
|
||
IN ULONG MinimumBytes,
|
||
OUT PNTSTATUS ExtendedStatus,
|
||
OUT PPACKED_BOOT_SECTOR *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reads a minimum numbers of bytes into a buffer starting at
|
||
the byte offset from the base of the device represented by the device
|
||
object.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object from which to read.
|
||
|
||
ByteOffset - Pointer to a 64-bit byte offset from the base of the device
|
||
from which to start the read.
|
||
|
||
MinimumBytes - Supplies the minimum number of bytes to be read.
|
||
|
||
ExtendedStatus - Variable to receive extended status information about
|
||
any I/O errors that occurred.
|
||
|
||
Buffer - Variable to receive a pointer to the allocated buffer containing
|
||
the bytes read.
|
||
|
||
Return Value:
|
||
|
||
The function value is TRUE if the bytes were read, otherwise FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
#define RoundUp( x, y ) ( ((x + (y-1)) / y) * y )
|
||
|
||
DISK_GEOMETRY diskGeometry;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
KEVENT event;
|
||
PIRP irp;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Begin by getting the disk geometry so that the number of bytes required
|
||
// for a single read can be determined.
|
||
//
|
||
|
||
*ExtendedStatus = STATUS_SUCCESS;
|
||
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
|
||
irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||
DeviceObject,
|
||
(PVOID) NULL,
|
||
0,
|
||
&diskGeometry,
|
||
sizeof( diskGeometry ),
|
||
FALSE,
|
||
&event,
|
||
&ioStatus );
|
||
if (!irp) {
|
||
return FALSE;
|
||
}
|
||
|
||
status = IoCallDriver( DeviceObject, irp );
|
||
if (status == STATUS_PENDING) {
|
||
(VOID) KeWaitForSingleObject( &event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
(PLARGE_INTEGER) NULL );
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS( status )) {
|
||
*ExtendedStatus = status;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Ensure that the drive actually knows how many bytes there are per
|
||
// sector. Floppy drives do not know if the media is unformatted.
|
||
//
|
||
|
||
if (!diskGeometry.BytesPerSector) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Set the minimum number of bytes to read to the maximum of the bytes that
|
||
// the caller wants to read, and the number of bytes in a sector.
|
||
//
|
||
|
||
if (MinimumBytes < diskGeometry.BytesPerSector) {
|
||
MinimumBytes = diskGeometry.BytesPerSector;
|
||
} else {
|
||
MinimumBytes = RoundUp( MinimumBytes, diskGeometry.BytesPerSector );
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer large enough to contain the bytes required, round the
|
||
// request to a page boundary to solve any alignment requirements.
|
||
//
|
||
|
||
*Buffer = ExAllocatePool( NonPagedPool,
|
||
(MinimumBytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) );
|
||
if (!*Buffer) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Read the actual bytes off of the disk.
|
||
//
|
||
|
||
KeResetEvent( &event );
|
||
|
||
irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
|
||
DeviceObject,
|
||
*Buffer,
|
||
MinimumBytes,
|
||
ByteOffset,
|
||
&event,
|
||
&ioStatus );
|
||
if (!irp) {
|
||
return FALSE;
|
||
}
|
||
|
||
status = IoCallDriver( DeviceObject, irp );
|
||
if (status == STATUS_PENDING) {
|
||
(VOID) KeWaitForSingleObject( &event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
(PLARGE_INTEGER) NULL );
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS( status )) {
|
||
*ExtendedStatus = status;
|
||
ExFreePool( *Buffer );
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
UnpackBiosParameterBlock(
|
||
IN PPACKED_BIOS_PARAMETER_BLOCK Bios,
|
||
OUT PBIOS_PARAMETER_BLOCK UnpackedBios
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies a packed Bios Parameter Block to an unpacked Bios
|
||
Parameter Block.
|
||
|
||
Arguments:
|
||
|
||
Bios - Pointer to the packed Bios Parameter Block.
|
||
|
||
UnpackedBios - Pointer to the unpacked Bios Parameter Block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Unpack the Bios Parameter Block.
|
||
//
|
||
|
||
CopyUchar2( &UnpackedBios->BytesPerSector, &Bios->BytesPerSector[0] );
|
||
CopyUchar2( &UnpackedBios->BytesPerSector, &Bios->BytesPerSector[0] );
|
||
CopyUchar1( &UnpackedBios->SectorsPerCluster, &Bios->SectorsPerCluster[0] );
|
||
CopyUchar2( &UnpackedBios->ReservedSectors, &Bios->ReservedSectors[0] );
|
||
CopyUchar1( &UnpackedBios->Fats, &Bios->Fats[0] );
|
||
CopyUchar2( &UnpackedBios->RootEntries, &Bios->RootEntries[0] );
|
||
CopyUchar2( &UnpackedBios->Sectors, &Bios->Sectors[0] );
|
||
CopyUchar1( &UnpackedBios->Media, &Bios->Media[0] );
|
||
CopyUchar2( &UnpackedBios->SectorsPerFat, &Bios->SectorsPerFat[0] );
|
||
CopyUchar2( &UnpackedBios->SectorsPerTrack, &Bios->SectorsPerTrack[0] );
|
||
CopyUchar2( &UnpackedBios->Heads, &Bios->Heads[0] );
|
||
CopyUchar4( &UnpackedBios->HiddenSectors, &Bios->HiddenSectors[0] );
|
||
CopyUchar4( &UnpackedBios->LargeSectors, &Bios->LargeSectors[0] );
|
||
}
|