mirror of
https://github.com/reactos/reactos.git
synced 2025-05-05 09:57:04 +00:00
[RTL/NTDLL]
- Implement registry transaction API (RXACT) - Add RtlCheckForOrphanedCriticalSections stub svn path=/trunk/; revision=61571
This commit is contained in:
parent
7ab5af14a3
commit
e5813955cb
4 changed files with 713 additions and 8 deletions
|
@ -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)
|
||||
|
|
|
@ -49,6 +49,7 @@ list(APPEND SOURCE
|
|||
registry.c
|
||||
res.c
|
||||
resource.c
|
||||
rxact.c
|
||||
sd.c
|
||||
security.c
|
||||
slist.c
|
||||
|
|
|
@ -757,4 +757,12 @@ RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlCheckForOrphanedCriticalSections(
|
||||
HANDLE ThreadHandle)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
696
reactos/lib/rtl/rxact.c
Normal file
696
reactos/lib/rtl/rxact.c
Normal file
|
@ -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 <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,
|
||||
};
|
||||
|
||||
#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;
|
||||
}
|
||||
|
Loading…
Reference in a new issue