3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
6 * PURPOSE: Atom managment
12 /* INCLUDES *****************************************************************/
19 /* PROTOTYPES ****************************************************************/
21 extern NTSTATUS
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
22 extern VOID
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
23 extern BOOLEAN
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
);
24 extern VOID
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
);
26 extern BOOLEAN
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
27 extern VOID
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
29 extern PRTL_ATOM_TABLE
RtlpAllocAtomTable(ULONG Size
);
30 extern VOID
RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
);
31 extern PRTL_ATOM_TABLE_ENTRY
RtlpAllocAtomTableEntry(ULONG Size
);
32 extern VOID
RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
);
34 extern BOOLEAN
RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
35 extern VOID
RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
);
36 extern PRTL_ATOM_TABLE_ENTRY
RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
);
38 /* FUNCTIONS *****************************************************************/
40 static PRTL_ATOM_TABLE_ENTRY
41 RtlpHashAtomName(IN PRTL_ATOM_TABLE AtomTable
,
43 OUT PRTL_ATOM_TABLE_ENTRY
**HashLink
)
48 RtlInitUnicodeString(&Name
,
51 if (Name
.Length
!= 0 &&
52 NT_SUCCESS(RtlHashUnicodeString(&Name
,
54 HASH_STRING_ALGORITHM_X65599
,
57 PRTL_ATOM_TABLE_ENTRY Current
;
58 PRTL_ATOM_TABLE_ENTRY
*Link
;
60 Link
= &AtomTable
->Buckets
[Hash
% AtomTable
->NumberOfBuckets
];
62 /* search for an existing entry */
64 while (Current
!= NULL
)
66 if (Current
->NameLength
== Name
.Length
/ sizeof(WCHAR
) &&
67 !_wcsicmp(Current
->Name
, Name
.Buffer
))
72 Link
= &Current
->HashLink
;
73 Current
= Current
->HashLink
;
76 /* no matching atom found, return the hash link */
86 RtlpCheckIntegerAtom(PWSTR AtomName
,
89 UNICODE_STRING AtomString
;
94 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
97 if (!((ULONG
)AtomName
& 0xFFFF0000))
99 LoValue
= (USHORT
)((ULONG
)AtomName
& 0xFFFF);
101 if (LoValue
>= 0xC000)
107 if (AtomValue
!= NULL
)
108 *AtomValue
= LoValue
;
113 if (*AtomName
!= L
'#')
120 if ((*p
< L
'0') || (*p
> L
'9'))
127 RtlInitUnicodeString(&AtomString
,
130 DPRINT("AtomString: %wZ\n", &AtomString
);
132 RtlUnicodeStringToInteger(&AtomString
,10, &LongValue
);
134 DPRINT("LongValue: %lu\n", LongValue
);
136 *AtomValue
= (USHORT
)(LongValue
& 0x0000FFFF);
146 RtlCreateAtomTable(IN ULONG TableSize
,
147 IN OUT PRTL_ATOM_TABLE
*AtomTable
)
149 PRTL_ATOM_TABLE Table
;
152 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
153 TableSize
, AtomTable
);
155 if (*AtomTable
!= NULL
)
157 return STATUS_SUCCESS
;
160 /* allocate atom table */
161 Table
= RtlpAllocAtomTable(((TableSize
- 1) * sizeof(PRTL_ATOM_TABLE_ENTRY
)) +
162 sizeof(RTL_ATOM_TABLE
));
165 return STATUS_NO_MEMORY
;
168 /* initialize atom table */
169 Table
->NumberOfBuckets
= TableSize
;
171 Status
= RtlpInitAtomTableLock(Table
);
172 if (!NT_SUCCESS(Status
))
174 RtlpFreeAtomTable(Table
);
178 if (!RtlpCreateAtomHandleTable(Table
))
180 RtlpDestroyAtomTableLock(Table
);
181 RtlpFreeAtomTable(Table
);
182 return STATUS_NO_MEMORY
;
186 return STATUS_SUCCESS
;
194 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable
)
196 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
197 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
;
199 DPRINT("RtlDestroyAtomTable (AtomTable %p)\n", AtomTable
);
201 if (!RtlpLockAtomTable(AtomTable
))
203 return (STATUS_INVALID_PARAMETER
);
206 /* delete all atoms */
207 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
208 for (CurrentBucket
= AtomTable
->Buckets
;
209 CurrentBucket
!= LastBucket
;
212 NextEntry
= *CurrentBucket
;
213 *CurrentBucket
= NULL
;
215 while (NextEntry
!= NULL
)
217 CurrentEntry
= NextEntry
;
218 NextEntry
= NextEntry
->HashLink
;
220 /* no need to delete the atom handle, the handles will all be freed
221 up when destroying the atom handle table! */
223 RtlpFreeAtomTableEntry(CurrentEntry
);
227 RtlpDestroyAtomHandleTable(AtomTable
);
229 RtlpUnlockAtomTable(AtomTable
);
231 RtlpDestroyAtomTableLock(AtomTable
);
233 RtlpFreeAtomTable(AtomTable
);
235 return STATUS_SUCCESS
;
243 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable
,
244 BOOLEAN DeletePinned
)
246 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
247 PRTL_ATOM_TABLE_ENTRY CurrentEntry
, NextEntry
;
249 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
250 AtomTable
, DeletePinned
);
252 if (RtlpLockAtomTable(AtomTable
) == FALSE
)
254 return (STATUS_INVALID_PARAMETER
);
257 /* delete all atoms */
258 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
259 for (CurrentBucket
= AtomTable
->Buckets
;
260 CurrentBucket
!= LastBucket
;
263 NextEntry
= *CurrentBucket
;
264 *CurrentBucket
= NULL
;
266 while (NextEntry
!= NULL
)
268 CurrentEntry
= NextEntry
;
269 NextEntry
= NextEntry
->HashLink
;
271 RtlpFreeAtomHandle(AtomTable
,
274 RtlpFreeAtomTableEntry(CurrentEntry
);
278 RtlpUnlockAtomTable(AtomTable
);
280 return STATUS_SUCCESS
;
288 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
293 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
294 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
295 NTSTATUS Status
= STATUS_SUCCESS
;
297 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
298 AtomTable
, AtomName
, Atom
);
300 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
303 if (AtomValue
>= 0xC000)
305 Status
= STATUS_INVALID_PARAMETER
;
307 else if (Atom
!= NULL
)
309 *Atom
= (RTL_ATOM
)AtomValue
;
315 RtlpLockAtomTable(AtomTable
);
317 /* string atom, hash it and try to find an existing atom with the same name */
318 Entry
= RtlpHashAtomName(AtomTable
,
324 /* found another atom, increment the reference counter unless it's pinned */
326 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
328 if (++Entry
->ReferenceCount
== 0)
330 /* FIXME - references overflowed, pin the atom? */
331 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
337 *Atom
= (RTL_ATOM
)Entry
->Atom
;
342 /* couldn't find an existing atom, HashLink now points to either the
343 HashLink pointer of the previous atom or to the bucket so we can
344 simply add it to the list */
345 if (HashLink
!= NULL
)
347 ULONG AtomNameLen
= wcslen(AtomName
);
349 Entry
= RtlpAllocAtomTableEntry(sizeof(RTL_ATOM_TABLE_ENTRY
) -
350 sizeof(Entry
->Name
) +
351 (AtomNameLen
+ 1) * sizeof(WCHAR
));
354 Entry
->HashLink
= NULL
;
355 Entry
->ReferenceCount
= 1;
358 Entry
->NameLength
= AtomNameLen
;
359 RtlCopyMemory(Entry
->Name
,
361 (AtomNameLen
+ 1) * sizeof(WCHAR
));
363 if (RtlpCreateAtomHandle(AtomTable
,
366 /* append the atom to the list */
371 *Atom
= (RTL_ATOM
)Entry
->Atom
;
376 RtlpFreeAtomTableEntry(Entry
);
377 Status
= STATUS_NO_MEMORY
;
382 Status
= STATUS_NO_MEMORY
;
387 /* The caller supplied an empty atom name! */
388 Status
= STATUS_INVALID_PARAMETER
;
392 RtlpUnlockAtomTable(AtomTable
);
402 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
405 PRTL_ATOM_TABLE_ENTRY Entry
;
406 NTSTATUS Status
= STATUS_SUCCESS
;
408 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
413 RtlpLockAtomTable(AtomTable
);
415 Entry
= RtlpGetAtomEntry(AtomTable
,
416 (ULONG
)((USHORT
)Atom
- 0xC000));
418 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
420 if (!(Entry
->Flags
& RTL_ATOM_IS_PINNED
))
422 if (--Entry
->ReferenceCount
== 0)
424 PRTL_ATOM_TABLE_ENTRY
*HashLink
;
426 /* it's time to delete the atom. we need to unlink it from
427 the list. The easiest way is to take the atom name and
428 hash it again, this way we get the pointer to either
429 the hash bucket or the previous atom that links to the
430 one we want to delete. This way we can easily bypass
432 if (RtlpHashAtomName(AtomTable
,
436 /* bypass this atom */
437 *HashLink
= Entry
->HashLink
;
439 RtlpFreeAtomHandle(AtomTable
,
442 RtlpFreeAtomTableEntry(Entry
);
446 /* WTF?! This should never happen!!! */
453 /* tried to delete a pinned atom, do nothing and return
454 STATUS_WAS_LOCKED, which is NOT a failure code! */
455 Status
= STATUS_WAS_LOCKED
;
460 Status
= STATUS_INVALID_HANDLE
;
463 RtlpUnlockAtomTable(AtomTable
);
474 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
478 PRTL_ATOM_TABLE_ENTRY Entry
, *HashLink
;
480 RTL_ATOM FoundAtom
= 0;
481 NTSTATUS Status
= STATUS_SUCCESS
;
483 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
484 AtomTable
, AtomName
, Atom
);
486 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
489 if (AtomValue
>= 0xC000)
491 Status
= STATUS_INVALID_PARAMETER
;
493 else if (Atom
!= NULL
)
495 *Atom
= (RTL_ATOM
)AtomValue
;
501 RtlpLockAtomTable(AtomTable
);
503 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
506 Entry
= RtlpHashAtomName(AtomTable
,
512 Status
= STATUS_SUCCESS
;
513 FoundAtom
= (RTL_ATOM
)Entry
->Atom
;
516 RtlpUnlockAtomTable(AtomTable
);
518 if (NT_SUCCESS(Status
) && Atom
!= NULL
)
531 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
534 NTSTATUS Status
= STATUS_SUCCESS
;
536 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
541 PRTL_ATOM_TABLE_ENTRY Entry
;
543 RtlpLockAtomTable(AtomTable
);
545 Entry
= RtlpGetAtomEntry(AtomTable
,
546 (ULONG
)((USHORT
)Atom
- 0xC000));
548 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
550 Entry
->Flags
|= RTL_ATOM_IS_PINNED
;
554 Status
= STATUS_INVALID_HANDLE
;
557 RtlpUnlockAtomTable(AtomTable
);
568 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable
,
576 PRTL_ATOM_TABLE_ENTRY Entry
;
577 NTSTATUS Status
= STATUS_SUCCESS
;
581 if (RefCount
!= NULL
)
586 if (PinCount
!= NULL
)
591 if ((AtomName
!= NULL
) && (NameLength
!= NULL
) && (NameLength
> 0))
593 WCHAR NameString
[12];
595 Length
= swprintf(NameString
, L
"#%lu", (ULONG
)Atom
) * sizeof(WCHAR
);
597 if (*NameLength
< Length
+ sizeof(WCHAR
))
599 /* prevent underflow! */
600 if (*NameLength
>= sizeof(WCHAR
))
602 Length
= *NameLength
- sizeof(WCHAR
);
607 Status
= STATUS_BUFFER_TOO_SMALL
;
613 RtlCopyMemory(AtomName
,
616 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
617 *NameLength
= Length
;
624 RtlpLockAtomTable(AtomTable
);
626 Entry
= RtlpGetAtomEntry(AtomTable
,
627 (ULONG
)((USHORT
)Atom
- 0xC000));
629 if (Entry
!= NULL
&& Entry
->Atom
== (USHORT
)Atom
)
631 DPRINT("Atom name: %wZ\n", &Entry
->Name
);
633 if (RefCount
!= NULL
)
635 *RefCount
= Entry
->ReferenceCount
;
638 if (PinCount
!= NULL
)
640 *PinCount
= ((Entry
->Flags
& RTL_ATOM_IS_PINNED
) != 0);
643 if ((AtomName
!= NULL
) && (NameLength
!= NULL
))
645 Length
= Entry
->NameLength
* sizeof(WCHAR
);
647 if (*NameLength
< Length
+ sizeof(WCHAR
))
649 /* prevent underflow! */
650 if (*NameLength
>= sizeof(WCHAR
))
652 Length
= *NameLength
- sizeof(WCHAR
);
657 Status
= STATUS_BUFFER_TOO_SMALL
;
663 RtlCopyMemory(AtomName
,
666 AtomName
[Length
/ sizeof(WCHAR
)] = L
'\0';
667 *NameLength
= Length
;
673 Status
= STATUS_INVALID_HANDLE
;
676 RtlpUnlockAtomTable(AtomTable
);
683 * @private - only used by NtQueryInformationAtom
686 RtlQueryAtomListInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
687 IN ULONG MaxAtomCount
,
688 OUT ULONG
*AtomCount
,
689 OUT RTL_ATOM
*AtomList
)
691 PRTL_ATOM_TABLE_ENTRY
*CurrentBucket
, *LastBucket
;
692 PRTL_ATOM_TABLE_ENTRY CurrentEntry
;
694 NTSTATUS Status
= STATUS_SUCCESS
;
696 RtlpLockAtomTable(AtomTable
);
698 LastBucket
= AtomTable
->Buckets
+ AtomTable
->NumberOfBuckets
;
699 for (CurrentBucket
= AtomTable
->Buckets
;
700 CurrentBucket
!= LastBucket
;
703 CurrentEntry
= *CurrentBucket
;
705 while (CurrentEntry
!= NULL
)
707 if (MaxAtomCount
> 0)
709 *(AtomList
++) = (RTL_ATOM
)CurrentEntry
->Atom
;
714 /* buffer too small, but don't bail. we need to determine the
715 total number of atoms in the table! */
716 Status
= STATUS_INFO_LENGTH_MISMATCH
;
720 CurrentEntry
= CurrentEntry
->HashLink
;
726 RtlpUnlockAtomTable(AtomTable
);