|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
ckmach.c
Abstract:
This is for supporting checking a machine to see if it can be converted to IntelliMirror.
Author:
Sean Selitrennikoff - 4/5/98
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <ntverp.h>
PMIRROR_CFG_INFO GlobalMirrorCfgInfo = NULL;
//
// Support functions to do individual tasks
//
NTSTATUS AddCheckMachineToDoItems( VOID )
/*++
Routine Description:
This routine adds all the to do items necessary for checking out the local machine for conversion.
Arguments:
None
Return Value:
STATUS_SUCCESS if it completes adding all the to do items properly.
--*/
{ NTSTATUS Status;
Status = AddToDoItem(VerifySystemIsNt5, NULL, 0);
if (!NT_SUCCESS(Status)) { IMirrorHandleError(Status, IMirrorInitialize); return Status; }
return STATUS_SUCCESS; }
NTSTATUS CheckIfNt5( IN PVOID pBuffer, IN ULONG Length )
/*++
Routine Description:
This routine verifies that the current system is NT5 workstation, x86
Arguments:
pBuffer - Pointer to any arguments passed in the to do item.
Length - Length, in bytes of the arguments.
Return Value:
STATUS_SUCCESS if it completes adding all the to do items properly.
--*/
{ OSVERSIONINFO OsVersion; DWORD productVersion[] = { VER_PRODUCTVERSION };
IMirrorNowDoing(VerifySystemIsNt5, NULL);
RtlZeroMemory(&OsVersion, sizeof(OSVERSIONINFO)); OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&OsVersion)) { IMirrorHandleError(GetLastError(), VerifySystemIsNt5); return GetLastError(); }
if (OsVersion.dwPlatformId != VER_PLATFORM_WIN32_NT) { IMirrorHandleError(ERROR_OLD_WIN_VERSION, VerifySystemIsNt5); return ERROR_OLD_WIN_VERSION; }
if (OsVersion.dwMajorVersion != productVersion[0]) { IMirrorHandleError(ERROR_OLD_WIN_VERSION, VerifySystemIsNt5); return ERROR_OLD_WIN_VERSION; }
//
// We're changing the format of the alternate data stream. As such,
// we're introducing an incompatiblility. We'll pick this up here and
// return to riprep.exe the error. Otherwise the user doesn't find out
// about it until text mode setup on restoring the image.
//
// The NT build number that this is getting checked into is 2080.
//
if (OsVersion.dwBuildNumber < 2080) {
DbgPrint("build number is %u\n", OsVersion.dwBuildNumber); IMirrorHandleError(ERROR_OLD_WIN_VERSION, VerifySystemIsNt5); return ERROR_OLD_WIN_VERSION; } return STATUS_SUCCESS; }
BOOLEAN ReadRegistryString( IN PWCHAR KeyName, IN PWCHAR ValueName, IN PVOID Buffer, IN ULONG BufferLength )
/*++
Routine Description:
This routine reads a string from the registry into Buffer.
Arguments:
KeyName - The registry key.
ValueName - The value under that key to read, or NULL if the name of the first key under that key is to be read.
Buffer - The buffer to hold the result.
BufferLength - The length of Buffer.
Return Value:
TRUE if success, FALSE if any errors occur.
--*/
{ UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; PKEY_VALUE_PARTIAL_INFORMATION pValueInfo = NULL; PKEY_BASIC_INFORMATION pKeyInfo = NULL; HANDLE Handle = NULL; ULONG ByteCount; ULONG BytesLeft; PBYTE pBuffer; NTSTATUS Status; PVOID ResultData; ULONG ResultDataLength; BOOLEAN ReturnValue = FALSE;
//
//
// Open the key.
//
//
RtlInitUnicodeString(&UnicodeString, KeyName);
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenKey(&Handle, KEY_ALL_ACCESS, &ObjectAttributes );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
if (ValueName != NULL) {
RtlInitUnicodeString(&UnicodeString, ValueName);
//
// Get the size of the buffer needed
//
ByteCount = 0; Status = NtQueryValueKey(Handle, &UnicodeString, KeyValuePartialInformation, NULL, 0, &ByteCount );
if (Status != STATUS_BUFFER_TOO_SMALL) { goto Cleanup; }
pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)IMirrorAllocMem(ByteCount);
if (pValueInfo == NULL) { goto Cleanup; }
//
// Get the buffer from the registry
//
Status = NtQueryValueKey(Handle, &UnicodeString, KeyValuePartialInformation, pValueInfo, ByteCount, &ByteCount );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
if (pValueInfo->Type != REG_SZ) { goto Cleanup; }
ResultData = pValueInfo->Data; ResultDataLength = pValueInfo->DataLength;
} else {
//
// Get the size of the buffer needed
//
ByteCount = 0; Status = NtEnumerateKey(Handle, 0, KeyBasicInformation, NULL, 0, &ByteCount );
if (Status != STATUS_BUFFER_TOO_SMALL) { goto Cleanup; }
pKeyInfo = (PKEY_BASIC_INFORMATION)IMirrorAllocMem(ByteCount);
if (pKeyInfo == NULL) { goto Cleanup; }
//
// Get the name from the registry
//
Status = NtEnumerateKey(Handle, 0, KeyBasicInformation, pKeyInfo, ByteCount, &ByteCount );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
ResultData = pKeyInfo->Name; ResultDataLength = pKeyInfo->NameLength;
}
if (ResultDataLength > BufferLength) { goto Cleanup; }
memcpy(Buffer, ResultData, ResultDataLength);
//
// NULL-terminate it just in case, if there is room.
//
if (ResultDataLength <= BufferLength - sizeof(WCHAR)) { ((PWCHAR)Buffer)[ResultDataLength / sizeof(WCHAR)] = L'\0'; }
ReturnValue = TRUE;
Cleanup:
if (pValueInfo != NULL) { IMirrorFreeMem(pValueInfo); }
if (pKeyInfo != NULL) { IMirrorFreeMem(pKeyInfo); }
if (Handle != NULL) { NtClose(Handle); }
return ReturnValue; }
NTSTATUS CheckForPartitions( IN PVOID pBuffer, IN ULONG Length )
/*++
Routine Description:
This routine enumerates all partitions and formats the GlobalMirrorCfgInfo global structure.
It also fills in the pConfigPath.
Arguments:
pBuffer - Pointer to any arguments passed in the to do item.
Length - Length, in bytes of the arguments.
Return Value:
STATUS_SUCCESS if it completes adding all the to do items properly.
--*/
{ UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; PARTITION_INFORMATION_EX PartitionInfoEx; PARTITION_INFORMATION PartitionInfo; HANDLE Handle; ULONG MirrorNumber; ULONG DiskNumber; ULONG PartitionNumber; PULONG pTmpUlong; NTSTATUS Status; BOOLEAN foundBoot = FALSE; BOOLEAN foundSystem = FALSE; FILE_FS_SIZE_INFORMATION SizeInfo; LARGE_INTEGER UsedSpace; LARGE_INTEGER FreeSpace; ON_DISK_MBR OnDiskMbr; PUCHAR AlignedBuffer; UINT previousMode;
HANDLE DosDevicesDir; ULONG Context; WCHAR SystemDriveLetter; POBJECT_DIRECTORY_INFORMATION DirInfo; ULONG dosLength; BOOLEAN RestartScan; PMIRROR_VOLUME_INFO mirrorVolInfo; ULONG diskSignature; DWORD fileSystemFlags; WCHAR fileSystemName[16]; WCHAR volumeLabel[33]; ULONG volumeLabelLength; WCHAR arcName[MAX_PATH]; ULONG ntNameLength; ULONG arcNameLength; OSVERSIONINFO osVersionInfo; SYSTEM_INFO systemInfo; DWORD fileVersionInfoSize; DWORD versionHandle; PVOID versionInfo; VS_FIXEDFILEINFO * fixedFileInfo; UINT fixedFileInfoLength; WCHAR kernelPath[MAX_PATH]; PWCHAR kernelPathPart; WCHAR versionString[64]; BOOL b; #ifndef IMIRROR_NO_TESTING_LIMITATIONS
ULONG numberOfDrives = 0; #endif
BOOLEAN isDynamic = FALSE; BOOLEAN UsePartitionInfoEx = TRUE;
IMirrorNowDoing(CheckPartitions, NULL);
if (GlobalMirrorCfgInfo) {
return STATUS_SUCCESS; }
GlobalMirrorCfgInfo = IMirrorAllocMem(sizeof(MIRROR_CFG_INFO));
if (GlobalMirrorCfgInfo == NULL) { Status = STATUS_NO_MEMORY; IMirrorHandleError(Status, CheckPartitions); return Status; }
//
// Disable hard error popups for this thread.
//
previousMode = SetErrorMode( SEM_FAILCRITICALERRORS );
GlobalMirrorCfgInfo->MirrorVersion = IMIRROR_CURRENT_VERSION; GlobalMirrorCfgInfo->FileLength = 0; GlobalMirrorCfgInfo->SystemPath = NULL; GlobalMirrorCfgInfo->SysPrepImage = TRUE; GlobalMirrorCfgInfo->NumberVolumes = 0;
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osVersionInfo)) { GlobalMirrorCfgInfo->MajorVersion = osVersionInfo.dwMajorVersion; GlobalMirrorCfgInfo->MinorVersion = osVersionInfo.dwMinorVersion; GlobalMirrorCfgInfo->BuildNumber = osVersionInfo.dwBuildNumber; lstrcpyW(pCSDVersion, osVersionInfo.szCSDVersion); GlobalMirrorCfgInfo->CSDVersion = pCSDVersion; }
if (SearchPath( NULL, L"ntoskrnl.exe", NULL, MAX_PATH, kernelPath, &kernelPathPart)) { fileVersionInfoSize = GetFileVersionInfoSize(kernelPath, &versionHandle); if (fileVersionInfoSize != 0) { versionInfo = IMirrorAllocMem(fileVersionInfoSize); if (versionInfo != NULL) { if (GetFileVersionInfo( kernelPath, versionHandle, fileVersionInfoSize, versionInfo)) { if (VerQueryValue( versionInfo, L"\\", &fixedFileInfo, &fixedFileInfoLength)) { GlobalMirrorCfgInfo->KernelFileVersionMS = fixedFileInfo->dwFileVersionMS; GlobalMirrorCfgInfo->KernelFileVersionLS = fixedFileInfo->dwFileVersionLS; GlobalMirrorCfgInfo->KernelFileFlags = fixedFileInfo->dwFileFlags; DbgPrint("MS %lx LS %lx flags %lx\n", GlobalMirrorCfgInfo->KernelFileVersionMS, GlobalMirrorCfgInfo->KernelFileVersionLS, GlobalMirrorCfgInfo->KernelFileFlags); } } IMirrorFreeMem(versionInfo); } } }
if (GetSystemMetrics(SM_DEBUG)) { GlobalMirrorCfgInfo->Debug = TRUE; }
GetSystemInfo(&systemInfo); GlobalMirrorCfgInfo->NumberOfProcessors = systemInfo.dwNumberOfProcessors;
if (ReadRegistryString( L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment", L"PROCESSOR_ARCHITECTURE", pProcessorArchitecture, sizeof(pProcessorArchitecture))) { DbgPrint("processor arch is %ws\n", pProcessorArchitecture); GlobalMirrorCfgInfo->ProcessorArchitecture = pProcessorArchitecture; }
if (ReadRegistryString( L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentType", pCurrentType, sizeof(pCurrentType))) { DbgPrint("current type is %ws\n", pCurrentType); GlobalMirrorCfgInfo->CurrentType = pCurrentType; }
if (ReadRegistryString( L"\\Registry\\Machine\\Hardware\\RESOURCEMAP\\Hardware Abstraction Layer", NULL, pHalName, sizeof(pHalName))) { DbgPrint("HAL name is %ws\n", pHalName); GlobalMirrorCfgInfo->HalName = pHalName; }
InitializeListHead( &GlobalMirrorCfgInfo->MirrorVolumeList );
//
// Get local system drive letter and \\Systemroot\System32\Config path
//
Status = GetBaseDeviceName(L"\\SystemRoot", (PWCHAR)TmpBuffer2, sizeof(TmpBuffer2));
if (!NT_SUCCESS(Status)) { IMirrorHandleError(Status, CheckPartitions); goto ExitCheckPartitions; }
Status = NtPathToDosPath( (PWCHAR) TmpBuffer2, pConfigPath, FALSE, FALSE);
if (!NT_SUCCESS(Status)) { IMirrorHandleError(Status, CheckPartitions); goto ExitCheckPartitions; }
ASSERT( pConfigPath[1] == L':' ); SystemDriveLetter = (WCHAR) pConfigPath[0];
//
// save off the system path so that we can write it out to
// the imirror.dat file
//
lstrcpyW( pSystemPath, pConfigPath );
GlobalMirrorCfgInfo->SystemPath = pSystemPath;
wcscat( pConfigPath, L"\\System32\\Config");
//
// Open \DosDevices directory.
//
RtlInitUnicodeString(&UnicodeString,L"\\Device");
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenDirectoryObject(&DosDevicesDir, DIRECTORY_QUERY, &ObjectAttributes );
if (!NT_SUCCESS(Status)) { IMirrorHandleError(Status, CheckPartitions); goto ExitCheckPartitions; }
//
// Iterate each object in that directory that is a directory.
//
Context = 0; RestartScan = TRUE;
Status = NtQueryDirectoryObject(DosDevicesDir, TmpBuffer, sizeof(TmpBuffer), TRUE, RestartScan, &Context, &dosLength );
RestartScan = FALSE; DirInfo = (POBJECT_DIRECTORY_INFORMATION)TmpBuffer; MirrorNumber = 1;
while (NT_SUCCESS(Status)) {
DirInfo->Name.Buffer[DirInfo->Name.Length/sizeof(WCHAR)] = 0; DirInfo->TypeName.Buffer[DirInfo->TypeName.Length/sizeof(WCHAR)] = 0;
//
// Skip this entry if it's not a "HardDiskN"
//
if ((DirInfo->Name.Length > (sizeof(L"Harddisk")-sizeof(WCHAR))) && (!wcsncmp(DirInfo->Name.Buffer,L"Harddisk",(sizeof(L"Harddisk")/sizeof(WCHAR))-1)) && !lstrcmpi(DirInfo->TypeName.Buffer, L"Directory")) {
PWCHAR diskNumberPtr;
PartitionNumber = 0; DiskNumber = 0;
diskNumberPtr = &DirInfo->Name.Buffer[(sizeof(L"Harddisk")/sizeof(WCHAR))-1];
while (*diskNumberPtr >= L'0' && *diskNumberPtr <= L'9' ) {
DiskNumber *= 10; DiskNumber += *(diskNumberPtr) - L'0'; diskNumberPtr++; }
if (*diskNumberPtr != L'\0') {
//
// if the device name wasn't of form HardDiskN, skip this entry.
//
goto getNextDevice; }
diskSignature = 0;
//
// get the disk signature, continue if it fails.
//
swprintf((PWCHAR)TmpBuffer2, L"\\Device\\Harddisk%d\\Partition0", DiskNumber);
RtlInitUnicodeString(&UnicodeString, (PWCHAR)TmpBuffer2);
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtCreateFile(&Handle, (ACCESS_MASK)FILE_GENERIC_READ, &ObjectAttributes, &IoStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (NT_SUCCESS(Status)) {
ASSERT(sizeof(ON_DISK_MBR) == 512); AlignedBuffer = ALIGN(TmpBuffer, 512);
Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatus, AlignedBuffer, sizeof(ON_DISK_MBR), NULL, NULL );
if (NT_SUCCESS(Status)) {
RtlMoveMemory(&OnDiskMbr, AlignedBuffer, sizeof(ON_DISK_MBR));
ASSERT(U_USHORT(OnDiskMbr.AA55Signature) == 0xAA55);
diskSignature = U_ULONG(OnDiskMbr.NTFTSignature);
//
// check to see if this disk is dynamic
//
if (OnDiskMbr.PartitionTable[0].SystemId == PARTITION_LDM || OnDiskMbr.PartitionTable[1].SystemId == PARTITION_LDM || OnDiskMbr.PartitionTable[2].SystemId == PARTITION_LDM || OnDiskMbr.PartitionTable[3].SystemId == PARTITION_LDM) {
isDynamic = TRUE; NtClose(Handle); goto getNextDevice; } } NtClose(Handle); }
while (1) {
PartitionNumber++;
swprintf((PWCHAR)TmpBuffer2, L"\\Device\\Harddisk%d\\Partition%d", DiskNumber, PartitionNumber);
RtlInitUnicodeString(&UnicodeString, (PWCHAR)TmpBuffer2);
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtCreateFile(&Handle, (ACCESS_MASK)FILE_GENERIC_READ, &ObjectAttributes, &IoStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (!NT_SUCCESS(Status)) { break; // on to next disk
}
Status = NtDeviceIoControlFile(Handle, NULL, NULL, NULL, &IoStatus, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &PartitionInfoEx, sizeof(PARTITION_INFORMATION_EX) );
if( (Status == STATUS_NOT_IMPLEMENTED) || (Status == STATUS_INVALID_DEVICE_REQUEST) ) {
//
// We're on an old build that didn't have this IOCTL.
//
UsePartitionInfoEx = FALSE;
Status = NtDeviceIoControlFile(Handle, NULL, NULL, NULL, &IoStatus, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &PartitionInfo, sizeof(PARTITION_INFORMATION) ); }
if (!NT_SUCCESS(Status)) { NtClose(Handle); continue; // on to next partition
}
//
// For Whistler, ignore GPT partitions.
//
if( (UsePartitionInfoEx) && (PartitionInfoEx.PartitionStyle != PARTITION_STYLE_MBR) ) { NtClose(Handle); continue; }
Status = NtQueryVolumeInformationFile(Handle, &IoStatus, &SizeInfo, sizeof(SizeInfo), FileFsSizeInformation );
NtClose(Handle);
if (!NT_SUCCESS(Status)) { continue; // on to next partition
}
Status = NtPathToDosPath( (PWCHAR) TmpBuffer2, (PWCHAR) TmpBuffer, TRUE, FALSE);
if (!NT_SUCCESS(Status)) { continue; // on to next partition
}
if ((lstrlenW((PWCHAR) TmpBuffer) == 0) || *(((PWCHAR)TmpBuffer)+1) != L':') {
continue; // on to next partition
}
//
// Get the ARC name of the partition.
//
NtNameToArcName( (PWCHAR) TmpBuffer2, (PWCHAR) arcName, FALSE);
//
// Get the file system type. We add a \ to the end
// of TmpBuffer if there isn't one.
//
if (((PWCHAR)TmpBuffer)[lstrlenW((PWCHAR)TmpBuffer) - 1] != L'\\') { wcscat((PWCHAR)TmpBuffer, L"\\"); }
b = GetVolumeInformationW( (PWCHAR) TmpBuffer, volumeLabel, ARRAYSIZE(volumeLabel), NULL, // no volume serial number requested
NULL, // no maximum name length requested
&fileSystemFlags, fileSystemName, ARRAYSIZE(fileSystemName));
if (!b) { continue; }
//
// Calculate the amount of free space on the drive.
//
FreeSpace = RtlExtendedIntegerMultiply( SizeInfo.AvailableAllocationUnits, SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector );
UsedSpace = RtlExtendedIntegerMultiply( SizeInfo.TotalAllocationUnits, SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector );
UsedSpace = RtlLargeIntegerSubtract( UsedSpace, FreeSpace );
#ifndef IMIRROR_NO_TESTING_LIMITATIONS
numberOfDrives++;
//
// for NT 5.0, the test group doesn't want to test more than a single
// partition. Now that the test team is dictating what the feature set
// is, we'll return an error if we have more than a single partition or
// disk.
//
if ( (UsePartitionInfoEx && !PartitionInfoEx.Mbr.BootIndicator) || (!UsePartitionInfoEx && !PartitionInfo.BootIndicator)) {
if (*(PWCHAR)TmpBuffer == SystemDriveLetter) {
IMirrorHandleError(STATUS_MISSING_SYSTEMFILE, CheckPartitions); NtClose(DosDevicesDir); Status = STATUS_MISSING_SYSTEMFILE; goto ExitCheckPartitions; } continue; }
if (*(PWCHAR)TmpBuffer != SystemDriveLetter) {
// if another drive is marked bootable but it isn't the
// system drive, we'll ignore it. We'll pick up the
// error down below if this is the only bootable drive.
#if 0
if ( (UsePartitionInfoEx && PartitionInfoEx.Mbr.BootIndicator) || (!UsePartitionInfoEx && PartitionInfo.BootIndicator)) {
IMirrorHandleError(STATUS_MISSING_SYSTEMFILE, CheckPartitions); NtClose(DosDevicesDir); Status = STATUS_MISSING_SYSTEMFILE; goto ExitCheckPartitions; } #endif
continue; } #endif
mirrorVolInfo = IMirrorAllocMem(sizeof(MIRROR_VOLUME_INFO));
if (mirrorVolInfo == NULL) { NtClose(DosDevicesDir); Status = STATUS_NO_MEMORY; IMirrorHandleError(Status, CheckPartitions); goto ExitCheckPartitions; }
//
// Save the NT and ARC device names.
//
ntNameLength = (lstrlenW( (PWCHAR)TmpBuffer2 ) + 1) * sizeof(WCHAR);
mirrorVolInfo->NtName = IMirrorAllocMem(ntNameLength);
if (mirrorVolInfo->NtName == NULL) {
Status = STATUS_NO_MEMORY; IMirrorHandleError(Status, CheckPartitions); NtClose(DosDevicesDir); goto ExitCheckPartitions; }
arcNameLength = (lstrlenW( (PWCHAR)arcName ) + 1) * sizeof(WCHAR);
mirrorVolInfo->ArcName = IMirrorAllocMem(arcNameLength);
if (mirrorVolInfo->ArcName == NULL) {
Status = STATUS_NO_MEMORY; IMirrorHandleError(Status, CheckPartitions); NtClose(DosDevicesDir); goto ExitCheckPartitions; }
memcpy(mirrorVolInfo->NtName, TmpBuffer2, ntNameLength); memcpy(mirrorVolInfo->ArcName, arcName, arcNameLength);
mirrorVolInfo->DriveLetter = *(PWCHAR)TmpBuffer; mirrorVolInfo->PartitionType = UsePartitionInfoEx ? PartitionInfoEx.Mbr.PartitionType : PartitionInfo.PartitionType;
//
// If this is a non-NTFS volume, check if it is configured
// for compression
//
if ( ((UsePartitionInfoEx && (PartitionInfoEx.Mbr.PartitionType != PARTITION_IFS)) || (!UsePartitionInfoEx && (PartitionInfo.PartitionType != PARTITION_IFS))) && (fileSystemFlags & FS_VOL_IS_COMPRESSED) ) {
mirrorVolInfo->CompressedVolume = TRUE;
} else {
mirrorVolInfo->CompressedVolume = FALSE; }
if ( (UsePartitionInfoEx && (PartitionInfoEx.Mbr.BootIndicator)) || (!UsePartitionInfoEx && (PartitionInfo.BootIndicator)) ) {
foundBoot = TRUE; mirrorVolInfo->PartitionActive = TRUE;
} else {
mirrorVolInfo->PartitionActive = FALSE; }
if (*(PWCHAR)TmpBuffer == SystemDriveLetter) {
foundSystem = TRUE; mirrorVolInfo->IsBootDisk = TRUE;
} else {
mirrorVolInfo->IsBootDisk = FALSE; }
mirrorVolInfo->DiskNumber = DiskNumber; mirrorVolInfo->PartitionNumber = PartitionNumber; mirrorVolInfo->MirrorTableIndex = MirrorNumber++; mirrorVolInfo->MirrorUncPath = NULL; mirrorVolInfo->LastUSNMirrored = 0; mirrorVolInfo->BlockSize = SizeInfo.BytesPerSector; mirrorVolInfo->DiskSignature = diskSignature; mirrorVolInfo->FileSystemFlags = fileSystemFlags; wcscpy(mirrorVolInfo->FileSystemName, fileSystemName);
volumeLabelLength = (lstrlenW( (PWCHAR)volumeLabel ) + 1) * sizeof(WCHAR); mirrorVolInfo->VolumeLabel = IMirrorAllocMem(volumeLabelLength); if (mirrorVolInfo->VolumeLabel == NULL) { Status = STATUS_NO_MEMORY; IMirrorHandleError(Status, CheckPartitions); NtClose(DosDevicesDir); goto ExitCheckPartitions; } memcpy(mirrorVolInfo->VolumeLabel, volumeLabel, volumeLabelLength);
mirrorVolInfo->StartingOffset = UsePartitionInfoEx ? PartitionInfoEx.StartingOffset : PartitionInfo.StartingOffset; mirrorVolInfo->PartitionSize = UsePartitionInfoEx ? PartitionInfoEx.PartitionLength : PartitionInfo.PartitionLength; mirrorVolInfo->DiskSpaceUsed = UsedSpace;
InsertTailList( &GlobalMirrorCfgInfo->MirrorVolumeList, &mirrorVolInfo->ListEntry );
GlobalMirrorCfgInfo->NumberVolumes = MirrorNumber - 1; } } //
// Go on to next object.
//
getNextDevice: Status = NtQueryDirectoryObject( DosDevicesDir, TmpBuffer, sizeof(TmpBuffer), TRUE, RestartScan, &Context, &dosLength ); }
NtClose(DosDevicesDir);
if ((!foundBoot) || (!foundSystem) ) {
Status = (isDynamic ? STATUS_OBJECT_TYPE_MISMATCH : STATUS_MISSING_SYSTEMFILE); IMirrorHandleError(Status, CheckPartitions); goto ExitCheckPartitions; } #ifndef IMIRROR_NO_TESTING_LIMITATIONS
if (numberOfDrives > 1) { IMirrorHandleError(ERROR_INVALID_DRIVE, CheckPartitions); Status = ERROR_INVALID_DRIVE; } else { Status = STATUS_SUCCESS; } #else
Status = STATUS_SUCCESS; #endif
ExitCheckPartitions:
SetErrorMode( previousMode ); return Status; }
NTSTATUS NtPathToDosPath( IN PWSTR NtPath, OUT PWSTR DosPath, IN BOOLEAN GetDriveOnly, IN BOOLEAN NtPathIsBasic )
/*++
Routine Description:
This routine calls off to convert a \Device\HarddiskX\PartitionY\<path> to Z:\<path>
Arguments:
NtPath - Something like \Device\Harddisk0\Partition2\WINNT
DosPath - Will be something like D: or D:\WINNT, depending on flag below.
GetDriveOnly - TRUE if the caller only wants the DOS drive.
NtPathIsBasic - TRUE if NtPath is not symbolic link.
Return Value:
STATUS_SUCCESS if it completes filling in DosDrive, else an appropriate error code.
--*/
{ OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; NTSTATUS Status; HANDLE DosDevicesDir; HANDLE DosDevicesObj; HANDLE ObjectHandle; ULONG Context; ULONG Length; BOOLEAN RestartScan; WCHAR LinkTarget[2*MAX_PATH]; POBJECT_DIRECTORY_INFORMATION DirInfo; WCHAR LocalBuffer[MAX_PATH]; WCHAR LocalBuffer2[MAX_PATH]; PWCHAR pTmp; PWCHAR NameSpace[] = { L"\\??", L"\\GLOBAL??" }; UINT i; if (NtPath == NULL) { return ERROR_PATH_NOT_FOUND; }
if (!NtPathIsBasic) {
//
// Find the end of the \device\harddiskX\partitionY string
//
wcscpy(LocalBuffer2, NtPath); pTmp = LocalBuffer2; if (*pTmp != L'\\') { return ERROR_PATH_NOT_FOUND; }
pTmp = wcsstr(pTmp + 1, L"\\");
if (pTmp == NULL) { return ERROR_PATH_NOT_FOUND; }
pTmp = wcsstr(pTmp + 1, L"\\");
if (pTmp == NULL) { return ERROR_PATH_NOT_FOUND; }
pTmp = wcsstr(pTmp + 1, L"\\");
if (pTmp != NULL) { *pTmp = UNICODE_NULL; pTmp++; }
//
// Find the base NT device name
//
Status = GetBaseDeviceName(LocalBuffer2, LocalBuffer, sizeof(LocalBuffer));
if (!NT_SUCCESS(Status)) { return Status; }
} else {
wcscpy(LocalBuffer, NtPath); pTmp = NULL;
}
//
// Open \DosDevices directory. First try the "normal" dosdevices path,
// then try the global dosdevices path.
//
for (i = 0; i < sizeof(NameSpace)/sizeof(PWCHAR *); i++) { RtlInitUnicodeString(&UnicodeString,NameSpace[i]); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenDirectoryObject(&DosDevicesDir, DIRECTORY_QUERY, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { DosDevicesDir = NULL; } else { //
// Iterate each object in that directory.
//
Context = 0; RestartScan = TRUE; Status = NtQueryDirectoryObject(DosDevicesDir, TmpBuffer3, sizeof(TmpBuffer3), TRUE, RestartScan, &Context, &Length ); RestartScan = FALSE; DirInfo = (POBJECT_DIRECTORY_INFORMATION)TmpBuffer3; while (NT_SUCCESS(Status)) { DirInfo->Name.Buffer[DirInfo->Name.Length/sizeof(WCHAR)] = 0; DirInfo->TypeName.Buffer[DirInfo->TypeName.Length/sizeof(WCHAR)] = 0; //
// Skip this entry if it's not a symbolic link.
//
if ((DirInfo->Name.Length != 0) && (DirInfo->Name.Buffer[1] == L':') && !lstrcmpi(DirInfo->TypeName.Buffer, L"SymbolicLink")) { //
// Get this \DosDevices object's link target.
//
swprintf(LocalBuffer2, L"%ws\\%ws", NameSpace[i], DirInfo->Name.Buffer); Status = GetBaseDeviceName(LocalBuffer2, LinkTarget, sizeof(LinkTarget)); if (NT_SUCCESS(Status)) { //
// See if it's a prefix of the path we're converting,
//
if(!_wcsnicmp(LocalBuffer, LinkTarget, wcslen(LinkTarget))) { //
// Got a match.
//
lstrcpy(DosPath, DirInfo->Name.Buffer); if (!GetDriveOnly) { if (NtPathIsBasic) { lstrcat(DosPath, LocalBuffer + wcslen(LinkTarget)); } else if (pTmp != NULL) { lstrcat(DosPath, L"\\"); lstrcat(DosPath, pTmp); } } NtClose(DosDevicesDir); return(STATUS_SUCCESS); } } }
//
// Go on to next object.
//
Status = NtQueryDirectoryObject( DosDevicesDir, TmpBuffer3, sizeof(TmpBuffer3), TRUE, RestartScan, &Context, &Length ); } NtClose(DosDevicesDir); }
}
return(Status);
}
NTSTATUS NtNameToArcName( IN PWSTR NtName, OUT PWSTR ArcName, IN BOOLEAN NtNameIsBasic )
/*++
Routine Description:
This routine calls off to convert a \Device\HarddiskX\PartitionY to the ARC name.
Arguments:
NtPath - Something like \Device\Harddisk0\Partition2
DosPath - Will be something like \Arcname\multi(0)disk(0)rdisk(0)partition(1).
NtNameIsBasic - TRUE if NtName is not symbolic link.
Return Value:
STATUS_SUCCESS if it completes filling in ArcName, else an appropriate error code.
--*/
{ OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; NTSTATUS Status; HANDLE DosDevicesDir; HANDLE DosDevicesObj; HANDLE ObjectHandle; ULONG Context; ULONG Length; BOOLEAN RestartScan; WCHAR LinkTarget[2*MAX_PATH]; POBJECT_DIRECTORY_INFORMATION DirInfo; WCHAR LocalBuffer[MAX_PATH]; WCHAR LocalBuffer2[MAX_PATH]; PWCHAR pTmp;
if (!NtNameIsBasic) {
//
// Find the base NT device name
//
Status = GetBaseDeviceName(NtName, LocalBuffer, sizeof(LocalBuffer));
if (!NT_SUCCESS(Status)) { return Status; }
} else {
wcscpy(LocalBuffer, NtName);
}
//
// Open \ArcName directory.
//
RtlInitUnicodeString(&UnicodeString,L"\\ArcName");
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenDirectoryObject(&DosDevicesDir, DIRECTORY_QUERY, &ObjectAttributes );
if (!NT_SUCCESS(Status)) { return Status; }
//
// Iterate each object in that directory.
//
Context = 0; RestartScan = TRUE;
Status = NtQueryDirectoryObject(DosDevicesDir, TmpBuffer3, sizeof(TmpBuffer3), TRUE, RestartScan, &Context, &Length );
RestartScan = FALSE; DirInfo = (POBJECT_DIRECTORY_INFORMATION)TmpBuffer3;
while (NT_SUCCESS(Status)) {
DirInfo->Name.Buffer[DirInfo->Name.Length/sizeof(WCHAR)] = 0; DirInfo->TypeName.Buffer[DirInfo->TypeName.Length/sizeof(WCHAR)] = 0;
//
// Skip this entry if it's not a symbolic link.
//
if ((DirInfo->Name.Length != 0) && !lstrcmpi(DirInfo->TypeName.Buffer, L"SymbolicLink")) {
//
// Get this \DosDevices object's link target.
//
swprintf(LocalBuffer2, L"\\ArcName\\%ws", DirInfo->Name.Buffer);
Status = GetBaseDeviceName(LocalBuffer2, LinkTarget, sizeof(LinkTarget));
if (NT_SUCCESS(Status)) {
//
// See if the base name of this link matches the base
// name of what we are looking for.
//
if(!_wcsnicmp(LocalBuffer, LinkTarget, wcslen(LinkTarget))) {
//
// Got a match.
//
lstrcpy(ArcName, DirInfo->Name.Buffer);
NtClose(DosDevicesDir); return STATUS_SUCCESS; } } }
//
// Go on to next object.
//
Status = NtQueryDirectoryObject( DosDevicesDir, TmpBuffer3, sizeof(TmpBuffer3), TRUE, RestartScan, &Context, &Length ); }
NtClose(DosDevicesDir); return Status; }
NTSTATUS GetBaseDeviceName( IN PWSTR SymbolicName, OUT PWSTR Buffer, IN ULONG Size )
/*++
Routine Description:
This routine drills down thru symbolic links until it finds the base device name.
Arguments:
SymbolicName - The name to start with.
Buffer - The output buffer.
Size - Length, in bytes of Buffer
Return Value:
STATUS_SUCCESS if it completes adding all the to do items properly.
--*/
{ UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Handle; NTSTATUS Status;
//
// Start at the first name
//
RtlInitUnicodeString(&UnicodeString, SymbolicName);
InitializeObjectAttributes( &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenSymbolicLinkObject(&Handle, (ACCESS_MASK)SYMBOLIC_LINK_QUERY, &ObjectAttributes );
if (!NT_SUCCESS(Status)) { return Status; }
while (TRUE) {
//
// Take this open and get the next name
//
UnicodeString.Length = 0; UnicodeString.MaximumLength = (USHORT)Size; UnicodeString.Buffer = (PWCHAR)Buffer; Status = NtQuerySymbolicLinkObject(Handle, &UnicodeString, NULL );
NtClose(Handle);
Buffer[(UnicodeString.Length / sizeof(WCHAR))] = UNICODE_NULL;
if (!NT_SUCCESS(Status)) { return Status; }
//
// See if the next name is also a symbolic name
//
RtlInitUnicodeString(&UnicodeString, Buffer);
InitializeObjectAttributes( &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenSymbolicLinkObject(&Handle, (ACCESS_MASK)SYMBOLIC_LINK_QUERY, &ObjectAttributes );
if (!NT_SUCCESS(Status)) { return STATUS_SUCCESS; }
}
}
|