480 lines
12 KiB
C
480 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
config.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module provides the configuration information to the
|
|||
|
cluster disk device driver.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rod Gamache (rodga) 7-Dec-1996
|
|||
|
Steal as much code as possible from FTDISK's config.c
|
|||
|
Charlie Wickham (charlwi) 20-Oct-1997
|
|||
|
NT5: stolen from ntos\fstub\drivesup.c
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "clusdskp.h"
|
|||
|
#include "mountmgr.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Size of default work area allocated when getting information from
|
|||
|
// the registry.
|
|||
|
//
|
|||
|
|
|||
|
#define WORK_AREA 4096
|
|||
|
|
|||
|
typedef struct _DRIVE_LETTER_ENTRY {
|
|||
|
struct _DRIVE_LETTER_ENTRY *Next;
|
|||
|
UCHAR DriveLetter;
|
|||
|
UCHAR Fill3[3];
|
|||
|
} DRIVE_LETTER_ENTRY, *PDRIVE_LETTER_ENTRY;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Global data
|
|||
|
//
|
|||
|
|
|||
|
PDRIVE_LETTER_ENTRY ClusDiskDriveLetters = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Forwards
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetDriveLetterFromMountMgr(
|
|||
|
IN LPWSTR PartitionString,
|
|||
|
OUT PUCHAR DriveLetter
|
|||
|
);
|
|||
|
|
|||
|
#pragma alloc_text(PAGE, GetDriveLetterFromMountMgr)
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetDriveLetterFromMountMgr(
|
|||
|
IN LPWSTR PartitionString,
|
|||
|
OUT PUCHAR DriveLetter
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine queries the mount mgr for the drive letter
|
|||
|
of the specified device.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceName - Supplies the device name.
|
|||
|
|
|||
|
DriveLetter - Returns the drive letter or 0 for none.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG partitionStringLength;
|
|||
|
ULONG mountPointSize;
|
|||
|
PMOUNTMGR_MOUNT_POINT mountPoint;
|
|||
|
UNICODE_STRING name;
|
|||
|
NTSTATUS status;
|
|||
|
PFILE_OBJECT fileObject;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
MOUNTMGR_MOUNT_POINTS points;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
ULONG mountPointsSize;
|
|||
|
PMOUNTMGR_MOUNT_POINTS mountPoints;
|
|||
|
BOOLEAN freeMountPoints;
|
|||
|
UNICODE_STRING dosDevices;
|
|||
|
UCHAR driveLetter;
|
|||
|
ULONG i;
|
|||
|
UNICODE_STRING subString;
|
|||
|
WCHAR c;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
partitionStringLength = wcslen( PartitionString ) * sizeof(WCHAR);
|
|||
|
|
|||
|
//
|
|||
|
// allocate a MOUNT_POINT structure plus enough space for the
|
|||
|
// device name to follow
|
|||
|
//
|
|||
|
|
|||
|
mountPointSize = sizeof( MOUNTMGR_MOUNT_POINT ) + partitionStringLength;
|
|||
|
|
|||
|
mountPoint = (PMOUNTMGR_MOUNT_POINT)ExAllocatePool( PagedPool, mountPointSize );
|
|||
|
if (!mountPoint) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory( mountPoint, sizeof( MOUNTMGR_MOUNT_POINT ));
|
|||
|
mountPoint->DeviceNameOffset = (USHORT) sizeof(MOUNTMGR_MOUNT_POINT);
|
|||
|
mountPoint->DeviceNameLength = (USHORT) partitionStringLength;
|
|||
|
RtlCopyMemory( mountPoint + 1, PartitionString, partitionStringLength );
|
|||
|
|
|||
|
//
|
|||
|
// get a pointer to the mount mgr device object and issue the first
|
|||
|
// query to get the size of the data
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &name, MOUNTMGR_DEVICE_NAME );
|
|||
|
status = IoGetDeviceObjectPointer(&name,
|
|||
|
FILE_READ_ATTRIBUTES,
|
|||
|
&fileObject,
|
|||
|
&deviceObject);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(mountPoint);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
|
|||
|
deviceObject,
|
|||
|
mountPoint,
|
|||
|
mountPointSize,
|
|||
|
&points,
|
|||
|
sizeof(points),
|
|||
|
FALSE,
|
|||
|
&event,
|
|||
|
&ioStatus);
|
|||
|
|
|||
|
if (!irp) {
|
|||
|
ObDereferenceObject(fileObject);
|
|||
|
ExFreePool(mountPoint);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(deviceObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// allocate enough space to get all the mount point info
|
|||
|
//
|
|||
|
|
|||
|
if (status == STATUS_BUFFER_OVERFLOW) {
|
|||
|
|
|||
|
mountPointsSize = points.Size;
|
|||
|
mountPoints = (PMOUNTMGR_MOUNT_POINTS)
|
|||
|
ExAllocatePool(PagedPool, mountPointsSize);
|
|||
|
if (!mountPoints) {
|
|||
|
ObDereferenceObject(fileObject);
|
|||
|
ExFreePool(mountPoint);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
|
|||
|
deviceObject,
|
|||
|
mountPoint,
|
|||
|
mountPointSize,
|
|||
|
mountPoints,
|
|||
|
mountPointsSize,
|
|||
|
FALSE,
|
|||
|
&event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(mountPoints);
|
|||
|
ObDereferenceObject(fileObject);
|
|||
|
ExFreePool(mountPoint);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(deviceObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
} else if ( !NT_SUCCESS( status )) {
|
|||
|
ClusDiskPrint((1,"[ClusDisk] GetDLFromMM: 2nd IRP failed %08X\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
|
|||
|
freeMountPoints = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
mountPoints = &points;
|
|||
|
freeMountPoints = FALSE;
|
|||
|
|
|||
|
if ( !NT_SUCCESS( status )) {
|
|||
|
ClusDiskPrint((1,"[ClusDisk] GetDLFromMM: 1st IRP failed %08X\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(mountPoint);
|
|||
|
ObDereferenceObject(fileObject);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
if (freeMountPoints) {
|
|||
|
ExFreePool(mountPoints);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// run through the list of mount points, matching the
|
|||
|
// supplied devicename against the mount point symname.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&dosDevices, L"\\DosDevices\\");
|
|||
|
|
|||
|
driveLetter = 0;
|
|||
|
for (i = 0; i < mountPoints->NumberOfMountPoints; i++) {
|
|||
|
|
|||
|
if (mountPoints->MountPoints[i].SymbolicLinkNameLength !=
|
|||
|
dosDevices.Length + 2*sizeof(WCHAR)) {
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
subString.Length = subString.MaximumLength = dosDevices.Length;
|
|||
|
subString.Buffer = (PWSTR) ((PCHAR) mountPoints +
|
|||
|
mountPoints->MountPoints[i].SymbolicLinkNameOffset);
|
|||
|
|
|||
|
if (RtlCompareUnicodeString(&dosDevices, &subString, TRUE)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
c = subString.Buffer[subString.Length/sizeof(WCHAR) + 1];
|
|||
|
|
|||
|
if (c != ':') {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
c = subString.Buffer[subString.Length/sizeof(WCHAR)];
|
|||
|
|
|||
|
if (c < 'C' || c > 'Z') {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
driveLetter = (UCHAR) c;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (freeMountPoints) {
|
|||
|
ExFreePool(mountPoints);
|
|||
|
}
|
|||
|
|
|||
|
if ( driveLetter != 0 ) {
|
|||
|
*DriveLetter = driveLetter;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
status = STATUS_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
} // ClusDiskQueryMountLetter
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ClusDiskAssignLetter(
|
|||
|
IN UCHAR DriveLetter,
|
|||
|
IN LPWSTR AssignDevice
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
For all of the disks signatures that are supposed to be attached, we
|
|||
|
assign their drive letters to the specified device.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriveLetter - the driver letter to assign to ClusDisk0.
|
|||
|
|
|||
|
AssignDevice - NULL if we are not to assign any device letters,
|
|||
|
NON-NULL if we are.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
} // ClusDiskAssignLetter
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ClusDiskReleaseDriveLetters(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called only when the driver is being unloaded. This
|
|||
|
routine releases all of the drive letters that were assigned to ClusDisk0.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
This routine is only called when UnLoading ClusDisk.
|
|||
|
|
|||
|
2000/02/05: stevedz - This routine appears to be unnecessary.
|
|||
|
|
|||
|
This routine should check if the drive letter is already assigned
|
|||
|
to ClusDisk0 before removing the assignment. Furthermore, it should
|
|||
|
probably reassign the letters back to the original drive, but since
|
|||
|
unload is not really supported, we won't worry about it now.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
} // ClusDiskReleaseDriveLetters
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ClusDiskDismount(
|
|||
|
IN ULONG Signature
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Dismount all partitions on a spindle, using the registry to grovel
|
|||
|
for the drive letters.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Signature - the signature of the device to grovel for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if successful.
|
|||
|
|
|||
|
An NTSTATUS error code on failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
ULONG diskNumber;
|
|||
|
ULONG partIndex;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
WCHAR NameBuffer[sizeof(L"\\Device\\Harddisk999\\Partition999")/sizeof(WCHAR)];
|
|||
|
UCHAR driveLetter;
|
|||
|
PCONFIGURATION_INFORMATION configurationInformation;
|
|||
|
PDRIVE_LAYOUT_INFORMATION DriveLayoutData;
|
|||
|
PPARTITION_INFORMATION partitionInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Get the system configuration information and take a
|
|||
|
// peek at each disk
|
|||
|
//
|
|||
|
|
|||
|
configurationInformation = IoGetConfigurationInformation();
|
|||
|
for (diskNumber = 0;
|
|||
|
diskNumber < configurationInformation->DiskCount;
|
|||
|
diskNumber++)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// get the device name for the physical disk and its
|
|||
|
// partition information
|
|||
|
//
|
|||
|
status = ClusDiskGetTargetDevice(diskNumber,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
&DeviceName,
|
|||
|
&DriveLayoutData,
|
|||
|
NULL,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
ClusDiskPrint((1, "[Clusdisk] Dismount: Can't get target device info - %08X\n",
|
|||
|
status));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if ( DriveLayoutData == NULL ) {
|
|||
|
ClusDiskPrint((1, "[Clusdisk] Dismount: Can't get partition info for disk %u\n",
|
|||
|
diskNumber));
|
|||
|
|
|||
|
RtlFreeUnicodeString(&DeviceName);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Skip till we find our device!
|
|||
|
//
|
|||
|
if ( DriveLayoutData->Signature == Signature ) {
|
|||
|
|
|||
|
for ( partIndex = 0;
|
|||
|
partIndex < DriveLayoutData->PartitionCount;
|
|||
|
partIndex++ )
|
|||
|
{
|
|||
|
|
|||
|
partitionInfo = &DriveLayoutData->PartitionEntry[partIndex];
|
|||
|
|
|||
|
//
|
|||
|
// Make sure this is a valid partition, i.e., it's recognized by
|
|||
|
// a FS and it has a non-zero starting offset and length
|
|||
|
//
|
|||
|
if (!partitionInfo->RecognizedPartition &&
|
|||
|
!partitionInfo->StartingOffset.QuadPart &&
|
|||
|
!partitionInfo->PartitionLength.QuadPart)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
swprintf(NameBuffer,
|
|||
|
L"\\Device\\Harddisk%u\\Partition%u",
|
|||
|
diskNumber,
|
|||
|
partitionInfo->PartitionNumber);
|
|||
|
|
|||
|
RtlInitUnicodeString(&DeviceName, NameBuffer);
|
|||
|
|
|||
|
status = GetDriveLetterFromMountMgr( NameBuffer, &driveLetter );
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && IsAlpha(driveLetter) ) {
|
|||
|
status = DismountPartitionDevice( driveLetter );
|
|||
|
} else {
|
|||
|
ClusDiskPrint((1,
|
|||
|
"[ClusDisk] Dismount: couldn't dismount drive. "
|
|||
|
"status %08X driveLetter %c (%02X)\n",
|
|||
|
status, driveLetter, driveLetter));
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool( DriveLayoutData );
|
|||
|
RtlFreeUnicodeString( &DeviceName );
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
} // ClusDiskDismount
|