- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ex / atom.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/atom.c
5 * PURPOSE: Executive Atom Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 #define TAG_ATOM TAG('A', 't', 'o', 'm')
17
18 /* GLOBALS ****************************************************************/
19
20 /*
21 * FIXME: this is WRONG! The global atom table should live in the WinSta struct
22 * and accessed through a win32k callout (received in PsEstablishWin32Callouts)
23 * NOTE: There is a session/win32k global atom table also, but its private to
24 * win32k. Its used for RegisterWindowMessage() and for window classes.
25 * -Gunnar
26 */
27 PRTL_ATOM_TABLE GlobalAtomTable;
28
29 /* PRIVATE FUNCTIONS *********************************************************/
30
31 /*++
32 * @name ExpGetGlobalAtomTable
33 *
34 * Gets pointer to a global atom table, creates it if not already created
35 *
36 * @return Pointer to the RTL_ATOM_TABLE, or NULL if it's impossible
37 * to create atom table
38 *
39 * @remarks Internal function
40 *
41 *--*/
42 PRTL_ATOM_TABLE
43 NTAPI
44 ExpGetGlobalAtomTable(VOID)
45 {
46 NTSTATUS Status;
47
48 /* Return it if we have one */
49 if (GlobalAtomTable) return GlobalAtomTable;
50
51 /* Create it */
52 Status = RtlCreateAtomTable(37, &GlobalAtomTable);
53
54 /* If we couldn't create it, return NULL */
55 if (!NT_SUCCESS(Status)) return NULL;
56
57 /* Return the newly created one */
58 return GlobalAtomTable;
59 }
60
61 /* FUNCTIONS ****************************************************************/
62
63 /*++
64 * @name NtAddAtom
65 * @implemented
66 *
67 * Function NtAddAtom creates new Atom in Global Atom Table. If Atom
68 * with the same name already exist, internal Atom counter is incremented.
69 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtAddAtom.html
70 *
71 * @param AtomName
72 * Atom name in Unicode
73 *
74 * @param AtomNameLength
75 * Length of the atom name
76 *
77 * @param Atom
78 * Pointer to RTL_ATOM
79 *
80 * @return STATUS_SUCCESS in case of success, proper error code
81 * othwerwise.
82 *
83 * @remarks None
84 *
85 *--*/
86 NTSTATUS
87 NTAPI
88 NtAddAtom(IN PWSTR AtomName,
89 IN ULONG AtomNameLength,
90 OUT PRTL_ATOM Atom)
91 {
92 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
93 NTSTATUS Status = STATUS_SUCCESS;
94 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
95 LPWSTR CapturedName = NULL;
96 ULONG CapturedSize;
97 RTL_ATOM SafeAtom;
98 PAGED_CODE();
99
100 /* Check for the table */
101 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
102
103 /* Check for valid name */
104 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
105 {
106 /* Fail */
107 DPRINT1("Atom name too long\n");
108 return STATUS_INVALID_PARAMETER;
109 }
110
111 /* Check if we're called from user-mode*/
112 if (PreviousMode != KernelMode)
113 {
114 /* Enter SEH */
115 _SEH_TRY
116 {
117 /* Check if we have a name */
118 if (AtomName)
119 {
120 /* Probe the atom */
121 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
122
123 /* Allocate an aligned buffer + the null char */
124 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
125 (sizeof(WCHAR) -1));
126 CapturedName = ExAllocatePoolWithTag(PagedPool,
127 CapturedSize,
128 TAG_ATOM);
129 if (!CapturedName)
130 {
131 /* Fail the call */
132 Status = STATUS_INSUFFICIENT_RESOURCES;
133 }
134 else
135 {
136 /* Copy the name and null-terminate it */
137 RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
138 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
139 }
140
141 /* Probe the atom too */
142 if (Atom) ProbeForWriteUshort(Atom);
143 }
144 }
145 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
146 {
147 Status = _SEH_GetExceptionCode();
148 }
149 _SEH_END;
150 }
151 else
152 {
153 /* Simplify code and re-use one variable */
154 if (AtomName) CapturedName = AtomName;
155 }
156
157 /* Make sure probe worked */
158 if (NT_SUCCESS(Status))
159 {
160 /* Call the runtime function */
161 Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom);
162 if (NT_SUCCESS(Status) && (Atom))
163 {
164 /* Success and caller wants the atom back.. .enter SEH */
165 _SEH_TRY
166 {
167 /* Return the atom */
168 *Atom = SafeAtom;
169 }
170 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
171 {
172 Status = _SEH_GetExceptionCode();
173 }
174 _SEH_END;
175 }
176 }
177
178 /* If we captured anything, free it */
179 if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
180
181 /* Return to caller */
182 return Status;
183 }
184
185 /*++
186 * @name NtDeleteAtom
187 * @implemented
188 *
189 * Removes Atom from Global Atom Table. If Atom's reference counter
190 * is greater then 1, function decrements this counter, but Atom
191 * stayed in Global Atom Table.
192 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
193 *
194 * @param Atom
195 * Atom identifier
196 *
197 * @return STATUS_SUCCESS in case of success, proper error code
198 * othwerwise.
199 *
200 * @remarks None
201 *
202 *--*/
203 NTSTATUS
204 NTAPI
205 NtDeleteAtom(IN RTL_ATOM Atom)
206 {
207 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
208 PAGED_CODE();
209
210 /* Check for valid table */
211 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
212
213 /* Call worker function */
214 return RtlDeleteAtomFromAtomTable(AtomTable, Atom);
215 }
216
217 /*++
218 * @name NtFindAtom
219 * @implemented
220 *
221 * Retrieves existing Atom's identifier without incrementing Atom's
222 * internal counter
223 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
224 *
225 * @param AtomName
226 * Atom name in Unicode
227 *
228 * @param AtomNameLength
229 * Length of the atom name
230 *
231 * @param Atom
232 * Pointer to RTL_ATOM
233 *
234 * @return STATUS_SUCCESS in case of success, proper error code
235 * othwerwise.
236 *
237 * @remarks None
238 *
239 *--*/
240 NTSTATUS
241 NTAPI
242 NtFindAtom(IN PWSTR AtomName,
243 IN ULONG AtomNameLength,
244 OUT PRTL_ATOM Atom)
245 {
246 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
247 NTSTATUS Status = STATUS_SUCCESS;
248 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
249 LPWSTR CapturedName = NULL;
250 ULONG CapturedSize;
251 RTL_ATOM SafeAtom;
252 PAGED_CODE();
253
254 /* Check for the table */
255 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
256
257 /* Check for valid name */
258 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
259 {
260 /* Fail */
261 DPRINT1("Atom name too long\n");
262 return STATUS_INVALID_PARAMETER;
263 }
264
265 /* Check if we're called from user-mode*/
266 if (PreviousMode != KernelMode)
267 {
268 /* Enter SEH */
269 _SEH_TRY
270 {
271 /* Check if we have a name */
272 if (AtomName)
273 {
274 /* Probe the atom */
275 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
276
277 /* Allocate an aligned buffer + the null char */
278 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
279 (sizeof(WCHAR) -1));
280 CapturedName = ExAllocatePoolWithTag(PagedPool,
281 CapturedSize,
282 TAG_ATOM);
283 if (!CapturedName)
284 {
285 /* Fail the call */
286 Status = STATUS_INSUFFICIENT_RESOURCES;
287 }
288 else
289 {
290 /* Copy the name and null-terminate it */
291 RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
292 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
293 }
294
295 /* Probe the atom too */
296 if (Atom) ProbeForWriteUshort(Atom);
297 }
298 }
299 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
300 {
301 Status = _SEH_GetExceptionCode();
302 }
303 _SEH_END;
304 }
305 else
306 {
307 /* Simplify code and re-use one variable */
308 if (AtomName) CapturedName = AtomName;
309 }
310
311 /* Make sure probe worked */
312 if (NT_SUCCESS(Status))
313 {
314 /* Call the runtime function */
315 Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom);
316 if (NT_SUCCESS(Status) && (Atom))
317 {
318 /* Success and caller wants the atom back.. .enter SEH */
319 _SEH_TRY
320 {
321 /* Return the atom */
322 *Atom = SafeAtom;
323 }
324 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
325 {
326 Status = _SEH_GetExceptionCode();
327 }
328 _SEH_END;
329 }
330 }
331
332 /* If we captured anything, free it */
333 if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
334
335 /* Return to caller */
336 return Status;
337 }
338
339 /*++
340 * @name NtQueryInformationAtom
341 * @implemented
342 *
343 * Gets single Atom properties or reads Global Atom Table
344 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
345 *
346 * @param Atom
347 * Atom to query. If AtomInformationClass parameter is
348 * AtomTableInformation, Atom parameter is not used.
349 *
350 * @param AtomInformationClass
351 * See ATOM_INFORMATION_CLASS enumeration type for details
352 *
353 * @param AtomInformation
354 * Result of call - pointer to user's allocated buffer for data
355 *
356 * @param AtomInformationLength
357 * Size of AtomInformation buffer, in bytes
358 *
359 * @param ReturnLength
360 * Pointer to ULONG value containing required AtomInformation
361 * buffer size
362 *
363 * @return STATUS_SUCCESS in case of success, proper error code
364 * othwerwise.
365 *
366 * @remarks None
367 *
368 *--*/
369 NTSTATUS
370 NTAPI
371 NtQueryInformationAtom(RTL_ATOM Atom,
372 ATOM_INFORMATION_CLASS AtomInformationClass,
373 PVOID AtomInformation,
374 ULONG AtomInformationLength,
375 PULONG ReturnLength)
376 {
377 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
378 PATOM_BASIC_INFORMATION BasicInformation = AtomInformation;
379 PATOM_TABLE_INFORMATION TableInformation = AtomInformation;
380 NTSTATUS Status = STATUS_SUCCESS;
381 ULONG Flags, UsageCount, NameLength, RequiredLength = 0;
382 KPROCESSOR_MODE PreviousMode;
383
384 PAGED_CODE();
385
386 /* Check for valid table */
387 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
388
389 PreviousMode = ExGetPreviousMode();
390
391 _SEH_TRY
392 {
393 /* Probe the parameters */
394 if (PreviousMode != KernelMode)
395 {
396 ProbeForWrite(AtomInformation,
397 AtomInformationLength,
398 sizeof(ULONG));
399
400 if (ReturnLength != NULL)
401 {
402 ProbeForWriteUlong(ReturnLength);
403 }
404 }
405
406 /* Choose class */
407 switch (AtomInformationClass)
408 {
409 /* Caller requested info about an atom */
410 case AtomBasicInformation:
411
412 /* Size check */
413 RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name);
414 if (RequiredLength > AtomInformationLength)
415 {
416 /* Fail */
417 DPRINT1("Buffer too small\n");
418 Status = STATUS_INFO_LENGTH_MISMATCH;
419 _SEH_LEAVE;
420 }
421
422 /* Prepare query */
423 UsageCount = 0;
424 NameLength = AtomInformationLength - RequiredLength;
425 BasicInformation->Name[0] = UNICODE_NULL;
426
427 /* Query the data */
428 Status = RtlQueryAtomInAtomTable(AtomTable,
429 Atom,
430 &UsageCount,
431 &Flags,
432 BasicInformation->Name,
433 &NameLength);
434 if (NT_SUCCESS(Status))
435 {
436 /* Return data */
437 BasicInformation->UsageCount = (USHORT)UsageCount;
438 BasicInformation->Flags = (USHORT)Flags;
439 BasicInformation->NameLength = (USHORT)NameLength;
440 RequiredLength += NameLength + sizeof(WCHAR);
441 }
442 break;
443
444 /* Caller requested info about an Atom Table */
445 case AtomTableInformation:
446
447 /* Size check */
448 RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms);
449 if (RequiredLength > AtomInformationLength)
450 {
451 /* Fail */
452 DPRINT1("Buffer too small\n");
453 Status = STATUS_INFO_LENGTH_MISMATCH;
454 _SEH_LEAVE;
455 }
456
457 /* Query the data */
458 Status = RtlQueryAtomListInAtomTable(AtomTable,
459 (AtomInformationLength - RequiredLength) /
460 sizeof(RTL_ATOM),
461 &TableInformation->NumberOfAtoms,
462 TableInformation->Atoms);
463 if (NT_SUCCESS(Status))
464 {
465 /* Update the return length */
466 RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM);
467 }
468 break;
469
470 /* Caller was on crack */
471 default:
472
473 /* Unrecognized class */
474 Status = STATUS_INVALID_INFO_CLASS;
475 break;
476 }
477
478 /* Return the required size */
479 if (ReturnLength != NULL)
480 {
481 *ReturnLength = RequiredLength;
482 }
483 }
484 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
485 {
486 Status = _SEH_GetExceptionCode();
487 }
488 _SEH_END;
489
490 /* Return to caller */
491 return Status;
492 }
493
494 /* EOF */