Author: tkreuzer
Date: Tue Jan 7 21:26:06 2014
New Revision: 61571
URL:
http://svn.reactos.org/svn/reactos?rev=61571&view=rev
Log:
[RTL/NTDLL]
- Implement registry transaction API (RXACT)
- Add RtlCheckForOrphanedCriticalSections stub
Added:
trunk/reactos/lib/rtl/rxact.c (with props)
Modified:
trunk/reactos/dll/ntdll/def/ntdll.spec
trunk/reactos/lib/rtl/CMakeLists.txt
trunk/reactos/lib/rtl/critical.c
Modified: trunk/reactos/dll/ntdll/def/ntdll.spec
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/ntdll/def/ntdll.spec?r…
==============================================================================
--- trunk/reactos/dll/ntdll/def/ntdll.spec [iso-8859-1] (original)
+++ trunk/reactos/dll/ntdll/def/ntdll.spec [iso-8859-1] Tue Jan 7 21:26:06 2014
@@ -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)
Modified: trunk/reactos/lib/rtl/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/CMakeLists.txt?rev…
==============================================================================
--- trunk/reactos/lib/rtl/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/CMakeLists.txt [iso-8859-1] Tue Jan 7 21:26:06 2014
@@ -49,6 +49,7 @@
registry.c
res.c
resource.c
+ rxact.c
sd.c
security.c
slist.c
Modified: trunk/reactos/lib/rtl/critical.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/critical.c?rev=615…
==============================================================================
--- trunk/reactos/lib/rtl/critical.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/critical.c [iso-8859-1] Tue Jan 7 21:26:06 2014
@@ -757,4 +757,12 @@
return FALSE;
}
+VOID
+NTAPI
+RtlCheckForOrphanedCriticalSections(
+ HANDLE ThreadHandle)
+{
+ UNIMPLEMENTED;
+}
+
/* EOF */
Added: trunk/reactos/lib/rtl/rxact.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/rxact.c?rev=61571
==============================================================================
--- trunk/reactos/lib/rtl/rxact.c (added)
+++ trunk/reactos/lib/rtl/rxact.c [iso-8859-1] Tue Jan 7 21:26:06 2014
@@ -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(a)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;
+}
+
Propchange: trunk/reactos/lib/rtl/rxact.c
------------------------------------------------------------------------------
svn:eol-style = native