From e5813955cb03e9e32d9ef8b181d9da18e574539d Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 7 Jan 2014 21:26:06 +0000 Subject: [PATCH] [RTL/NTDLL] - Implement registry transaction API (RXACT) - Add RtlCheckForOrphanedCriticalSections stub svn path=/trunk/; revision=61571 --- reactos/dll/ntdll/def/ntdll.spec | 16 +- reactos/lib/rtl/CMakeLists.txt | 1 + reactos/lib/rtl/critical.c | 8 + reactos/lib/rtl/rxact.c | 696 +++++++++++++++++++++++++++++++ 4 files changed, 713 insertions(+), 8 deletions(-) create mode 100644 reactos/lib/rtl/rxact.c diff --git a/reactos/dll/ntdll/def/ntdll.spec b/reactos/dll/ntdll/def/ntdll.spec index cb6cd81610f..4ed630d4604 100644 --- a/reactos/dll/ntdll/def/ntdll.spec +++ b/reactos/dll/ntdll/def/ntdll.spec @@ -376,7 +376,7 @@ ;@ stdcall PfxInsertPrefix ;@ stdcall PfxRemovePrefix ;@ stdcall PropertyLengthAsVariant -;@ stdcall RtlAbortRXact +@ stdcall RtlAbortRXact(ptr) @ stdcall RtlAbsoluteToSelfRelativeSD(ptr ptr ptr) @ stdcall RtlAcquirePebLock() @ stdcall RtlAcquirePrivilege(ptr long long ptr) @@ -394,9 +394,9 @@ @ stdcall RtlAddAccessDeniedAceEx(ptr long long long ptr) @ stdcall RtlAddAccessDeniedObjectAce(ptr long long long ptr ptr ptr) @ stdcall RtlAddAce(ptr long long ptr long) -;@ stdcall RtlAddActionToRXact +@ stdcall RtlAddActionToRXact(ptr long ptr long ptr long) @ stdcall RtlAddAtomToAtomTable(ptr wstr ptr) -;@ stdcall RtlAddAttributeActionToRXact +@ stdcall RtlAddAttributeActionToRXact(ptr long ptr ptr ptr long ptr long) @ stdcall RtlAddAuditAccessAce(ptr long long ptr long long) @ stdcall RtlAddAuditAccessAceEx(ptr long long long ptr long long) @ stdcall RtlAddAuditAccessObjectAce(ptr long long long ptr ptr ptr long long) @@ -423,8 +423,8 @@ @ stdcall RtlAppendUnicodeStringToString(ptr ptr) @ stdcall RtlAppendUnicodeToString(ptr wstr) ;@ stdcall RtlApplicationVerifierStop -;@ stdcall RtlApplyRXact -;@ stdcall RtlApplyRXactNoFlush +@ stdcall RtlApplyRXact(ptr) +@ stdcall RtlApplyRXactNoFlush(ptr) @ stdcall RtlAreAllAccessesGranted(long long) @ stdcall RtlAreAnyAccessesGranted(long long) @ stdcall RtlAreBitsClear(ptr long long) @@ -435,7 +435,7 @@ @ stdcall RtlCaptureStackBackTrace(long long ptr ptr) ;@ stdcall RtlCaptureStackContext @ stdcall RtlCharToInteger(ptr long ptr) -;@ stdcall RtlCheckForOrphanedCriticalSections +@ stdcall RtlCheckForOrphanedCriticalSections(ptr) ;@ stdcall RtlCheckProcessParameters @ stdcall RtlCheckRegistryKey(long ptr) @ stdcall RtlClearAllBits(ptr) @@ -673,7 +673,7 @@ @ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr) @ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr) @ stdcall RtlInitializeHandleTable(long long ptr) -;@ stdcall RtlInitializeRXact +@ stdcall RtlInitializeRXact(ptr long ptr) @ stdcall RtlInitializeRangeList(ptr) @ stdcall RtlInitializeResource(ptr) @ stdcall RtlInitializeSListHead(ptr) @@ -868,7 +868,7 @@ @ stdcall RtlSleepConditionVariableCS(ptr ptr ptr) @ stdcall RtlSleepConditionVariableSRW(ptr ptr ptr long) @ stdcall RtlSplay(ptr) -;@ stdcall RtlStartRXact +@ stdcall RtlStartRXact(ptr) @ stdcall RtlStatMemoryStream(ptr ptr long) @ stdcall RtlStringFromGUID(ptr ptr) @ stdcall RtlSubAuthorityCountSid(ptr) diff --git a/reactos/lib/rtl/CMakeLists.txt b/reactos/lib/rtl/CMakeLists.txt index e584c063a6e..815faa8e12a 100644 --- a/reactos/lib/rtl/CMakeLists.txt +++ b/reactos/lib/rtl/CMakeLists.txt @@ -49,6 +49,7 @@ list(APPEND SOURCE registry.c res.c resource.c + rxact.c sd.c security.c slist.c diff --git a/reactos/lib/rtl/critical.c b/reactos/lib/rtl/critical.c index 917cbf2dda9..ab3590b429a 100644 --- a/reactos/lib/rtl/critical.c +++ b/reactos/lib/rtl/critical.c @@ -757,4 +757,12 @@ RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) return FALSE; } +VOID +NTAPI +RtlCheckForOrphanedCriticalSections( + HANDLE ThreadHandle) +{ + UNIMPLEMENTED; +} + /* EOF */ diff --git a/reactos/lib/rtl/rxact.c b/reactos/lib/rtl/rxact.c new file mode 100644 index 00000000000..cc9f9609a65 --- /dev/null +++ b/reactos/lib/rtl/rxact.c @@ -0,0 +1,696 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/rtl/rxact.c + * PURPOSE: Registry Transaction API + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#define RXACT_DEFAULT_BUFFER_SIZE (4 * PAGE_SIZE) + +typedef struct _RXACT_INFO +{ + ULONG Revision; + ULONG Unknown1; + ULONG Unknown2; +} RXACT_INFO, *PRXACT_INFO; + +typedef struct _RXACT_DATA +{ + ULONG ActionCount; + ULONG BufferSize; + ULONG CurrentSize; +} RXACT_DATA, *PRXACT_DATA; + +typedef struct _RXACT_CONTEXT +{ + HANDLE RootDirectory; + HANDLE KeyHandle; + BOOLEAN CanUseHandles; + PRXACT_DATA Data; +} RXACT_CONTEXT, *PRXACT_CONTEXT; + +typedef struct _RXACT_ACTION +{ + ULONG Size; + ULONG Type; + UNICODE_STRING KeyName; + UNICODE_STRING ValueName; + HANDLE KeyHandle; + ULONG ValueType; + ULONG ValueDataSize; + PVOID ValueData; +} RXACT_ACTION, *PRXACT_ACTION; + +enum +{ + RXactDeleteKey = 1, + RXactSetValueKey = 2, +}; + +#define ALIGN_UP_BY ROUND_UP + +/* FUNCTIONS *****************************************************************/ + +static +VOID +NTAPI +RXactInitializeContext( + PRXACT_CONTEXT Context, + HANDLE RootDirectory, + HANDLE KeyHandle) +{ + Context->Data = NULL; + Context->RootDirectory = RootDirectory; + Context->CanUseHandles = TRUE; + Context->KeyHandle = KeyHandle; +} + +static +NTSTATUS +NTAPI +RXactpOpenTargetKey( + HANDLE RootDirectory, + ULONG ActionType, + PUNICODE_STRING KeyName, + PHANDLE KeyHandle) +{ + NTSTATUS Status; + ULONG Disposition; + OBJECT_ATTRIBUTES ObjectAttributes; + + /* Check what kind of action this is */ + if (ActionType == RXactDeleteKey) + { + /* This is a delete, so open the key for delete */ + InitializeObjectAttributes(&ObjectAttributes, + KeyName, + OBJ_CASE_INSENSITIVE, + RootDirectory, + NULL); + Status = ZwOpenKey(KeyHandle, DELETE, &ObjectAttributes); + } + else if (ActionType == RXactSetValueKey) + { + /* This is a create, so open or create with write access */ + InitializeObjectAttributes(&ObjectAttributes, + KeyName, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + RootDirectory, + NULL); + Status = ZwCreateKey(KeyHandle, + KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + } + else + { + return STATUS_INVALID_PARAMETER; + } + + return Status; +} + +static +NTSTATUS +NTAPI +RXactpCommit( + PRXACT_CONTEXT Context) +{ + PRXACT_DATA Data; + PRXACT_ACTION Action; + NTSTATUS Status, TmpStatus; + HANDLE KeyHandle; + ULONG i; + + Data = Context->Data; + + /* The first action record starts after the data header */ + Action = (PRXACT_ACTION)(Data + 1); + + /* Loop all recorded actions */ + for (i = 0; i < Data->ActionCount; i++) + { + /* Translate relative offsets to actual pointers */ + Action->KeyName.Buffer = (PWSTR)((PUCHAR)Data + (ULONG_PTR)Action->KeyName.Buffer); + Action->ValueName.Buffer = (PWSTR)((PUCHAR)Data + (ULONG_PTR)Action->ValueName.Buffer); + Action->ValueData = (PUCHAR)Data + (ULONG_PTR)Action->ValueData; + + /* Check what kind of action this is */ + if (Action->Type == RXactDeleteKey) + { + /* This is a delete action. Check if we can use a handle */ + if ((Action->KeyHandle != INVALID_HANDLE_VALUE) && Context->CanUseHandles) + { + /* Delete the key by the given handle */ + Status = ZwDeleteKey(Action->KeyHandle); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + else + { + /* We cannot use a handle, open the key first by it's name */ + Status = RXactpOpenTargetKey(Context->RootDirectory, + RXactDeleteKey, + &Action->KeyName, + &KeyHandle); + if (NT_SUCCESS(Status)) + { + Status = ZwDeleteKey(KeyHandle); + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + else + { + /* Failed to open the key, it's ok, if it was not found */ + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) + return Status; + } + } + } + else if (Action->Type == RXactSetValueKey) + { + /* This is a set action. Check if we can use a handle */ + if ((Action->KeyHandle != INVALID_HANDLE_VALUE) && Context->CanUseHandles) + { + /* Set the key value using the given key handle */ + Status = ZwSetValueKey(Action->KeyHandle, + &Action->ValueName, + 0, + Action->ValueType, + Action->ValueData, + Action->ValueDataSize); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + else + { + /* We cannot use a handle, open the key first by it's name */ + Status = RXactpOpenTargetKey(Context->RootDirectory, + RXactSetValueKey, + &Action->KeyName, + &KeyHandle); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Set the key value */ + Status = ZwSetValueKey(KeyHandle, + &Action->ValueName, + 0, + Action->ValueType, + Action->ValueData, + Action->ValueDataSize); + + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + } + else + { + ASSERT(FALSE); + return STATUS_INVALID_PARAMETER; + } + + /* Go to the next action record */ + Action = (PRXACT_ACTION)((PUCHAR)Action + Action->Size); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +RtlStartRXact( + PRXACT_CONTEXT Context) +{ + PRXACT_DATA Buffer; + + /* We must not have a buffer yet */ + if (Context->Data != NULL) + { + return STATUS_RXACT_INVALID_STATE; + } + + /* Allocate a buffer */ + Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, RXACT_DEFAULT_BUFFER_SIZE); + if (Buffer == NULL) + { + return STATUS_NO_MEMORY; + } + + /* Initialize the buffer */ + Buffer->ActionCount = 0; + Buffer->BufferSize = RXACT_DEFAULT_BUFFER_SIZE; + Buffer->CurrentSize = sizeof(RXACT_DATA); + Context->Data = Buffer; + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +RtlAbortRXact( + PRXACT_CONTEXT Context) +{ + /* We must have a data buffer */ + if (Context->Data == NULL) + { + return STATUS_RXACT_INVALID_STATE; + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Context->Data); + + /* Reinitialize the context */ + RXactInitializeContext(Context, Context->RootDirectory, Context->KeyHandle); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +RtlInitializeRXact( + HANDLE RootDirectory, + BOOLEAN Commit, + PRXACT_CONTEXT *OutContext) +{ + NTSTATUS Status, TmpStatus; + PRXACT_CONTEXT Context; + PKEY_VALUE_FULL_INFORMATION KeyValueInformation; + KEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo; + UNICODE_STRING ValueName; + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES ObjectAttributes; + RXACT_INFO TransactionInfo; + ULONG Disposition; + ULONG ValueType; + ULONG ValueDataLength; + ULONG Length; + HANDLE KeyHandle; + + /* Open or create the 'RXACT' key in the root directory */ + RtlInitUnicodeString(&KeyName, L"RXACT"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + RootDirectory, + NULL); + Status = ZwCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE | DELETE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Allocate a new context */ + Context = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Context)); + *OutContext = Context; + if (Context == NULL) + { + TmpStatus = ZwDeleteKey(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + + return STATUS_NO_MEMORY; + } + + /* Initialize the context */ + RXactInitializeContext(Context, RootDirectory, KeyHandle); + + /* Check if we created a new key */ + if (Disposition == REG_CREATED_NEW_KEY) + { + /* The key is new, set the default value */ + TransactionInfo.Revision = 1; + RtlInitUnicodeString(&ValueName, NULL); + Status = ZwSetValueKey(KeyHandle, + &ValueName, + 0, + REG_NONE, + &TransactionInfo, + sizeof(TransactionInfo)); + if (!NT_SUCCESS(Status)) + { + TmpStatus = ZwDeleteKey(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + + RtlFreeHeap(RtlGetProcessHeap(), 0, *OutContext); + return Status; + } + + return STATUS_RXACT_STATE_CREATED; + } + else + { + /* The key exited, get the default key value */ + ValueDataLength = sizeof(TransactionInfo); + Status = RtlpNtQueryValueKey(KeyHandle, + &ValueType, + &TransactionInfo, + &ValueDataLength, + 0); + if (!NT_SUCCESS(Status)) + { + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + RtlFreeHeap(RtlGetProcessHeap(), 0, Context); + return Status; + } + + /* Check if the value date is valid */ + if ((ValueDataLength != sizeof(TransactionInfo)) || + (TransactionInfo.Revision != 1)) + { + TmpStatus = NtClose(KeyHandle); + ASSERT(NT_SUCCESS(TmpStatus)); + RtlFreeHeap(RtlGetProcessHeap(), 0, Context); + return STATUS_UNKNOWN_REVISION; + } + + /* Query the 'Log' key value */ + RtlInitUnicodeString(&ValueName, L"Log"); + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValueBasicInformation, + &KeyValueBasicInfo, + sizeof(KeyValueBasicInfo), + &Length); + if (!NT_SUCCESS(Status)) + { + /* There is no 'Log', so we are done */ + return STATUS_SUCCESS; + } + + /* Check if the caller asked to commit the current state */ + if (!Commit) + { + /* We have a log, that must be committed first! */ + return STATUS_RXACT_COMMIT_NECESSARY; + } + + /* Query the size of the 'Log' key value */ + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValueFullInformation, + NULL, + 0, + &Length); + if (Status != STATUS_BUFFER_TOO_SMALL) + { + return Status; + } + + /* Allocate a buffer for the key value information */ + KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); + if (KeyValueInformation == NULL) + { + return STATUS_NO_MEMORY; + } + + /* Query the 'Log' key value */ + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValueFullInformation, + KeyValueInformation, + Length, + &Length); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); + RtlFreeHeap(RtlGetProcessHeap(), 0, Context); + return Status; + } + + /* Set the Data pointer to the key value data */ + Context->Data = (PRXACT_DATA)((PUCHAR)KeyValueInformation + + KeyValueInformation->DataOffset); + + /* This is an old log, don't use handles when committing! */ + Context->CanUseHandles = FALSE; + + /* Commit the data */ + Status = RXactpCommit(Context); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); + RtlFreeHeap(RtlGetProcessHeap(), 0, Context); + return Status; + } + + /* Delete the old key */ + Status = NtDeleteValueKey(KeyHandle, &ValueName); + ASSERT(NT_SUCCESS(Status)); + + /* Set the data member to the allocated buffer, so it will get freed */ + Context->Data = (PRXACT_DATA)KeyValueInformation; + + /* Abort the old transaction */ + Status = RtlAbortRXact(Context); + ASSERT(NT_SUCCESS(Status)); + + return Status; + } +} + +NTSTATUS +NTAPI +RtlAddAttributeActionToRXact( + PRXACT_CONTEXT Context, + ULONG ActionType, + PUNICODE_STRING KeyName, + HANDLE KeyHandle, + PUNICODE_STRING ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueDataSize) +{ + ULONG ActionSize; + ULONG RequiredSize; + ULONG BufferSize; + ULONG CurrentOffset; + PRXACT_DATA NewData; + PRXACT_ACTION Action; + + /* Validate ActionType parameter */ + if ((ActionType != RXactDeleteKey) && (ActionType != RXactSetValueKey)) + { + return STATUS_INVALID_PARAMETER; + } + + /* Calculate the size of the new action record */ + ActionSize = ALIGN_UP_BY(ValueName->Length, sizeof(ULONG)) + + ALIGN_UP_BY(ValueDataSize, sizeof(ULONG)) + + ALIGN_UP_BY(KeyName->Length, sizeof(ULONG)) + + ALIGN_UP_BY(sizeof(RXACT_ACTION), sizeof(ULONG)); + + /* Calculate the new buffer size we need */ + RequiredSize = ActionSize + Context->Data->CurrentSize; + + /* Check for integer overflow */ + if (RequiredSize < ActionSize) + { + return STATUS_NO_MEMORY; + } + + /* Check if the buffer is large enough */ + BufferSize = Context->Data->BufferSize; + if (RequiredSize > BufferSize) + { + /* Increase by a factor of 2, until it is large enough */ + while (BufferSize < RequiredSize) + { + BufferSize *= 2; + } + + /* Allocate a new buffer from the heap */ + NewData = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); + if (NewData == NULL) + { + return STATUS_NO_MEMORY; + } + + /* Copy the old buffer to the new one */ + RtlCopyMemory(NewData, Context->Data, Context->Data->CurrentSize); + + /* Free the old buffer and use the new one */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Context->Data); + Context->Data = NewData; + NewData->BufferSize = BufferSize; + } + + /* Get the next action record */ + Action = (RXACT_ACTION *)((PUCHAR)Context->Data + Context->Data->CurrentSize); + + /* Fill in the fields */ + Action->Size = ActionSize; + Action->Type = ActionType; + Action->KeyName = *KeyName; + Action->ValueName = *ValueName; + Action->ValueType = ValueType; + Action->ValueDataSize = ValueDataSize; + Action->KeyHandle = KeyHandle; + + /* Copy the key name (and convert the pointer to a buffer offset) */ + CurrentOffset = Context->Data->CurrentSize + sizeof(RXACT_ACTION); + Action->KeyName.Buffer = UlongToPtr(CurrentOffset); + RtlCopyMemory((PUCHAR)Context->Data + CurrentOffset, + KeyName->Buffer, + KeyName->Length); + + /* Copy the value name (and convert the pointer to a buffer offset) */ + CurrentOffset += ALIGN_UP_BY(KeyName->Length, sizeof(ULONG)); + Action->ValueName.Buffer = UlongToPtr(CurrentOffset); + RtlCopyMemory((PUCHAR)Context->Data + CurrentOffset, + ValueName->Buffer, + ValueName->Length); + + /* Update the offset */ + CurrentOffset += ALIGN_UP_BY(ValueName->Length, sizeof(ULONG)); + + /* Is this a set action? */ + if (ActionType == RXactSetValueKey) + { + /* Copy the key value data as well */ + Action->ValueData = UlongToPtr(CurrentOffset); + RtlCopyMemory((PUCHAR)Context->Data + CurrentOffset, + ValueData, + ValueDataSize); + CurrentOffset += ALIGN_UP_BY(ValueDataSize, sizeof(ULONG)); + } + + /* Update data site and action count */ + Context->Data->CurrentSize = CurrentOffset; + Context->Data->ActionCount++; + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +RtlAddActionToRXact( + PRXACT_CONTEXT Context, + ULONG ActionType, + PUNICODE_STRING KeyName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueDataSize) +{ + UNICODE_STRING ValueName; + + /* Create a key and set the default key value or delete a key. */ + RtlInitUnicodeString(&ValueName, NULL); + return RtlAddAttributeActionToRXact(Context, + ActionType, + KeyName, + INVALID_HANDLE_VALUE, + &ValueName, + ValueType, + ValueData, + ValueDataSize); +} + +NTSTATUS +NTAPI +RtlApplyRXactNoFlush( + PRXACT_CONTEXT Context) +{ + NTSTATUS Status; + + /* Commit the transaction */ + Status = RXactpCommit(Context); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Reset the transaction */ + Status = RtlAbortRXact(Context); + ASSERT(NT_SUCCESS(Status)); + + return Status; +} + +NTSTATUS +NTAPI +RtlApplyRXact( + PRXACT_CONTEXT Context) +{ + UNICODE_STRING ValueName; + NTSTATUS Status; + + /* Temporarily safe the current transaction in the 'Log' key value */ + RtlInitUnicodeString(&ValueName, L"Log"); + Status = ZwSetValueKey(Context->KeyHandle, + &ValueName, + 0, + REG_BINARY, + Context->Data, + Context->Data->CurrentSize); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Flush the key */ + Status = NtFlushKey(Context->KeyHandle); + if (!NT_SUCCESS(Status)) + { + NtDeleteValueKey(Context->KeyHandle, &ValueName); + return Status; + } + + /* Now commit the transaction */ + Status = RXactpCommit(Context); + if (!NT_SUCCESS(Status)) + { + NtDeleteValueKey(Context->KeyHandle, &ValueName); + return Status; + } + + /* Delete the 'Log' key value */ + Status = NtDeleteValueKey(Context->KeyHandle, &ValueName); + ASSERT(NT_SUCCESS(Status)); + + /* Reset the transaction */ + Status = RtlAbortRXact(Context); + ASSERT(NT_SUCCESS(Status)); + + return STATUS_SUCCESS; +} + -- 2.17.1