2086 lines
54 KiB
C
2086 lines
54 KiB
C
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
|