1007 lines
23 KiB
C++
1007 lines
23 KiB
C++
/*++
|
|
|
|
Copyright (C) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ftcomp.cpp
|
|
|
|
Abstract:
|
|
|
|
This compatibility dll is used by winnt32.exe in order to decide
|
|
whether the installation process should be aborted because of FT
|
|
sets present in the system.
|
|
|
|
Author:
|
|
|
|
Cristian Teodorescu (cristiat) 6-July-2000
|
|
|
|
Environment:
|
|
|
|
compatibility dll for winnt32.exe
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <initguid.h>
|
|
#include <winnt32.h>
|
|
#include <ntddft.h>
|
|
#include <ntddft2.h>
|
|
|
|
#include "ftcomp.h"
|
|
#include "ftcomprc.h"
|
|
|
|
|
|
HINSTANCE g_hinst;
|
|
WCHAR g_FTCOMP50_ERROR_HTML_FILE[] = L"compdata\\ftcomp1.htm";
|
|
WCHAR g_FTCOMP50_ERROR_TEXT_FILE[] = L"compdata\\ftcomp1.txt";
|
|
WCHAR g_FTCOMP40_ERROR_HTML_FILE[] = L"compdata\\ftcomp2.htm";
|
|
WCHAR g_FTCOMP40_ERROR_TEXT_FILE[] = L"compdata\\ftcomp2.txt";
|
|
WCHAR g_FTCOMP40_WARNING_HTML_FILE[] = L"compdata\\ftcomp3.htm";
|
|
WCHAR g_FTCOMP40_WARNING_TEXT_FILE[] = L"compdata\\ftcomp3.txt";
|
|
|
|
extern "C"
|
|
BOOL WINAPI
|
|
DllMain(
|
|
HINSTANCE hInstance,
|
|
DWORD dwReasonForCall,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
BOOL status = TRUE;
|
|
|
|
switch( dwReasonForCall )
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
g_hinst = hInstance;
|
|
DisableThreadLibraryCalls(hInstance);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
BOOL WINAPI
|
|
FtCompatibilityCheckError(
|
|
IN PCOMPAIBILITYCALLBACK CompatibilityCallback,
|
|
IN LPVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by winnt32.exe in order to decide whether
|
|
the installation process should be aborted because of FT sets present
|
|
in a Windows 2000 system or later. It also aborts the installation on
|
|
NT 4.0 systems if the boot/system/pagefile volumes are FT sets
|
|
|
|
Arguments:
|
|
|
|
CompatibilityCallback - Supplies the winnt32 callback
|
|
|
|
Context - Supplies the compatibility context
|
|
|
|
Return Value:
|
|
|
|
FALSE if the installation can continue
|
|
TRUE if the installation must be aborted
|
|
|
|
--*/
|
|
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
BOOL ftPresent;
|
|
BOOL result;
|
|
COMPATIBILITY_ENTRY ce;
|
|
WCHAR description[100];
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osvi)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT ||
|
|
osvi.dwMajorVersion < 4) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (osvi.dwMajorVersion == 4) {
|
|
|
|
//
|
|
// On NT 4.0 look for boot/system/pagefile FT sets
|
|
//
|
|
|
|
result = FtBootSystemPagefilePresent40(&ftPresent);
|
|
|
|
} else {
|
|
|
|
//
|
|
// On Windows 2000 or later look for any FT sets.
|
|
//
|
|
|
|
result = FtPresent50(&ftPresent);
|
|
}
|
|
|
|
if (result && !ftPresent) {
|
|
|
|
//
|
|
// The setup can continue.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// FT sets are present in the system or a fatal error occured.
|
|
// Queue the incompatibility error
|
|
//
|
|
|
|
ZeroMemory((PVOID) &ce, sizeof(COMPATIBILITY_ENTRY));
|
|
if (osvi.dwMajorVersion == 4) {
|
|
if (!LoadString(g_hinst, FTCOMP_STR_ERROR40_DESCRIPTION, description, 100)) {
|
|
description[0] = 0;
|
|
}
|
|
ce.HtmlName = g_FTCOMP40_ERROR_HTML_FILE;
|
|
ce.TextName = g_FTCOMP40_ERROR_TEXT_FILE;
|
|
} else {
|
|
if (!LoadString(g_hinst, FTCOMP_STR_ERROR50_DESCRIPTION, description, 100)) {
|
|
description[0] = 0;
|
|
}
|
|
ce.HtmlName = g_FTCOMP50_ERROR_HTML_FILE;
|
|
ce.TextName = g_FTCOMP50_ERROR_TEXT_FILE;
|
|
}
|
|
ce.Description = description;
|
|
ce.RegKeyName = NULL;
|
|
ce.RegValName = NULL;
|
|
ce.RegValDataSize = 0;
|
|
ce.RegValData = NULL;
|
|
ce.SaveValue = NULL;
|
|
ce.Flags = 0;
|
|
CompatibilityCallback(&ce, Context);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI
|
|
FtCompatibilityCheckWarning(
|
|
IN PCOMPAIBILITYCALLBACK CompatibilityCallback,
|
|
IN LPVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by winnt32.exe in order to decide whether the user
|
|
should be warned about the presence of FT sets in a Windows NT 4.0 system
|
|
|
|
Arguments:
|
|
|
|
CompatibilityCallback - Supplies the winnt32 callback
|
|
|
|
Context - Supplies the compatibility context
|
|
|
|
Return Value:
|
|
|
|
FALSE if the installation can continue
|
|
TRUE if the installation must be aborted
|
|
|
|
--*/
|
|
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
BOOL ftPresent;
|
|
BOOL result;
|
|
COMPATIBILITY_ENTRY ce;
|
|
WCHAR description[100];
|
|
|
|
//
|
|
// This function is supposed to work only on Windows NT 4.0
|
|
//
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osvi)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT ||
|
|
osvi.dwMajorVersion != 4) {
|
|
return FALSE;
|
|
}
|
|
|
|
result = FtPresent40(&ftPresent);
|
|
if (result && !ftPresent) {
|
|
|
|
//
|
|
// No FT sets are present in the system. The setup can continue.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// FT sets are present in the system or a fatal error occured.
|
|
// Queue the incompatibility warning
|
|
//
|
|
|
|
if (!LoadString(g_hinst, FTCOMP_STR_WARNING40_DESCRIPTION, description, 100)) {
|
|
description[0] = 0;
|
|
}
|
|
|
|
ZeroMemory((PVOID) &ce, sizeof(COMPATIBILITY_ENTRY));
|
|
ce.Description = description;
|
|
ce.HtmlName = g_FTCOMP40_WARNING_HTML_FILE;
|
|
ce.TextName = g_FTCOMP40_WARNING_TEXT_FILE;
|
|
ce.RegKeyName = NULL;
|
|
ce.RegValName = NULL;
|
|
ce.RegValDataSize = 0;
|
|
ce.RegValData = NULL;
|
|
ce.SaveValue = NULL;
|
|
ce.Flags = 0;
|
|
CompatibilityCallback(&ce, Context);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
FtPresent50(
|
|
PBOOL FtPresent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for FT volumes on a Window 2000 or later
|
|
system.
|
|
|
|
Arguments:
|
|
|
|
FtPresent - is set to true if FT sets are detected in the system
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function is successful
|
|
FALSE if some fatal error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
FT_ENUMERATE_LOGICAL_DISKS_OUTPUT output;
|
|
BOOL result;
|
|
DWORD bytes;
|
|
|
|
*FtPresent = FALSE;
|
|
|
|
handle = CreateFile(L"\\\\.\\FtControl", GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
|
INVALID_HANDLE_VALUE);
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
memset(&output, 0, sizeof(output));
|
|
result = DeviceIoControl(handle, FT_ENUMERATE_LOGICAL_DISKS, NULL, 0,
|
|
&output, sizeof(output), &bytes, NULL);
|
|
CloseHandle(handle);
|
|
|
|
if (!result && GetLastError() != ERROR_MORE_DATA) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (output.NumberOfRootLogicalDisks > 0) {
|
|
*FtPresent = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
FtPresent40(
|
|
PBOOL FtPresent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for NTFT partitions on a Window NT 4.0 system
|
|
|
|
Arguments:
|
|
|
|
FtPresent - is set to true if FT sets are detected in the system
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function is successful
|
|
FALSE if some fatal error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hkey;
|
|
DWORD registrySize;
|
|
PDISK_CONFIG_HEADER registry;
|
|
PDISK_REGISTRY diskRegistry;
|
|
ULONG i;
|
|
WCHAR devicePath[50];
|
|
NTSTATUS status;
|
|
HANDLE hdev;
|
|
|
|
*FtPresent = FALSE;
|
|
|
|
//
|
|
// Get the ftdisk database from registry.
|
|
// Key: HKLM\System\Disk
|
|
// Value: Information
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Disk", 0, KEY_QUERY_VALUE, &hkey) !=
|
|
ERROR_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (RegQueryValueEx(hkey, L"Information", NULL, NULL, NULL, ®istrySize) !=
|
|
ERROR_SUCCESS) {
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
registry = (PDISK_CONFIG_HEADER) LocalAlloc(0, registrySize);
|
|
if (!registry) {
|
|
RegCloseKey(hkey);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegQueryValueEx(hkey, L"Information", NULL, NULL, (LPBYTE) registry, ®istrySize) !=
|
|
ERROR_SUCCESS) {
|
|
LocalFree(registry);
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
//
|
|
// If no FT volume info is present in the registry database we are done
|
|
//
|
|
|
|
if (registry->FtInformationSize == 0) {
|
|
LocalFree(registry);
|
|
return TRUE;
|
|
}
|
|
|
|
diskRegistry = (PDISK_REGISTRY)
|
|
((PUCHAR) registry + registry->DiskInformationOffset);
|
|
|
|
|
|
//
|
|
// Enumerate all disks present in the system by opening \Device\HarddiskX\Partition0
|
|
// in sequence starting with disk 0. Stop when getting STATUS_OBJECT_PATH_NOT_FOUND
|
|
//
|
|
//
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
//
|
|
// Open the device
|
|
//
|
|
|
|
swprintf(devicePath, L"\\Device\\Harddisk%lu\\Partition0", i);
|
|
status = OpenDevice(devicePath, &hdev);
|
|
|
|
if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) || hdev == NULL ||
|
|
hdev == INVALID_HANDLE_VALUE) {
|
|
// inaccessible device
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Look for FT partitions on disk
|
|
//
|
|
|
|
if (!FtPresentOnDisk40(hdev, diskRegistry, FtPresent)) {
|
|
CloseHandle(hdev);
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(hdev);
|
|
|
|
if (*FtPresent) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
LocalFree(registry);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
FtBootSystemPagefilePresent40(
|
|
PBOOL FtPresent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for FT sets that are boot/system/pagefile volumes
|
|
on a NT 4.0 system
|
|
|
|
Arguments:
|
|
|
|
FtPresent - is set to true if boot/system/pagefile FT sets are detected
|
|
in the system
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function is successful
|
|
FALSE if some fatal error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hkey;
|
|
DWORD registrySize;
|
|
PDISK_CONFIG_HEADER registry;
|
|
PDISK_REGISTRY diskRegistry;
|
|
WCHAR buffer[MAX_PATH + 1];
|
|
NTSTATUS status;
|
|
UCHAR genericBuffer[0x10000];
|
|
PSYSTEM_PAGEFILE_INFORMATION pageFileInfo;
|
|
PWCHAR p;
|
|
WCHAR bootDL = 0, systemDL = 0;
|
|
WCHAR dl;
|
|
|
|
*FtPresent = FALSE;
|
|
|
|
//
|
|
// Get the ftdisk database from registry.
|
|
// Key: HKLM\System\Disk
|
|
// Value: Information
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Disk", 0, KEY_QUERY_VALUE, &hkey) !=
|
|
ERROR_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (RegQueryValueEx(hkey, L"Information", NULL, NULL, NULL, ®istrySize) !=
|
|
ERROR_SUCCESS) {
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
registry = (PDISK_CONFIG_HEADER) LocalAlloc(0, registrySize);
|
|
if (!registry) {
|
|
RegCloseKey(hkey);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegQueryValueEx(hkey, L"Information", NULL, NULL, (LPBYTE) registry, ®istrySize) !=
|
|
ERROR_SUCCESS) {
|
|
LocalFree(registry);
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
//
|
|
// If no FT volume info is present in the registry database we are done
|
|
//
|
|
|
|
if (registry->FtInformationSize == 0) {
|
|
LocalFree(registry);
|
|
return TRUE;
|
|
}
|
|
|
|
diskRegistry = (PDISK_REGISTRY)
|
|
((PUCHAR) registry + registry->DiskInformationOffset);
|
|
|
|
|
|
//
|
|
// Check the boot volume
|
|
//
|
|
|
|
if (!GetSystemDirectory(buffer, MAX_PATH)) {
|
|
goto system;
|
|
}
|
|
|
|
if (buffer[1] != L':') {
|
|
goto system;
|
|
}
|
|
|
|
bootDL = (WCHAR) tolower(buffer[0]);
|
|
if (IsFtSet40(bootDL, diskRegistry)) {
|
|
*FtPresent = TRUE;
|
|
goto exit;
|
|
}
|
|
|
|
system:
|
|
|
|
//
|
|
// Check the system volume
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Setup", 0, KEY_QUERY_VALUE, &hkey) !=
|
|
ERROR_SUCCESS) {
|
|
goto paging;
|
|
}
|
|
|
|
registrySize = MAX_PATH * sizeof(WCHAR);
|
|
if (RegQueryValueEx(hkey, L"SystemPartition", NULL, NULL, (LPBYTE) buffer, ®istrySize) !=
|
|
ERROR_SUCCESS) {
|
|
RegCloseKey(hkey);
|
|
goto paging;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
if (!GetDeviceDriveLetter(buffer, &systemDL)) {
|
|
goto paging;
|
|
}
|
|
|
|
systemDL = (WCHAR) tolower(systemDL);
|
|
if (systemDL == bootDL) {
|
|
// already checked this drive letter
|
|
goto paging;
|
|
}
|
|
|
|
if (IsFtSet40(systemDL, diskRegistry)) {
|
|
*FtPresent = TRUE;
|
|
goto exit;
|
|
}
|
|
|
|
paging:
|
|
|
|
//
|
|
// Check the paging volumes
|
|
//
|
|
|
|
if (!NT_SUCCESS(NtQuerySystemInformation(
|
|
SystemPageFileInformation,
|
|
genericBuffer, sizeof(genericBuffer),
|
|
NULL))) {
|
|
goto exit;
|
|
}
|
|
|
|
pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) genericBuffer;
|
|
|
|
while (TRUE) {
|
|
|
|
//
|
|
// Since the format of the pagefile name generally
|
|
// looks something like "\DosDevices\x:\pagefile.sys",
|
|
// just use the first character before the column
|
|
// and assume that's the drive letter.
|
|
//
|
|
|
|
for (p = pageFileInfo->PageFileName.Buffer;
|
|
p < pageFileInfo->PageFileName.Buffer + pageFileInfo->PageFileName.Length
|
|
&& *p != L':'; p++);
|
|
|
|
if (p < pageFileInfo->PageFileName.Buffer + pageFileInfo->PageFileName.Length &&
|
|
p > pageFileInfo->PageFileName.Buffer) {
|
|
|
|
p--;
|
|
dl = (WCHAR) tolower(*p);
|
|
if (dl >= L'a' && dl <= L'z') {
|
|
|
|
//
|
|
// Found the drive letter of a paging volume
|
|
//
|
|
|
|
if (dl != bootDL && dl != systemDL) {
|
|
if (IsFtSet40(dl, diskRegistry)) {
|
|
*FtPresent = TRUE;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pageFileInfo->NextEntryOffset) {
|
|
break;
|
|
}
|
|
|
|
pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR) pageFileInfo +
|
|
pageFileInfo->NextEntryOffset);
|
|
}
|
|
|
|
exit:
|
|
|
|
LocalFree(registry);
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
OpenDevice(
|
|
PWSTR DeviceName,
|
|
PHANDLE Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a device for read
|
|
|
|
Arguments:
|
|
|
|
DeviceName - supplies the device name
|
|
|
|
Handle - returns a handle to the open device
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
UNICODE_STRING unicodeName;
|
|
int i;
|
|
|
|
status = RtlCreateUnicodeString(&unicodeName, DeviceName);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
memset(&statusBlock, 0, sizeof(IO_STATUS_BLOCK));
|
|
memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
|
|
oa.Length = sizeof(OBJECT_ATTRIBUTES);
|
|
oa.ObjectName = &unicodeName;
|
|
oa.Attributes = OBJ_CASE_INSENSITIVE;
|
|
|
|
//
|
|
// If a sharing violation occurs, retry it for
|
|
// max. 10 seconds
|
|
//
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
status = NtOpenFile(Handle, SYNCHRONIZE | GENERIC_READ,
|
|
&oa, &statusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
if (status == STATUS_SHARING_VIOLATION) {
|
|
Sleep(2000);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtlFreeUnicodeString(&unicodeName);
|
|
return status;
|
|
}
|
|
|
|
PDISK_PARTITION
|
|
FindPartitionInRegistry40(
|
|
PDISK_REGISTRY DiskRegistry,
|
|
ULONG Signature,
|
|
LONGLONG Offset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for a gicen partition into the NT 4.0 ftdisk registry
|
|
database
|
|
|
|
Arguments:
|
|
|
|
DiskRegistry - supplies the ftdisk registry database
|
|
|
|
Signature - supplies the signature of the disk where the partition resides
|
|
|
|
Offset - supplies the offset of the partition
|
|
|
|
Return Value:
|
|
|
|
The partition structure in the registry database.
|
|
NULL if the partition is not there.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_DESCRIPTION diskDescription;
|
|
USHORT i, j;
|
|
PDISK_PARTITION diskPartition;
|
|
LONGLONG tmp;
|
|
|
|
diskDescription = &DiskRegistry->Disks[0];
|
|
for (i = 0; i < DiskRegistry->NumberOfDisks; i++) {
|
|
if (diskDescription->Signature == Signature) {
|
|
for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
|
|
diskPartition = &diskDescription->Partitions[j];
|
|
memcpy(&tmp, &diskPartition->StartingOffset.QuadPart,
|
|
sizeof(LONGLONG));
|
|
if (tmp == Offset) {
|
|
return diskPartition;
|
|
}
|
|
}
|
|
}
|
|
|
|
diskDescription = (PDISK_DESCRIPTION) &diskDescription->
|
|
Partitions[diskDescription->NumberOfPartitions];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL
|
|
FtPresentOnDisk40(
|
|
HANDLE Handle,
|
|
PDISK_REGISTRY DiskRegistry,
|
|
PBOOL FtPresent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks for FT partitions on a disk
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies a handle to the open disk
|
|
|
|
DiskRegistry - supplies the ftdisk registry database
|
|
|
|
FtPresent - is set to true if FT partitions are detected on the disk
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function is successful
|
|
FALSE if some fatal error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION layout;
|
|
DWORD layoutSize;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
ULONG i;
|
|
PPARTITION_INFORMATION partInfo;
|
|
PDISK_PARTITION diskPartition;
|
|
|
|
*FtPresent = FALSE;
|
|
|
|
//
|
|
// Allocate memory for IOCTL_GET_DRIVE_LAYOUT
|
|
//
|
|
|
|
layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
|
|
32 * sizeof(PARTITION_INFORMATION);
|
|
layout = (PDRIVE_LAYOUT_INFORMATION) LocalAlloc(0, layoutSize);
|
|
if (!layout) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Read the drive layout
|
|
//
|
|
|
|
while (1) {
|
|
|
|
status = NtDeviceIoControlFile(Handle, 0, NULL, NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
NULL, 0,
|
|
layout, layoutSize);
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
break;
|
|
}
|
|
|
|
layoutSize += 32 * sizeof(PARTITION_INFORMATION);
|
|
if (layout) {
|
|
LocalFree(layout);
|
|
}
|
|
layout = (PDRIVE_LAYOUT_INFORMATION) LocalAlloc(0, layoutSize);
|
|
if (!layout) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
// inaccessible device. Act like it has no FT volumes
|
|
LocalFree(layout);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Look for FT partitions
|
|
//
|
|
|
|
for (i = 0; i < layout->PartitionCount; i++) {
|
|
|
|
//
|
|
// We're looking after recognized partitions marked
|
|
// with the 0x80 flag
|
|
//
|
|
|
|
partInfo = &(layout->PartitionEntry[i]);
|
|
if (!IsFTPartition(partInfo->PartitionType)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether the partition is marked as a member
|
|
// of an FT volume in the registry database
|
|
//
|
|
|
|
diskPartition = FindPartitionInRegistry40(
|
|
DiskRegistry, layout->Signature,
|
|
partInfo->StartingOffset.QuadPart);
|
|
if (!diskPartition) {
|
|
continue;
|
|
}
|
|
|
|
if (diskPartition->FtType != NotAnFtMember) {
|
|
*FtPresent = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LocalFree(layout);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
IsFtSet40(
|
|
WCHAR DriveLetter,
|
|
PDISK_REGISTRY DiskRegistry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cheks whether the given drive letter belongs to
|
|
an FT set
|
|
|
|
Arguments:
|
|
|
|
DriveLetter - supplies a drive letter
|
|
|
|
DiskRegistry - supplies the ftdisk registry database
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function is the drive letter belongs to an FT set
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE handle;
|
|
NTSTATUS status;
|
|
WCHAR deviceName[20];
|
|
PARTITION_INFORMATION partInfo;
|
|
BOOL b;
|
|
DWORD bytes;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PDISK_PARTITION diskPartition;
|
|
USHORT i, j;
|
|
|
|
//
|
|
// Open the volume and get its "partition" type
|
|
// If the NTFT flag is not set the volume is not an FT set
|
|
//
|
|
|
|
wsprintf(deviceName, L"\\DosDevices\\%c:", DriveLetter);
|
|
status = OpenDevice(deviceName, &handle);
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = DeviceIoControl(handle, IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL, 0, &partInfo, sizeof(partInfo),
|
|
&bytes, NULL);
|
|
CloseHandle(handle);
|
|
|
|
if (!b) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!IsFTPartition(partInfo.PartitionType)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Look for the drive letter in the FT registry. See if it belongs
|
|
// to an FT set
|
|
//
|
|
|
|
diskDescription = &DiskRegistry->Disks[0];
|
|
for (i = 0; i < DiskRegistry->NumberOfDisks; i++) {
|
|
for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
|
|
diskPartition = &diskDescription->Partitions[j];
|
|
if (diskPartition->AssignDriveLetter &&
|
|
tolower(diskPartition->DriveLetter) == tolower(DriveLetter) &&
|
|
diskPartition->FtType != NotAnFtMember) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
diskDescription = (PDISK_DESCRIPTION) &diskDescription->
|
|
Partitions[diskDescription->NumberOfPartitions];
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
GetDeviceDriveLetter(
|
|
PWSTR DeviceName,
|
|
PWCHAR DriveLetter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the drive letter (if any) of a device given
|
|
the device name (like \Device\HarddiskVolume1)
|
|
|
|
Arguments:
|
|
|
|
DeviceName - supplies the device name
|
|
|
|
DriveLetter - returns the drive letter
|
|
|
|
Return Value:
|
|
|
|
TRUE if the device has a drive letter
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cch;
|
|
WCHAR dosDevices[4096];
|
|
WCHAR target[4096];
|
|
PWCHAR dosDevice;
|
|
|
|
*DriveLetter = 0;
|
|
|
|
if (!QueryDosDevice(NULL, dosDevices, 4096)) {
|
|
return FALSE;
|
|
}
|
|
|
|
dosDevice = dosDevices;
|
|
while (*dosDevice) {
|
|
|
|
if (wcslen(dosDevice) == 2 && dosDevice[1] == L':' &&
|
|
QueryDosDevice(dosDevice, target, 4096)) {
|
|
|
|
if (!wcscmp(target, DeviceName)) {
|
|
*DriveLetter = (WCHAR) tolower(dosDevice[0]);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
while (*dosDevice++);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|