588 lines
16 KiB
C
588 lines
16 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
diskreg.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is a tool to interface between applications and the configuration
|
|||
|
registry.
|
|||
|
|
|||
|
The format of the registry information is described in the two
|
|||
|
include files ntdskreg.h and ntddft.h. The registry information
|
|||
|
is stored in a single value within the key \registry\machine\system\disk.
|
|||
|
The value name is "information". The format of this single value is
|
|||
|
a collection of "compressed" structures. Compressed structures are
|
|||
|
multi element structures where the following structure starts at the
|
|||
|
end of the preceeding structure. The picture below attempts to display
|
|||
|
this:
|
|||
|
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| DISK_CONFIG_HEADER |
|
|||
|
| contains the offset to the |
|
|||
|
| DISK_REGISTRY header and the |
|
|||
|
| FT_REGISTRY header. |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| DISK_REGISTRY |
|
|||
|
| contains a count of disks |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| DISK_DESCRIPTION |
|
|||
|
| contains a count of partitions |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| PARTITION_DESCRIPTION |
|
|||
|
| entry for each partition |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
= More DISK_DESCRIPTION plus =
|
|||
|
= PARTITION_DESCRIPTIONS for =
|
|||
|
= the number of disks in the =
|
|||
|
= system. Note, the second disk =
|
|||
|
= description starts in the "n"th =
|
|||
|
= partition location of the memory =
|
|||
|
= area. This is the meaning of =
|
|||
|
= "compressed" format. =
|
|||
|
| |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| FT_REGISTRY |
|
|||
|
| contains a count of FT components |
|
|||
|
| this is located by an offset in |
|
|||
|
| the DISK_CONFIG_HEADER |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| FT_DESCRIPTION |
|
|||
|
| contains a count of FT members |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
| FT_MEMBER |
|
|||
|
| entry for each member |
|
|||
|
+---------------------------------------+
|
|||
|
| |
|
|||
|
= More FT_DESCRIPTION plus =
|
|||
|
= FT_MEMBER entries for the number =
|
|||
|
= of FT compenents in the system =
|
|||
|
| |
|
|||
|
+---------------------------------------+
|
|||
|
|
|||
|
This packing of structures is done for two reasons:
|
|||
|
|
|||
|
1. to conserve space in the registry. If there are only two partitions
|
|||
|
on a disk then there are only two PARTITION_DESCRIPTIONs in the
|
|||
|
registry for that disk.
|
|||
|
2. to not impose a maximum on the number of items that can be described
|
|||
|
in the registry. For example if the number of members in a stripe
|
|||
|
set were to change from 32 to 64 there would be no effect on the
|
|||
|
registry format, only on the UI that presents it to the user.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bob Rinne (bobri) 2-Apr-1992
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User process. Library written for DiskMan use.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
8-Dec-93 (bobri) Added double space and cdrom registry manipulation routines.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <conio.h>
|
|||
|
#include <ctype.h>
|
|||
|
#include <string.h>
|
|||
|
//#include <io.h>
|
|||
|
#include <ntdskreg.h>
|
|||
|
#include <ntddft.h>
|
|||
|
#include <ntdddisk.h>
|
|||
|
#include <windef.h>
|
|||
|
#include <winbase.h>
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Size of memory area to allocate for configuration registry use.
|
|||
|
//
|
|||
|
|
|||
|
#define DISKS_PRINT printf
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Constant strings.
|
|||
|
//
|
|||
|
|
|||
|
PUCHAR DiskRegistryKey = DISK_REGISTRY_KEY;
|
|||
|
PUCHAR DiskRegistryValue = DISK_REGISTRY_VALUE;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FtCreateKey(
|
|||
|
PHANDLE HandlePtr,
|
|||
|
PUCHAR KeyName,
|
|||
|
PUCHAR KeyClass
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an asciiz name, this routine will create a key in the configuration
|
|||
|
registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandlePtr - pointer to handle if create is successful.
|
|||
|
KeyName - asciiz string, the name of the key to create.
|
|||
|
KeyClass - registry class for the new key.
|
|||
|
DiskInfo - disk information for the associated partition.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - from the config registry calls.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
STRING keyString;
|
|||
|
UNICODE_STRING unicodeKeyName;
|
|||
|
STRING classString;
|
|||
|
UNICODE_STRING unicodeClassName;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
ULONG disposition;
|
|||
|
HANDLE tempHandle;
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ((KeyName == NULL) ||
|
|||
|
(KeyClass == NULL)) {
|
|||
|
DISKS_PRINT("FtCreateKey: Invalid parameter 0x%1!x!, 0x%2!x!\n",
|
|||
|
KeyName,
|
|||
|
KeyClass);
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the object for the key.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitString(&keyString,
|
|||
|
KeyName);
|
|||
|
|
|||
|
(VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
|
|||
|
&keyString,
|
|||
|
TRUE);
|
|||
|
|
|||
|
memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
&unicodeKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Setup the unicode class value.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitString(&classString,
|
|||
|
KeyClass);
|
|||
|
(VOID)RtlAnsiStringToUnicodeString(&unicodeClassName,
|
|||
|
&classString,
|
|||
|
TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Create the key.
|
|||
|
//
|
|||
|
|
|||
|
status = NtCreateKey(&tempHandle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
&unicodeClassName,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
&disposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
switch (disposition)
|
|||
|
{
|
|||
|
case REG_CREATED_NEW_KEY:
|
|||
|
break;
|
|||
|
|
|||
|
case REG_OPENED_EXISTING_KEY:
|
|||
|
DISKS_PRINT("Warning: Creation was for an existing key!\n");
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DISKS_PRINT("New disposition returned == 0x%x\n", disposition);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free all allocated space.
|
|||
|
//
|
|||
|
|
|||
|
RtlFreeUnicodeString(&unicodeKeyName);
|
|||
|
RtlFreeUnicodeString(&unicodeClassName);
|
|||
|
|
|||
|
if (HandlePtr != NULL) {
|
|||
|
*HandlePtr = tempHandle;
|
|||
|
} else {
|
|||
|
NtClose(tempHandle);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FtOpenKey(
|
|||
|
PHANDLE HandlePtr,
|
|||
|
PUCHAR KeyName,
|
|||
|
PUCHAR CreateKeyClass
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an asciiz string, this routine will open a key in the configuration
|
|||
|
registry and return the HANDLE to the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandlePtr - location for HANDLE on success.
|
|||
|
KeyName - asciiz string for the key to be opened.
|
|||
|
CreateKeyClass - if NULL do not create key name.
|
|||
|
If !NULL call create if open fails.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - from the config registry calls.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
STRING keyString;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
UNICODE_STRING unicodeKeyName;
|
|||
|
|
|||
|
RtlInitString(&keyString,
|
|||
|
KeyName);
|
|||
|
|
|||
|
(VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
|
|||
|
&keyString,
|
|||
|
TRUE);
|
|||
|
|
|||
|
memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
&unicodeKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
status = NtOpenKey(HandlePtr,
|
|||
|
MAXIMUM_ALLOWED,
|
|||
|
&objectAttributes);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&unicodeKeyName);
|
|||
|
|
|||
|
|
|||
|
if ((!NT_SUCCESS(status)) && (CreateKeyClass)) {
|
|||
|
status = FtCreateKey(HandlePtr,
|
|||
|
KeyName,
|
|||
|
CreateKeyClass);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FtRegistryQuery(
|
|||
|
IN PUCHAR ValueName,
|
|||
|
OUT PVOID *FreeToken,
|
|||
|
OUT PVOID *Buffer,
|
|||
|
OUT ULONG *LengthReturned,
|
|||
|
OUT PHANDLE HandlePtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens the Disk Registry key and gets the contents of the
|
|||
|
disk information value. It returns this contents to the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ValueName - asciiz string for the value name to query.
|
|||
|
FreeToken - A pointer to a buffer to be freed by the caller. This is the
|
|||
|
buffer pointer allocated to obtain the registry information
|
|||
|
via the registry APIs. To the caller it is an opaque value.
|
|||
|
Buffer - pointer to a pointer for a buffer containing the desired
|
|||
|
registry value contents. This is allocated by this routine and
|
|||
|
is part of the "FreeToken" buffer allocated once the actual
|
|||
|
size of the registry information is known.
|
|||
|
LengthReturned - pointer to location for the size of the contents returned.
|
|||
|
HandlePtr - pointer to a handle pointer if the caller wishes to keep it
|
|||
|
open for later use.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - from the configuration registry.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE handle;
|
|||
|
ULONG resultLength;
|
|||
|
STRING valueString;
|
|||
|
UNICODE_STRING unicodeValueName;
|
|||
|
PDISK_CONFIG_HEADER regHeader;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
|
|||
|
*LengthReturned = 0;
|
|||
|
status = FtOpenKey(&handle,
|
|||
|
DiskRegistryKey,
|
|||
|
NULL);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
RtlInitString(&valueString,
|
|||
|
ValueName);
|
|||
|
RtlAnsiStringToUnicodeString(&unicodeValueName,
|
|||
|
&valueString,
|
|||
|
TRUE);
|
|||
|
resultLength = 0;
|
|||
|
|
|||
|
while (1) {
|
|||
|
if ( resultLength != 0 ) {
|
|||
|
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
|
|||
|
LocalAlloc(LMEM_FIXED, resultLength);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// PREFIX bug: 47610
|
|||
|
// If the memory can't be allocated, stop processing. This code will
|
|||
|
// correctly fall through and return NULL to FreeToken (because
|
|||
|
// keyValueInformation is NULL).
|
|||
|
//
|
|||
|
|
|||
|
if ( !keyValueInformation ) {
|
|||
|
status = STATUS_NO_MEMORY;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status = NtQueryValueKey(handle,
|
|||
|
&unicodeValueName,
|
|||
|
KeyValueFullInformation,
|
|||
|
keyValueInformation,
|
|||
|
resultLength,
|
|||
|
&resultLength);
|
|||
|
|
|||
|
if ( status != STATUS_BUFFER_TOO_SMALL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Either a real error or the information fit.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
|
|||
|
if (HandlePtr != NULL) {
|
|||
|
*HandlePtr = handle;
|
|||
|
} else {
|
|||
|
NtClose(handle);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if (keyValueInformation->DataLength == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Treat this as if there was not disk information.
|
|||
|
//
|
|||
|
|
|||
|
LocalFree(keyValueInformation);
|
|||
|
*FreeToken = (PVOID) NULL;
|
|||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Set up the pointers for the caller.
|
|||
|
//
|
|||
|
|
|||
|
regHeader = (PDISK_CONFIG_HEADER)
|
|||
|
((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
|
|||
|
*LengthReturned = regHeader->FtInformationOffset +
|
|||
|
regHeader->FtInformationSize;
|
|||
|
*Buffer = (PVOID) regHeader;
|
|||
|
}
|
|||
|
}
|
|||
|
*FreeToken = (PVOID) keyValueInformation;
|
|||
|
} else {
|
|||
|
*FreeToken = (PVOID) NULL;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
GetAssignedDriveLetter(
|
|||
|
ULONG Signature,
|
|||
|
LARGE_INTEGER StartingOffset,
|
|||
|
LARGE_INTEGER Length,
|
|||
|
PUCHAR DriveLetter,
|
|||
|
PULONG Partition
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will get the information from the disk registry
|
|||
|
and return the drive letter assigned for the partition in
|
|||
|
the registry information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Signature - disk signature for disk containing partition for letter.
|
|||
|
StartingOffset - Starting offset of partition for the letter.
|
|||
|
Length - length of specified partition.
|
|||
|
DriveLetter - Place to return drive letter for partition.
|
|||
|
Partition - Found partition number.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if all works.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOID freeToken = NULL;
|
|||
|
ULONG lengthReturned,
|
|||
|
i,
|
|||
|
j;
|
|||
|
NTSTATUS status;
|
|||
|
PDISK_CONFIG_HEADER regHeader;
|
|||
|
PDISK_REGISTRY diskRegistry;
|
|||
|
PDISK_DESCRIPTION diskDescription;
|
|||
|
PDISK_PARTITION diskPartition;
|
|||
|
HANDLE handle;
|
|||
|
|
|||
|
*DriveLetter = ' ';
|
|||
|
|
|||
|
//
|
|||
|
// Get the registry information.
|
|||
|
//
|
|||
|
|
|||
|
status = FtRegistryQuery(DiskRegistryValue,
|
|||
|
&freeToken,
|
|||
|
(PVOID *) ®Header,
|
|||
|
&lengthReturned,
|
|||
|
&handle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Could be permission problem, or there is no registry information.
|
|||
|
//
|
|||
|
|
|||
|
lengthReturned = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Try to open the key for later use when setting the new value.
|
|||
|
//
|
|||
|
|
|||
|
status = FtOpenKey(&handle,
|
|||
|
DiskRegistryKey,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// There is no registry key for the disk information.
|
|||
|
// Return FALSE and force caller to create registry information.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (lengthReturned == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// There is currently no registry information.
|
|||
|
//
|
|||
|
|
|||
|
NtClose(handle);
|
|||
|
LocalFree(freeToken);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Search all disks.
|
|||
|
//
|
|||
|
|
|||
|
diskRegistry = (PDISK_REGISTRY)
|
|||
|
((PUCHAR)regHeader + regHeader->DiskInformationOffset);
|
|||
|
diskDescription = &diskRegistry->Disks[0];
|
|||
|
|
|||
|
for (i = 0; i < diskRegistry->NumberOfDisks; i++) {
|
|||
|
|
|||
|
if ( diskDescription->Signature != Signature ) {
|
|||
|
goto next_disk;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now locate the partition.
|
|||
|
//
|
|||
|
|
|||
|
for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
|
|||
|
|
|||
|
diskPartition = &diskDescription->Partitions[j];
|
|||
|
|
|||
|
if ( (diskPartition->StartingOffset.QuadPart == StartingOffset.QuadPart) &&
|
|||
|
(diskPartition->Length.QuadPart == Length.QuadPart) ) {
|
|||
|
|
|||
|
*DriveLetter = diskPartition->DriveLetter;
|
|||
|
*Partition = j;
|
|||
|
NtClose(handle);
|
|||
|
LocalFree( freeToken );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
next_disk:
|
|||
|
//
|
|||
|
// Look at the next disk
|
|||
|
//
|
|||
|
|
|||
|
diskDescription = (PDISK_DESCRIPTION)
|
|||
|
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
|||
|
}
|
|||
|
|
|||
|
NtClose(handle);
|
|||
|
LocalFree(freeToken);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|