migrate substitution keywords to SVN
[reactos.git] / reactos / ntoskrnl / ex / uuid.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: UUID generator
6 * FILE: kernel/ex/uuid.c
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 #define SEED_BUFFER_SIZE 6
16
17 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock
18 resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
19 #define TICKS_PER_CLOCK_TICK 1000
20 #define SECSPERDAY 86400
21 #define TICKSPERSEC 10000000
22
23 /* UUID system time starts at October 15, 1582 */
24 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
25 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
26
27
28 /* GLOBALS ****************************************************************/
29
30 static FAST_MUTEX UuidMutex;
31 static LARGE_INTEGER UuidLastTime;
32 static ULONG UuidSequence;
33 static BOOLEAN UuidSequenceInitialized = FALSE;
34 static BOOLEAN UuidSequenceChanged = FALSE;
35 static UCHAR UuidSeed[SEED_BUFFER_SIZE];
36 static ULONG UuidCount;
37
38
39
40 /* FUNCTIONS ****************************************************************/
41
42 VOID INIT_FUNCTION
43 ExpInitUuids(VOID)
44 {
45 ExInitializeFastMutex(&UuidMutex);
46
47 KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime);
48 UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601;
49
50 UuidCount = TICKS_PER_CLOCK_TICK;
51 RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE);
52 }
53
54
55 #define VALUE_BUFFER_SIZE 256
56
57 static NTSTATUS
58 ExpLoadUuidSequence(PULONG Sequence)
59 {
60 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
61 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
62 OBJECT_ATTRIBUTES ObjectAttributes;
63 UNICODE_STRING Name;
64 HANDLE KeyHandle;
65 ULONG ValueLength;
66 NTSTATUS Status;
67
68 RtlInitUnicodeString(&Name,
69 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
70 InitializeObjectAttributes(&ObjectAttributes,
71 &Name,
72 OBJ_CASE_INSENSITIVE,
73 NULL,
74 NULL);
75 Status = NtOpenKey(&KeyHandle,
76 KEY_QUERY_VALUE,
77 &ObjectAttributes);
78 if (!NT_SUCCESS(Status))
79 {
80 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
81 return Status;
82 }
83
84 RtlInitUnicodeString(&Name,
85 L"UuidSequenceNumber");
86
87 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
88 Status = NtQueryValueKey(KeyHandle,
89 &Name,
90 KeyValuePartialInformation,
91 ValueBuffer,
92 VALUE_BUFFER_SIZE,
93 &ValueLength);
94 NtClose(KeyHandle);
95 if (!NT_SUCCESS(Status))
96 {
97 DPRINT("NtQueryValueKey() failed (Status %lx)\n", Status);
98 return Status;
99 }
100
101 *Sequence = *((PULONG)ValueInfo->Data);
102
103 DPRINT("Loaded sequence %lx\n", *Sequence);
104
105 return STATUS_SUCCESS;
106 }
107 #undef VALUE_BUFFER_SIZE
108
109
110 static NTSTATUS
111 ExpSaveUuidSequence(PULONG Sequence)
112 {
113 OBJECT_ATTRIBUTES ObjectAttributes;
114 UNICODE_STRING Name;
115 HANDLE KeyHandle;
116 NTSTATUS Status;
117
118 RtlInitUnicodeString(&Name,
119 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
120 InitializeObjectAttributes(&ObjectAttributes,
121 &Name,
122 OBJ_CASE_INSENSITIVE,
123 NULL,
124 NULL);
125 Status = NtOpenKey(&KeyHandle,
126 KEY_SET_VALUE,
127 &ObjectAttributes);
128 if (!NT_SUCCESS(Status))
129 {
130 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
131 return Status;
132 }
133
134 RtlInitUnicodeString(&Name,
135 L"UuidSequenceNumber");
136 Status = NtSetValueKey(KeyHandle,
137 &Name,
138 0,
139 REG_DWORD,
140 Sequence,
141 sizeof(ULONG));
142 NtClose(KeyHandle);
143 if (!NT_SUCCESS(Status))
144 {
145 DPRINT("NtSetValueKey() failed (Status %lx)\n", Status);
146 }
147
148 return Status;
149 }
150
151
152 static VOID
153 ExpGetRandomUuidSequence(PULONG Sequence)
154 {
155 LARGE_INTEGER Counter;
156 LARGE_INTEGER Frequency;
157 ULONG Value;
158
159 Counter = KeQueryPerformanceCounter(&Frequency);
160 Value = Counter.u.LowPart ^ Counter.u.HighPart;
161
162 *Sequence = *Sequence ^ Value;
163
164 DPRINT("Sequence %lx\n", *Sequence);
165 }
166
167
168 static NTSTATUS
169 ExpCreateUuids(PULARGE_INTEGER Time,
170 PULONG Range,
171 PULONG Sequence)
172 {
173 /*
174 * Generate time element of the UUID. Account for going faster
175 * than our clock as well as the clock going backwards.
176 */
177 while (1)
178 {
179 KeQuerySystemTime((PLARGE_INTEGER)Time);
180 Time->QuadPart += TICKS_15_OCT_1582_TO_1601;
181
182 if (Time->QuadPart > UuidLastTime.QuadPart)
183 {
184 UuidCount = 0;
185 break;
186 }
187
188 if (Time->QuadPart < UuidLastTime.QuadPart)
189 {
190 (*Sequence)++;
191 UuidSequenceChanged = TRUE;
192 UuidCount = 0;
193 break;
194 }
195
196 if (UuidCount < TICKS_PER_CLOCK_TICK)
197 {
198 UuidCount++;
199 break;
200 }
201 }
202
203 UuidLastTime.QuadPart = Time->QuadPart;
204 Time->QuadPart += UuidCount;
205
206 *Range = 10000; /* What does this mean? Ticks per millisecond?*/
207
208 return STATUS_SUCCESS;
209 }
210
211
212 /*
213 * @unimplemented
214 */
215 NTSTATUS STDCALL
216 NtAllocateUuids(OUT PULARGE_INTEGER Time,
217 OUT PULONG Range,
218 OUT PULONG Sequence,
219 OUT PUCHAR Seed)
220 {
221 ULARGE_INTEGER IntTime;
222 ULONG IntRange;
223 NTSTATUS Status;
224
225 ExAcquireFastMutex(&UuidMutex);
226
227 if (!UuidSequenceInitialized)
228 {
229 Status = ExpLoadUuidSequence(&UuidSequence);
230 if (NT_SUCCESS(Status))
231 {
232 UuidSequence++;
233 }
234 else
235 {
236 ExpGetRandomUuidSequence(&UuidSequence);
237 }
238
239 UuidSequenceInitialized = TRUE;
240 UuidSequenceChanged = TRUE;
241 }
242
243 Status = ExpCreateUuids(&IntTime,
244 &IntRange,
245 &UuidSequence);
246 if (!NT_SUCCESS(Status))
247 {
248 ExReleaseFastMutex(&UuidMutex);
249 return Status;
250 }
251
252 if (UuidSequenceChanged)
253 {
254 Status = ExpSaveUuidSequence(&UuidSequence);
255 if (NT_SUCCESS(Status))
256 UuidSequenceChanged = FALSE;
257 }
258
259 ExReleaseFastMutex(&UuidMutex);
260
261 Time->QuadPart = IntTime.QuadPart;
262 *Range = IntRange;
263 *Sequence = UuidSequence;
264
265 RtlCopyMemory(Seed,
266 UuidSeed,
267 SEED_BUFFER_SIZE);
268
269 return STATUS_SUCCESS;
270 }
271
272
273 /*
274 * @implemented
275 */
276 NTSTATUS STDCALL
277 NtSetUuidSeed(IN PUCHAR Seed)
278 {
279 RtlCopyMemory(UuidSeed,
280 Seed,
281 SEED_BUFFER_SIZE);
282 return STATUS_SUCCESS;
283 }
284
285 /* EOF */