[WDF] Add Windows Driver Framework files
[reactos.git] / sdk / lib / drivers / wdf / shared / support / km / fxregkeykm.cpp
diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp
new file mode 100644 (file)
index 0000000..a6c5e3f
--- /dev/null
@@ -0,0 +1,296 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+    FxRegKey.cpp
+
+Abstract:
+
+Author:
+
+Environment:
+
+    kernel mode only
+
+Revision History:
+
+--*/
+
+#include "FxSupportPch.hpp"
+
+extern "C" {
+#include "FxRegKeyKM.tmh"
+}
+
+#define AT_PASSIVE()     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL)
+
+FxRegKey::FxRegKey(
+    PFX_DRIVER_GLOBALS FxDriverGlobals
+    ) :
+    FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals),
+    m_Key(NULL),
+    m_Globals(FxDriverGlobals)
+{
+}
+
+__drv_maxIRQL(PASSIVE_LEVEL)
+FxRegKey::~FxRegKey()
+{
+    if (m_Key != NULL) {
+        ZwClose(m_Key);
+        m_Key = NULL;
+    }
+}
+
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_Close(
+    __in HANDLE Key
+    )
+{
+    return ZwClose(Key);
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_Create(
+    __in_opt  HANDLE ParentKey,
+    __in  PCUNICODE_STRING KeyName,
+    __out HANDLE* NewKey,
+    __in  ACCESS_MASK DesiredAccess,
+    __in  ULONG CreateOptions,
+    __out_opt PULONG CreateDisposition
+    )
+{
+    OBJECT_ATTRIBUTES oa;
+
+    AT_PASSIVE();
+
+    //
+    // Force OBJ_KERNEL_HANDLE because we are never passing the handle back
+    // up to a process and we don't want to create a handle in an arbitrary
+    // process from which that process can close the handle out from underneath
+    // us.
+    //
+    InitializeObjectAttributes(
+        &oa,
+        (PUNICODE_STRING) KeyName,
+        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+        ParentKey,
+        NULL);
+
+    return ZwCreateKey(NewKey,
+                       DesiredAccess,
+                       &oa,
+                       0,
+                       0,
+                       CreateOptions,
+                       CreateDisposition);
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_OpenKey(
+    __in_opt  HANDLE ParentKey,
+    __in  PCUNICODE_STRING KeyName,
+    __out HANDLE* Key,
+    __in  ACCESS_MASK DesiredAccess
+    )
+{
+    OBJECT_ATTRIBUTES oa;
+
+    AT_PASSIVE();
+
+    //
+    // Force OBJ_KERNEL_HANDLE because we are never passing the handle back
+    // up to a process and we don't want to create a handle in an arbitrary
+    // process from which that process can close the handle out from underneath
+    // us.
+    //
+    InitializeObjectAttributes(
+        &oa,
+        (PUNICODE_STRING)KeyName,
+        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+        ParentKey,
+        NULL);
+
+    return ZwOpenKey(Key, DesiredAccess, &oa);
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_SetValue(
+    _In_ HANDLE Key,
+    __in PCUNICODE_STRING ValueName,
+    __in ULONG ValueType,
+    __in_bcount(ValueLength) PVOID Value,
+    __in ULONG ValueLength
+    )
+{
+    AT_PASSIVE();
+
+    return ZwSetValueKey(Key,
+                         (PUNICODE_STRING)ValueName,
+                         0,
+                         ValueType,
+                         Value,
+                         ValueLength);
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_QueryValue(
+    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+    __in HANDLE Key,
+    __in PCUNICODE_STRING ValueName,
+    __in ULONG ValueLength,
+    __out_bcount_opt(ValueLength) PVOID Value,
+    __out_opt PULONG ValueLengthQueried,
+    __out_opt PULONG ValueType
+    )
+{
+    KEY_VALUE_PARTIAL_INFORMATION *pPartial, partial;
+    NTSTATUS status;
+    ULONG length;
+
+    if (Value == NULL) {
+        //
+        // Caller wants just the length
+        //
+        pPartial = &partial;
+        length = _ComputePartialSize(0);
+        RtlZeroMemory(&partial, length);
+    }
+    else {
+        length = _ComputePartialSize(ValueLength);
+        pPartial = (PKEY_VALUE_PARTIAL_INFORMATION)
+            MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag);
+
+        if (pPartial == NULL) {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+    }
+
+    //
+    // We always pass a buffer of at least sizeof(KEY_VALUE_PARTIAL_INFORMATION)
+    // to ZwQueryValueKey. This means that ZwQueryValueKey will write at least
+    // some information to the buffer it receives, even if the user-supplied data
+    // buffer is NULL or too small.
+    //
+    // According to ZwQueryValueKey's contract, this means that it will never return
+    // STATUS_BUFFER_TOO_SMALL (returned when no data is written). Therefore, if the
+    // user passes a NULL or insufficient buffer and the value exists in the registry,
+    // ZwQueryValueKey will return STATUS_BUFFER_OVERFLOW.
+    //
+    status = ZwQueryValueKey(Key,
+                             (PUNICODE_STRING)ValueName,
+                             KeyValuePartialInformation,
+                             pPartial,
+                             length,
+                             &length);
+
+    if (NT_SUCCESS(status) && Value != NULL && (ValueLength >= pPartial->DataLength)) {
+        RtlCopyMemory(Value, &pPartial->Data[0], pPartial->DataLength);
+    }
+
+    if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
+        if (ValueLengthQueried != NULL) {
+            *ValueLengthQueried = pPartial->DataLength;
+        }
+        if (ValueType != NULL) {
+            *ValueType = pPartial->Type;
+        }
+    }
+
+    if (pPartial != &partial) {
+        MxMemory::MxFreePool(pPartial);
+    }
+
+    return status;
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_QueryULong(
+    __in  HANDLE Key,
+    __in  PCUNICODE_STRING ValueName,
+    __out PULONG Value
+    )
+{
+    NTSTATUS status;
+    ULONG length;
+
+    PKEY_VALUE_PARTIAL_INFORMATION pPartial;
+    UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(ULONG))];
+
+    length = sizeof(buffer);
+    pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0];
+
+    status = ZwQueryValueKey(Key,
+                             (PUNICODE_STRING)ValueName,
+                             KeyValuePartialInformation,
+                             pPartial,
+                             length,
+                             &length);
+
+    if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
+         pPartial->Type != REG_DWORD) {
+        status = STATUS_OBJECT_TYPE_MISMATCH;
+    }
+
+    if (NT_SUCCESS(status)) {
+        ASSERT(sizeof(ULONG) == pPartial->DataLength);
+
+        RtlCopyMemory(Value, &pPartial->Data[0], sizeof(ULONG));
+    }
+
+    return status;
+}
+
+_Must_inspect_result_
+__drv_maxIRQL(PASSIVE_LEVEL)
+NTSTATUS
+FxRegKey::_QueryQuadWord(
+    __in  HANDLE Key,
+    __in  PCUNICODE_STRING ValueName,
+    __out PLARGE_INTEGER Value
+    )
+{
+    NTSTATUS status;
+    ULONG length;
+
+    PKEY_VALUE_PARTIAL_INFORMATION pPartial;
+    UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(LARGE_INTEGER))];
+
+    length = sizeof(buffer);
+    pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0];
+
+    status = ZwQueryValueKey(Key,
+                             (PUNICODE_STRING)ValueName,
+                             KeyValuePartialInformation,
+                             pPartial,
+                             length,
+                             &length);
+
+    if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) &&
+         pPartial->Type != REG_QWORD) {
+        status = STATUS_OBJECT_TYPE_MISMATCH;
+    }
+
+    if (NT_SUCCESS(status)) {
+        ASSERT(sizeof(LARGE_INTEGER) == pPartial->DataLength);
+
+        RtlCopyMemory(Value, &pPartial->Data[0], sizeof(LARGE_INTEGER));
+    }
+
+    return status;
+}
+
+