845 lines
20 KiB
C
845 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rtmisc1.c
|
|
|
|
Abstract:
|
|
|
|
NT level registry api test program #1, basic non-error paths.
|
|
|
|
Test open, create, setvalue, queryvalue, enumeratekey, enumeratevalue,
|
|
querykey.
|
|
|
|
Author:
|
|
|
|
Bryan Willman (bryanwi) 19-Nov-91
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "cmp.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
//
|
|
// NOTE: This version of the test operations on \REGISTRY\MACHINE\TEST\*,
|
|
// which is the TEST hive. This hive will not exist in production
|
|
// systems, so the test will have to change.
|
|
//
|
|
|
|
|
|
void __cdecl main(int, char *);
|
|
|
|
VOID
|
|
NameClassAndTitle(
|
|
KEY_NODE_INFORMATION *NodeInformation,
|
|
UNICODE_STRING ClassName,
|
|
ULONG TitleIndex,
|
|
UNICODE_STRING KeyName,
|
|
LARGE_INTEGER CompTime,
|
|
BOOLEAN Strong, // time must be >= CompTime
|
|
PUCHAR TestName
|
|
);
|
|
|
|
VOID
|
|
expectstring(
|
|
PWSTR expected,
|
|
ULONG expectedlength,
|
|
PWSTR actual,
|
|
ULONG actuallength
|
|
);
|
|
|
|
VOID
|
|
expecttime(
|
|
LARGE_INTEGER ExpectTime,
|
|
LARGE_INTEGER ActualTime
|
|
);
|
|
|
|
|
|
#define TITLE_INDEX_1 122259
|
|
#define TITLE_INDEX_2 120858
|
|
#define TITLE_INDEX_3 120159
|
|
#define TYPE_1 666
|
|
#define TYPE_2 1066
|
|
|
|
|
|
ULONG failure = 0;
|
|
|
|
|
|
void
|
|
__cdecl main(int, char *)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING KeyName2;
|
|
UNICODE_STRING ClassName;
|
|
UNICODE_STRING ClassName2;
|
|
UNICODE_STRING ValueName;
|
|
UNICODE_STRING ValueName2;
|
|
HANDLE BaseHandle;
|
|
HANDLE Testhand1;
|
|
ULONG Disposition;
|
|
LARGE_INTEGER CompTime;
|
|
ULONG buffer[100];
|
|
ULONG bufsize = sizeof(ULONG) * 100;
|
|
PKEY_NODE_INFORMATION NodeInformation;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
|
|
PKEY_VALUE_BASIC_INFORMATION KeyValueBasic;
|
|
ULONG ResultLength;
|
|
PUCHAR datastring = "Some simple ascii data for use as a value";
|
|
PUCHAR datastring2 = "Some more not so simple data $#";
|
|
ULONG expected;
|
|
PVOID tp;
|
|
|
|
|
|
printf("rtmisc1: starting\n");
|
|
|
|
NodeInformation = (PKEY_NODE_INFORMATION)&(buffer[0]);
|
|
KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)&(buffer[0]);
|
|
KeyValueBasic = (PKEY_VALUE_BASIC_INFORMATION)&(buffer[0]);
|
|
|
|
//
|
|
// t0: Perform all operations against a base node, open it here.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"\\REGISTRY\\MACHINE\\TEST"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
0,
|
|
(HANDLE)NULL,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
status = NtOpenKey(
|
|
&BaseHandle,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t0: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
|
|
//
|
|
// t1: Create a key with class and title index
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ClassName,
|
|
L"t1 Class Name"
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"first_test_node"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
0,
|
|
BaseHandle,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
NtQuerySystemTime(&CompTime);
|
|
|
|
// printf("ClassName@%08lx KeyName@%08lx\n",
|
|
// ClassName.Buffer, KeyName.Buffer);
|
|
|
|
status = NtCreateKey(
|
|
&Testhand1,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjectAttributes,
|
|
TITLE_INDEX_1,
|
|
&ClassName,
|
|
0,
|
|
&Disposition
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t1: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
if (Disposition != REG_CREATED_NEW_KEY) {
|
|
printf("rtmisc1: t1a: got old key, expected to create new one\n");
|
|
failure++;
|
|
}
|
|
|
|
//
|
|
// t2: See if we can get data back, and if it makes sense
|
|
//
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtQueryKey(
|
|
Testhand1,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t2a: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
if (ResultLength != 80) {
|
|
printf("rtmisc1: t2i: expect 80, ResultLength = %d\n", ResultLength);
|
|
failure++;
|
|
}
|
|
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName,
|
|
TITLE_INDEX_1,
|
|
KeyName,
|
|
CompTime,
|
|
FALSE, // time must be >= CompTime
|
|
"rtmisc1: t2b: "
|
|
);
|
|
CompTime = NodeInformation->LastWriteTime;
|
|
|
|
status = NtClose(Testhand1);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t2c: %08lx\n");
|
|
goto punt;
|
|
}
|
|
|
|
|
|
//
|
|
// t3: Reopen the key with create, see if data still there.
|
|
//
|
|
|
|
status = NtCreateKey(
|
|
&Testhand1,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjectAttributes,
|
|
TITLE_INDEX_1,
|
|
&ClassName,
|
|
0,
|
|
&Disposition
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t3: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
if (Disposition != REG_OPENED_EXISTING_KEY) {
|
|
printf("rtmisc1: t3a failure\n");
|
|
failure++;
|
|
}
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtQueryKey(
|
|
Testhand1,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t3b: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName,
|
|
TITLE_INDEX_1,
|
|
KeyName,
|
|
CompTime,
|
|
FALSE, // time must be >= CompTime
|
|
"rtmisc1: t3c: "
|
|
);
|
|
|
|
status = NtClose(Testhand1);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t3d: %08lx\n");
|
|
goto punt;
|
|
}
|
|
|
|
|
|
//
|
|
// t4: Reopen the key with open, see if data still there.
|
|
//
|
|
|
|
status = NtOpenKey(
|
|
&Testhand1,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t4: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtQueryKey(
|
|
Testhand1,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t4a: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName,
|
|
TITLE_INDEX_1,
|
|
KeyName,
|
|
CompTime,
|
|
FALSE, // time must be >= CompTime
|
|
"rtmisc1: t4b: "
|
|
);
|
|
|
|
// status = NtClose(Testhand1);
|
|
// if (!NT_SUCCESS(status)) {
|
|
// printf("rtmisc1: t4c: %08lx\n");
|
|
// exit(1);
|
|
// }
|
|
|
|
|
|
//
|
|
// t5: Create a value
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName,
|
|
L"the very first value stored in the registry"
|
|
);
|
|
|
|
|
|
status = NtSetValueKey(
|
|
Testhand1,
|
|
&ValueName,
|
|
TITLE_INDEX_2,
|
|
TYPE_1,
|
|
datastring,
|
|
strlen(datastring)+1
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t5: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
|
|
|
|
//
|
|
// t6: Read the value back
|
|
//
|
|
|
|
RtlZeroMemory(KeyValueInformation, bufsize);
|
|
status = NtQueryValueKey(
|
|
Testhand1,
|
|
&ValueName,
|
|
KeyValueFullInformation,
|
|
KeyValueInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t6: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
expected = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
|
|
ValueName.Length + strlen(datastring) + 1;
|
|
if (ResultLength != expected) {
|
|
printf("rtmisc1: t6a: expected = %08lx actual = %08lx",
|
|
expected, ResultLength);
|
|
failure++;
|
|
}
|
|
|
|
if ( (KeyValueInformation->TitleIndex != TITLE_INDEX_2) ||
|
|
(KeyValueInformation->Type != TYPE_1) ||
|
|
(KeyValueInformation->NameLength != ValueName.Length) ||
|
|
(KeyValueInformation->DataLength != strlen(datastring)+1))
|
|
{
|
|
printf("rtmisc1: t6b: wrong description data\n");
|
|
failure++;
|
|
}
|
|
|
|
|
|
tp = (PWSTR)&(KeyValueInformation->Name[0]);
|
|
if (wcsncmp(ValueName.Buffer, tp, (ValueName.Length/sizeof(WCHAR))) != 0) {
|
|
printf("rtmisc1: t6c: wrong name\n");
|
|
expectstring(
|
|
ValueName.Buffer,
|
|
(ValueName.Length/sizeof(WCHAR)),
|
|
(PWSTR)&(KeyValueInformation->Name[0]),
|
|
(KeyValueInformation->NameLength/sizeof(WCHAR))
|
|
);
|
|
failure++;
|
|
}
|
|
|
|
|
|
tp = (PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset;
|
|
if (strcmp(tp, datastring) != 0) {
|
|
printf("rtmisc1: t6d: wrong data\n");
|
|
printf("expected '%s', got '%s'\n", datastring, tp);
|
|
failure++;
|
|
}
|
|
|
|
//
|
|
// t7: Create a second value
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&ValueName2,
|
|
L"the second value stored in the registry"
|
|
);
|
|
|
|
|
|
status = NtSetValueKey(
|
|
Testhand1,
|
|
&ValueName2,
|
|
TITLE_INDEX_3,
|
|
TYPE_2,
|
|
datastring2,
|
|
strlen(datastring2)+1
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t7: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
|
|
//
|
|
// t8: Read the second value back (short form)
|
|
//
|
|
|
|
RtlZeroMemory(KeyValueBasic, bufsize);
|
|
status = NtQueryValueKey(
|
|
Testhand1,
|
|
&ValueName2,
|
|
KeyValueBasicInformation,
|
|
KeyValueBasic,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t8: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
expected = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
|
|
ValueName2.Length;
|
|
if (ResultLength != expected) {
|
|
printf("rtmisc1: t8a: expected = %08lx actual = %08lx",
|
|
expected, ResultLength);
|
|
failure++;
|
|
}
|
|
|
|
if ( (KeyValueBasic->TitleIndex != TITLE_INDEX_3) ||
|
|
(KeyValueBasic->Type != TYPE_2) ||
|
|
(KeyValueBasic->NameLength != ValueName2.Length))
|
|
{
|
|
printf("rtmisc1: t8b: wrong description data\n");
|
|
failure++;
|
|
}
|
|
|
|
|
|
tp = (PWSTR)&(KeyValueBasic->Name[0]);
|
|
if (wcsncmp(ValueName2.Buffer, tp, (ValueName2.Length/sizeof(WCHAR))) != 0) {
|
|
printf("rtmisc1: t8c: wrong name\n");
|
|
expectstring(
|
|
ValueName2.Buffer,
|
|
(ValueName2.Length/sizeof(WCHAR)),
|
|
(PWSTR)&(KeyValueBasic->Name[0]),
|
|
(KeyValueBasic->NameLength/sizeof(WCHAR))
|
|
);
|
|
failure++;
|
|
}
|
|
|
|
|
|
//
|
|
// t9: Enumerate the values (short form)
|
|
//
|
|
|
|
RtlZeroMemory(KeyValueBasic, bufsize);
|
|
status = NtEnumerateValueKey(
|
|
Testhand1,
|
|
0, // Index
|
|
KeyValueBasicInformation,
|
|
KeyValueBasic,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t9: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
expected = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
|
|
ValueName.Length;
|
|
if (ResultLength != expected) {
|
|
printf("rtmisc1: t9a: expected = %08lx actual = %08lx",
|
|
expected, ResultLength);
|
|
failure++;
|
|
}
|
|
|
|
if (KeyValueBasic->NameLength != ValueName.Length)
|
|
{
|
|
printf("rtmisc1: t9b: wrong description data\n");
|
|
failure++;
|
|
}
|
|
|
|
|
|
tp = (PWSTR)&(KeyValueBasic->Name[0]);
|
|
if (wcsncmp(ValueName.Buffer, tp, (ValueName.Length/sizeof(WCHAR))) != 0) {
|
|
printf("rtmisc1: t9c: wrong name\n");
|
|
expectstring(
|
|
ValueName.Buffer,
|
|
(ValueName.Length/sizeof(WCHAR)),
|
|
(PWSTR)&(KeyValueBasic->Name[0]),
|
|
(KeyValueBasic->NameLength/sizeof(WCHAR))
|
|
);
|
|
failure++;
|
|
}
|
|
|
|
RtlZeroMemory(KeyValueBasic, bufsize);
|
|
status = NtEnumerateValueKey(
|
|
Testhand1,
|
|
1, // Index
|
|
KeyValueBasicInformation,
|
|
KeyValueBasic,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t9d: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
expected = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
|
|
ValueName2.Length;
|
|
if (ResultLength != expected) {
|
|
printf("rtmisc1: t9e: expected = %08lx actual = %08lx",
|
|
expected, ResultLength);
|
|
failure++;
|
|
}
|
|
|
|
if (KeyValueBasic->NameLength != ValueName2.Length)
|
|
{
|
|
printf("rtmisc1: t9f: wrong description data\n");
|
|
failure++;
|
|
}
|
|
|
|
|
|
tp = (PWSTR)&(KeyValueBasic->Name[0]);
|
|
if (wcsncmp(ValueName2.Buffer, tp, (ValueName2.Length/sizeof(WCHAR))) != 0) {
|
|
printf("rtmisc1: t9g: wrong name\n");
|
|
expectstring(
|
|
ValueName2.Buffer,
|
|
(ValueName2.Length/sizeof(WCHAR)),
|
|
(PWSTR)&(KeyValueBasic->Name[0]),
|
|
(KeyValueBasic->NameLength/sizeof(WCHAR))
|
|
);
|
|
failure++;
|
|
}
|
|
|
|
status = NtEnumerateValueKey(
|
|
Testhand1,
|
|
2, // Index
|
|
KeyValueBasicInformation,
|
|
KeyValueBasic,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (status != STATUS_NO_MORE_ENTRIES) {
|
|
printf("rtmisc1: t9h: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
//
|
|
// t10: create a second subkey and ennumerate the subkeys
|
|
//
|
|
|
|
status = NtClose(Testhand1);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10a: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
|
|
RtlInitUnicodeString(
|
|
&ClassName2,
|
|
L"t2 Class Name"
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName2,
|
|
L"second_test_node"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName2,
|
|
0,
|
|
BaseHandle,
|
|
NULL
|
|
);
|
|
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
|
|
|
|
status = NtCreateKey(
|
|
&Testhand1,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjectAttributes,
|
|
TITLE_INDEX_2,
|
|
&ClassName2,
|
|
0,
|
|
&Disposition
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10b: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
|
|
if (Disposition != REG_CREATED_NEW_KEY) {
|
|
printf("rtmisc1: t10c: got old key, expected to create new one\n");
|
|
failure++;
|
|
}
|
|
|
|
//
|
|
// See if we can get data back, and if it makes sense
|
|
//
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtQueryKey(
|
|
Testhand1,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10d: %08lx\n", status);
|
|
goto punt;
|
|
}
|
|
CompTime = NodeInformation->LastWriteTime;
|
|
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName2,
|
|
TITLE_INDEX_2,
|
|
KeyName2,
|
|
CompTime,
|
|
TRUE,
|
|
"rtmisc1: t10e: "
|
|
);
|
|
|
|
status = NtClose(Testhand1);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10f: %08lx\n");
|
|
goto punt;
|
|
}
|
|
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtEnumerateKey(
|
|
BaseHandle,
|
|
0,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10g: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
CompTime = NodeInformation->LastWriteTime;
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName,
|
|
TITLE_INDEX_1,
|
|
KeyName,
|
|
CompTime,
|
|
TRUE,
|
|
"rtmisc1: t10h: "
|
|
);
|
|
|
|
|
|
RtlZeroMemory(NodeInformation, bufsize);
|
|
status = NtEnumerateKey(
|
|
BaseHandle,
|
|
1,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
printf("rtmisc1: t10i: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
CompTime = NodeInformation->LastWriteTime;
|
|
|
|
NameClassAndTitle(
|
|
NodeInformation,
|
|
ClassName2,
|
|
TITLE_INDEX_2,
|
|
KeyName2,
|
|
CompTime,
|
|
TRUE,
|
|
"rtmisc1: t10j: "
|
|
);
|
|
|
|
|
|
status = NtEnumerateKey(
|
|
BaseHandle,
|
|
2,
|
|
KeyNodeInformation,
|
|
NodeInformation,
|
|
bufsize,
|
|
&ResultLength
|
|
);
|
|
if (status != STATUS_NO_MORE_ENTRIES) {
|
|
printf("rtmisc1: t10k: %08lx\n", status);
|
|
failure++;
|
|
}
|
|
|
|
//
|
|
// Summary report
|
|
//
|
|
|
|
if (!failure) {
|
|
printf("rtmisc1: success");
|
|
exit(0);
|
|
} else {
|
|
printf("rtmisc1: failed, %d failures\n", failure);
|
|
exit(1);
|
|
}
|
|
|
|
punt:
|
|
failure++;
|
|
printf("rtmisc1: failed, %d failures\n", failure);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NameClassAndTitle(
|
|
KEY_NODE_INFORMATION *NodeInformation,
|
|
UNICODE_STRING ClassName,
|
|
ULONG TitleIndex,
|
|
UNICODE_STRING KeyName,
|
|
LARGE_INTEGER CompTime,
|
|
BOOLEAN Strong, // time must be >= CompTime
|
|
PUCHAR TestName
|
|
)
|
|
{
|
|
PWSTR p;
|
|
|
|
if (Strong) {
|
|
|
|
//
|
|
// require exact match
|
|
//
|
|
|
|
if ((CompTime.HighPart != NodeInformation->LastWriteTime.HighPart) ||
|
|
(CompTime.LowPart != NodeInformation->LastWriteTime.LowPart))
|
|
{
|
|
printf("%s Wrong time (a)\n", TestName);
|
|
expecttime(CompTime, NodeInformation->LastWriteTime);
|
|
failure++;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// >= will do
|
|
//
|
|
|
|
if ( (CompTime.HighPart > NodeInformation->LastWriteTime.HighPart) ||
|
|
((CompTime.HighPart == NodeInformation->LastWriteTime.HighPart) &&
|
|
(CompTime.LowPart > NodeInformation->LastWriteTime.LowPart)) )
|
|
{
|
|
printf("%s Wrong time (b)\n", TestName);
|
|
expecttime(CompTime, NodeInformation->LastWriteTime);
|
|
failure++;
|
|
}
|
|
}
|
|
|
|
|
|
p = (PWSTR)((PUCHAR)NodeInformation + NodeInformation->ClassOffset);
|
|
if ( (NodeInformation->ClassLength != ClassName.Length) ||
|
|
(wcsncmp(ClassName.Buffer, p, (ClassName.Length/sizeof(WCHAR))) != 0))
|
|
{
|
|
printf("%s wrong class name\n", TestName);
|
|
failure++;
|
|
}
|
|
|
|
if (NodeInformation->TitleIndex != TitleIndex) {
|
|
printf("%s wrong title index\n", TestName);
|
|
failure++;
|
|
}
|
|
|
|
p = (PWSTR)(&(NodeInformation->Name[0]));
|
|
if ( (NodeInformation->NameLength != KeyName.Length) ||
|
|
(wcsncmp(KeyName.Buffer, p, (KeyName.Length/sizeof(WCHAR))) != 0))
|
|
{
|
|
printf("%s wrong name\n", TestName);
|
|
expectstring(
|
|
KeyName.Buffer,
|
|
(KeyName.Length/sizeof(WCHAR)),
|
|
(PWSTR)&(NodeInformation->Name[0]),
|
|
(NodeInformation->NameLength/sizeof(WCHAR))
|
|
);
|
|
failure++;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
expecttime(
|
|
LARGE_INTEGER ExpectTime,
|
|
LARGE_INTEGER ActualTime
|
|
)
|
|
{
|
|
printf("Expected %08lx%08lx\n", ExpectTime.HighPart, ExpectTime.LowPart);
|
|
printf("Got %08lx%08lx\n", ActualTime.HighPart, ActualTime.LowPart);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
expectstring(
|
|
PWSTR expected,
|
|
ULONG expectedlength,
|
|
PWSTR actual,
|
|
ULONG actuallength
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
printf("Expected Len %d Str = '", expectedlength);
|
|
for (i = 0; i < expectedlength; i++) {
|
|
printf("%c", (UCHAR)(expected[i]));
|
|
}
|
|
printf("'\n");
|
|
|
|
printf("Got Len %d Str = '", actuallength);
|
|
for (i = 0; i < actuallength; i++) {
|
|
printf("%c", (UCHAR)(actual[i]));
|
|
}
|
|
printf("'\n");
|
|
return;
|
|
}
|