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