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