mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
388 lines
8.9 KiB
C
388 lines
8.9 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/ex/uuid.c
|
|
* PURPOSE: UUID generator
|
|
*
|
|
* PROGRAMMERS: Eric Kohl
|
|
Thomas Weidenmueller
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define SEED_BUFFER_SIZE 6
|
|
|
|
/* Number of 100ns ticks per clock tick. To be safe, assume that the clock
|
|
resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
|
|
#define TICKS_PER_CLOCK_TICK 1000
|
|
#define SECSPERDAY 86400
|
|
#define TICKSPERSEC 10000000
|
|
|
|
/* UUID system time starts at October 15, 1582 */
|
|
#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
|
|
#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
|
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
#pragma alloc_text(INIT, ExpInitUuids)
|
|
#endif
|
|
|
|
|
|
/* GLOBALS ****************************************************************/
|
|
|
|
static FAST_MUTEX UuidMutex;
|
|
static ULARGE_INTEGER UuidLastTime;
|
|
static ULONG UuidSequence;
|
|
static BOOLEAN UuidSequenceInitialized = FALSE;
|
|
static BOOLEAN UuidSequenceChanged = FALSE;
|
|
static UCHAR UuidSeed[SEED_BUFFER_SIZE];
|
|
static ULONG UuidCount;
|
|
static LARGE_INTEGER LuidIncrement;
|
|
static LARGE_INTEGER LuidValue;
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
VOID
|
|
INIT_FUNCTION
|
|
NTAPI
|
|
ExpInitUuids(VOID)
|
|
{
|
|
ExInitializeFastMutex(&UuidMutex);
|
|
|
|
KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime);
|
|
UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601;
|
|
|
|
UuidCount = TICKS_PER_CLOCK_TICK;
|
|
RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE);
|
|
}
|
|
|
|
|
|
#define VALUE_BUFFER_SIZE 256
|
|
|
|
static NTSTATUS
|
|
ExpLoadUuidSequence(PULONG Sequence)
|
|
{
|
|
UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING Name;
|
|
HANDLE KeyHandle;
|
|
ULONG ValueLength;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&Name,
|
|
L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
Status = ZwOpenKey(&KeyHandle,
|
|
KEY_QUERY_VALUE,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString(&Name, L"UuidSequenceNumber");
|
|
|
|
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
Status = ZwQueryValueKey(KeyHandle,
|
|
&Name,
|
|
KeyValuePartialInformation,
|
|
ValueBuffer,
|
|
VALUE_BUFFER_SIZE,
|
|
&ValueLength);
|
|
ZwClose(KeyHandle);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
*Sequence = *((PULONG)ValueInfo->Data);
|
|
|
|
DPRINT("Loaded sequence %lx\n", *Sequence);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#undef VALUE_BUFFER_SIZE
|
|
|
|
|
|
static NTSTATUS
|
|
ExpSaveUuidSequence(PULONG Sequence)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING Name;
|
|
HANDLE KeyHandle;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(&Name,
|
|
L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
Status = ZwOpenKey(&KeyHandle,
|
|
KEY_SET_VALUE,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString(&Name, L"UuidSequenceNumber");
|
|
Status = ZwSetValueKey(KeyHandle,
|
|
&Name,
|
|
0,
|
|
REG_DWORD,
|
|
Sequence,
|
|
sizeof(ULONG));
|
|
ZwClose(KeyHandle);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
static VOID
|
|
ExpGetRandomUuidSequence(PULONG Sequence)
|
|
{
|
|
LARGE_INTEGER Counter;
|
|
LARGE_INTEGER Frequency;
|
|
ULONG Value;
|
|
|
|
Counter = KeQueryPerformanceCounter(&Frequency);
|
|
Value = Counter.u.LowPart ^ Counter.u.HighPart;
|
|
|
|
*Sequence = *Sequence ^ Value;
|
|
|
|
DPRINT("Sequence %lx\n", *Sequence);
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ExpCreateUuids(PULARGE_INTEGER Time,
|
|
PULONG Range,
|
|
PULONG Sequence)
|
|
{
|
|
/*
|
|
* Generate time element of the UUID. Account for going faster
|
|
* than our clock as well as the clock going backwards.
|
|
*/
|
|
while (1)
|
|
{
|
|
KeQuerySystemTime((PLARGE_INTEGER)Time);
|
|
Time->QuadPart += TICKS_15_OCT_1582_TO_1601;
|
|
|
|
if (Time->QuadPart > UuidLastTime.QuadPart)
|
|
{
|
|
UuidCount = 0;
|
|
break;
|
|
}
|
|
|
|
if (Time->QuadPart < UuidLastTime.QuadPart)
|
|
{
|
|
(*Sequence)++;
|
|
UuidSequenceChanged = TRUE;
|
|
UuidCount = 0;
|
|
break;
|
|
}
|
|
|
|
if (UuidCount < TICKS_PER_CLOCK_TICK)
|
|
{
|
|
UuidCount++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UuidLastTime.QuadPart = Time->QuadPart;
|
|
Time->QuadPart += UuidCount;
|
|
|
|
*Range = 10000; /* What does this mean? Ticks per millisecond?*/
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
INIT_FUNCTION
|
|
NTAPI
|
|
ExpInitLuid(VOID)
|
|
{
|
|
LUID DummyLuidValue = SYSTEM_LUID;
|
|
|
|
LuidValue.u.HighPart = DummyLuidValue.HighPart;
|
|
LuidValue.u.LowPart = DummyLuidValue.LowPart;
|
|
LuidIncrement.QuadPart = 1;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
|
|
{
|
|
LARGE_INTEGER NewLuid, PrevLuid;
|
|
|
|
/* atomically increment the luid */
|
|
do
|
|
{
|
|
PrevLuid = LuidValue;
|
|
NewLuid = RtlLargeIntegerAdd(PrevLuid,
|
|
LuidIncrement);
|
|
} while(ExInterlockedCompareExchange64(&LuidValue.QuadPart,
|
|
&NewLuid.QuadPart,
|
|
&PrevLuid.QuadPart,
|
|
NULL) != PrevLuid.QuadPart);
|
|
|
|
LocallyUniqueId->LowPart = NewLuid.u.LowPart;
|
|
LocallyUniqueId->HighPart = NewLuid.u.HighPart;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
|
|
{
|
|
LUID NewLuid;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Probe if user mode */
|
|
PreviousMode = ExGetPreviousMode();
|
|
if (PreviousMode != KernelMode)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForWrite(LocallyUniqueId,
|
|
sizeof(LUID),
|
|
sizeof(ULONG));
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Do the allocation */
|
|
ExAllocateLocallyUniqueId(&NewLuid);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
/* Write back LUID to caller */
|
|
_SEH2_TRY
|
|
{
|
|
*LocallyUniqueId = NewLuid;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
ExUuidCreate(OUT UUID *Uuid)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtAllocateUuids(OUT PULARGE_INTEGER Time,
|
|
OUT PULONG Range,
|
|
OUT PULONG Sequence,
|
|
OUT PUCHAR Seed)
|
|
{
|
|
ULARGE_INTEGER IntTime;
|
|
ULONG IntRange;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
ExAcquireFastMutex(&UuidMutex);
|
|
|
|
if (!UuidSequenceInitialized)
|
|
{
|
|
Status = ExpLoadUuidSequence(&UuidSequence);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
UuidSequence++;
|
|
}
|
|
else
|
|
{
|
|
ExpGetRandomUuidSequence(&UuidSequence);
|
|
}
|
|
|
|
UuidSequenceInitialized = TRUE;
|
|
UuidSequenceChanged = TRUE;
|
|
}
|
|
|
|
Status = ExpCreateUuids(&IntTime,
|
|
&IntRange,
|
|
&UuidSequence);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExReleaseFastMutex(&UuidMutex);
|
|
return Status;
|
|
}
|
|
|
|
if (UuidSequenceChanged)
|
|
{
|
|
Status = ExpSaveUuidSequence(&UuidSequence);
|
|
if (NT_SUCCESS(Status))
|
|
UuidSequenceChanged = FALSE;
|
|
}
|
|
|
|
ExReleaseFastMutex(&UuidMutex);
|
|
|
|
Time->QuadPart = IntTime.QuadPart;
|
|
*Range = IntRange;
|
|
*Sequence = UuidSequence;
|
|
|
|
RtlCopyMemory(Seed,
|
|
UuidSeed,
|
|
SEED_BUFFER_SIZE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSetUuidSeed(IN PUCHAR Seed)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RtlCopyMemory(UuidSeed,
|
|
Seed,
|
|
SEED_BUFFER_SIZE);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|