[CMAKE]
[reactos.git] / 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 <debug.h>
15
16 #define TAG_ATOM 'motA'
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;
94 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
95 LPWSTR CapturedName;
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 /* Re-use the given name if kernel mode or no atom name */
112 CapturedName = AtomName;
113
114 /* Check if we're called from user-mode*/
115 if (PreviousMode != KernelMode)
116 {
117 /* Enter SEH */
118 _SEH2_TRY
119 {
120 /* Check if we have a name */
121 if (AtomName)
122 {
123 /* Probe the atom */
124 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
125
126 /* Allocate an aligned buffer + the null char */
127 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
128 (sizeof(WCHAR) -1));
129 CapturedName = ExAllocatePoolWithTag(PagedPool,
130 CapturedSize,
131 TAG_ATOM);
132 if (!CapturedName)
133 {
134 /* Fail the call */
135 Status = STATUS_INSUFFICIENT_RESOURCES;
136 }
137 else
138 {
139 /* Copy the name and null-terminate it */
140 RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
141 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
142 }
143
144 /* Probe the atom too */
145 if (Atom) ProbeForWriteUshort(Atom);
146 }
147 }
148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
149 {
150 /* Return the exception code */
151 _SEH2_YIELD(return _SEH2_GetExceptionCode());
152 }
153 _SEH2_END;
154 }
155
156 /* Call the runtime function */
157 Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom);
158 if (NT_SUCCESS(Status) && (Atom))
159 {
160 /* Success and caller wants the atom back.. .enter SEH */
161 _SEH2_TRY
162 {
163 /* Return the atom */
164 *Atom = SafeAtom;
165 }
166 _SEH2_EXCEPT(ExSystemExceptionFilter())
167 {
168 /* Get the exception code */
169 Status = _SEH2_GetExceptionCode();
170 }
171 _SEH2_END;
172 }
173
174 /* If we captured anything, free it */
175 if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
176
177 /* Return to caller */
178 return Status;
179 }
180
181 /*++
182 * @name NtDeleteAtom
183 * @implemented
184 *
185 * Removes Atom from Global Atom Table. If Atom's reference counter
186 * is greater then 1, function decrements this counter, but Atom
187 * stayed in Global Atom Table.
188 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
189 *
190 * @param Atom
191 * Atom identifier
192 *
193 * @return STATUS_SUCCESS in case of success, proper error code
194 * othwerwise.
195 *
196 * @remarks None
197 *
198 *--*/
199 NTSTATUS
200 NTAPI
201 NtDeleteAtom(IN RTL_ATOM Atom)
202 {
203 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
204 PAGED_CODE();
205
206 /* Check for valid table */
207 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
208
209 /* Call worker function */
210 return RtlDeleteAtomFromAtomTable(AtomTable, Atom);
211 }
212
213 /*++
214 * @name NtFindAtom
215 * @implemented
216 *
217 * Retrieves existing Atom's identifier without incrementing Atom's
218 * internal counter
219 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
220 *
221 * @param AtomName
222 * Atom name in Unicode
223 *
224 * @param AtomNameLength
225 * Length of the atom name
226 *
227 * @param Atom
228 * Pointer to RTL_ATOM
229 *
230 * @return STATUS_SUCCESS in case of success, proper error code
231 * othwerwise.
232 *
233 * @remarks None
234 *
235 *--*/
236 NTSTATUS
237 NTAPI
238 NtFindAtom(IN PWSTR AtomName,
239 IN ULONG AtomNameLength,
240 OUT PRTL_ATOM Atom)
241 {
242 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
243 NTSTATUS Status;
244 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
245 LPWSTR CapturedName = NULL;
246 ULONG CapturedSize;
247 RTL_ATOM SafeAtom;
248 PAGED_CODE();
249
250 /* Check for the table */
251 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
252
253 /* Check for valid name */
254 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
255 {
256 /* Fail */
257 DPRINT1("Atom name too long\n");
258 return STATUS_INVALID_PARAMETER;
259 }
260
261 /* Re-use the given name if kernel mode or no atom name */
262 CapturedName = AtomName;
263
264 /* Check if we're called from user-mode*/
265 if (PreviousMode != KernelMode)
266 {
267 /* Enter SEH */
268 _SEH2_TRY
269 {
270 /* Check if we have a name */
271 if (AtomName)
272 {
273 /* Probe the atom */
274 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
275
276 /* Allocate an aligned buffer + the null char */
277 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
278 (sizeof(WCHAR) -1));
279 CapturedName = ExAllocatePoolWithTag(PagedPool,
280 CapturedSize,
281 TAG_ATOM);
282 if (!CapturedName)
283 {
284 /* Fail the call */
285 Status = STATUS_INSUFFICIENT_RESOURCES;
286 }
287 else
288 {
289 /* Copy the name and null-terminate it */
290 RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
291 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
292 }
293
294 /* Probe the atom too */
295 if (Atom) ProbeForWriteUshort(Atom);
296 }
297 }
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
299 {
300 /* Return the exception code */
301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
302 }
303 _SEH2_END;
304 }
305
306 /* Call the runtime function */
307 Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom);
308 if (NT_SUCCESS(Status) && (Atom))
309 {
310 /* Success and caller wants the atom back.. .enter SEH */
311 _SEH2_TRY
312 {
313 /* Return the atom */
314 *Atom = SafeAtom;
315 }
316 _SEH2_EXCEPT(ExSystemExceptionFilter())
317 {
318 Status = _SEH2_GetExceptionCode();
319 }
320 _SEH2_END;
321 }
322
323 /* If we captured anything, free it */
324 if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
325
326 /* Return to caller */
327 return Status;
328 }
329
330 /*++
331 * @name NtQueryInformationAtom
332 * @implemented
333 *
334 * Gets single Atom properties or reads Global Atom Table
335 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
336 *
337 * @param Atom
338 * Atom to query. If AtomInformationClass parameter is
339 * AtomTableInformation, Atom parameter is not used.
340 *
341 * @param AtomInformationClass
342 * See ATOM_INFORMATION_CLASS enumeration type for details
343 *
344 * @param AtomInformation
345 * Result of call - pointer to user's allocated buffer for data
346 *
347 * @param AtomInformationLength
348 * Size of AtomInformation buffer, in bytes
349 *
350 * @param ReturnLength
351 * Pointer to ULONG value containing required AtomInformation
352 * buffer size
353 *
354 * @return STATUS_SUCCESS in case of success, proper error code
355 * othwerwise.
356 *
357 * @remarks None
358 *
359 *--*/
360 NTSTATUS
361 NTAPI
362 NtQueryInformationAtom(RTL_ATOM Atom,
363 ATOM_INFORMATION_CLASS AtomInformationClass,
364 PVOID AtomInformation,
365 ULONG AtomInformationLength,
366 PULONG ReturnLength)
367 {
368 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
369 PATOM_BASIC_INFORMATION BasicInformation = AtomInformation;
370 PATOM_TABLE_INFORMATION TableInformation = AtomInformation;
371 NTSTATUS Status = STATUS_SUCCESS;
372 ULONG Flags, UsageCount, NameLength, RequiredLength = 0;
373 KPROCESSOR_MODE PreviousMode;
374
375 PAGED_CODE();
376
377 /* Check for valid table */
378 if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
379
380 PreviousMode = ExGetPreviousMode();
381
382 _SEH2_TRY
383 {
384 /* Probe the parameters */
385 if (PreviousMode != KernelMode)
386 {
387 ProbeForWrite(AtomInformation,
388 AtomInformationLength,
389 sizeof(ULONG));
390
391 if (ReturnLength != NULL)
392 {
393 ProbeForWriteUlong(ReturnLength);
394 }
395 }
396
397 /* Choose class */
398 switch (AtomInformationClass)
399 {
400 /* Caller requested info about an atom */
401 case AtomBasicInformation:
402
403 /* Size check */
404 RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name);
405 if (RequiredLength > AtomInformationLength)
406 {
407 /* Fail */
408 DPRINT1("Buffer too small\n");
409 Status = STATUS_INFO_LENGTH_MISMATCH;
410 _SEH2_LEAVE;
411 }
412
413 /* Prepare query */
414 UsageCount = 0;
415 NameLength = AtomInformationLength - RequiredLength;
416 BasicInformation->Name[0] = UNICODE_NULL;
417
418 /* Query the data */
419 Status = RtlQueryAtomInAtomTable(AtomTable,
420 Atom,
421 &UsageCount,
422 &Flags,
423 BasicInformation->Name,
424 &NameLength);
425 if (NT_SUCCESS(Status))
426 {
427 /* Return data */
428 BasicInformation->UsageCount = (USHORT)UsageCount;
429 BasicInformation->Flags = (USHORT)Flags;
430 BasicInformation->NameLength = (USHORT)NameLength;
431 RequiredLength += NameLength + sizeof(WCHAR);
432 }
433 break;
434
435 /* Caller requested info about an Atom Table */
436 case AtomTableInformation:
437
438 /* Size check */
439 RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms);
440 if (RequiredLength > AtomInformationLength)
441 {
442 /* Fail */
443 DPRINT1("Buffer too small\n");
444 Status = STATUS_INFO_LENGTH_MISMATCH;
445 _SEH2_LEAVE;
446 }
447
448 /* Query the data */
449 Status = RtlQueryAtomListInAtomTable(AtomTable,
450 (AtomInformationLength - RequiredLength) /
451 sizeof(RTL_ATOM),
452 &TableInformation->NumberOfAtoms,
453 TableInformation->Atoms);
454 if (NT_SUCCESS(Status))
455 {
456 /* Update the return length */
457 RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM);
458 }
459 break;
460
461 /* Caller was on crack */
462 default:
463
464 /* Unrecognized class */
465 Status = STATUS_INVALID_INFO_CLASS;
466 break;
467 }
468
469 /* Return the required size */
470 if (ReturnLength != NULL)
471 {
472 *ReturnLength = RequiredLength;
473 }
474 }
475 _SEH2_EXCEPT(ExSystemExceptionFilter())
476 {
477 Status = _SEH2_GetExceptionCode();
478 }
479 _SEH2_END;
480
481 /* Return to caller */
482 return Status;
483 }
484
485 /* EOF */