3315 lines
76 KiB
C
3315 lines
76 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
editreg.c
|
||
|
||
Abstract:
|
||
|
||
This program acts as an interactive shell allowing a user to view
|
||
and manipulate the configuration registry. Also, it has some specific
|
||
commands for support of the NTFT component of the registry.
|
||
|
||
Author:
|
||
|
||
Mike Glass
|
||
Bob Rinne
|
||
|
||
Environment:
|
||
|
||
User process.
|
||
|
||
Notes:
|
||
|
||
The commands "disk", "fix", "restore" are commands that know where
|
||
the configuration information is for the NTFT component of the NT
|
||
system.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "cmp.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include "ntdskreg.h"
|
||
#include "ntddft.h"
|
||
|
||
//
|
||
// Tempory stuff to get types and values to print in help.
|
||
//
|
||
|
||
PUCHAR TypeNames[] =
|
||
{
|
||
"REG_NONE",
|
||
"REG_SZ",
|
||
"REG_BINARY",
|
||
"REG_DWORD",
|
||
"REG_DWORD_LITTLE_ENDIAN",
|
||
"REG_DWORD_BIG_ENDIAN",
|
||
"REG_LINK",
|
||
"REG_MULTI_SZ",
|
||
"REG_RESOURCE_LIST",
|
||
NULL
|
||
};
|
||
|
||
ULONG TypeNumbers[] =
|
||
{
|
||
REG_NONE,
|
||
REG_SZ,
|
||
REG_BINARY,
|
||
REG_DWORD,
|
||
REG_DWORD_LITTLE_ENDIAN,
|
||
REG_DWORD_BIG_ENDIAN,
|
||
REG_LINK,
|
||
REG_MULTI_SZ,
|
||
REG_RESOURCE_LIST
|
||
};
|
||
|
||
//
|
||
// Special support for the driver load lists in the registry.
|
||
//
|
||
|
||
PUCHAR StartDescription[] =
|
||
{
|
||
"Boot loader",
|
||
"System",
|
||
"2",
|
||
"3",
|
||
|
||
//
|
||
// Anything above 3 is not loaded.
|
||
//
|
||
|
||
NULL
|
||
};
|
||
|
||
PUCHAR TypeDescription[] =
|
||
{
|
||
"System driver",
|
||
"File system",
|
||
"Service",
|
||
NULL
|
||
};
|
||
|
||
|
||
//
|
||
// Constants and defines.
|
||
//
|
||
|
||
#define WORK_BUFFER_SIZE 4096
|
||
|
||
//
|
||
// Amount to fudge when mallocing for strings.
|
||
//
|
||
|
||
#define FUDGE 8
|
||
|
||
//
|
||
// Registry base.
|
||
//
|
||
|
||
#define REGISTRY_BASE "\\REGISTRY\\MACHINE"
|
||
|
||
//
|
||
// Default type value when key value set.
|
||
//
|
||
|
||
#define DEFAULT_TYPE REG_SZ
|
||
|
||
//
|
||
// Base location for component descriptions of FT elements.
|
||
//
|
||
|
||
#define FT_REGISTRY_ROOT "\\REGISTRY\\MACHINE\\SYSTEM\\NTFT"
|
||
|
||
//
|
||
// Subkey name located in the FT_REGISTRY_ROOT for stripes.
|
||
//
|
||
|
||
#define FT_STRIPE_BASE "Stripe%d"
|
||
|
||
//
|
||
// Subkey name located in the FT_REGISTRY_ROOT for mirrors.
|
||
//
|
||
|
||
#define FT_MIRROR_BASE "Mirror%d"
|
||
|
||
//
|
||
// Subkey name located in the FT_REGISTRY_ROOT for volume sets.
|
||
//
|
||
|
||
#define FT_VOLSET_BASE "VolSet%d"
|
||
|
||
|
||
//
|
||
// Constants for the command values.
|
||
//
|
||
|
||
#define INVALID -1
|
||
#define DIR 0
|
||
#define CREATE 1
|
||
#define LIST 2
|
||
#define CHDIR 3
|
||
#define HELP 4
|
||
#define QUIT 5
|
||
#define DDEBUG 6
|
||
#define SETVALUE 7
|
||
#define DELKEY 8
|
||
#define DELVALUE 9
|
||
#define DIRLONG 10
|
||
#define INLONG 11
|
||
#define INSHORT 12
|
||
#define INBYTE 13
|
||
#define DUMP 14
|
||
#define DISKREG 15
|
||
#define FIXDISK 16
|
||
#define RESTORE 17
|
||
#define DRIVERS 18
|
||
#define ORPHAN 19
|
||
#define REGEN 20
|
||
#define INIT 21
|
||
#define MAKEFT 22
|
||
|
||
#define CTRL_C 0x03
|
||
|
||
//
|
||
// Table of recognized commands.
|
||
//
|
||
|
||
PUCHAR Commands[] = {
|
||
"dir",
|
||
"keys",
|
||
"lc",
|
||
"ls",
|
||
"create",
|
||
"set",
|
||
"unset",
|
||
"erase",
|
||
"delete",
|
||
"rm",
|
||
"list",
|
||
"values",
|
||
"display",
|
||
"cd",
|
||
"chdir",
|
||
"help",
|
||
"?",
|
||
"quit",
|
||
"exit",
|
||
"debug",
|
||
"longs",
|
||
"shorts",
|
||
"bytes",
|
||
"dump",
|
||
"disks",
|
||
"fix",
|
||
"restore",
|
||
"drivers",
|
||
"orphan",
|
||
"regenerate",
|
||
"initialize",
|
||
"makeft",
|
||
NULL
|
||
};
|
||
|
||
//
|
||
// Using the index from the match on the commands in Commands[], this
|
||
// table gives the proper command value to be executed. This allows
|
||
// for multiple entries in Commands[] for the same command code.
|
||
//
|
||
|
||
int CommandMap[] = {
|
||
|
||
DIRLONG,
|
||
DIR,
|
||
DIR,
|
||
DIR,
|
||
CREATE,
|
||
SETVALUE,
|
||
DELVALUE,
|
||
DELVALUE,
|
||
DELKEY,
|
||
DELKEY,
|
||
LIST,
|
||
LIST,
|
||
LIST,
|
||
CHDIR,
|
||
CHDIR,
|
||
HELP,
|
||
HELP,
|
||
QUIT,
|
||
QUIT,
|
||
DDEBUG,
|
||
INLONG,
|
||
INSHORT,
|
||
INBYTE,
|
||
DUMP,
|
||
DISKREG,
|
||
FIXDISK,
|
||
RESTORE,
|
||
DRIVERS,
|
||
ORPHAN,
|
||
REGEN,
|
||
INIT,
|
||
MAKEFT
|
||
};
|
||
|
||
//
|
||
// CommandHelp is an array of help strings for each of the commands.
|
||
// The array is indexed by the result of CommandMap[i] for the Commands[]
|
||
// array. This way the same help message will print for each of the
|
||
// commands aliases.
|
||
//
|
||
|
||
PUCHAR CommandHelp[] = {
|
||
|
||
"Displays keys.",
|
||
"Create a new key.",
|
||
"Displays values withing a key.",
|
||
"Change current location in registry.",
|
||
"This help information.",
|
||
"Exit the program.",
|
||
"Set internal debug on for this program.",
|
||
"Set a new value within a key.",
|
||
"Delete a key.",
|
||
"Unset (erase) a key value.",
|
||
"Unset (erase) a key value.",
|
||
"Change dump format to Longs (default).",
|
||
"Change dump format to Shorts.",
|
||
"Change dump format to Bytes.",
|
||
"Toggle dump mode (force hex dump for all value types).",
|
||
"Display the disk registry.",
|
||
"Set disk signatures in registry.",
|
||
"Restore an FT orphan to working state.",
|
||
"List the information on the drivers from the registry.",
|
||
"Orphan a member of an FT set.",
|
||
"Mark a FT set member for regeneration on next boot.",
|
||
"Mark a stripe with parity for initialization on next boot.",
|
||
"Construct an FT set from existing partitions",
|
||
NULL
|
||
|
||
};
|
||
|
||
//
|
||
// Space for working location string in registry.
|
||
//
|
||
|
||
UCHAR WorkingDirectory[512];
|
||
|
||
//
|
||
// Space for current location string in registry.
|
||
//
|
||
|
||
UCHAR CurrentDirectory[512];
|
||
|
||
//
|
||
// Space for command input.
|
||
//
|
||
|
||
UCHAR CommandLine[512];
|
||
|
||
//
|
||
// Prompt strings for getting definition for an FT_COPY request.
|
||
//
|
||
|
||
PUCHAR SetPrompts[] = {
|
||
|
||
"Name => ",
|
||
"Value => ",
|
||
"Index => ",
|
||
NULL
|
||
};
|
||
|
||
//
|
||
// Version indicator. Should be changed every time a major edit occurs.
|
||
//
|
||
|
||
PUCHAR Version = "Version 1.30";
|
||
|
||
//
|
||
// Debug print level.
|
||
//
|
||
|
||
ULONG Debug = 0;
|
||
|
||
//
|
||
// Dump control values.
|
||
//
|
||
|
||
typedef enum _DUMP_CONTROL {
|
||
|
||
InBytes,
|
||
InShorts,
|
||
InLongs
|
||
|
||
} DUMP_CONTROL, *PDUMP_CONTROL;
|
||
|
||
ULONG ForceDump = 0;
|
||
|
||
DUMP_CONTROL DumpControl = InLongs;
|
||
|
||
NTSTATUS
|
||
FtOpenKey(
|
||
PHANDLE HandlePtr,
|
||
PUCHAR KeyName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
STRING keyString;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
UNICODE_STRING unicodeKeyName;
|
||
|
||
RtlInitString(&keyString,
|
||
KeyName);
|
||
|
||
(VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
|
||
&keyString,
|
||
(BOOLEAN) TRUE);
|
||
|
||
memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
||
InitializeObjectAttributes(&objectAttributes,
|
||
&unicodeKeyName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
status = NtOpenKey(HandlePtr,
|
||
MAXIMUM_ALLOWED,
|
||
&objectAttributes);
|
||
|
||
RtlFreeUnicodeString(&unicodeKeyName);
|
||
|
||
if (Debug == 1) {
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Failed NtOpenKey for %s => %x\n",
|
||
KeyName,
|
||
status);
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FtDeleteKey(
|
||
PUCHAR KeyName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
HANDLE keyToDelete;
|
||
|
||
status = FtOpenKey(&keyToDelete,
|
||
KeyName);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Key %s not found (0x%x).\n", KeyName, status);
|
||
return status;
|
||
}
|
||
|
||
status = NtDeleteKey(keyToDelete);
|
||
|
||
if (Debug == 1) {
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not delete key %s => %x\n",
|
||
KeyName,
|
||
status);
|
||
}
|
||
}
|
||
|
||
NtClose(keyToDelete);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FtCreateKey(
|
||
PUCHAR KeyName,
|
||
PUCHAR KeyClass,
|
||
ULONG Index
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
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)) {
|
||
printf("FtCreateKey: Invalid parameter 0x%x, 0x%x\n",
|
||
KeyName,
|
||
KeyClass);
|
||
ASSERT(0);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Initialize the object for the key.
|
||
//
|
||
|
||
RtlInitString(&keyString,
|
||
KeyName);
|
||
|
||
(VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
|
||
&keyString,
|
||
(BOOLEAN) 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,
|
||
(BOOLEAN) TRUE);
|
||
|
||
//
|
||
// Create the key.
|
||
//
|
||
|
||
status = NtCreateKey(&tempHandle,
|
||
MAXIMUM_ALLOWED,
|
||
&objectAttributes,
|
||
Index,
|
||
&unicodeClassName,
|
||
REG_OPTION_NON_VOLATILE,
|
||
&disposition);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
switch (disposition)
|
||
{
|
||
case REG_CREATED_NEW_KEY:
|
||
break;
|
||
|
||
case REG_OPENED_EXISTING_KEY:
|
||
printf("Warning: Creation was for an existing key!\n");
|
||
break;
|
||
|
||
default:
|
||
printf("New disposition returned == 0x%x\n", disposition);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Free all allocated space.
|
||
//
|
||
|
||
RtlFreeUnicodeString(&unicodeKeyName);
|
||
RtlFreeUnicodeString(&unicodeClassName);
|
||
NtClose(tempHandle);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FtDeleteValue(
|
||
HANDLE KeyHandle,
|
||
PUCHAR ValueName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
STRING valueString;
|
||
UNICODE_STRING unicodeValueName;
|
||
|
||
RtlInitString(&valueString,
|
||
ValueName);
|
||
status = RtlAnsiStringToUnicodeString(&unicodeValueName,
|
||
&valueString,
|
||
(BOOLEAN) TRUE);
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("FtDeleteValue: internal conversion error 0x%x\n", status);
|
||
return status;
|
||
}
|
||
|
||
status = NtDeleteValueKey(KeyHandle,
|
||
&unicodeValueName);
|
||
if (Debug == 1) {
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not delete value %s => %x\n",
|
||
ValueName,
|
||
status);
|
||
}
|
||
}
|
||
|
||
RtlFreeUnicodeString(&unicodeValueName);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
FtSetValue(
|
||
HANDLE KeyHandle,
|
||
PUCHAR ValueName,
|
||
PVOID DataBuffer,
|
||
ULONG DataLength,
|
||
ULONG Type
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
STRING valueString;
|
||
UNICODE_STRING unicodeValueName;
|
||
|
||
RtlInitString(&valueString,
|
||
ValueName);
|
||
RtlAnsiStringToUnicodeString(&unicodeValueName,
|
||
&valueString,
|
||
(BOOLEAN) TRUE);
|
||
status = NtSetValueKey(KeyHandle,
|
||
&unicodeValueName,
|
||
0,
|
||
Type,
|
||
DataBuffer,
|
||
DataLength);
|
||
if (Debug == 1) {
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not set value %s => %x\n",
|
||
ValueName,
|
||
status);
|
||
}
|
||
}
|
||
|
||
RtlFreeUnicodeString(&unicodeValueName);
|
||
return status;
|
||
}
|
||
|
||
|
||
PUCHAR
|
||
FindTypeString(
|
||
ULONG Type
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; TypeNames[i] != NULL; i++) {
|
||
|
||
if (TypeNumbers[i] == Type) {
|
||
return TypeNames[i];
|
||
}
|
||
}
|
||
return "(Unknown)";
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
ProcessHex(
|
||
PUCHAR String,
|
||
PULONG Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG workValue;
|
||
int i;
|
||
PUCHAR cp;
|
||
|
||
if (String == NULL) {
|
||
return FALSE;
|
||
}
|
||
|
||
cp = String;
|
||
|
||
//
|
||
// 'i' is an index value. It contains the maximum index into the String.
|
||
// Therefore it is initialized to -1.
|
||
//
|
||
|
||
i = -1;
|
||
while ((*cp) && (*cp != '\n')) {
|
||
i++;
|
||
cp++;
|
||
}
|
||
|
||
if (i >= 8) {
|
||
|
||
//
|
||
// String to long for a long.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
workValue = 0;
|
||
cp = String;
|
||
while (*cp) {
|
||
*cp = (UCHAR) tolower(*cp);
|
||
|
||
switch (*cp) {
|
||
|
||
case '0':
|
||
case '1':
|
||
case '2':
|
||
case '3':
|
||
case '4':
|
||
case '5':
|
||
case '6':
|
||
case '7':
|
||
case '8':
|
||
case '9':
|
||
workValue |= (((*cp) - '0') << (i * 4));
|
||
break;
|
||
|
||
case 'a':
|
||
case 'b':
|
||
case 'c':
|
||
case 'd':
|
||
case 'e':
|
||
case 'f':
|
||
workValue |= ((((*cp) - 'a') + 10) << (i * 4));
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Illegal value, just punt.
|
||
//
|
||
|
||
return FALSE;
|
||
break;
|
||
}
|
||
cp++;
|
||
i--;
|
||
}
|
||
|
||
*Value = workValue;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
Dump(
|
||
PVOID Buffer,
|
||
ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dump the value data from a buffer in the format specified.
|
||
|
||
Arguments:
|
||
|
||
Buffer - pointer to the data.
|
||
Length - length of the data.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PUCHAR location;
|
||
PUCHAR internalBuffer;
|
||
int i;
|
||
int j;
|
||
int numberLines;
|
||
UCHAR outHexLine[128];
|
||
UCHAR outPrintable[64];
|
||
|
||
numberLines = (Length + 15) / 16;
|
||
|
||
//
|
||
// Since the amount of data displayed has been rounded up, this
|
||
// routine mallocs enough space and copies the data in. This way
|
||
// it won't fault if the data is at the end of memory.
|
||
//
|
||
|
||
internalBuffer = (PUCHAR) malloc(numberLines * 16);
|
||
RtlMoveMemory(internalBuffer, Buffer, Length);
|
||
location = (PUCHAR) internalBuffer;
|
||
|
||
for (i = 0; i < numberLines; i++) {
|
||
|
||
sprintf(outHexLine, "%8x: ", (i * 16));
|
||
sprintf(outPrintable, "*");
|
||
switch (DumpControl) {
|
||
|
||
case InBytes:
|
||
|
||
for (j = 0; j < 16; j++) {
|
||
sprintf(outHexLine, "%s%2X ", outHexLine, *location);
|
||
sprintf(outPrintable, "%s%c", outPrintable,
|
||
(isprint(location[0])) ? location[0] : '.');
|
||
location++;
|
||
}
|
||
break;
|
||
|
||
case InShorts:
|
||
|
||
for (j = 0; j < 8; j++) {
|
||
sprintf(outHexLine, "%s%4X ", outHexLine,
|
||
*((PUSHORT)location));
|
||
sprintf(outPrintable, "%s%c%c", outPrintable,
|
||
(isprint(location[0])) ? location[0] : '.',
|
||
(isprint(location[1])) ? location[1] : '.');
|
||
location += 2;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
case InLongs:
|
||
|
||
for (j = 0; j < 4; j++) {
|
||
sprintf(outHexLine, "%s%8X ", outHexLine,
|
||
*((PULONG)location));
|
||
sprintf(outPrintable, "%s%c%c%c%c", outPrintable,
|
||
(isprint(location[0])) ? location[0] : '.',
|
||
(isprint(location[1])) ? location[1] : '.',
|
||
(isprint(location[2])) ? location[2] : '.',
|
||
(isprint(location[3])) ? location[3] : '.');
|
||
location += 4;
|
||
}
|
||
break;
|
||
}
|
||
|
||
printf("%s %s*\n", outHexLine, outPrintable);
|
||
}
|
||
printf("\n");
|
||
free(internalBuffer);
|
||
}
|
||
|
||
|
||
void
|
||
UnicodePrint(
|
||
PUNICODE_STRING UnicodeString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Print a unicode string.
|
||
|
||
Arguments:
|
||
|
||
UnicodeString - pointer to the string.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ANSI_STRING ansiString;
|
||
PUCHAR tempbuffer = (PUCHAR) malloc(WORK_BUFFER_SIZE);
|
||
|
||
ansiString.MaximumLength = WORK_BUFFER_SIZE;
|
||
ansiString.Length = 0L;
|
||
ansiString.Buffer = tempbuffer;
|
||
|
||
RtlUnicodeStringToAnsiString(&ansiString,
|
||
UnicodeString,
|
||
(BOOLEAN) FALSE);
|
||
printf("%s", ansiString.Buffer);
|
||
free(tempbuffer);
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
Directory(
|
||
HANDLE KeyHandle,
|
||
BOOLEAN LongListing
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
ULONG index;
|
||
ULONG resultLength;
|
||
UNICODE_STRING unicodeValueName;
|
||
PKEY_BASIC_INFORMATION keyInformation;
|
||
|
||
keyInformation = (PKEY_BASIC_INFORMATION) malloc(WORK_BUFFER_SIZE);
|
||
|
||
for (index = 0; TRUE; index++) {
|
||
|
||
RtlZeroMemory(keyInformation, WORK_BUFFER_SIZE);
|
||
|
||
status = NtEnumerateKey(KeyHandle,
|
||
index,
|
||
KeyBasicInformation,
|
||
keyInformation,
|
||
WORK_BUFFER_SIZE,
|
||
&resultLength);
|
||
|
||
if (status == STATUS_NO_MORE_ENTRIES) {
|
||
|
||
break;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
|
||
printf("readreg: Error on Enumerate status = %x\n", status);
|
||
break;
|
||
|
||
}
|
||
|
||
unicodeValueName.Length = (USHORT)keyInformation->NameLength;
|
||
unicodeValueName.MaximumLength = (USHORT)keyInformation->NameLength;
|
||
unicodeValueName.Buffer = (PWSTR)&keyInformation->Name[0];
|
||
UnicodePrint(&unicodeValueName);
|
||
printf("\n");
|
||
|
||
if (LongListing) {
|
||
}
|
||
}
|
||
|
||
free(keyInformation);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
List(
|
||
HANDLE KeyHandle,
|
||
PUCHAR ItemName
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
ULONG index;
|
||
ULONG resultLength;
|
||
ULONG type;
|
||
PUCHAR typeString;
|
||
UNICODE_STRING unicodeValueName;
|
||
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
||
|
||
UNREFERENCED_PARAMETER(ItemName);
|
||
|
||
resultLength = WORK_BUFFER_SIZE;
|
||
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
|
||
|
||
for (index = 0; TRUE; index++) {
|
||
|
||
while (1) {
|
||
|
||
RtlZeroMemory(keyValueInformation, resultLength);
|
||
status = NtEnumerateValueKey(KeyHandle,
|
||
index,
|
||
KeyValueFullInformation,
|
||
keyValueInformation,
|
||
resultLength,
|
||
&resultLength);
|
||
|
||
if (status == STATUS_BUFFER_OVERFLOW) {
|
||
free(keyValueInformation);
|
||
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
|
||
malloc(resultLength + 10);
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (status == STATUS_NO_MORE_ENTRIES) {
|
||
|
||
break;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
|
||
printf("readreg: Cannot list (%x)\n", status);
|
||
break;
|
||
|
||
}
|
||
|
||
type = keyValueInformation->Type;
|
||
typeString = FindTypeString(type);
|
||
unicodeValueName.Length = (USHORT)keyValueInformation->NameLength;
|
||
unicodeValueName.MaximumLength =(USHORT)keyValueInformation->NameLength;
|
||
unicodeValueName.Buffer = (PWSTR)&keyValueInformation->Name[0];
|
||
printf("Name-> """);
|
||
UnicodePrint(&unicodeValueName);
|
||
printf("""\n");
|
||
printf("\ttype = %s (%d)\ttitle index = %d\tdata length = %d\n",
|
||
typeString,
|
||
type,
|
||
keyValueInformation->TitleIndex,
|
||
keyValueInformation->DataLength);
|
||
printf("\tData:\n");
|
||
|
||
if (ForceDump) {
|
||
type = REG_BINARY;
|
||
}
|
||
|
||
switch (type) {
|
||
|
||
case REG_DWORD:
|
||
// case REG_DWORD_LITTLE_ENDIAN:
|
||
printf("\tDWORD value == %d, (0x%x)\n",
|
||
*((PULONG)((PUCHAR)keyValueInformation +
|
||
keyValueInformation->DataOffset)),
|
||
*((PULONG)((PUCHAR)keyValueInformation +
|
||
keyValueInformation->DataOffset)));
|
||
break;
|
||
|
||
case REG_SZ:
|
||
|
||
unicodeValueName.Length = (USHORT)keyValueInformation->DataLength;
|
||
unicodeValueName.MaximumLength = (USHORT)
|
||
keyValueInformation->DataLength;
|
||
unicodeValueName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation +
|
||
keyValueInformation->DataOffset);
|
||
UnicodePrint(&unicodeValueName);
|
||
break;
|
||
|
||
case REG_BINARY:
|
||
default:
|
||
Dump(((PUCHAR)keyValueInformation +keyValueInformation->DataOffset),
|
||
keyValueInformation->DataLength);
|
||
}
|
||
printf("\n");
|
||
}
|
||
|
||
free(keyValueInformation);
|
||
return status;
|
||
}
|
||
|
||
|
||
UCHAR
|
||
GetCharacter(
|
||
BOOLEAN Batch
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a single character from the input stream.
|
||
It discards leading blanks if the input is not from the console.
|
||
|
||
Arguments:
|
||
|
||
Batch - a boolean indicating if the input it coming from the console.
|
||
|
||
Return Value:
|
||
|
||
A character
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR c;
|
||
|
||
if (Batch) {
|
||
|
||
while ((c = (UCHAR) getchar()) == ' ')
|
||
;
|
||
|
||
} else {
|
||
|
||
c = (UCHAR) getchar();
|
||
}
|
||
|
||
return c;
|
||
} // GetCharacter
|
||
|
||
|
||
PUCHAR
|
||
GetArgumentString(
|
||
BOOLEAN Batch,
|
||
PUCHAR Prompt,
|
||
BOOLEAN ConvertToLower
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine prints the prompt if the input is coming from the console,
|
||
then proceeds to collect the user input until a carraige return is typed.
|
||
|
||
Arguments:
|
||
|
||
Batch - a boolean indicating if the input is coming from the console.
|
||
Prompt - String to prompt with.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the input string.
|
||
NULL if the user escaped.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// The command line data area is used to store the argument string.
|
||
//
|
||
|
||
PUCHAR argument = CommandLine;
|
||
int i;
|
||
UCHAR c;
|
||
|
||
if (!Batch) {
|
||
|
||
printf("%s", Prompt);
|
||
}
|
||
|
||
while ((c = GetCharacter(Batch)) == ' ') {
|
||
|
||
//
|
||
// Ignore leading spaces.
|
||
//
|
||
}
|
||
|
||
i = 0;
|
||
while (c) {
|
||
|
||
putchar(c);
|
||
|
||
if (c == CTRL_C) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if ((c == '\n') || (c == '\r')) {
|
||
|
||
putchar('\n');
|
||
|
||
if (i == 0) {
|
||
return NULL;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (c == '\b') {
|
||
|
||
if (i > 0) {
|
||
|
||
//
|
||
// blank over last char
|
||
//
|
||
|
||
putchar(' ');
|
||
putchar('\b');
|
||
i--;
|
||
|
||
} else {
|
||
|
||
//
|
||
// space forward to keep prompt in the same place.
|
||
//
|
||
|
||
putchar(' ');
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Collect the argument.
|
||
//
|
||
|
||
if (ConvertToLower == TRUE) {
|
||
argument[i] = (UCHAR) tolower(c);
|
||
} else {
|
||
argument[i] = (UCHAR) c;
|
||
}
|
||
i++;
|
||
|
||
}
|
||
|
||
c = GetCharacter(Batch);
|
||
}
|
||
|
||
argument[i] = '\0';
|
||
return CommandLine;
|
||
|
||
} // GetArgumentString
|
||
|
||
|
||
ULONG
|
||
ParseArgumentNumeric(
|
||
PUCHAR *ArgumentPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine prints the prompt if the input is coming from the console.
|
||
|
||
Arguments:
|
||
|
||
Batch - a boolean indicating if the input is coming from the console.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR c;
|
||
ULONG number;
|
||
int i;
|
||
BOOLEAN complete = FALSE;
|
||
PUCHAR argument = *ArgumentPtr;
|
||
|
||
while (*argument == ' ') {
|
||
|
||
//
|
||
// skip spaces.
|
||
//
|
||
|
||
argument++;
|
||
}
|
||
|
||
//
|
||
// Assume there is only one option to parse until proven
|
||
// otherwise.
|
||
//
|
||
|
||
*ArgumentPtr = NULL;
|
||
|
||
i = 0;
|
||
|
||
while (complete == FALSE) {
|
||
|
||
c = argument[i];
|
||
|
||
switch (c) {
|
||
|
||
case '\n':
|
||
case '\r':
|
||
case '\t':
|
||
case ' ':
|
||
|
||
//
|
||
// Update the caller argument pointer to the remaining string.
|
||
//
|
||
|
||
*ArgumentPtr = &argument[i + 1];
|
||
|
||
//
|
||
// fall through.
|
||
//
|
||
|
||
case '\0':
|
||
|
||
argument[i] = '\0';
|
||
complete = TRUE;
|
||
break;
|
||
|
||
default:
|
||
|
||
i++;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
if (i > 0) {
|
||
number = (ULONG) atoi(argument);
|
||
} else {
|
||
number = (ULONG) -1;
|
||
}
|
||
|
||
return number;
|
||
|
||
} // ParseArgumentNumeric
|
||
|
||
|
||
VOID
|
||
PromptUser(
|
||
BOOLEAN Batch
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine prints the prompt if the input is coming from the console.
|
||
|
||
Arguments:
|
||
|
||
Batch - a boolean indicating if the input is coming from the console.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
if (!Batch) {
|
||
|
||
printf("\n%s> ", CurrentDirectory);
|
||
}
|
||
|
||
} // PromptUser
|
||
|
||
|
||
int
|
||
GetCommand(
|
||
BOOLEAN Batch,
|
||
PUCHAR *ArgumentPtr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes the user input and returns the code for the
|
||
command entered. If the command has an argument, either the default
|
||
value for the argument (if none is given) or the value provided by the
|
||
user is returned.
|
||
|
||
Arguments:
|
||
|
||
Batch - a boolean indicating if the input it coming from the console.
|
||
|
||
Return Value:
|
||
|
||
A command code
|
||
|
||
--*/
|
||
|
||
{
|
||
int i;
|
||
int commandIndex;
|
||
int commandCode;
|
||
UCHAR c;
|
||
PUCHAR commandPtr;
|
||
PUCHAR command = CommandLine;
|
||
int argumentIndex = -1;
|
||
PUCHAR argument = NULL;
|
||
|
||
PromptUser(Batch);
|
||
|
||
while ((c = GetCharacter(Batch)) == ' ') {
|
||
|
||
//
|
||
// Ignore leading spaces.
|
||
//
|
||
}
|
||
|
||
i = 0;
|
||
while (c) {
|
||
|
||
putchar(c);
|
||
|
||
if ((c == '\n') || (c == '\r')) {
|
||
putchar('\n');
|
||
if (i == 0) {
|
||
PromptUser(Batch);
|
||
c = GetCharacter(Batch);
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (c == '\b') {
|
||
|
||
if (i > 0) {
|
||
|
||
//
|
||
// blank over last char
|
||
//
|
||
|
||
putchar(' ');
|
||
putchar('\b');
|
||
i--;
|
||
|
||
if (argumentIndex == i) {
|
||
argumentIndex = -1;
|
||
argument = NULL;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// space forward to keep prompt in the same place.
|
||
//
|
||
|
||
putchar(' ');
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Collect the command.
|
||
//
|
||
|
||
command[i] = (UCHAR)tolower(c);
|
||
i++;
|
||
}
|
||
|
||
if ((c == ' ') && (argument == NULL)) {
|
||
|
||
argument = &command[i];
|
||
argumentIndex = i;
|
||
command[i - 1] = '\0';
|
||
}
|
||
|
||
c = GetCharacter(Batch);
|
||
}
|
||
|
||
//
|
||
// add end of string.
|
||
//
|
||
|
||
command[i] = '\0';
|
||
|
||
if (Debug) {
|
||
printf("command => %s$\n", command);
|
||
}
|
||
|
||
//
|
||
// Identify the command and return its code.
|
||
//
|
||
|
||
commandIndex = 0;
|
||
|
||
for (commandPtr = Commands[commandIndex];
|
||
commandPtr != NULL;
|
||
commandPtr = Commands[commandIndex]) {
|
||
|
||
if (Debug) {
|
||
printf("Testing => %s$ ... ", commandPtr);
|
||
}
|
||
|
||
i = 0;
|
||
while (commandPtr[i] == command[i]) {
|
||
if (command[i] == '\0') {
|
||
break;
|
||
}
|
||
i++;
|
||
}
|
||
|
||
if (Debug) {
|
||
printf(" i == %d, command[i] == 0x%x\n", i, command[i]);
|
||
}
|
||
|
||
if (command[i]) {
|
||
|
||
//
|
||
// Not complete there was a mismatch on the command.
|
||
//
|
||
|
||
commandIndex++;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Have a match on the command.
|
||
//
|
||
|
||
if (Debug) {
|
||
printf("Command match %d, argument %s\n",
|
||
commandIndex,
|
||
(argument == NULL) ? "(none)" : argument);
|
||
}
|
||
|
||
commandCode = CommandMap[commandIndex];
|
||
*ArgumentPtr = argument;
|
||
return commandCode;
|
||
}
|
||
|
||
printf("Command was invalid\n");
|
||
return INVALID;
|
||
} // GetCommand
|
||
|
||
|
||
VOID
|
||
NotImplemented()
|
||
|
||
/*++
|
||
|
||
--*/
|
||
|
||
{
|
||
printf("Sorry, function not implemented yet.\n");
|
||
}
|
||
|
||
NTSTATUS
|
||
FtReturnValue(
|
||
IN HANDLE Handle,
|
||
IN PUCHAR ValueName,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Formatted display of the disk registry information.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
ULONG resultLength;
|
||
ULONG length;
|
||
STRING valueString;
|
||
UNICODE_STRING unicodeValueName;
|
||
PUCHAR internalBuffer;
|
||
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
||
|
||
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
|
||
if (keyValueInformation == NULL) {
|
||
printf("FtReturnValue: cannot allocate memory.\n");
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
RtlInitString(&valueString,
|
||
ValueName);
|
||
RtlAnsiStringToUnicodeString(&unicodeValueName,
|
||
&valueString,
|
||
(BOOLEAN) TRUE);
|
||
status = NtQueryValueKey(Handle,
|
||
&unicodeValueName,
|
||
KeyValueFullInformation,
|
||
keyValueInformation,
|
||
WORK_BUFFER_SIZE,
|
||
&resultLength);
|
||
RtlFreeUnicodeString(&unicodeValueName);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
length = (resultLength > BufferLength) ? BufferLength : resultLength;
|
||
internalBuffer =
|
||
((PUCHAR)keyValueInformation + keyValueInformation->DataOffset);
|
||
|
||
RtlMoveMemory(Buffer, internalBuffer, length);
|
||
}
|
||
free(keyValueInformation);
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
DiskDump()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Formatted display of the disk registry information.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG outerLoop;
|
||
ULONG innerLoop;
|
||
HANDLE handle;
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER configHeader;
|
||
PDISK_REGISTRY diskRegistry;
|
||
PDISK_DESCRIPTION diskDescription;
|
||
PDISK_PARTITION diskPartition;
|
||
PFT_REGISTRY ftRegistry;
|
||
PFT_DESCRIPTION ftDescription;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
|
||
status = FtOpenKey(&handle,
|
||
DISK_REGISTRY_KEY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Currently there is no key in the registry"
|
||
" for the disk information.\n");
|
||
return;
|
||
}
|
||
|
||
configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
|
||
if (configHeader == NULL) {
|
||
printf("Unable to allocate memory for the disk registy information.\n");
|
||
return;
|
||
}
|
||
|
||
RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
|
||
|
||
status = FtReturnValue(handle,
|
||
(PUCHAR) DISK_REGISTRY_VALUE,
|
||
(PUCHAR) configHeader,
|
||
WORK_BUFFER_SIZE);
|
||
NtClose(handle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("There is no disk registry information (%x)\n", status);
|
||
free(configHeader);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Print the header.
|
||
//
|
||
|
||
printf("Registry header information:\n");
|
||
printf("\tVersion = 0x%x, Checksum = 0x%x\n",
|
||
configHeader->Version,
|
||
configHeader->CheckSum);
|
||
printf("\tDisk info Offset = 0x%x, Size = 0x%x\n",
|
||
configHeader->DiskInformationOffset,
|
||
configHeader->DiskInformationSize);
|
||
printf("\tFT info Offset = 0x%x, Size = 0x%x\n",
|
||
configHeader->FtInformationOffset,
|
||
configHeader->FtInformationSize);
|
||
|
||
//
|
||
// Print the information on disks.
|
||
//
|
||
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->DiskInformationOffset);
|
||
printf("\nDisk information for %d disks:\n",
|
||
diskRegistry->NumberOfDisks);
|
||
|
||
diskDescription = &diskRegistry->Disks[0];
|
||
for (outerLoop = 0;
|
||
outerLoop < diskRegistry->NumberOfDisks;
|
||
outerLoop++) {
|
||
|
||
printf("\nDisk %d signature 0x%08x has %d partitions:\n",
|
||
outerLoop,
|
||
diskDescription->Signature,
|
||
diskDescription->NumberOfPartitions);
|
||
|
||
printf(" Ln Type Start Length FtGrp Member\n");
|
||
for (innerLoop = 0;
|
||
innerLoop < diskDescription->NumberOfPartitions;
|
||
innerLoop++) {
|
||
diskPartition = &diskDescription->Partitions[innerLoop];
|
||
printf(" %c: %c %1d %3d %08x:%08x %08x:%08x %5d %4d %s\n",
|
||
(diskPartition->DriveLetter != '\0') ?
|
||
diskPartition->DriveLetter : ' ',
|
||
(diskPartition->AssignDriveLetter) ? 'A' : ' ',
|
||
diskPartition->LogicalNumber,
|
||
diskPartition->FtType,
|
||
diskPartition->StartingOffset.HighPart,
|
||
diskPartition->StartingOffset.LowPart,
|
||
diskPartition->Length.HighPart,
|
||
diskPartition->Length.LowPart,
|
||
diskPartition->FtGroup,
|
||
diskPartition->FtMember,
|
||
(diskPartition->FtState == Orphaned) ? "Orphan" :
|
||
(diskPartition->FtState == Regenerating) ? "Regen" :
|
||
(diskPartition->FtState == Initializing) ? "Init" : "");
|
||
|
||
}
|
||
|
||
diskDescription = (PDISK_DESCRIPTION)
|
||
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
||
}
|
||
|
||
//
|
||
// Print the information for FT.
|
||
//
|
||
|
||
if (configHeader->FtInformationSize == 0) {
|
||
printf("There is no FT configuration.\n");
|
||
free(configHeader);
|
||
return;
|
||
}
|
||
|
||
ftRegistry = (PFT_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->FtInformationOffset);
|
||
|
||
printf("\nNumber of FT components = %d\n",
|
||
ftRegistry->NumberOfComponents);
|
||
|
||
ftDescription = &ftRegistry->FtDescription[0];
|
||
for (outerLoop = 0;
|
||
outerLoop < ftRegistry->NumberOfComponents;
|
||
outerLoop++) {
|
||
|
||
printf("Component %d has %d members and is type %d\n",
|
||
outerLoop,
|
||
ftDescription->NumberOfMembers,
|
||
ftDescription->Type);
|
||
|
||
printf(" State Signature Start Length #\n");
|
||
for (innerLoop = 0;
|
||
innerLoop < ftDescription->NumberOfMembers;
|
||
innerLoop++) {
|
||
ftMember = &ftDescription->FtMemberDescription[innerLoop];
|
||
|
||
diskPartition = (PDISK_PARTITION)
|
||
((PUCHAR) configHeader + ftMember->OffsetToPartitionInfo);
|
||
|
||
printf("%5x %2x %08x %08x:%08x %08x:%08x %d\n",
|
||
ftMember->OffsetToPartitionInfo,
|
||
ftMember->State,
|
||
ftMember->Signature,
|
||
diskPartition->StartingOffset.HighPart,
|
||
diskPartition->StartingOffset.LowPart,
|
||
diskPartition->Length.HighPart,
|
||
diskPartition->Length.LowPart,
|
||
ftMember->LogicalNumber);
|
||
}
|
||
|
||
ftDescription = (PFT_DESCRIPTION)
|
||
&ftDescription->FtMemberDescription[ftDescription->NumberOfMembers];
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
ChangeMemberState(
|
||
IN ULONG Type,
|
||
IN ULONG Group,
|
||
IN ULONG Member,
|
||
IN FT_PARTITION_STATE NewState
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Set the FT state for a partition.
|
||
|
||
Arguments:
|
||
|
||
Type - the FT type.
|
||
Group - the FT Group number for that type.
|
||
Member - the member number within the group.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN writeBackRegistry = FALSE;
|
||
HANDLE handle;
|
||
ULONG outerLoop;
|
||
ULONG innerLoop;
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER configHeader;
|
||
PDISK_REGISTRY diskRegistry;
|
||
PDISK_DESCRIPTION diskDescription;
|
||
PDISK_PARTITION partitionDescription;
|
||
|
||
status = FtOpenKey(&handle,
|
||
DISK_REGISTRY_KEY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Currently there is no key in the registry"
|
||
" for the disk information.\n");
|
||
return;
|
||
}
|
||
|
||
configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
|
||
if (configHeader == NULL) {
|
||
printf("Unable to allocate memory for the disk registy information.\n");
|
||
NtClose(handle);
|
||
return;
|
||
}
|
||
|
||
RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
|
||
|
||
status = FtReturnValue(handle,
|
||
(PUCHAR) DISK_REGISTRY_VALUE,
|
||
(PUCHAR) configHeader,
|
||
WORK_BUFFER_SIZE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("There is no disk registry information (%x)\n", status);
|
||
free(configHeader);
|
||
NtClose(handle);
|
||
return;
|
||
}
|
||
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->DiskInformationOffset);
|
||
|
||
diskDescription = &diskRegistry->Disks[0];
|
||
for (outerLoop = 0;
|
||
outerLoop < diskRegistry->NumberOfDisks;
|
||
outerLoop++) {
|
||
|
||
for (innerLoop = 0;
|
||
innerLoop < diskDescription->NumberOfPartitions;
|
||
innerLoop++) {
|
||
|
||
partitionDescription = &diskDescription->Partitions[innerLoop];
|
||
|
||
if ((partitionDescription->FtType == (FT_TYPE) Type) &&
|
||
(partitionDescription->FtGroup == (USHORT) Group) &&
|
||
(partitionDescription->FtMember == (USHORT) Member)) {
|
||
|
||
partitionDescription->FtState = NewState;
|
||
writeBackRegistry = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (writeBackRegistry == TRUE) {
|
||
ULONG size;
|
||
|
||
if (configHeader->FtInformationSize == 0) {
|
||
printf("Seems a little odd to be setting FT state " // no comma
|
||
"with no FT information...\n");
|
||
size = configHeader->DiskInformationOffset +
|
||
configHeader->DiskInformationSize;
|
||
} else {
|
||
size = configHeader->FtInformationOffset +
|
||
configHeader->FtInformationSize;
|
||
}
|
||
|
||
(VOID) FtSetValue(handle,
|
||
(PUCHAR) DISK_REGISTRY_VALUE,
|
||
(PUCHAR) configHeader,
|
||
size,
|
||
REG_BINARY);
|
||
break;
|
||
}
|
||
diskDescription = (PDISK_DESCRIPTION)
|
||
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
||
}
|
||
|
||
NtClose(handle);
|
||
free(configHeader);
|
||
}
|
||
|
||
|
||
VOID
|
||
RestoreOrphan(
|
||
IN ULONG Type,
|
||
IN ULONG Group,
|
||
IN ULONG Member
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Set the FT state for a partition back to Healthy.
|
||
|
||
Arguments:
|
||
|
||
Type - the FT type.
|
||
Group - the FT Group number for that type.
|
||
Member - the member number within the group.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ChangeMemberState(Type,
|
||
Group,
|
||
Member,
|
||
Healthy);
|
||
}
|
||
|
||
|
||
VOID
|
||
OrphanMember(
|
||
IN ULONG Type,
|
||
IN ULONG Group,
|
||
IN ULONG Member
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Set the FT state for a partition to Orphaned.
|
||
|
||
Arguments:
|
||
|
||
Type - the FT type.
|
||
Group - the FT Group number for that type.
|
||
Member - the member number within the group.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ChangeMemberState(Type,
|
||
Group,
|
||
Member,
|
||
Orphaned);
|
||
}
|
||
|
||
|
||
VOID
|
||
RegenerateMember(
|
||
IN ULONG Type,
|
||
IN ULONG Group,
|
||
IN ULONG Member
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Set the FT state for a partition to regenerate.
|
||
|
||
Arguments:
|
||
|
||
Type - the FT type.
|
||
Group - the FT Group number for that type.
|
||
Member - the member number within the group.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ChangeMemberState(Type,
|
||
Group,
|
||
Member,
|
||
Regenerating);
|
||
}
|
||
|
||
|
||
VOID
|
||
FixDisk()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fix the disk signatures in the registry.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG outerLoop;
|
||
ULONG innerLoop;
|
||
ULONG length;
|
||
HANDLE handle;
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER configHeader;
|
||
PDISK_REGISTRY diskRegistry;
|
||
PDISK_DESCRIPTION diskDescription;
|
||
PFT_REGISTRY ftRegistry;
|
||
PFT_DESCRIPTION ftDescription;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
UCHAR prompt[128];
|
||
PUCHAR hexString;
|
||
BOOLEAN changed = FALSE;
|
||
|
||
status = FtOpenKey(&handle,
|
||
DISK_REGISTRY_KEY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Currently there is no key in the registry"
|
||
" for the disk information.\n");
|
||
return;
|
||
}
|
||
|
||
configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
|
||
if (configHeader == NULL) {
|
||
printf("Unable to allocate memory for the disk registy information.\n");
|
||
NtClose(handle);
|
||
return;
|
||
}
|
||
|
||
RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
|
||
|
||
status = FtReturnValue(handle,
|
||
(PUCHAR) DISK_REGISTRY_VALUE,
|
||
(PUCHAR) configHeader,
|
||
WORK_BUFFER_SIZE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("There is no disk registry information (%x)\n", status);
|
||
free(configHeader);
|
||
NtClose(handle);
|
||
return;
|
||
}
|
||
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->DiskInformationOffset);
|
||
printf("\nDisk information for %d disks:\n",
|
||
diskRegistry->NumberOfDisks);
|
||
|
||
diskDescription = &diskRegistry->Disks[0];
|
||
for (outerLoop = 0;
|
||
outerLoop < diskRegistry->NumberOfDisks;
|
||
outerLoop++) {
|
||
|
||
sprintf(prompt,
|
||
"\nDisk %d signature 0x%08x = ",
|
||
outerLoop,
|
||
diskDescription->Signature);
|
||
|
||
hexString = GetArgumentString((BOOLEAN) FALSE,
|
||
prompt,
|
||
(BOOLEAN) TRUE);
|
||
|
||
if (hexString != NULL) {
|
||
|
||
changed = ProcessHex(hexString, &diskDescription->Signature);
|
||
}
|
||
|
||
diskDescription = (PDISK_DESCRIPTION)
|
||
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
||
}
|
||
|
||
//
|
||
// Print the information for FT.
|
||
//
|
||
|
||
if (configHeader->FtInformationSize == 0) {
|
||
printf("There is no FT configuration.\n");
|
||
free(configHeader);
|
||
NtClose(handle);
|
||
return;
|
||
}
|
||
|
||
ftRegistry = (PFT_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->FtInformationOffset);
|
||
|
||
printf("\nNumber of FT components = %d\n",
|
||
ftRegistry->NumberOfComponents);
|
||
|
||
ftDescription = &ftRegistry->FtDescription[0];
|
||
for (outerLoop = 0;
|
||
outerLoop < ftRegistry->NumberOfComponents;
|
||
outerLoop++) {
|
||
|
||
printf("Component %d has %d members and is type %d\n",
|
||
outerLoop,
|
||
ftDescription->NumberOfMembers,
|
||
ftDescription->Type);
|
||
|
||
for (innerLoop = 0;
|
||
innerLoop < ftDescription->NumberOfMembers;
|
||
innerLoop++) {
|
||
ftMember = &ftDescription->FtMemberDescription[innerLoop];
|
||
|
||
sprintf(prompt,
|
||
"FT Member Signature 0x%x = ",
|
||
ftMember->Signature);
|
||
|
||
hexString = GetArgumentString((BOOLEAN) FALSE,
|
||
prompt,
|
||
(BOOLEAN) TRUE);
|
||
|
||
if (hexString != NULL) {
|
||
|
||
changed = ProcessHex(hexString, &ftMember->Signature);
|
||
}
|
||
}
|
||
|
||
ftDescription = (PFT_DESCRIPTION)
|
||
&ftDescription->FtMemberDescription[ftDescription->NumberOfMembers];
|
||
}
|
||
|
||
if (changed == TRUE) {
|
||
|
||
printf("Attempting to update registry information.\n");
|
||
|
||
//
|
||
// Delete the current registry value and write the new one.
|
||
//
|
||
|
||
status = FtDeleteValue(handle,
|
||
DISK_REGISTRY_VALUE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not delete value (0x%x).\n", status);
|
||
} else {
|
||
|
||
length = (ULONG) ((PCHAR)ftDescription - (PUCHAR)configHeader);
|
||
status = FtSetValue(handle,
|
||
DISK_REGISTRY_VALUE,
|
||
configHeader,
|
||
length,
|
||
REG_BINARY);
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not write value (0x%x)\n.", status);
|
||
}
|
||
}
|
||
}
|
||
|
||
NtClose(handle);
|
||
}
|
||
|
||
PDISK_CONFIG_HEADER
|
||
GetDiskInfo()
|
||
|
||
/*++
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE handle;
|
||
ULONG length;
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER configHeader;
|
||
|
||
status = FtOpenKey(&handle,
|
||
DISK_REGISTRY_KEY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Currently there is no key in the registry"
|
||
" for the disk information.\n");
|
||
return NULL;
|
||
}
|
||
|
||
configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
|
||
if (configHeader == NULL) {
|
||
printf("Unable to allocate memory for the disk registy information.\n");
|
||
NtClose(handle);
|
||
return NULL;
|
||
}
|
||
|
||
RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
|
||
|
||
status = FtReturnValue(handle,
|
||
(PUCHAR) DISK_REGISTRY_VALUE,
|
||
(PUCHAR) configHeader,
|
||
WORK_BUFFER_SIZE);
|
||
NtClose(handle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("There is no disk registry information (%x)\n", status);
|
||
free(configHeader);
|
||
return NULL;
|
||
}
|
||
|
||
return configHeader;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
CreateFtMember(
|
||
IN PDISK_CONFIG_HEADER ConfigHeader,
|
||
IN ULONG Disk,
|
||
IN ULONG Partition,
|
||
IN ULONG Type,
|
||
IN ULONG Group,
|
||
IN ULONG Member
|
||
)
|
||
|
||
/*++
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG innerLoop;
|
||
ULONG outerLoop;
|
||
ULONG length;
|
||
NTSTATUS status;
|
||
PDISK_REGISTRY diskRegistry;
|
||
PDISK_DESCRIPTION diskDescription;
|
||
PDISK_PARTITION diskPartition;
|
||
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) ConfigHeader + ConfigHeader->DiskInformationOffset);
|
||
diskDescription = &diskRegistry->Disks[0];
|
||
|
||
//
|
||
// Have to walk the disk information by hand to find a match on
|
||
// disk number and partition
|
||
//
|
||
|
||
for (outerLoop = 0;
|
||
outerLoop < diskRegistry->NumberOfDisks;
|
||
outerLoop++) {
|
||
|
||
if (outerLoop == Disk) {
|
||
for (innerLoop = 0;
|
||
innerLoop < diskDescription->NumberOfPartitions;
|
||
innerLoop++) {
|
||
diskPartition = &diskDescription->Partitions[innerLoop];
|
||
|
||
if (diskPartition->LogicalNumber == Partition) {
|
||
|
||
//
|
||
// Found a match.
|
||
//
|
||
|
||
diskPartition->FtType = Type;
|
||
diskPartition->FtMember = Member;
|
||
diskPartition->FtGroup = Group;
|
||
diskPartition->FtState = Healthy;
|
||
diskPartition->AssignDriveLetter = FALSE;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
diskDescription = (PDISK_DESCRIPTION)
|
||
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
||
}
|
||
|
||
//
|
||
// Didn't find it.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
#define DRIVER_KEY "\\REGISTRY\\MACHINE\\System\\CurrentControlSet\\Services"
|
||
|
||
#define TYPE_KEY "Type"
|
||
#define START_KEY "Start"
|
||
#define GROUP_KEY "Group"
|
||
#define DEPENDENCIES "DependOnGroup"
|
||
|
||
#if 0
|
||
VOID
|
||
DisplayLoadInformation(
|
||
IN PUNICODE_STRING DriverKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
DriverKey - a Unicode string pointer for the driver key name.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE keyHandle;
|
||
UNICODE_STRING unicodeKeyName;
|
||
UNICODE_STRING unicodeValueName;
|
||
ULONG resultLength;
|
||
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
||
|
||
resultLength = WORK_BUFFER_SIZE;
|
||
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
|
||
|
||
//
|
||
// Type
|
||
//
|
||
|
||
//
|
||
// Start
|
||
//
|
||
|
||
//
|
||
// Group
|
||
//
|
||
|
||
//
|
||
// DependOnGroup
|
||
//
|
||
|
||
while (1) {
|
||
|
||
RtlZeroMemory(keyValueInformation, resultLength);
|
||
status = NtEnumerateValueKey(KeyHandle,
|
||
0,
|
||
KeyValueFullInformation,
|
||
keyValueInformation,
|
||
resultLength,
|
||
&resultLength);
|
||
|
||
if (status == STATUS_BUFFER_OVERFLOW) {
|
||
free(keyValueInformation);
|
||
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
|
||
malloc(resultLength + 10);
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
free(keyValueInformation);
|
||
NtClose(keyHandle);
|
||
}
|
||
#else
|
||
VOID
|
||
DisplayLoadInformation(
|
||
IN PUCHAR DriverKey
|
||
)
|
||
{
|
||
UNREFERENCED_PARAMETER(DriverKey);
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
#define TEMP_BUFFER_SIZE 256
|
||
VOID
|
||
ListDrivers()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Got to the load list for the drivers, interpret and display what is there.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
int index;
|
||
NTSTATUS status;
|
||
HANDLE keyHandle;
|
||
ULONG resultLength;
|
||
UCHAR tempBuffer[TEMP_BUFFER_SIZE];
|
||
ANSI_STRING ansiString;
|
||
UNICODE_STRING unicodeValueName;
|
||
PKEY_BASIC_INFORMATION keyInformation;
|
||
|
||
keyInformation = (PKEY_BASIC_INFORMATION)malloc(WORK_BUFFER_SIZE);
|
||
|
||
status = FtOpenKey(&keyHandle, DRIVER_KEY);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
printf("Could not open Services key (0x%x).\n", status);
|
||
return;
|
||
}
|
||
|
||
for (index = 0; TRUE; index++) {
|
||
|
||
RtlZeroMemory(keyInformation, WORK_BUFFER_SIZE);
|
||
|
||
status = NtEnumerateKey(keyHandle,
|
||
index,
|
||
KeyBasicInformation,
|
||
keyInformation,
|
||
WORK_BUFFER_SIZE,
|
||
&resultLength);
|
||
|
||
if (status == STATUS_NO_MORE_ENTRIES) {
|
||
|
||
break;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
|
||
printf("readreg: Error on Enumerate status = %x\n", status);
|
||
break;
|
||
|
||
}
|
||
|
||
unicodeValueName.Length = (USHORT)keyInformation->NameLength;
|
||
unicodeValueName.MaximumLength = (USHORT)keyInformation->NameLength;
|
||
unicodeValueName.Buffer = (PWSTR)&keyInformation->Name[0];
|
||
|
||
ansiString.MaximumLength = TEMP_BUFFER_SIZE;
|
||
ansiString.Length = 0L;
|
||
ansiString.Buffer = &tempBuffer[0];
|
||
|
||
RtlUnicodeStringToAnsiString(&ansiString,
|
||
&unicodeValueName,
|
||
(BOOLEAN) FALSE);
|
||
|
||
//
|
||
// Now have the key name for the driver - concatenate it and
|
||
// call the routine to display what is in the key.
|
||
//
|
||
|
||
sprintf(WorkingDirectory,
|
||
"%s\\%s",
|
||
DRIVER_KEY,
|
||
tempBuffer);
|
||
|
||
DisplayLoadInformation(WorkingDirectory);
|
||
}
|
||
|
||
free(keyInformation);
|
||
NtClose(keyHandle);
|
||
}
|
||
|
||
|
||
VOID
|
||
main()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The main entry point for the user process.
|
||
This process will prompt the user for the action desired. This
|
||
includes starting performance, stopping performance, and retreiving
|
||
performance data collected by the FT driver.
|
||
|
||
Arguments:
|
||
|
||
Command line:
|
||
No options.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
BOOLEAN batch;
|
||
PUCHAR argumentString;
|
||
int commandCode;
|
||
HANDLE keyHandle;
|
||
|
||
|
||
status = FtOpenKey(&keyHandle, REGISTRY_BASE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
printf("readreg: Unable to open registry base (0x%x)\n", status);
|
||
exit(1);
|
||
}
|
||
|
||
sprintf(CurrentDirectory,
|
||
REGISTRY_BASE);
|
||
|
||
//
|
||
// See if we are connected to CON
|
||
//
|
||
|
||
batch = FALSE;
|
||
// batch = (BOOLEAN)(!isatty(0));
|
||
|
||
if (!batch) {
|
||
printf("FT registry edit utility. %s:\n", Version);
|
||
}
|
||
|
||
while(1) {
|
||
while ((commandCode = GetCommand(batch,
|
||
&argumentString)) == INVALID) {
|
||
|
||
//
|
||
// Continue until we get a valid command.
|
||
//
|
||
|
||
}
|
||
|
||
if (Debug) {
|
||
printf("Command code == %d, argumentString = %s\n",
|
||
commandCode,
|
||
(argumentString == NULL) ? "(none)" : argumentString);
|
||
}
|
||
|
||
switch (commandCode) {
|
||
|
||
case DIRLONG:
|
||
|
||
Directory(keyHandle, (BOOLEAN) TRUE);
|
||
break;
|
||
|
||
case DIR:
|
||
|
||
Directory(keyHandle, (BOOLEAN) FALSE);
|
||
break;
|
||
|
||
case CREATE:
|
||
{
|
||
ULONG index;
|
||
PUCHAR keyClass;
|
||
BOOLEAN classAllocated = FALSE;
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Key Name = ",
|
||
(BOOLEAN) FALSE);
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
break;
|
||
}
|
||
|
||
sprintf(WorkingDirectory,
|
||
"%s\\%s",
|
||
CurrentDirectory,
|
||
argumentString);
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"Key Class = ",
|
||
(BOOLEAN) FALSE);
|
||
|
||
if (argumentString == NULL) {
|
||
keyClass = "Default Class";
|
||
} else {
|
||
keyClass = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
|
||
classAllocated = TRUE;
|
||
|
||
sprintf(keyClass,
|
||
"%s",
|
||
argumentString);
|
||
}
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"Index = ",
|
||
(BOOLEAN) TRUE);
|
||
|
||
if (argumentString == NULL) {
|
||
index = 1;
|
||
} else {
|
||
index = ParseArgumentNumeric(&argumentString);
|
||
}
|
||
|
||
if (Debug) {
|
||
printf("Creating key %s, index %d with class %s\n",
|
||
WorkingDirectory,
|
||
index,
|
||
keyClass);
|
||
}
|
||
|
||
status = FtCreateKey(WorkingDirectory,
|
||
keyClass,
|
||
index);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
printf("Could not create key %s (0x%x).\n",
|
||
WorkingDirectory,
|
||
status);
|
||
}
|
||
|
||
if (classAllocated == TRUE) {
|
||
free(keyClass);
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
case LIST:
|
||
|
||
List(keyHandle,
|
||
argumentString);
|
||
break;
|
||
|
||
case CHDIR:
|
||
|
||
NtClose(keyHandle);
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"New location = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
|
||
if (argumentString != NULL) {
|
||
|
||
if (*argumentString == '\\') {
|
||
|
||
//
|
||
// Root relative string.
|
||
// Use text provided (i.e. %s is to avoid user crashing
|
||
// by putting %s in the string).
|
||
//
|
||
|
||
sprintf(WorkingDirectory,
|
||
"%s",
|
||
argumentString);
|
||
|
||
} else {
|
||
|
||
while ((*argumentString == '.') &&
|
||
(*(argumentString + 1) == '.')) {
|
||
|
||
if ((*(argumentString + 2) == '\\') ||
|
||
(*(argumentString + 2) == '\0')) {
|
||
|
||
PUCHAR cptr = CurrentDirectory;
|
||
|
||
//
|
||
// move argumentString past ".."
|
||
//
|
||
|
||
argumentString += 2;
|
||
|
||
//
|
||
// Find end of current directory.
|
||
//
|
||
|
||
while (*cptr != '\0') {
|
||
cptr++;
|
||
}
|
||
|
||
//
|
||
// Backup to last component.
|
||
//
|
||
|
||
while (*cptr != '\\') {
|
||
cptr--;
|
||
}
|
||
|
||
if (cptr == CurrentDirectory) {
|
||
|
||
//
|
||
// Cannot backup anymore. Continue parsing
|
||
// argument.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Remove component from path.
|
||
//
|
||
|
||
*cptr = '\0';
|
||
|
||
if (*argumentString == '\0') {
|
||
|
||
//
|
||
// All done with argument.
|
||
//
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Step around backslash.
|
||
//
|
||
|
||
argumentString++;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Assume it is a real name.
|
||
//
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (*argumentString != '\0') {
|
||
sprintf(WorkingDirectory,
|
||
"%s\\%s",
|
||
CurrentDirectory,
|
||
argumentString);
|
||
} else {
|
||
sprintf(WorkingDirectory,
|
||
"%s",
|
||
CurrentDirectory);
|
||
}
|
||
}
|
||
|
||
status = FtOpenKey(&keyHandle,
|
||
WorkingDirectory);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
sprintf(CurrentDirectory,
|
||
"%s",
|
||
WorkingDirectory);
|
||
} else {
|
||
|
||
(VOID) FtOpenKey(&keyHandle,
|
||
CurrentDirectory);
|
||
|
||
//
|
||
// No error checks because this was opened once before.
|
||
//
|
||
}
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case HELP:
|
||
{
|
||
int i;
|
||
|
||
printf("Valid commands are:\n");
|
||
|
||
for (i = 0; Commands[i] != NULL; i++) {
|
||
printf(" %10s - %s\n",
|
||
Commands[i],
|
||
CommandHelp[CommandMap[i]]);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case QUIT:
|
||
|
||
exit(0);
|
||
break;
|
||
|
||
case DDEBUG:
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
if (Debug) {
|
||
|
||
printf("Debug turned off.\n");
|
||
Debug = 0;
|
||
} else {
|
||
|
||
Debug = 1;
|
||
}
|
||
} else {
|
||
|
||
Debug = atoi(argumentString);
|
||
printf("Debug set to %d\n", Debug);
|
||
}
|
||
break;
|
||
|
||
case SETVALUE:
|
||
{
|
||
int i;
|
||
BOOLEAN convertToUnicode = FALSE;
|
||
PUCHAR valueName;
|
||
PUCHAR valueData;
|
||
ULONG valueLength;
|
||
ULONG valueWord;
|
||
PVOID valuePtr;
|
||
ULONG type = DEFAULT_TYPE;
|
||
STRING valueString;
|
||
UNICODE_STRING unicodeValue;
|
||
BOOLEAN dataAllocated = FALSE;
|
||
BOOLEAN unicodeAllocated = FALSE;
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"Value Name = ",
|
||
(BOOLEAN) FALSE);
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
valueName = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
|
||
|
||
sprintf(valueName,
|
||
"%s",
|
||
argumentString);
|
||
|
||
//
|
||
// print a help banner on type and get the type.
|
||
//
|
||
|
||
for (i = 0; TypeNames[i] != NULL; i++) {
|
||
|
||
printf("%d - %s\n", TypeNumbers[i], TypeNames[i]);
|
||
}
|
||
printf("# - Other numbers are user defined\n");
|
||
argumentString = GetArgumentString(batch,
|
||
"Numeric value for type = ",
|
||
(BOOLEAN) TRUE);
|
||
|
||
if (argumentString != NULL) {
|
||
type = ParseArgumentNumeric(&argumentString);
|
||
}
|
||
|
||
switch(type)
|
||
{
|
||
default:
|
||
case REG_SZ:
|
||
if (type == REG_SZ) {
|
||
convertToUnicode = TRUE;
|
||
printf("Typed in string will be converted to unicode...\n");
|
||
argumentString = GetArgumentString(batch,
|
||
"Value Data = ",
|
||
(BOOLEAN) FALSE);
|
||
} else {
|
||
printf("For now the data must be typed in...\n");
|
||
argumentString = GetArgumentString(batch,
|
||
"Value Data = ",
|
||
(BOOLEAN) FALSE);
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
valueData = "Default Data";
|
||
valueLength = strlen(valueData);
|
||
} else {
|
||
valueData = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
|
||
dataAllocated = TRUE;
|
||
sprintf(valueData,
|
||
"%s",
|
||
argumentString);
|
||
if (convertToUnicode == TRUE) {
|
||
RtlInitString(&valueString,
|
||
valueData);
|
||
RtlAnsiStringToUnicodeString(&unicodeValue,
|
||
&valueString,
|
||
(BOOLEAN) TRUE);
|
||
unicodeAllocated = TRUE;
|
||
valueLength = unicodeValue.Length + 2;
|
||
} else {
|
||
valueLength = strlen(valueData);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case REG_DWORD:
|
||
argumentString = GetArgumentString(batch,
|
||
"Value Data Word = ",
|
||
(BOOLEAN) TRUE);
|
||
if (argumentString == NULL) {
|
||
valueWord = 0;
|
||
} else {
|
||
valueWord = ParseArgumentNumeric(&argumentString);
|
||
}
|
||
|
||
valueLength = sizeof(ULONG);
|
||
break;
|
||
}
|
||
|
||
switch (type) {
|
||
|
||
case REG_DWORD:
|
||
valuePtr = (PVOID) &valueWord;
|
||
break;
|
||
|
||
case REG_SZ:
|
||
valuePtr = (PVOID) unicodeValue.Buffer;
|
||
break;
|
||
|
||
default:
|
||
valuePtr = (PVOID) valueData;
|
||
break;
|
||
}
|
||
status = FtSetValue(keyHandle,
|
||
valueName,
|
||
valuePtr,
|
||
valueLength,
|
||
type);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Could not set value %s (0x%x).\n", valueName, status);
|
||
}
|
||
|
||
free(valueName);
|
||
if (dataAllocated == TRUE) {
|
||
free(valueData);
|
||
}
|
||
if (unicodeAllocated == TRUE) {
|
||
RtlFreeUnicodeString(&unicodeValue);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case DELKEY:
|
||
{
|
||
if (argumentString == NULL) {
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"Key Name = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
sprintf(WorkingDirectory,
|
||
"%s\\%s",
|
||
CurrentDirectory,
|
||
argumentString);
|
||
|
||
status = FtDeleteKey(WorkingDirectory);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
printf("Unable to delete key %s (0x%x)\n",
|
||
WorkingDirectory,
|
||
status);
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
case DELVALUE:
|
||
{
|
||
if (argumentString == NULL) {
|
||
|
||
argumentString = GetArgumentString(batch,
|
||
"Key Name = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
|
||
break;
|
||
}
|
||
|
||
status = FtDeleteValue(keyHandle,
|
||
argumentString);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
printf("Unable to delete value %s (0x%x)\n",
|
||
argumentString,
|
||
status);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case INLONG:
|
||
DumpControl = InLongs;
|
||
break;
|
||
|
||
case INSHORT:
|
||
DumpControl = InShorts;
|
||
break;
|
||
|
||
case INBYTE:
|
||
DumpControl = InBytes;
|
||
break;
|
||
|
||
case DUMP:
|
||
|
||
if (ForceDump) {
|
||
ForceDump = 0;
|
||
} else {
|
||
ForceDump++;
|
||
}
|
||
break;
|
||
|
||
case DISKREG:
|
||
DiskDump();
|
||
break;
|
||
|
||
case FIXDISK:
|
||
FixDisk();
|
||
break;
|
||
|
||
case RESTORE:
|
||
{
|
||
ULONG type;
|
||
ULONG group;
|
||
ULONG member;
|
||
|
||
printf("FT types that can be restored are:\n");
|
||
printf("\t%d - for Mirrors\n", Mirror);
|
||
printf("\t%d - for Stripes with parity\n", StripeWithParity);
|
||
|
||
//
|
||
// Get the type
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT volume type = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
type = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the group
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT group number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
group = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the member
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT member number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
member = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
RestoreOrphan(type, group, member);
|
||
break;
|
||
}
|
||
|
||
case DRIVERS:
|
||
NotImplemented();
|
||
// ListDrivers();
|
||
break;
|
||
|
||
case ORPHAN:
|
||
{
|
||
ULONG type;
|
||
ULONG group;
|
||
ULONG member;
|
||
|
||
printf("FT types that can be orphaned are:\n");
|
||
printf("\t%d - for Mirrors\n", Mirror);
|
||
printf("\t%d - for Stripes with parity\n", StripeWithParity);
|
||
|
||
//
|
||
// Get the type
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT volume type = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
type = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the group
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT group number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
group = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the member
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT member number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
member = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
OrphanMember(type, group, member);
|
||
break;
|
||
}
|
||
|
||
case REGEN:
|
||
{
|
||
ULONG type;
|
||
ULONG group;
|
||
ULONG member;
|
||
|
||
printf("FT types that can be regenerated are:\n");
|
||
printf("\t%d - for Mirrors\n", Mirror);
|
||
printf("\t%d - for Stripes with parity\n", StripeWithParity);
|
||
|
||
//
|
||
// Get the type
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT volume type = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
type = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the group
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT group number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
group = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the member
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"FT member number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
member = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
RegenerateMember(type, group, member);
|
||
break;
|
||
}
|
||
|
||
case INIT:
|
||
{
|
||
ULONG type;
|
||
ULONG group;
|
||
ULONG member;
|
||
|
||
printf("Only stripes with parity are initialized.\n");
|
||
|
||
//
|
||
// Get the group
|
||
//
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Parity stripe group number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
group = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
ChangeMemberState(StripeWithParity,
|
||
group,
|
||
0,
|
||
Initializing);
|
||
break;
|
||
}
|
||
|
||
case MAKEFT:
|
||
{
|
||
ULONG type;
|
||
ULONG group;
|
||
ULONG member;
|
||
ULONG disk;
|
||
ULONG partition;
|
||
PDISK_CONFIG_HEADER configHeader;
|
||
BOOLEAN doUpdate = TRUE;
|
||
|
||
configHeader = GetDiskInfo();
|
||
if (configHeader == NULL) {
|
||
break;
|
||
}
|
||
printf("\t%d for Mirrors\n", Mirror);
|
||
printf("\t%d for Stripe Set\n", Stripe);
|
||
printf("\t%d for Stripe with parity\n", StripeWithParity);
|
||
printf("\t%d for Volume Set\n", VolumeSet);
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Which FT set to create? ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
type = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Please give an FT group # - ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
if (argumentString != NULL) {
|
||
group = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
for (member = 0; TRUE; member++) {
|
||
printf("Information for member %d\n", member);
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Disk Number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
|
||
if (argumentString != NULL) {
|
||
disk = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
if (argumentString == NULL) {
|
||
argumentString = GetArgumentString(batch,
|
||
"Partition Number = ",
|
||
(BOOLEAN) TRUE);
|
||
}
|
||
|
||
if (argumentString != NULL) {
|
||
partition = ParseArgumentNumeric(&argumentString);
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
if (CreateFtMember(configHeader, disk, partition, type, group, member) == FALSE) {
|
||
printf("Failed to change member state\n");
|
||
printf("No update will be made\n");
|
||
doUpdate = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
if (doUpdate == TRUE) {
|
||
PDISK_REGISTRY diskRegistry;
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) configHeader + configHeader->DiskInformationOffset);
|
||
DiskRegistrySet(diskRegistry);
|
||
}
|
||
free(configHeader);
|
||
break;
|
||
}
|
||
|
||
default:
|
||
|
||
printf("WDF homer?!?\n");
|
||
break;
|
||
}
|
||
}
|
||
} // main
|