361 lines
10 KiB
C
361 lines
10 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ntfs_rec.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the mini-file system recognizer for NTFS.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Darryl E. Havens (darrylh) 8-dec-1992
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode, local to I/O system
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "fs_rec.h"
|
|||
|
#include "ntfs_rec.h"
|
|||
|
|
|||
|
//
|
|||
|
// The local debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (FSREC_DEBUG_LEVEL_NTFS)
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE,NtfsRecFsControl)
|
|||
|
#pragma alloc_text(PAGE,IsNtfsVolume)
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NtfsRecFsControl(
|
|||
|
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;
|
|||
|
LARGE_INTEGER secondByteOffset;
|
|||
|
LARGE_INTEGER lastByteOffset;
|
|||
|
UNICODE_STRING driverName;
|
|||
|
ULONG bytesPerSector;
|
|||
|
LARGE_INTEGER numberOfSectors;
|
|||
|
|
|||
|
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 an NTFS 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 NTFS file system.
|
|||
|
//
|
|||
|
|
|||
|
status = STATUS_UNRECOGNIZED_VOLUME;
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to determine whether or not the target volume being mounted
|
|||
|
// is an NTFS volume.
|
|||
|
//
|
|||
|
|
|||
|
targetDevice = irpSp->Parameters.MountVolume.DeviceObject;
|
|||
|
|
|||
|
if (FsRecGetDeviceSectorSize( targetDevice,
|
|||
|
&bytesPerSector ) &&
|
|||
|
FsRecGetDeviceSectors( targetDevice,
|
|||
|
bytesPerSector,
|
|||
|
&numberOfSectors )) {
|
|||
|
|
|||
|
byteOffset.QuadPart = 0;
|
|||
|
buffer = NULL;
|
|||
|
secondByteOffset.QuadPart = numberOfSectors.QuadPart >> 1;
|
|||
|
secondByteOffset.QuadPart *= (LONG) bytesPerSector;
|
|||
|
lastByteOffset.QuadPart = (numberOfSectors.QuadPart - 1) * (LONG) bytesPerSector;
|
|||
|
|
|||
|
if (FsRecReadBlock( targetDevice,
|
|||
|
&byteOffset,
|
|||
|
sizeof( PACKED_BOOT_SECTOR ),
|
|||
|
bytesPerSector,
|
|||
|
(PVOID *)&buffer,
|
|||
|
NULL ))
|
|||
|
{
|
|||
|
|
|||
|
if (IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
|
|||
|
status = STATUS_FS_DRIVER_REQUIRED;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (FsRecReadBlock( targetDevice,
|
|||
|
&secondByteOffset,
|
|||
|
sizeof( PACKED_BOOT_SECTOR ),
|
|||
|
bytesPerSector,
|
|||
|
(PVOID *)&buffer,
|
|||
|
NULL ) &&
|
|||
|
IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
|
|||
|
|
|||
|
status = STATUS_FS_DRIVER_REQUIRED;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (FsRecReadBlock( targetDevice,
|
|||
|
&lastByteOffset,
|
|||
|
sizeof( PACKED_BOOT_SECTOR ),
|
|||
|
bytesPerSector,
|
|||
|
(PVOID *)&buffer,
|
|||
|
NULL ) &&
|
|||
|
IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
|
|||
|
|
|||
|
status = STATUS_FS_DRIVER_REQUIRED;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (buffer != NULL) {
|
|||
|
ExFreePool( buffer );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case IRP_MN_LOAD_FILE_SYSTEM:
|
|||
|
|
|||
|
status = FsRecLoadFileSystem( DeviceObject,
|
|||
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ntfs" );
|
|||
|
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
|
|||
|
IsNtfsVolume(
|
|||
|
IN PPACKED_BOOT_SECTOR BootSector,
|
|||
|
IN ULONG BytesPerSector,
|
|||
|
IN PLARGE_INTEGER NumberOfSectors
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine looks at the buffer passed in which contains the NTFS boot
|
|||
|
sector and determines whether or not it represents an NTFS volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BootSector - Pointer to buffer containing a potential NTFS boot sector.
|
|||
|
|
|||
|
BytesPerSector - Supplies the number of bytes per sector for the drive.
|
|||
|
|
|||
|
NumberOfSectors - Supplies the number of sectors on the partition.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function returns TRUE if the buffer contains a recognizable NTFS boot
|
|||
|
sector, otherwise it returns FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Now perform all the checks, starting with the Name and Checksum.
|
|||
|
// The remaining checks should be obvious, including some fields which
|
|||
|
// must be 0 and other fields which must be a small power of 2.
|
|||
|
//
|
|||
|
|
|||
|
if (BootSector->Oem[0] == 'N' &&
|
|||
|
BootSector->Oem[1] == 'T' &&
|
|||
|
BootSector->Oem[2] == 'F' &&
|
|||
|
BootSector->Oem[3] == 'S' &&
|
|||
|
BootSector->Oem[4] == ' ' &&
|
|||
|
BootSector->Oem[5] == ' ' &&
|
|||
|
BootSector->Oem[6] == ' ' &&
|
|||
|
BootSector->Oem[7] == ' '
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// Check number of bytes per sector. The low order byte of this
|
|||
|
// number must be zero (smallest sector size = 0x100) and the
|
|||
|
// high order byte shifted must equal the bytes per sector gotten
|
|||
|
// from the device and stored in the Vcb. And just to be sure,
|
|||
|
// sector size must be less than page size.
|
|||
|
//
|
|||
|
|
|||
|
BootSector->PackedBpb.BytesPerSector[0] == 0
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
((ULONG) (BootSector->PackedBpb.BytesPerSector[1] << 8) == BytesPerSector)
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
BootSector->PackedBpb.BytesPerSector[1] << 8 <= PAGE_SIZE
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// Sectors per cluster must be a power of 2.
|
|||
|
//
|
|||
|
|
|||
|
(BootSector->PackedBpb.SectorsPerCluster[0] == 0x1 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x2 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x4 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x8 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x10 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x20 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x40 ||
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] == 0x80)
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// These fields must all be zero. For both Fat and HPFS, some of
|
|||
|
// these fields must be nonzero.
|
|||
|
//
|
|||
|
|
|||
|
BootSector->PackedBpb.ReservedSectors[0] == 0 &&
|
|||
|
BootSector->PackedBpb.ReservedSectors[1] == 0 &&
|
|||
|
BootSector->PackedBpb.Fats[0] == 0 &&
|
|||
|
BootSector->PackedBpb.RootEntries[0] == 0 &&
|
|||
|
BootSector->PackedBpb.RootEntries[1] == 0 &&
|
|||
|
BootSector->PackedBpb.Sectors[0] == 0 &&
|
|||
|
BootSector->PackedBpb.Sectors[1] == 0 &&
|
|||
|
BootSector->PackedBpb.SectorsPerFat[0] == 0 &&
|
|||
|
BootSector->PackedBpb.SectorsPerFat[1] == 0 &&
|
|||
|
BootSector->PackedBpb.LargeSectors[0] == 0 &&
|
|||
|
BootSector->PackedBpb.LargeSectors[1] == 0 &&
|
|||
|
BootSector->PackedBpb.LargeSectors[2] == 0 &&
|
|||
|
BootSector->PackedBpb.LargeSectors[3] == 0
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// Number of Sectors cannot be greater than the number of sectors
|
|||
|
// on the partition.
|
|||
|
//
|
|||
|
|
|||
|
!( BootSector->NumberSectors.QuadPart > NumberOfSectors->QuadPart )
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// Check that both Lcn values are for sectors within the partition.
|
|||
|
//
|
|||
|
|
|||
|
!( BootSector->MftStartLcn.QuadPart *
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] >
|
|||
|
NumberOfSectors->QuadPart )
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
!( BootSector->Mft2StartLcn.QuadPart *
|
|||
|
BootSector->PackedBpb.SectorsPerCluster[0] >
|
|||
|
NumberOfSectors->QuadPart )
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
//
|
|||
|
// Clusters per file record segment and default clusters for Index
|
|||
|
// Allocation Buffers must be a power of 2. A negative number indicates
|
|||
|
// a shift value to get the actual size of the structure.
|
|||
|
//
|
|||
|
|
|||
|
((BootSector->ClustersPerFileRecordSegment >= -31 &&
|
|||
|
BootSector->ClustersPerFileRecordSegment <= -9) ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x1 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x2 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x4 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x8 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x10 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x20 ||
|
|||
|
BootSector->ClustersPerFileRecordSegment == 0x40)
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
((BootSector->DefaultClustersPerIndexAllocationBuffer >= -31 &&
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer <= -9) ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x1 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x2 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x4 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x8 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x10 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x20 ||
|
|||
|
BootSector->DefaultClustersPerIndexAllocationBuffer == 0x40)) {
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This does not appear to be an NTFS volume.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|