mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
695 lines
20 KiB
C
695 lines
20 KiB
C
![]() |
/*
|
||
|
* 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 <rtl.h>
|
||
|
#include <ndk/cmfuncs.h>
|
||
|
|
||
|
#define NDEBUG
|
||
|
#include <debug.h>
|
||
|
|
||
|
#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,
|
||
|
};
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
|