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