c184900161718449380dcf211e174353924d70c7
[reactos.git] / ntoskrnl / rtl / atom.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/nt/atom.c
6  * PURPOSE:         Atom managment
7  * PROGRAMMER:      Nobody
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/handle.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21
22
23 typedef struct _RTL_ATOM_ENTRY
24 {
25    LIST_ENTRY List;
26    UNICODE_STRING Name;
27    ULONG RefCount;
28    BOOLEAN Locked;
29    ULONG Index;
30 } RTL_ATOM_ENTRY, *PRTL_ATOM_ENTRY;
31
32
33 /* PROTOTYPES ****************************************************************/
34
35 static PRTL_ATOM_TABLE RtlpGetGlobalAtomTable(VOID);
36
37 static ULONG RtlpHashAtomName(ULONG TableSize, PWSTR AtomName);
38 static BOOLEAN RtlpCheckIntegerAtom(PWSTR AtomName, PUSHORT AtomValue);
39
40 static NTSTATUS RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable);
41 static VOID RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable);
42 static BOOLEAN RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable);
43 static VOID RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable);
44
45 static BOOLEAN RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
46 static VOID RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
47
48 static NTSTATUS RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
49                                          RTL_ATOM Atom,
50                                          PATOM_BASIC_INFORMATION AtomInformation,
51                                          ULONG AtomInformationLength,
52                                          PULONG ReturnLength);
53
54 static NTSTATUS RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
55                                               RTL_ATOM Atom,
56                                               PATOM_TABLE_INFORMATION AtomInformation,
57                                               ULONG AtomInformationLength,
58                                               PULONG ReturnLength);
59
60
61 /* GLOBALS *******************************************************************/
62
63 static PRTL_ATOM_TABLE GlobalAtomTable = NULL;
64
65 /* FUNCTIONS *****************************************************************/
66
67
68 /*
69  * @implemented
70  */
71 NTSTATUS STDCALL
72 NtAddAtom(IN PWSTR AtomName,
73           OUT PRTL_ATOM Atom)
74 {
75    PRTL_ATOM_TABLE AtomTable;
76
77    AtomTable = RtlpGetGlobalAtomTable();
78    if (AtomTable == NULL)
79      return STATUS_ACCESS_DENIED;
80
81    return (RtlAddAtomToAtomTable(AtomTable,
82                                  AtomName,
83                                  Atom));
84 }
85
86
87 /*
88  * @implemented
89  */
90 NTSTATUS STDCALL
91 NtDeleteAtom(IN RTL_ATOM Atom)
92 {
93    PRTL_ATOM_TABLE AtomTable;
94
95    AtomTable = RtlpGetGlobalAtomTable();
96    if (AtomTable == NULL)
97      return STATUS_ACCESS_DENIED;
98
99    return (RtlDeleteAtomFromAtomTable(AtomTable,
100                                       Atom));
101 }
102
103
104 /*
105  * @implemented
106  */
107 NTSTATUS STDCALL
108 NtFindAtom(IN PWSTR AtomName,
109            OUT PRTL_ATOM Atom)
110 {
111    PRTL_ATOM_TABLE AtomTable;
112
113    AtomTable = RtlpGetGlobalAtomTable();
114    if (AtomTable == NULL)
115      return STATUS_ACCESS_DENIED;
116
117    return (RtlLookupAtomInAtomTable(AtomTable,
118                                     AtomName,
119                                     Atom));
120 }
121
122
123 /*
124  * @implemented
125  */
126 NTSTATUS STDCALL
127 NtQueryInformationAtom(RTL_ATOM Atom,
128                        ATOM_INFORMATION_CLASS AtomInformationClass,
129                        PVOID AtomInformation,
130                        ULONG AtomInformationLength,
131                        PULONG ReturnLength)
132 {
133    PRTL_ATOM_TABLE AtomTable;
134    NTSTATUS Status;
135
136    AtomTable = RtlpGetGlobalAtomTable();
137    if (AtomTable == NULL)
138      return STATUS_ACCESS_DENIED;
139
140    switch (AtomInformationClass)
141      {
142      case AtomBasicInformation:
143         Status = RtlpQueryAtomInformation(AtomTable,
144                                           Atom,
145                                           AtomInformation,
146                                           AtomInformationLength,
147                                           ReturnLength);
148         break;
149
150      case AtomTableInformation:
151         Status = RtlpQueryAtomTableInformation(AtomTable,
152                                                Atom,
153                                                AtomInformation,
154                                                AtomInformationLength,
155                                                ReturnLength);
156         break;
157
158      default:
159         Status = STATUS_INVALID_INFO_CLASS;
160      }
161
162    return Status;
163 }
164
165
166 /*
167  * @implemented
168  */
169 NTSTATUS STDCALL
170 RtlCreateAtomTable(ULONG TableSize,
171                    PRTL_ATOM_TABLE *AtomTable)
172 {
173    PRTL_ATOM_TABLE Table;
174    ULONG i;
175    NTSTATUS Status;
176
177    DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
178           TableSize, AtomTable);
179
180    if (*AtomTable != NULL)
181      {
182         return STATUS_SUCCESS;
183      }
184
185    /* allocate atom table */
186    Table = ExAllocatePool(NonPagedPool,
187                           TableSize * sizeof(RTL_ATOM_ENTRY) +
188                           sizeof(RTL_ATOM_TABLE));
189    if (Table == NULL)
190      return STATUS_NO_MEMORY;
191
192    /* initialize atom table */
193    Table->TableSize = TableSize;
194    Table->NumberOfAtoms = 0;
195
196    for (i = 0; i < TableSize; i++)
197      {
198         InitializeListHead(&Table->Slot[i]);
199      }
200
201    Status = RtlpInitAtomTableLock(Table);
202    if (!NT_SUCCESS(Status))
203      {
204         ExFreePool(Table);
205         return Status;
206      }
207
208    if (RtlpCreateAtomHandleTable(Table) == FALSE)
209      {
210         RtlpDestroyAtomTableLock(Table);
211         ExFreePool(Table);
212         return STATUS_NO_MEMORY;
213      }
214
215    *AtomTable = Table;
216    return STATUS_SUCCESS;
217 }
218
219
220 /*
221  * @implemented
222  */
223 NTSTATUS STDCALL
224 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
225 {
226    PLIST_ENTRY Current;
227    PRTL_ATOM_ENTRY AtomEntry;
228    ULONG i;
229
230    if (RtlpLockAtomTable(AtomTable) == FALSE)
231      {
232         return (STATUS_INVALID_PARAMETER);
233      }
234
235    /* delete all atoms */
236    for (i = 0; i < AtomTable->TableSize; i++)
237      {
238
239         Current = AtomTable->Slot[i].Flink;
240         while (Current != &AtomTable->Slot[i])
241           {
242              AtomEntry = (PRTL_ATOM_ENTRY)Current;
243              RtlFreeUnicodeString(&AtomEntry->Name);
244              RemoveEntryList(&AtomEntry->List);
245              ExFreePool(AtomEntry);
246              Current = AtomTable->Slot[i].Flink;
247           }
248
249      }
250
251    RtlpDestroyAtomHandleTable(AtomTable);
252
253    RtlpUnlockAtomTable(AtomTable);
254
255    RtlpDestroyAtomTableLock(AtomTable);
256
257    ExFreePool(AtomTable);
258
259    return STATUS_SUCCESS;
260 }
261
262
263 /*
264  * @implemented
265  */
266 NTSTATUS STDCALL
267 RtlEmptyAtomTable(IN PRTL_ATOM_TABLE AtomTable,
268                   IN BOOLEAN DeletePinned)
269 {
270    PLIST_ENTRY Current, Next;
271    PRTL_ATOM_ENTRY AtomEntry;
272    ULONG i;
273
274    DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
275           AtomTable, DeletePinned);
276
277    if (RtlpLockAtomTable(AtomTable) == FALSE)
278      {
279         return (STATUS_INVALID_PARAMETER);
280      }
281
282    /* delete all atoms */
283    for (i = 0; i < AtomTable->TableSize; i++)
284      {
285         Current = AtomTable->Slot[i].Flink;
286         while (Current != &AtomTable->Slot[i])
287           {
288              Next = Current->Flink;
289              AtomEntry = (PRTL_ATOM_ENTRY)Current;
290
291              if ((AtomEntry->Locked == FALSE) ||
292                  ((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
293                {
294                   RtlFreeUnicodeString(&AtomEntry->Name);
295
296                   RtlpFreeHandle(AtomTable->HandleTable,
297                                  AtomEntry->Index);
298
299                   RemoveEntryList(&AtomEntry->List);
300                   ExFreePool(AtomEntry);
301                }
302              Current = Next;
303           }
304
305      }
306
307    AtomTable->NumberOfAtoms = 0;
308
309    RtlpUnlockAtomTable(AtomTable);
310
311    return STATUS_SUCCESS;
312 }
313
314
315 /*
316  * @implemented
317  */
318 NTSTATUS STDCALL
319 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
320                       IN PWSTR AtomName,
321                       OUT PRTL_ATOM Atom)
322 {
323    ULONG Hash;
324    PLIST_ENTRY Current;
325    PRTL_ATOM_ENTRY Entry;
326    USHORT AtomValue;
327    NTSTATUS Status;
328    ULONG AtomIndex;
329
330    DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
331           AtomTable, AtomName, Atom);
332
333    if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
334      {
335         /* integer atom */
336         if (AtomValue >= 0xC000)
337           {
338              AtomValue = 0;
339              Status = STATUS_INVALID_PARAMETER;
340           }
341         else
342           {
343              Status = STATUS_SUCCESS;
344           }
345
346         if (Atom)
347           *Atom = (RTL_ATOM)AtomValue;
348
349         return Status;
350      }
351
352    RtlpLockAtomTable(AtomTable);
353
354    /* string atom */
355    Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
356
357    /* search for existing atom */
358    Current = AtomTable->Slot[Hash].Flink;
359    while (Current != &AtomTable->Slot[Hash])
360      {
361         Entry = (PRTL_ATOM_ENTRY)Current;
362
363         DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
364         if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
365           {
366              Entry->RefCount++;
367              if (Atom)
368                *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
369              RtlpUnlockAtomTable(AtomTable);
370              return STATUS_SUCCESS;
371           }
372         Current = Current->Flink;
373      }
374
375    /* insert new atom */
376    Entry = ExAllocatePool(NonPagedPool,
377                           sizeof(RTL_ATOM_ENTRY));
378    if (Entry == NULL)
379      {
380         RtlpUnlockAtomTable(AtomTable);
381         return STATUS_NO_MEMORY;
382      }
383
384    InsertTailList(&AtomTable->Slot[Hash], &Entry->List)
385    RtlCreateUnicodeString (&Entry->Name,
386                            AtomName);
387    Entry->RefCount = 1;
388    Entry->Locked = FALSE;
389
390    /* FIXME: use general function instead !! */
391    RtlpAllocateHandle(AtomTable->HandleTable,
392                       (PVOID)Entry,
393                       &AtomIndex);
394
395    DPRINT("AtomIndex %x\n", AtomIndex);
396
397    Entry->Index = AtomIndex;
398    AtomTable->NumberOfAtoms++;
399
400    if (Atom)
401      *Atom = (RTL_ATOM)(AtomIndex + 0xC000);
402
403    RtlpUnlockAtomTable(AtomTable);
404
405    return STATUS_SUCCESS;
406 }
407
408
409 /*
410  * @implemented
411  */
412 NTSTATUS STDCALL
413 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
414                            IN RTL_ATOM Atom)
415 {
416    PRTL_ATOM_ENTRY AtomEntry;
417
418    DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
419           AtomTable, Atom);
420
421    if (Atom < 0xC000)
422      {
423         return STATUS_SUCCESS;
424      }
425
426    RtlpLockAtomTable(AtomTable);
427
428    /* FIXME: use general function instead !! */
429    AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
430                                                        (ULONG)Atom - 0xC000);
431    if (AtomEntry == NULL)
432      {
433         RtlpUnlockAtomTable(AtomTable);
434         return STATUS_INVALID_HANDLE;
435      }
436
437    DPRINT("AtomEntry %x\n", AtomEntry);
438    DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
439
440    AtomEntry->RefCount--;
441
442    if (AtomEntry->RefCount == 0)
443      {
444         if (AtomEntry->Locked == TRUE)
445           {
446              DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
447
448              RtlpUnlockAtomTable(AtomTable);
449              return STATUS_WAS_LOCKED;
450           }
451
452         DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
453
454         RtlFreeUnicodeString(&AtomEntry->Name);
455         RemoveEntryList(&AtomEntry->List);
456         ExFreePool(AtomEntry);
457         RtlpFreeHandle(AtomTable->HandleTable,
458                        (ULONG)Atom - 0xC000);
459         AtomTable->NumberOfAtoms++;
460      }
461
462    RtlpUnlockAtomTable(AtomTable);
463
464    return STATUS_SUCCESS;
465 }
466
467
468 /*
469  * @implemented
470  */
471 NTSTATUS STDCALL
472 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
473                          IN PWSTR AtomName,
474                          OUT PRTL_ATOM Atom)
475 {
476    ULONG Hash;
477    PLIST_ENTRY Current;
478    PRTL_ATOM_ENTRY Entry;
479    USHORT AtomValue;
480    NTSTATUS Status;
481
482    DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
483           AtomTable, AtomName, Atom);
484
485    if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
486      {
487         /* integer atom */
488         if (AtomValue >= 0xC000)
489           {
490              AtomValue = 0;
491              Status = STATUS_INVALID_PARAMETER;
492           }
493         else
494           {
495              Status = STATUS_SUCCESS;
496           }
497
498         if (Atom)
499           *Atom = (RTL_ATOM)AtomValue;
500
501         return Status;
502      }
503
504    RtlpLockAtomTable(AtomTable);
505
506    /* string atom */
507    Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
508
509    /* search for existing atom */
510    Current = AtomTable->Slot[Hash].Flink;
511    while (Current != &AtomTable->Slot[Hash])
512      {
513         Entry = (PRTL_ATOM_ENTRY)Current;
514
515         DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
516         if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
517           {
518              if (Atom)
519                *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
520              RtlpUnlockAtomTable(AtomTable);
521              return STATUS_SUCCESS;
522           }
523
524         Current = Current->Flink;
525      }
526
527    return STATUS_OBJECT_NAME_NOT_FOUND;
528 }
529
530
531 /*
532  * @unimplemented
533  */
534 NTSTATUS STDCALL
535 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
536                       IN RTL_ATOM Atom)
537 {
538    PRTL_ATOM_ENTRY AtomEntry;
539
540    DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
541           AtomTable, Atom);
542
543    if (Atom < 0xC000)
544      {
545         return STATUS_SUCCESS;
546      }
547
548    RtlpLockAtomTable(AtomTable);
549
550    /* FIXME: use general function instead !! */
551    AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
552                                                        (ULONG)Atom - 0xC000);
553    if (AtomEntry == NULL)
554      {
555         RtlpUnlockAtomTable(AtomTable);
556         return STATUS_INVALID_HANDLE;
557      }
558
559    DPRINT("AtomEntry %x\n", AtomEntry);
560    DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
561
562    AtomEntry->Locked = TRUE;
563
564    RtlpUnlockAtomTable(AtomTable);
565
566    return STATUS_SUCCESS;
567 }
568
569
570 /*
571  * @implemented
572  */
573 NTSTATUS STDCALL
574 RtlQueryAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
575                         IN RTL_ATOM Atom,
576                         IN OUT PULONG RefCount,
577                         IN OUT PULONG PinCount,
578                         IN OUT PWSTR AtomName,
579                         IN OUT PULONG NameLength)
580 {
581    ULONG Length;
582    PRTL_ATOM_ENTRY AtomEntry;
583
584    if (Atom < 0xC000)
585      {
586         if (RefCount != NULL)
587           {
588              *RefCount = 1;
589           }
590
591         if (PinCount != NULL)
592           {
593              *PinCount = 1;
594           }
595
596         if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
597           {
598              Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
599              *NameLength = Length * sizeof(WCHAR);
600           }
601
602         return STATUS_SUCCESS;
603      }
604
605    RtlpLockAtomTable(AtomTable);
606
607    /* FIXME: use general function instead !! */
608    AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
609                                                        (ULONG)Atom - 0xC000);
610    if (AtomEntry == NULL)
611      {
612         RtlpUnlockAtomTable(AtomTable);
613         return STATUS_INVALID_HANDLE;
614      }
615
616    DPRINT("AtomEntry %x\n", AtomEntry);
617    DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
618
619    if (RefCount != NULL)
620      {
621         *RefCount = AtomEntry->RefCount;
622      }
623
624    if (PinCount != NULL)
625      {
626         *PinCount = (ULONG)AtomEntry->Locked;
627      }
628
629    if ((AtomName != NULL) && (NameLength != NULL))
630      {
631         if (*NameLength < AtomEntry->Name.Length)
632           {
633              *NameLength = AtomEntry->Name.Length;
634              RtlpUnlockAtomTable(AtomTable);
635              return STATUS_BUFFER_TOO_SMALL;
636           }
637
638         Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
639         *NameLength = Length * sizeof(WCHAR);
640      }
641
642    RtlpUnlockAtomTable(AtomTable);
643
644    return STATUS_SUCCESS;
645 }
646
647
648 /* INTERNAL FUNCTIONS ********************************************************/
649
650 static PRTL_ATOM_TABLE
651 RtlpGetGlobalAtomTable(VOID)
652 {
653    NTSTATUS Status;
654
655    if (GlobalAtomTable != NULL)
656      return GlobalAtomTable;
657
658    Status = RtlCreateAtomTable(37, &GlobalAtomTable);
659    if (!NT_SUCCESS(Status))
660      return NULL;
661
662    return GlobalAtomTable;
663 }
664
665
666 static ULONG
667 RtlpHashAtomName(ULONG TableSize,
668                  PWSTR AtomName)
669 {
670    ULONG q = 0;
671    PWCHAR p;
672
673    DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
674           TableSize, AtomName);
675
676    /* convert the string to an internal representation */
677    p = AtomName;
678    while (*p != 0)
679      {
680         q += (ULONG)towupper(*p);
681         p++;
682      }
683
684    DPRINT("q %lu Hash %lu\n", q, q % TableSize);
685
686    return (q % TableSize);
687 }
688
689
690 static BOOLEAN
691 RtlpCheckIntegerAtom(PWSTR AtomName,
692                      PUSHORT AtomValue)
693 {
694    UNICODE_STRING AtomString;
695    ULONG LongValue;
696    USHORT LoValue;
697    PWCHAR p;
698
699    DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
700           AtomName, AtomValue);
701
702    if (!((ULONG)AtomName & 0xFFFF0000))
703      {
704         LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
705
706         if (LoValue >= 0xC000)
707           return FALSE;
708
709         if (LoValue == 0)
710           LoValue = 0xC000;
711
712         if (AtomValue != NULL)
713           *AtomValue = LoValue;
714
715         return TRUE;
716      }
717
718    if (*AtomName != L'#')
719      return FALSE;
720
721    p = AtomName;
722    p++;
723    while (*p)
724      {
725         if ((*p < L'0') || (*p > L'9'))
726           return FALSE;
727         p++;
728      }
729
730    p = AtomName;
731    p++;
732    RtlInitUnicodeString(&AtomString,
733                         p);
734
735    DPRINT1("AtomString: %wZ\n", &AtomString);
736
737    RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
738
739    DPRINT1("LongValue: %lu\n", LongValue);
740
741    *AtomValue = (USHORT)(LongValue & 0x0000FFFF);
742
743    return TRUE;
744 }
745
746
747 /* lock functions */
748
749 static NTSTATUS
750 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
751 {
752    AtomTable->Lock = ExAllocatePool(NonPagedPool,
753                                     sizeof(FAST_MUTEX));
754    if (AtomTable->Lock == NULL)
755      return STATUS_NO_MEMORY;
756
757    ExInitializeFastMutex((PFAST_MUTEX)AtomTable->Lock);
758
759    return STATUS_SUCCESS;
760 }
761
762
763 static VOID
764 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
765 {
766    if (AtomTable->Lock)
767      ExFreePool(AtomTable->Lock);
768 }
769
770
771 static BOOLEAN
772 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
773 {
774 //   ExAcquireFastMutex((PFAST_MUTEX)AtomTable->Lock);
775    return TRUE;
776 }
777
778 static VOID
779 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
780 {
781 //   ExReleaseFastMutex((PFAST_MUTEX)AtomTable->Lock);
782 }
783
784 #if 0
785 static NTSTATUS
786 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
787 {
788    AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
789                                      HEAP_ZERO_MEMORY,
790                                      sizeof(CRITICAL_SECTION));
791    if (AtomTable->Lock == NULL)
792      return STATUS_NO_MEMORY;
793
794    RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
795
796    return STATUS_SUCCESS;
797 }
798
799
800 static VOID
801 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
802 {
803    if (AtomTable->Lock)
804      {
805         RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
806         RtlFreeHeap(RtlGetProcessHeap(),
807                     0,
808                     AtomTable->Lock);
809         AtomTable->Lock = NULL;
810      }
811 }
812
813
814 static BOOLEAN
815 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
816 {
817    RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
818    return TRUE;
819 }
820
821
822 static VOID
823 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
824 {
825    RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
826 }
827 #endif
828
829 /* handle functions */
830
831 static BOOLEAN
832 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
833 {
834    AtomTable->HandleTable = ExAllocatePool(NonPagedPool,
835                                            sizeof(RTL_HANDLE_TABLE));
836    if (AtomTable->HandleTable == NULL)
837      return FALSE;
838
839    RtlpInitializeHandleTable(0xCFFF,
840                              (PRTL_HANDLE_TABLE)AtomTable->HandleTable);
841
842    return TRUE;
843 }
844
845
846 static VOID
847 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
848 {
849    if (AtomTable->HandleTable)
850      {
851         RtlpDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
852         ExFreePool(AtomTable->HandleTable);
853         AtomTable->HandleTable = NULL;
854      }
855 }
856
857
858 static NTSTATUS
859 RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
860                          RTL_ATOM Atom,
861                          PATOM_BASIC_INFORMATION AtomInformation,
862                          ULONG AtomInformationLength,
863                          PULONG ReturnLength)
864 {
865    NTSTATUS Status;
866    ULONG UsageCount;
867    ULONG Flags;
868    ULONG NameLength;
869
870    NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR);
871    Status = RtlQueryAtomInAtomTable(AtomTable,
872                                     Atom,
873                                     &UsageCount,
874                                     &Flags,
875                                     AtomInformation->Name,
876                                     &NameLength);
877    if (!NT_SUCCESS(Status))
878      {
879         return Status;
880      }
881
882    DPRINT1("NameLength: %lu\n", NameLength);
883
884    if (ReturnLength != NULL)
885      {
886         *ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION);
887      }
888
889    if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength)
890      {
891         return STATUS_BUFFER_TOO_SMALL;
892      }
893
894    AtomInformation->UsageCount = (USHORT)UsageCount;
895    AtomInformation->Flags = (USHORT)Flags;
896    AtomInformation->NameLength = (USHORT)NameLength;
897
898    return STATUS_SUCCESS;
899 }
900
901
902 static NTSTATUS
903 RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
904                               RTL_ATOM Atom,
905                               PATOM_TABLE_INFORMATION AtomInformation,
906                               ULONG AtomInformationLength,
907                               PULONG ReturnLength)
908 {
909    PLIST_ENTRY Current, Next;
910    PRTL_ATOM_ENTRY AtomEntry;
911    ULONG Length;
912    ULONG i, j;
913
914    Length = sizeof(ATOM_TABLE_INFORMATION);
915    if (AtomTable->NumberOfAtoms > 1)
916      {
917         Length += ((AtomTable->NumberOfAtoms - 1)* sizeof(RTL_ATOM));
918      }
919
920    DPRINT1("RequiredLength: %lu\n", Length);
921
922    if (ReturnLength != NULL)
923      {
924         *ReturnLength = Length;
925      }
926
927    if (Length > AtomInformationLength)
928      {
929         return STATUS_BUFFER_TOO_SMALL;
930      }
931
932    AtomInformation->NumberOfAtoms = AtomTable->NumberOfAtoms;
933
934    j = 0;
935    for (i = 0; i < AtomTable->TableSize; i++)
936      {
937         Current = AtomTable->Slot[i].Flink;
938         while (Current != &AtomTable->Slot[i])
939           {
940              Next = Current->Flink;
941              AtomEntry = (PRTL_ATOM_ENTRY)Current;
942
943              AtomInformation->Atoms[j] = AtomEntry->Index + 0xC000;
944              j++;
945
946              Current = Next;
947           }
948      }
949
950    return STATUS_SUCCESS;
951 }
952
953 /* EOF */