windows-nt/Source/XPSP1/NT/base/cluster/resdll/disks/newmount.c

2086 lines
54 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
newmount.c
Abstract:
Replacement for mountie.c
Author:
Gor Nishanov (GorN) 31-July-1998
Environment:
User Mode
Revision History:
--*/
#include <nt.h>
#include <ntdef.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <devioctl.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <mountmgr.h>
#include <winioctl.h>
#include <ntddscsi.h>
#include "clusdisk.h"
#include "disksp.h"
#include "newmount.h"
#define LOG_CURRENT_MODULE LOG_MODULE_DISK
extern PWCHAR DEVICE_HARDDISK_PARTITION_FMT; // L"\\Device\\Harddisk%u\\Partition%u" //
extern PWCHAR GLOBALROOT_HARDDISK_PARTITION_FMT; // L"\\\\\?\\GLOBALROOT\\Device\\Harddisk%u\\Partition%u\\";
#define MOUNTIE_VOLUME_INFO L"MountVolumeInfo"
#define DISKS_DISK_INFO L"DiskInfo"
#define BOGUS_BUFFER_LENGTH 512
#define FIRST_SHOT_SIZE 512
//
// LETTER_ASSIGNMENT structure is used to store letter assignment
// information from various information providers
//
typedef USHORT PARTITION_NUMBER_TYPE;
typedef struct _LETTER_ASSIGNMENT {
DWORD MatchCount;
DWORD MismatchCount;
DWORD DriveLetters;
PARTITION_NUMBER_TYPE PartNumber[26];
} LETTER_ASSIGNMENT, *PLETTER_ASSIGNMENT;
DWORD
MountMgr_Get(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry,
PLETTER_ASSIGNMENT Result);
/*
* DoIoctlAndAllocate - allocates a result buffer and
* tries to perform DeviceIoControl, it it fails due to insufficient buffer,
* it tries again with a bigger buffer.
*
* FIRST_SHOT_SIZE is a constant that regulates the size of the buffer
* for the first attempt to do DeviceIoControl.
*
* Return a non-zero code for error.
*/
PVOID
DoIoctlAndAllocate(
IN HANDLE FileHandle,
IN DWORD IoControlCode,
IN PVOID InBuf,
IN ULONG InBufSize,
OUT LPDWORD BytesReturned
)
{
UCHAR firstShot[ FIRST_SHOT_SIZE ];
DWORD status = ERROR_SUCCESS;
BOOL success;
DWORD outBufSize;
PVOID outBuf = 0;
DWORD bytesReturned;
success = DeviceIoControl( FileHandle,
IoControlCode,
InBuf,
InBufSize,
&firstShot,
sizeof(firstShot),
&bytesReturned,
(LPOVERLAPPED) NULL );
if ( success ) {
outBufSize = bytesReturned;
outBuf = malloc( outBufSize );
if (!outBuf) {
status = ERROR_OUTOFMEMORY;
} else {
RtlCopyMemory(outBuf, &firstShot, outBufSize);
status = ERROR_SUCCESS;
}
} else {
outBufSize = sizeof(firstShot);
for(;;) {
status = GetLastError();
//
// If it is not a buffer size related error, then we cannot do much
//
if ( status != ERROR_INSUFFICIENT_BUFFER
&& status != ERROR_MORE_DATA
&& status != ERROR_BAD_LENGTH
) {
break;
}
//
// Otherwise, try an outbut buffer twice the previous size
//
outBufSize *= 2;
outBuf = malloc( outBufSize );
if ( !outBuf ) {
status = ERROR_OUTOFMEMORY;
break;
}
success = DeviceIoControl( FileHandle,
IoControlCode,
InBuf,
InBufSize,
outBuf,
outBufSize,
&bytesReturned,
(LPOVERLAPPED) NULL );
if (success) {
status = ERROR_SUCCESS;
break;
}
free( outBuf );
}
}
if (status != ERROR_SUCCESS) {
free( outBuf ); // free( 0 ) is legal //
outBuf = 0;
bytesReturned = 0;
}
SetLastError( status );
*BytesReturned = bytesReturned;
return outBuf;
}
/*
* DevfileOpen - open a device file given a pathname
*
* Return a non-zero code for error.
*/
NTSTATUS
DevfileOpen(
OUT HANDLE *Handle,
IN wchar_t *pathname
)
{
HANDLE fh;
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING cwspath;
NTSTATUS status;
IO_STATUS_BLOCK iostatus;
RtlInitUnicodeString(&cwspath, pathname);
InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
NULL, NULL);
fh = NULL;
status = NtOpenFile(&fh,
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
&objattrs, &iostatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_ALERT);
if (status != STATUS_SUCCESS) {
return status;
}
if ( !NT_SUCCESS(iostatus.Status) ) {
if (fh) {
NtClose(fh);
}
return iostatus.Status;
}
*Handle = fh;
return STATUS_SUCCESS;
} // DevfileOpen
/*
* DevfileClose - close a file
*/
VOID
DevfileClose(
IN HANDLE Handle
)
{
NtClose(Handle);
} // DevFileClose
/*
* DevfileIoctl - issue an ioctl to a device
*/
NTSTATUS
DevfileIoctl(
IN HANDLE Handle,
IN DWORD Ioctl,
IN PVOID InBuf,
IN ULONG InBufSize,
IN OUT PVOID OutBuf,
IN DWORD OutBufSize,
OUT LPDWORD returnLength
)
{
NTSTATUS status;
IO_STATUS_BLOCK ioStatus;
status = NtDeviceIoControlFile(Handle,
(HANDLE) NULL,
(PIO_APC_ROUTINE) NULL,
NULL,
&ioStatus,
Ioctl,
InBuf, InBufSize,
OutBuf, OutBufSize);
if ( status == STATUS_PENDING ) {
status = NtWaitForSingleObject( Handle, FALSE, NULL );
}
if ( NT_SUCCESS(status) ) {
status = ioStatus.Status;
}
if ( ARGUMENT_PRESENT(returnLength) ) {
*returnLength = (ULONG)ioStatus.Information;
}
return status;
} // DevfileIoctl
#define OUTPUT_BUFFER_LEN (1024)
#define INPUT_BUFFER_LEN (sizeof(MOUNTMGR_MOUNT_POINT) + 2 * MAX_PATH * sizeof(WCHAR))
DWORD
DisksAssignDosDeviceM(
HANDLE MountManager,
PCHAR MountName,
PWCHAR VolumeDevName
)
/*++
Routine Description:
Inputs:
MountManager - Handle to MountMgr
MountName -
VolumeDevName -
Return value:
A Win32 error code.
--*/
{
WCHAR mount_device[MAX_PATH];
USHORT mount_point_len;
USHORT dev_name_len;
DWORD status;
USHORT inputlength;
PMOUNTMGR_CREATE_POINT_INPUT input;
swprintf(mount_device, L"\\DosDevices\\%S\0", MountName);
mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
dev_name_len = wcslen(VolumeDevName) * sizeof(WCHAR);
inputlength = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
mount_point_len + dev_name_len;
input = (PMOUNTMGR_CREATE_POINT_INPUT)malloc(inputlength);
if (!input) {
return ERROR_NOT_ENOUGH_MEMORY;
}
input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
input->SymbolicLinkNameLength = mount_point_len;
input->DeviceNameOffset = input->SymbolicLinkNameOffset +
input->SymbolicLinkNameLength;
input->DeviceNameLength = dev_name_len;
RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
mount_device, mount_point_len);
RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
VolumeDevName, dev_name_len);
status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_CREATE_POINT,
input, inputlength, NULL, 0, NULL);
free(input);
return status;
} // DisksAssignDosDevice
DWORD
DisksRemoveDosDeviceM(
HANDLE MountManager,
PCHAR MountName
)
/*++
Routine Description:
Inputs:
MountManager - Handle to MountMgr
MountName -
Return value:
--*/
{
WCHAR mount_device[MAX_PATH];
USHORT mount_point_len;
USHORT dev_name_len;
DWORD status;
USHORT inputlength;
PMOUNTMGR_MOUNT_POINT input;
PUCHAR bogusBuffer; // this buffer should NOT be required!
DWORD bogusBufferLength = BOGUS_BUFFER_LENGTH;
//
// Remove old mount points for this mount name.
//
swprintf(mount_device, L"\\DosDevices\\%S", MountName);
mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
inputlength = sizeof(MOUNTMGR_MOUNT_POINT) + mount_point_len;
input = (PMOUNTMGR_MOUNT_POINT)malloc(inputlength);
if (!input) {
return ERROR_NOT_ENOUGH_MEMORY;
}
bogusBuffer = malloc(bogusBufferLength);
if (!bogusBuffer) {
free(input);
return ERROR_NOT_ENOUGH_MEMORY;
}
input->UniqueIdOffset = 0;
input->UniqueIdLength = 0;
input->DeviceNameOffset = 0;
input->DeviceNameLength = 0;
input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
input->SymbolicLinkNameLength = mount_point_len;
RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
mount_device, mount_point_len);
do {
status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_DELETE_POINTS,
input, inputlength, bogusBuffer, bogusBufferLength, NULL);
free( bogusBuffer );
if ( status == ERROR_MORE_DATA ) {
bogusBufferLength += BOGUS_BUFFER_LENGTH;
bogusBuffer = malloc(bogusBufferLength);
if (!bogusBuffer) {
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
} while ( status == ERROR_MORE_DATA );
free(input);
//
// Use the 'old-style' name on error in case we got a 'half-built' stack.
//
if ( status != ERROR_SUCCESS ) {
DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM,
MountName,
NULL );
}
return status;
} // DisksRemoveDosDevice
static
NTSTATUS
GetAssignedLetterM (
IN HANDLE MountMgrHandle,
IN PWCHAR deviceName,
OUT PCHAR driveLetter )
/*++
Routine Description:
Get an assigned drive letter from MountMgr, if any
Inputs:
MountMgrHandle -
deviceName -
driveLetter - receives drive letter
Return value:
STATUS_SUCCESS - on success
NTSTATUS code - on failure
--*/
{
DWORD status = STATUS_SUCCESS;
PMOUNTMGR_MOUNT_POINT input = NULL;
PMOUNTMGR_MOUNT_POINTS output = NULL;
PMOUNTMGR_MOUNT_POINT out;
DWORD len = wcslen( deviceName ) * sizeof(WCHAR);
DWORD bytesReturned;
DWORD idx;
DWORD outputLen;
DWORD inputLen;
WCHAR wc;
inputLen = INPUT_BUFFER_LEN;
input = LocalAlloc( LPTR, inputLen );
if ( !input ) {
goto FnExit;
}
input->SymbolicLinkNameOffset = 0;
input->SymbolicLinkNameLength = 0;
input->UniqueIdOffset = 0;
input->UniqueIdLength = 0;
input->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
input->DeviceNameLength = (USHORT) len;
RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
deviceName, len );
if (len > sizeof(WCHAR) && deviceName[1] == L'\\') {
// convert Dos name to NT name
((PWCHAR)(input + input->DeviceNameOffset))[1] = L'?';
}
outputLen = OUTPUT_BUFFER_LEN;
output = LocalAlloc( LPTR, outputLen );
if ( !output ) {
goto FnExit;
}
status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
input, inputLen, output, outputLen, &bytesReturned);
if ( STATUS_BUFFER_OVERFLOW == status ) {
outputLen = output->Size;
LocalFree( output );
output = LocalAlloc( LPTR, outputLen );
if ( !output ) {
goto FnExit;
}
status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
input, inputLen, output, outputLen, &bytesReturned);
}
if ( !NT_SUCCESS(status) ) {
goto FnExit;
}
if (driveLetter) {
*driveLetter = 0;
}
for ( idx = 0; idx < output->NumberOfMountPoints; ++idx ) {
out = &output->MountPoints[idx];
if (out->SymbolicLinkNameLength/sizeof(WCHAR) == 14 &&
(_wcsnicmp((PWCHAR)((PCHAR)output + out->SymbolicLinkNameOffset), L"\\DosDevices\\", 12) == 0) &&
L':' == *((PCHAR)output + out->SymbolicLinkNameOffset + 13*sizeof(WCHAR)) )
{
wc = *((PCHAR)output + out->SymbolicLinkNameOffset + 12*sizeof(WCHAR));
if (driveLetter && out->UniqueIdLength) {
*driveLetter = (CHAR)toupper((UCHAR)wc);
break;
}
}
}
FnExit:
if ( output ) {
LocalFree( output );
}
if ( input ) {
LocalFree( input );
}
return status;
}
BOOL
InterestingPartition(
PPARTITION_INFORMATION info
)
/*++
Routine Description:
Quick check whether a partition is "interesting" for us
Inputs:
info - GetDriveLayout's partition information
Return value:
TRUE or FALSE
--*/
{
return ( (info->RecognizedPartition)
&& ((info->PartitionType == PARTITION_IFS) ||
IsContainerPartition(info->PartitionType)) );
}
PMOUNTIE_VOLUME
CreateMountieVolumeFromDriveLayoutInfo (
IN PDRIVE_LAYOUT_INFORMATION info,
IN HANDLE ResourceHandle
)
/*++
Routine Description:
Collects all interesing partition from DriveLayoutInformation
then it allocates and fills MountieVolume structure
Inputs:
info - GetDriveLayout's information
ResourceHandle - for error logging - not used (may be NULL!)
Return value:
TRUE or FALSE
--*/
{
DWORD i;
DWORD nPartitions = 0;
PMOUNTIE_VOLUME vol;
PMOUNTIE_PARTITION mountie;
DWORD size;
//
// Count Partitions
//
for (i = 0; i < info->PartitionCount; ++i) {
if ( InterestingPartition( info->PartitionEntry + i ) ) {
++nPartitions;
}
}
if (!nPartitions) {
SetLastError(ERROR_INVALID_DATA);
return 0;
}
//
// Allocate memory for Mountie structure
//
size = sizeof(MOUNTIE_VOLUME) + sizeof(MOUNTIE_PARTITION) * (nPartitions - 1);
vol = malloc( size );
if (!vol) {
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
RtlZeroMemory(vol, size);
vol->PartitionCount = nPartitions;
vol->Signature = info->Signature;
//
// Copy all relevant Information from DriveLayout info
//
mountie = vol->Partition;
for (i = 0; i < info->PartitionCount; ++i) {
PPARTITION_INFORMATION entry = info->PartitionEntry + i;
if ( InterestingPartition(entry) ) {
mountie->StartingOffset = entry->StartingOffset;
mountie->PartitionLength = entry->PartitionLength;
mountie->PartitionNumber = entry->PartitionNumber;
mountie->PartitionType = entry->PartitionType;
++mountie;
}
}
return vol;
}
VOID
MountieUpdateDriveLetters(
IN OUT PMOUNTIE_INFO info
)
/*++
Routine Description:
Updates DriveLetter bitmap.
This routine needs to be called every time
drive letter information is changed in MountieInfo
Inputs:
info - MountieInfo
--*/
{
DWORD i;
DWORD driveLetters = 0;
PMOUNTIE_VOLUME vol = info->Volume;
if (vol) {
for (i = 0; i < vol->PartitionCount; ++i) {
UCHAR ch = vol->Partition[i].DriveLetter;
if (ch) {
driveLetters |= 1 << (ch - 'A');
}
}
}
info->DriveLetters = driveLetters;
}
PMOUNTIE_PARTITION
MountiePartitionByOffsetAndLength(
IN PMOUNTIE_INFO Info,
LARGE_INTEGER Offset, LARGE_INTEGER Len)
{
DWORD PartitionCount;
PMOUNTIE_PARTITION entry;
if (!Info->Volume) {
return 0;
}
PartitionCount = Info->Volume->PartitionCount;
entry = Info->Volume->Partition;
while ( PartitionCount-- ) {
if (entry->StartingOffset.QuadPart == Offset.QuadPart
&& entry->PartitionLength.QuadPart == Len.QuadPart) {
return entry;
}
++entry;
}
return 0;
}
DWORD
MountiePartitionCount(
IN PMOUNTIE_INFO Info)
{
if (Info->Volume) {
return Info->Volume->PartitionCount;
} else {
return 0;
}
}
PMOUNTIE_PARTITION
MountiePartition(
IN PMOUNTIE_INFO Info,
IN DWORD Index)
{
return Info->Volume->Partition + Index;
}
PMOUNTIE_PARTITION
MountiePartitionByPartitionNo(
IN PMOUNTIE_INFO Info,
IN DWORD PartitionNumber
)
{
DWORD i, n;
PMOUNTIE_PARTITION entry;
if (Info->Volume == 0) {
return 0;
}
n = Info->Volume->PartitionCount;
entry = Info->Volume->Partition;
for (i = 0; i < n; ++i, ++entry) {
if (entry->PartitionNumber == PartitionNumber)
{
return entry;
}
}
return 0;
}
VOID
MountiePrint(
IN PMOUNTIE_INFO Info,
IN HANDLE ResourceHandle
)
{
DWORD i, n;
PMOUNTIE_PARTITION entry;
if (Info->Volume == 0) {
return;
}
n = Info->Volume->PartitionCount;
entry = Info->Volume->Partition;
for (i = 0; i < n; ++i, ++entry) {
(DiskpLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Mountie[%1!u!]: %2!u!, let=%3!c!, start=%4!X!, len=%5!X!.\n",
i,
entry->PartitionNumber,
NICE_DRIVE_LETTER(entry->DriveLetter),
entry->StartingOffset.LowPart,
entry->PartitionLength.LowPart );
}
}
DWORD
DisksGetLettersForSignature(
IN PDISK_RESOURCE ResourceEntry
)
{
return ResourceEntry->MountieInfo.DriveLetters;
}
DWORD
MountieRecreateVolumeInfoFromHandle(
IN HANDLE FileHandle,
IN DWORD HarddiskNo,
IN HANDLE ResourceHandle,
IN OUT PMOUNTIE_INFO Info
)
/*++
Routine Description:
Recreate a MountieInfo that has no
DriveLetter assignments.
IMPORTANT!!! The code assumes that Info->Volume
either contains a valid pointer or NULL
Inputs:
ResourceHandle - may be NULL.
Outputs:
Info - MountieInfo
--*/
{
PDRIVE_LAYOUT_INFORMATION layout;
DWORD status;
DWORD bytesReturned;
free( Info->Volume ); // free(0) is OK //
Info->HarddiskNo = HarddiskNo;
Info->DriveLetters = 0;
Info->Volume = 0;
Info->VolumeStructSize = 0;
layout = DoIoctlAndAllocate(
FileHandle, IOCTL_DISK_GET_DRIVE_LAYOUT, 0,0, &bytesReturned);
if (!layout) {
return GetLastError();
}
status = ERROR_SUCCESS;
try {
Info->Volume = CreateMountieVolumeFromDriveLayoutInfo( layout , ResourceHandle );
if (!Info->Volume) {
status = GetLastError();
leave;
}
Info->VolumeStructSize = sizeof(MOUNTIE_VOLUME) +
sizeof(MOUNTIE_PARTITION) * (Info->Volume->PartitionCount - 1);
} finally {
free( layout );
}
if ( ResourceHandle ) MountiePrint(Info, ResourceHandle);
return status;
}
DWORD
MountieFindPartitionsForDisk(
IN DWORD HarddiskNo,
OUT PMOUNTIE_INFO MountieInfo
)
/*++
Note that Caller of this routine is responsible for freeing Volume Information
via call to MountieCleanup().
--*/
{
UCHAR deviceName[MAX_PATH];
HANDLE fileHandle;
DWORD status;
sprintf( deviceName,
"\\\\.\\PhysicalDrive%u",
HarddiskNo );
ASSERT( strlen(deviceName) < sizeof( deviceName ));
fileHandle = CreateFile( deviceName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
if ( (fileHandle == NULL) ||
(fileHandle == INVALID_HANDLE_VALUE) ) {
status = GetLastError();
return status;
}
RtlZeroMemory( MountieInfo, sizeof(MOUNTIE_INFO) );
status = MountieRecreateVolumeInfoFromHandle(
fileHandle,
HarddiskNo,
NULL,
MountieInfo );
if ( status != ERROR_SUCCESS ) {
CloseHandle( fileHandle );
return status;
}
CloseHandle( fileHandle );
return(ERROR_SUCCESS);
} // MountieFindPartitionsForDisk
VOID
MountieCleanup(
IN OUT PMOUNTIE_INFO Info
)
/*++
Routine Description:
Deallocates Volume information
Inputs:
Info - MountieInfo
--*/
{
PVOID volume;
Info->VolumeStructSize = 0;
volume = InterlockedExchangePointer(&(Info->Volume), 0);
free(volume);
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Disk information is specified in different formats in various places
//
// The following code is an attempt to provide some common denominator
// to simplify verification of all disk information and keeping it in sync.
//
UCHAR
AssignedLetterByPartitionNumber (
PLETTER_ASSIGNMENT Assignment,
DWORD PartitionNo)
/*++
Routine Description:
Returns a drive letter assigned to a partition
Inputs:
Assignment - drive letter assignment info
PartitionNo - partition number (As in Harddisk0\PartitionX)
--*/
{
UCHAR i;
for( i = 0; i < 26; ++i ) {
if (Assignment->PartNumber[i] == PartitionNo) {
return ('A' + i);
}
}
return 0;
}
// For every different way to describe a disk information
// there should be two functions defined GetInfo and SetInfo
// which will read/write the information into/from LETTER_ASSIGNMENT structure
typedef DWORD (*GetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry, PLETTER_ASSIGNMENT Result);
typedef DWORD (*SetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry);
//
// The following structure is a description of disk information provider.
//
// It is used to bind a provider name (Used as a label in error logging)
// and information access routines
//
typedef struct _INFO_PROVIDER {
PWCHAR Name;
GetInfoFunc GetInfo;
SetInfoFunc SetInfo;
} INFO_PROVIDER, *PINFO_PROVIDER;
////////////////////////////////////////////////////////////////////
//
// The following routine gets FtInfo, by reading existing one or
// creating an empty one if there is no System\DISK in the registry)
//
// Then it adds/updates drive letter assignment for the specified drive,
// using the information supplied in MOUNTIE_INFO structure.
//
PFT_INFO
FtInfo_CreateFromMountie(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry)
{
PFT_INFO ftInfo = 0;
DWORD i, n;
DWORD Status = ERROR_SUCCESS;
PMOUNTIE_PARTITION entry;
try {
ftInfo = DiskGetFtInfo();
if ( !ftInfo ) {
(DiskpLogEvent)(ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Failed to get FtInfo.\n");
Status = ERROR_NOT_ENOUGH_MEMORY;
ftInfo = 0;
leave;
}
Status = DiskAddDiskInfoEx( ftInfo,
ResourceEntry->DiskInfo.PhysicalDrive,
ResourceEntry->DiskInfo.Params.Signature,
DISKRTL_REPLACE_IF_EXISTS );
if ( Status != ERROR_SUCCESS ) {
(DiskpLogEvent)(ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error %1!d! adding DiskInfo.\n",
Status);
ftInfo = 0;
leave;
}
n = Info->Volume->PartitionCount;
entry = Info->Volume->Partition;
//
// Now add the partition info for each partition
//
for ( i = 0; i < n; ++i,++entry ) {
UCHAR driveLetter;
Status = DiskAddDriveLetterEx( ftInfo,
ResourceEntry->DiskInfo.Params.Signature,
entry->StartingOffset,
entry->PartitionLength,
entry->DriveLetter, 0);
if ( Status != ERROR_SUCCESS ) {
(DiskpLogEvent)(ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error %1!d! adding partition %2!x!:%3!x! letter %4!X! sig %5!x!.\n",
Status, entry->StartingOffset.LowPart,
entry->PartitionLength.LowPart,
entry->DriveLetter,
Info->Volume->Signature);
break;
}
}
} finally {
if (Status != ERROR_SUCCESS) {
SetLastError(Status);
if (ftInfo) {
DiskFreeFtInfo(ftInfo);
ftInfo = 0;
}
}
}
return ftInfo;
}
DWORD FtInfo_GetFromFtInfo(
IN PMOUNTIE_INFO Info,
IN PDISK_RESOURCE ResourceEntry,
IN PFT_INFO FtInfo,
IN OUT PLETTER_ASSIGNMENT Result)
{
DWORD i, n;
PFT_DISK_INFO FtDisk;
FtDisk = FtInfo_GetFtDiskInfoBySignature(
FtInfo, ResourceEntry->DiskInfo.Params.Signature);
if ( !FtDisk ) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"FtInfo_GetFromFtInfo: GetFtDiskInfoBySignature failed.\n");
++Result->MismatchCount;
return ERROR_NOT_FOUND;
}
n = FtDiskInfo_GetPartitionCount(FtDisk);
if (n == 0) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"FtInfo_GetFromFtInfo: DiskInfo has no partitions.\n");
++Result->MismatchCount;
return ERROR_NOT_FOUND;
}
// sanity check //
// number 10 is completely arbitrary //
if (n > Info->Volume->PartitionCount * 10) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"FtInfo_GetFromFtInfo: DiskInfo has %1!u! partitions!\n", n);
n = Info->Volume->PartitionCount * 10;
}
for(i = 0; i < n; ++i) {
DISK_PARTITION UNALIGNED *entry;
PMOUNTIE_PARTITION mountie;
entry = FtDiskInfo_GetPartitionInfoByIndex(FtDisk, i);
mountie = MountiePartitionByOffsetAndLength(
Info,
entry->StartingOffset,
entry->Length);
if (mountie) {
UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
if ( isalpha(ch) ) {
ch -= 'A';
Result->DriveLetters |= ( 1 << ch );
Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
++Result->MatchCount;
}
} else {
//
// Chittur Subbaraman (chitturs) - 11/5/98
//
// Added the following 4 statements for event logging in MountieVerify
//
UCHAR uch = (UCHAR)toupper( entry->DriveLetter );
if ( isalpha(uch) ) {
uch -= 'A';
Result->DriveLetters |= ( 1 << uch );
}
++Result->MismatchCount;
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"Strange partition: %1!X!, %2!X!, Type=%3!u!, letter=%4!c!.\n",
entry->StartingOffset.LowPart, entry->Length.LowPart,
entry->FtType, NICE_DRIVE_LETTER(entry->DriveLetter) );
}
}
return ERROR_SUCCESS;
}
/////////////////////////////////////////////////////////////////
//
// NT4 style System\DISK and ClusReg\DiskInfo
// accessing routines
//
// ClusDiskInfo_Get
// ClusDiskInfo_Set
// FtInfo_Get
// FtInfo_Set
//
DWORD
CluDiskInfo_Get(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry,
PLETTER_ASSIGNMENT Result)
{
DWORD Length;
DWORD Status;
DWORD errorLevel;
PFULL_DISK_INFO DiskInfo = 0;
try {
//
// Read out the diskinfo parameter from our resource.
//
Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
DISKS_DISK_INFO,
NULL,
NULL,
&Length);
if (Status == ERROR_SUCCESS ) {
DiskInfo = malloc(Length);
if (!DiskInfo) {
Status = ERROR_OUTOFMEMORY;
} else {
Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
DISKS_DISK_INFO,
NULL,
(LPBYTE)DiskInfo,
&Length);
if (Status == ERROR_SUCCESS) {
PFT_INFO ftInfo = DiskGetFtInfoFromFullDiskinfo(DiskInfo);
if (ftInfo) {
Status = FtInfo_GetFromFtInfo(Info,
ResourceEntry,
ftInfo,
Result);
DiskFreeFtInfo(ftInfo);
} else {
Status = GetLastError();
}
}
}
}
} finally {
if (Status != ERROR_SUCCESS) {
if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
// No drive letters, we are using mount points and this is not an error.
errorLevel = LOG_WARNING;
} else {
// Drive letters exist, this is likely an error.
errorLevel = LOG_ERROR;
}
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
errorLevel,
L"CluDiskInfo_Get: Status=%1!u!.\n", Status);
++Result->MismatchCount;
}
free(DiskInfo);
}
return ERROR_SUCCESS;
}
DWORD
FtInfo_Get(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry,
PLETTER_ASSIGNMENT Result)
{
PFT_INFO FtInfo;
DWORD Status;
//
// Get registry info.
//
FtInfo = DiskGetFtInfo();
if ( !FtInfo ) {
return ERROR_OUTOFMEMORY;
}
Status = FtInfo_GetFromFtInfo(Info, ResourceEntry, FtInfo, Result);
DiskFreeFtInfo(FtInfo);
if (Status != ERROR_SUCCESS) {
++Result->MismatchCount;
}
return ERROR_SUCCESS;
}
DWORD
FtInfo_Set(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry)
{
PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
if (ftInfo) {
DWORD status = DiskCommitFtInfo(ftInfo);
if (status != ERROR_SUCCESS) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"FtInfo_Set: CommitFtInfo status = %1!u!.\n", status);
} else {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"FtInfo_Set: Update successful.\n");
}
DiskFreeFtInfo(ftInfo);
return status;
} else {
DWORD status = GetLastError();
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"FtInfoSet: CreateFromMountie failed, status = %1!u!.\n", status);
return status;
}
}
DWORD
CluDiskInfo_Set(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry)
{
PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
if (ftInfo) {
PFULL_DISK_INFO DiskInfo;
DWORD Length;
DWORD Status;
DiskInfo = DiskGetFullDiskInfo( ftInfo,
ResourceEntry->DiskInfo.Params.Signature,
&Length );
if ( DiskInfo ) {
Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
DISKS_DISK_INFO,
REG_BINARY,
(CONST BYTE *)DiskInfo,
Length);
if (Status != ERROR_SUCCESS && Status != ERROR_SHARING_PAUSED) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"CluDiskInfo_Set: Data Length = %1!u!.\n", Length);
}
LocalFree( DiskInfo );
} else {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"CluDiskInfo_Set: Disk with signature %1!x! is not found. Error=%2!u!\n", ResourceEntry->DiskInfo.Params.Signature, GetLastError());
Status = ERROR_FILE_NOT_FOUND;
}
DiskFreeFtInfo(ftInfo);
return Status;
} else {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"CluDiskInfo_Set: Failed to create FtInfo.\n");
return GetLastError();
}
}
////////////////////////////////////////////////////////
//
// New NT5 clusreg volume information access routines
//
// Mountie_Get
// Mountie_Set
//
//////////
DWORD
Mountie_Get(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry,
PLETTER_ASSIGNMENT Result)
{
DWORD Length = 0; // Prefix bug 56153: initialize variable.
DWORD Status;
PMOUNTIE_VOLUME Volume = NULL;
DWORD i, n;
PMOUNTIE_PARTITION entry;
try {
//
// Read out the diskinfo parameter from our resource.
//
Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
MOUNTIE_VOLUME_INFO,
NULL,
NULL,
&Length);
if (Status == ERROR_FILE_NOT_FOUND ) {
++Result->MismatchCount;
Status = ERROR_SUCCESS;
leave;
}
//
// Prefix bug 56153: Make sure the length is valid before allocating
// memory.
//
if ( !Length ) {
Status = ERROR_BAD_LENGTH;
leave;
}
Volume = malloc(Length);
if (!Volume) {
Status = ERROR_OUTOFMEMORY;
leave;
}
Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
MOUNTIE_VOLUME_INFO,
NULL,
(LPBYTE)Volume,
&Length);
if (Status != ERROR_SUCCESS) {
leave;
}
if (Length < sizeof(MOUNTIE_VOLUME) ) {
++Result->MismatchCount;
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Get: MountVolumeInfo key is truncated. Cannot read header, length %1!d!.\n", Length);
Status = ERROR_SUCCESS;
leave;
}
n = Volume->PartitionCount;
entry = Volume->Partition;
if (n == 0) {
++Result->MismatchCount;
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Get: MountVolumeInfo key is corrupted. No partitions.\n");
Status = ERROR_SUCCESS;
leave;
}
if ( Length < (sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION)) ) {
DWORD delta = sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION) - Length;
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Get: MountVolumeInfo key is corrupted. "
L"Length %1!d!, PartitionCount %2!d!, delta %3!d!.\n", Length, n, delta);
++Result->MismatchCount;
Status = ERROR_SUCCESS;
leave;
}
for (i = 0; i < n; ++i, ++entry) {
PMOUNTIE_PARTITION mountie;
mountie = MountiePartitionByOffsetAndLength(
Info,
entry->StartingOffset,
entry->PartitionLength);
if (mountie) {
UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
if ( isalpha(ch) ) {
ch -= 'A';
Result->DriveLetters |= ( 1 << ch );
Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
++Result->MatchCount;
}
} else {
++Result->MismatchCount;
}
}
} finally {
if (Status != ERROR_SUCCESS) {
++Result->MismatchCount;
}
free(Volume);
}
return ERROR_SUCCESS;
}
DWORD
Mountie_Set(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry)
{
DWORD Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
MOUNTIE_VOLUME_INFO,
REG_BINARY,
(LPBYTE)Info->Volume,
Info->VolumeStructSize);
return Status;
}
///////////////////////////////////////////////////////////
//
// NT5 MountManager's volume information access routines
//
// MountMgr_Get
// MountMgr_Set
//
//////////
DWORD
MountMgr_Get(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry,
PLETTER_ASSIGNMENT Result)
{
DWORD PartitionCount = Info->Volume->PartitionCount;
DWORD i;
DWORD error;
NTSTATUS ntStatus;
HANDLE MountManager;
ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
if (!NT_SUCCESS(ntStatus)) {
if ( ResourceEntry ) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Get: MountMgr open failed, status %1!X!.\n", ntStatus);
}
return RtlNtStatusToDosError(ntStatus);
}
error = ERROR_SUCCESS;
try {
for (i = 0; i < PartitionCount; ++i) {
PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
WCHAR DeviceName[MAX_PATH];
UCHAR ch;
swprintf(DeviceName, DEVICE_HARDDISK_PARTITION_FMT,
Info->HarddiskNo, entry->PartitionNumber);
ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
if ( NT_SUCCESS(ntStatus) ) {
if (Result && ch) {
ch -= 'A';
Result->DriveLetters |= ( 1 << ch );
Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) entry->PartitionNumber;
++Result->MatchCount;
}
} else {
if ( ResourceEntry ) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Get Assigned Letter for %1!ws! returned status %2!X!.\n", DeviceName, ntStatus);
}
error = RtlNtStatusToDosError(ntStatus);
leave;
}
}
} finally {
DevfileClose(MountManager);
}
return error;
}
DWORD
MountMgr_Set(
PMOUNTIE_INFO Info,
PDISK_RESOURCE ResourceEntry
)
{
HANDLE MountManager;
DWORD PartitionCount = Info->Volume->PartitionCount;
DWORD i, status;
UCHAR dosName[3];
NTSTATUS ntStatus;
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountMgr_Set: Entry\n");
ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
if (!NT_SUCCESS(ntStatus)) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Set: MountMgr open failed, status %1!X!.\n", ntStatus);
return RtlNtStatusToDosError(ntStatus);
}
try {
dosName[1] = ':';
dosName[2] = '\0';
//
// Remove old assignment of letters we are going to use
//
for (i = 0; i < 26; ++i) {
if ( (1 << i) & Info->DriveLetters ) {
dosName[0] = (UCHAR)('A' + i);
status = DisksRemoveDosDeviceM(MountManager, dosName);
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountMgr_Set: Remove Dos Device, letter=%1!c!, status=%2!u!\n",
NICE_DRIVE_LETTER(dosName[0]), status);
}
}
for (i = 0; i < PartitionCount; ++i) {
PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
WCHAR DeviceName[MAX_PATH];
UCHAR ch;
swprintf(DeviceName, DEVICE_HARDDISK_PARTITION_FMT,
Info->HarddiskNo, entry->PartitionNumber);
ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
if ( NT_SUCCESS(ntStatus) && ch) {
dosName[0] = ch;
status = DisksRemoveDosDeviceM(MountManager, dosName);
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountMgr_Set: Remove Dos Device 2, letter=%1!c!, status=%2!u!\n",
NICE_DRIVE_LETTER(dosName[0]), status);
}
if (entry->DriveLetter) {
dosName[0] = entry->DriveLetter;
status = DisksAssignDosDeviceM(MountManager, dosName, DeviceName);
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountMgr_Set: Assign Dos Device, letter=%1!c!, status=%2!u!\n",
NICE_DRIVE_LETTER(dosName[0]), status);
}
}
} finally {
DevfileClose( MountManager );
}
return ERROR_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////
//
// information providers table
//
// Disk\Information has to be the last entry of the table
//
// Order of the entries is important
//
/////////////////////////////////////////////////////////////////
INFO_PROVIDER Providers[] = {
{L"ClusReg-DiskInfo", CluDiskInfo_Get, CluDiskInfo_Set},
{L"ClusReg-Mountie", Mountie_Get, Mountie_Set},
{L"MountMgr", MountMgr_Get, MountMgr_Set},
{L"Registry-System\\DISK", FtInfo_Get, FtInfo_Set}, // Disk\Information must be the last (Why?)
};
enum {
PROVIDER_COUNT = sizeof(Providers)/sizeof(Providers[0]),
MOUNT_MANAGER = PROVIDER_COUNT - 2,
};
DWORD
MountieUpdate(
PMOUNTIE_INFO info,
PDISK_RESOURCE ResourceEntry)
/*++
Routine Description:
Update disk information for all providers
marked in NeedsUpdate bitmask
Inputs:
Info - MountieInfo
--*/
{
DWORD NeedsUpdate = info->NeedsUpdate;
BOOLEAN SharingPausedError = FALSE;
DWORD LastError = ERROR_SUCCESS;
INT i;
if (!NeedsUpdate) {
return ERROR_SUCCESS;
}
for (i = 0; i < PROVIDER_COUNT; ++i) {
if ( (1 << i) & NeedsUpdate ) {
DWORD status;
status = Providers[i].SetInfo(info, ResourceEntry);
if (status != ERROR_SUCCESS) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieUpdate: %1!ws!.SetInfo failed, error %2!u!.\n", Providers[i].Name, status);
if (status == ERROR_SHARING_PAUSED) {
SharingPausedError = TRUE;
} else {
LastError = status;
}
} else {
NeedsUpdate &= ~(1 << i);
}
}
}
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieUpdate: Update needed for %1!02x!.\n", NeedsUpdate);
info->NeedsUpdate = NeedsUpdate;
if (NeedsUpdate) {
if (SharingPausedError) {
return ERROR_SHARING_PAUSED;
}
return LastError;
}
return ERROR_SUCCESS;
}
DWORD
MountieVerify(
PMOUNTIE_INFO info,
PDISK_RESOURCE ResourceEntry,
BOOL UseMountMgr
)
/*++
Routine Description:
1. Compares information from all
providers and select one of them as source of
drive letter assignment.
2. Update MountieInfo with this drive letter assignment
3. Set NeedsUpdate for every provider whose information
differ from the MountieInfo
Inputs:
Info - MountieInfo
--*/
{
LETTER_ASSIGNMENT results[PROVIDER_COUNT + 1];
INT i;
INT GoodProvider = -1;
INT BestProvider = -1;
DWORD BestMatch = 0;
INT PartitionCount;
DWORD DriveLetters;
BOOLEAN UnassignedPartitions = FALSE;
DWORD NeedsUpdate = 0;
DWORD errorLevel;
if (!info->Volume || info->Volume->PartitionCount == 0) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"FatalError: Bad Mountie Info.\n");
return ERROR_INVALID_HANDLE;
}
PartitionCount = info->Volume->PartitionCount;
//
// Clear old DriveLetters in MOUNTIE_INFO
//
for (i = 0; i < PartitionCount; ++i) {
info->Volume->Partition[i].DriveLetter = 0;
}
//
// Collect Letter Assignments from Providers
//
RtlZeroMemory( results, sizeof(results) );
for (i = PROVIDER_COUNT; --i >= 0;) {
DWORD status;
status = Providers[i].GetInfo(info, ResourceEntry, results + i);
if (status != ERROR_SUCCESS) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
return status;
}
if (results[i].MatchCount && !results[i].MismatchCount) {
GoodProvider = i;
if (results[i].MatchCount >= BestMatch) {
BestProvider = i;
BestMatch = results[i].MatchCount;
}
} else {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
}
}
if (GoodProvider < 0 || GoodProvider >= PROVIDER_COUNT) {
if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
// No drive letters, we are using mount points and this is not an error.
errorLevel = LOG_WARNING;
} else {
// Drive letters exist, this is likely an error.
errorLevel = LOG_ERROR;
}
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
errorLevel,
L"MountieVerify: No good providers: %1!d!. \n", GoodProvider);
return ERROR_INVALID_HANDLE;
}
if (UseMountMgr) {
GoodProvider = MOUNT_MANAGER;
}
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieVerify: %1!ws! selected.\n",
Providers[GoodProvider].Name);
if (GoodProvider != BestProvider) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"MountieVerify: %1!ws! is better.\n",
Providers[BestProvider].Name);
}
//
// Now GoodProvider now holds an index of the highest
// provider with non stale information.
//
// Copy its letter assignment to a MOUNTIE_INFO
//
for (i = 0; i < PartitionCount; ++i) {
UCHAR ch = AssignedLetterByPartitionNumber(
results + GoodProvider,
info->Volume->Partition[i].PartitionNumber);
info->Volume->Partition[i].DriveLetter = ch;
if (!ch) {
UnassignedPartitions = TRUE;
}
}
#if 0
// No need to assign drive letters, since now we understand
// PnP
if (UnassignedPartitions) {
//
// Now give some arbitrary letter assignment to all
// partitions without a drive letter
//
DriveLetters = GetLogicalDrives();
if (!DriveLetters) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"GetLogicalDrivers failed, error %u.\n", GetLastError() );
} else {
DWORD Letter = 0;
DriveLetters &= ~results[MOUNT_MANAGER].DriveLetters;
DriveLetters |= results[GoodProvider].DriveLetters;
DriveLetters |= 3; // Consider A and B drive letters busy //
for (i = 0; i < PartitionCount; ++i) {
PUCHAR pch = &info->Volume->Partition[i].DriveLetter;
if (!*pch) {
while( (1 << Letter) & DriveLetters ){
if (++Letter == 26) {
goto no_more_letters;
}
}
*pch = (UCHAR) ('A' + Letter);
if (++Letter == 26) {
break;
}
}
}
no_more_letters:;
}
}
#endif
// Update Drive Letters Mask //
MountieUpdateDriveLetters(info);
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieVerify: DriveLetters mask is now %1!08x!.\n", info->DriveLetters );
//
// At this point MOUNTIE_INFO has a complete letter assignment
// for all partitions
//
// Now let's find which Providers needs to be updated
//
for (i = 0; i < PartitionCount; ++i) {
PMOUNTIE_PARTITION entry = info->Volume->Partition + i;
if (entry->DriveLetter) {
results[PROVIDER_COUNT].PartNumber[ entry->DriveLetter - 'A' ] =
(PARTITION_NUMBER_TYPE) entry->PartitionNumber;
}
}
results[PROVIDER_COUNT].DriveLetters = info->DriveLetters;
//
// All provides whose entries are different from results[PROVIDER_COUNT]
// need to be updated
//
for (i = 0; i < PROVIDER_COUNT; ++i) {
if (results[i].DriveLetters != results[PROVIDER_COUNT].DriveLetters
|| results[i].MismatchCount
|| 0 != memcmp(results[i].PartNumber,
results[PROVIDER_COUNT].PartNumber, sizeof(results[i].PartNumber) )
)
{
NeedsUpdate |= (1 << i);
}
}
info->NeedsUpdate = NeedsUpdate;
if (NeedsUpdate) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"MountieVerify: Update needed for %1!02x!.\n", NeedsUpdate);
//
// Chittur Subbaraman (chitturs) - 11/5/98
//
// If you plan to update the cluster registry values with info
// from the other providers, then log a warning to the event log.
//
if ( ( NeedsUpdate & 0x0003 ) && (GoodProvider == 2) && !UseMountMgr )
{
WCHAR szNewDriveLetterList[55];
WCHAR szOriginalDriveLetterList[55];
DWORD j = 0, k = 0;
for (i = 0; i < 26; ++i) {
if ( (1 << i) & results[PROVIDER_COUNT].DriveLetters ) {
szNewDriveLetterList[j] = (WCHAR)(L'A' + i);
szNewDriveLetterList[j+1] = L' ';
j += 2;
}
if ( (1 << i) & results[0].DriveLetters ) {
szOriginalDriveLetterList[k] = (WCHAR)(L'A' + i);
szOriginalDriveLetterList[k+1] = L' ';
k += 2;
}
}
szNewDriveLetterList[j] = L'\0';
szOriginalDriveLetterList[k] = L'\0';
//
// GorN. 8/25/99.
//
// Log the event only if OriginalDriveLetterList is empty.
//
if ( results[PROVIDER_COUNT].DriveLetters ) {
ClusResLogSystemEventByKey2( ResourceEntry->ResourceKey,
LOG_NOISE,
RES_DISK_WRITING_TO_CLUSREG,
szOriginalDriveLetterList,
szNewDriveLetterList
);
}
}
}
return ERROR_SUCCESS;
}
DWORD VolumesReady(
IN PMOUNTIE_INFO Info,
IN PDISK_RESOURCE ResourceEntry
)
/*++
Routine Description:
Checks whether each partition described in the MountieInfo can be seen by the
Mount Manager.
Inputs:
--*/
{
PMOUNTIE_PARTITION entry;
DWORD status = NO_ERROR;
DWORD nPartitions = MountiePartitionCount( Info );
DWORD i;
DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
WCHAR szGlobalDiskPartName[MAX_PATH];
WCHAR szVolumeName[MAX_PATH];
for ( i = 0; i < nPartitions; ++i ) {
entry = MountiePartition( Info, i );
if ( !entry ) {
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"VolumesReady: no partition entry for partition %1!u! \n", i );
//
// Something bad happened to our data structures. Stop processing and
// return error.
//
status = ERROR_INVALID_DATA;
break;
}
//
// Given the DiskPartName, get the VolGuid name. This name must have a trailing
// backslash to work correctly.
//
_snwprintf( szGlobalDiskPartName,
MAX_PATH,
GLOBALROOT_HARDDISK_PARTITION_FMT,
physicalDrive,
entry->PartitionNumber );
if ( !GetVolumeNameForVolumeMountPointW( szGlobalDiskPartName,
szVolumeName,
sizeof(szVolumeName)/sizeof(WCHAR) )) {
status = GetLastError();
(DiskpLogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"VolumesReady: GetVolumeNameForVolumeMountPoint for %1!ws! returned %2!u!\n",
szGlobalDiskPartName,
status );
//
// Something bad happened - stop checking this disk. Return the
// error status we received.
//
break;
}
//
// If we get here, this volume is recognized by the Mount Manager.
//
}
return status;
} // VolumesReady
NTSTATUS
GetAssignedLetter (
PWCHAR deviceName,
PCHAR driveLetter )
{
HANDLE MountMgrHandle = NULL;
DWORD status = DevfileOpen( &MountMgrHandle, MOUNTMGR_DEVICE_NAME );
if (driveLetter) {
*driveLetter = 0;
}
if ( NT_SUCCESS(status) && MountMgrHandle ) {
status = GetAssignedLetterM(MountMgrHandle, deviceName, driveLetter);
DevfileClose(MountMgrHandle);
}
return status;
}