Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

479 lines
12 KiB

/*++
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