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
|