Fix kernel-mode executive atom implementation (mostly add SEH and tidy up the code...
[reactos.git] / reactos / lib / rtl / atom.c
index 4dd69c9..1c643df 100644 (file)
@@ -1,17 +1,13 @@
-/* $Id$
- *
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+/* COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
  * FILE:            lib/rtl/atom.c
  * PURPOSE:         Atom managment
- * PROGRAMMER:      Nobody
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * PROGRAMMER:      Thomas Weidenmueller
  */
 
 /* INCLUDES *****************************************************************/
 
-#include "rtl.h"
+#include <rtl.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -98,9 +94,6 @@ RtlpCheckIntegerAtom(PWSTR AtomName,
      {
         LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
 
-        if (LoValue >= 0xC000)
-          return FALSE;
-
         if (LoValue == 0)
           LoValue = 0xC000;
 
@@ -142,7 +135,7 @@ RtlpCheckIntegerAtom(PWSTR AtomName,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlCreateAtomTable(IN ULONG TableSize,
                    IN OUT PRTL_ATOM_TABLE *AtomTable)
 {
@@ -157,6 +150,9 @@ RtlCreateAtomTable(IN ULONG TableSize,
         return STATUS_SUCCESS;
      }
 
+   /* Use default if size was incorrect */
+   if (TableSize <= 1) TableSize = 37;
+
    /* allocate atom table */
    Table = RtlpAllocAtomTable(((TableSize - 1) * sizeof(PRTL_ATOM_TABLE_ENTRY)) +
                               sizeof(RTL_ATOM_TABLE));
@@ -190,7 +186,7 @@ RtlCreateAtomTable(IN ULONG TableSize,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
 {
    PRTL_ATOM_TABLE_ENTRY *CurrentBucket, *LastBucket;
@@ -239,12 +235,12 @@ RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
                   BOOLEAN DeletePinned)
 {
    PRTL_ATOM_TABLE_ENTRY *CurrentBucket, *LastBucket;
-   PRTL_ATOM_TABLE_ENTRY CurrentEntry, NextEntry;
+   PRTL_ATOM_TABLE_ENTRY CurrentEntry, NextEntry, *PtrEntry;
 
    DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
           AtomTable, DeletePinned);
@@ -261,17 +257,26 @@ RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
         CurrentBucket++)
      {
         NextEntry = *CurrentBucket;
-        *CurrentBucket = NULL;
+        PtrEntry = CurrentBucket;
 
         while (NextEntry != NULL)
           {
              CurrentEntry = NextEntry;
              NextEntry = NextEntry->HashLink;
 
-             RtlpFreeAtomHandle(AtomTable,
-                                CurrentEntry);
+             if (DeletePinned || !(CurrentEntry->Flags & RTL_ATOM_IS_PINNED))
+               {
+                 *PtrEntry = NextEntry;
+
+                 RtlpFreeAtomHandle(AtomTable,
+                                    CurrentEntry);
 
-             RtlpFreeAtomTableEntry(CurrentEntry);
+                 RtlpFreeAtomTableEntry(CurrentEntry);
+               }
+             else
+               {
+                 PtrEntry = &CurrentEntry->HashLink;
+               }
           }
      }
 
@@ -284,7 +289,7 @@ RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
                       IN PWSTR AtomName,
                       OUT PRTL_ATOM Atom)
@@ -345,6 +350,12 @@ RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
         if (HashLink != NULL)
           {
              ULONG AtomNameLen = wcslen(AtomName);
+             
+             if (AtomNameLen > RTL_MAXIMUM_ATOM_LENGTH)
+             {
+                Status = STATUS_INVALID_PARAMETER;
+                goto end;
+             }
 
              Entry = RtlpAllocAtomTableEntry(sizeof(RTL_ATOM_TABLE_ENTRY) -
                                              sizeof(Entry->Name) +
@@ -385,10 +396,10 @@ RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
         else
           {
              /* The caller supplied an empty atom name! */
-             Status = STATUS_INVALID_PARAMETER;
+             Status = STATUS_OBJECT_NAME_INVALID;
           }
      }
-
+end:
    RtlpUnlockAtomTable(AtomTable);
 
    return Status;
@@ -398,7 +409,7 @@ RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
                            IN RTL_ATOM Atom)
 {
@@ -470,7 +481,7 @@ RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
                          IN PWSTR AtomName,
                          OUT PRTL_ATOM Atom)
@@ -499,27 +510,22 @@ RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
      }
 
    RtlpLockAtomTable(AtomTable);
-
    Status = STATUS_OBJECT_NAME_NOT_FOUND;
 
    /* string atom */
    Entry = RtlpHashAtomName(AtomTable,
                             AtomName,
                             &HashLink);
-
    if (Entry != NULL)
      {
         Status = STATUS_SUCCESS;
         FoundAtom = (RTL_ATOM)Entry->Atom;
      }
-
    RtlpUnlockAtomTable(AtomTable);
-
    if (NT_SUCCESS(Status) && Atom != NULL)
      {
         *Atom = FoundAtom;
      }
-
    return Status;
 }
 
@@ -527,7 +533,7 @@ RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
                       IN RTL_ATOM Atom)
 {
@@ -557,16 +563,31 @@ RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
         RtlpUnlockAtomTable(AtomTable);
      }
 
-   RtlpLockAtomTable(AtomTable);
-
    return Status;
 }
 
 
 /*
  * @implemented
+ *
+ * This API is really messed up with regards to NameLength. If you pass in a
+ * valid buffer for AtomName, NameLength should be the size of the buffer
+ * (in bytes, not characters). So if you expect the string to be 6 char long,
+ * you need to allocate a buffer of 7 WCHARs and pass 14 for NameLength.
+ * The AtomName returned is always null terminated. If the NameLength you pass
+ * is smaller than 4 (4 would leave room for 1 character) the function will
+ * return with status STATUS_BUFFER_TOO_SMALL. If you pass more than 4, the
+ * return status will be STATUS_SUCCESS, even if the buffer is not large enough
+ * to hold the complete string. In that case, the string is silently truncated
+ * and made to fit in the provided buffer. On return NameLength is set to the
+ * number of bytes (but EXCLUDING the bytes for the null terminator) copied.
+ * So, if the string is 6 char long, you pass a buffer of 10 bytes, on return
+ * NameLength will be set to 8.
+ * If you pass in a NULL value for AtomName, the length of the string in bytes
+ * (again EXCLUDING the null terminator) is returned in NameLength, at least
+ * on Win2k, XP and ReactOS. NT4 will return 0 in that case.
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
                         RTL_ATOM Atom,
                         PULONG RefCount,
@@ -575,58 +596,37 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
                         PULONG NameLength)
 {
    ULONG Length;
+   BOOL Unlock = FALSE;
+   
+   union
+     {
+     /* A RTL_ATOM_TABLE_ENTRY has a "WCHAR Name[1]" entry at the end.
+      * Make sure we reserve enough room to facilitate a 12 character name */
+     RTL_ATOM_TABLE_ENTRY AtomTableEntry;
+     WCHAR StringBuffer[sizeof(RTL_ATOM_TABLE_ENTRY) / sizeof(WCHAR) + 12];
+     } NumberEntry;
    PRTL_ATOM_TABLE_ENTRY Entry;
    NTSTATUS Status = STATUS_SUCCESS;
 
    if (Atom < 0xC000)
      {
-        if (RefCount != NULL)
-          {
-             *RefCount = 1;
-          }
-
-        if (PinCount != NULL)
-          {
-             *PinCount = 1;
-          }
-
-        if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
-          {
-             WCHAR NameString[12];
-             
-             Length = swprintf(NameString, L"#%lu", (ULONG)Atom) * sizeof(WCHAR);
-
-             if (*NameLength < Length + sizeof(WCHAR))
-               {
-                  /* prevent underflow! */
-                  if (*NameLength >= sizeof(WCHAR))
-                    {
-                       Length = *NameLength - sizeof(WCHAR);
-                    }
-                  else
-                    {
-                       Length = 0;
-                       Status = STATUS_BUFFER_TOO_SMALL;
-                    }
-               }
-
-             if (Length)
-               {
-                  RtlCopyMemory(AtomName,
-                                NameString,
-                                Length);
-                  AtomName[Length / sizeof(WCHAR)] = L'\0';
-                  *NameLength = Length;
-               }
-          }
-
-        return Status;
+        /* Synthesize an entry */
+        NumberEntry.AtomTableEntry.Atom = Atom;
+        NumberEntry.AtomTableEntry.NameLength = swprintf(NumberEntry.AtomTableEntry.Name,
+                                                         L"#%lu",
+                                                         (ULONG)Atom);
+        NumberEntry.AtomTableEntry.ReferenceCount = 1;
+        NumberEntry.AtomTableEntry.Flags = RTL_ATOM_IS_PINNED;
+        Entry = &NumberEntry.AtomTableEntry;
      }
+   else
+     {
+        RtlpLockAtomTable(AtomTable);
+        Unlock = TRUE;
 
-   RtlpLockAtomTable(AtomTable);
-
-   Entry = RtlpGetAtomEntry(AtomTable,
-                            (ULONG)((USHORT)Atom - 0xC000));
+        Entry = RtlpGetAtomEntry(AtomTable,
+                                 (ULONG)((USHORT)Atom - 0xC000));
+     }
 
    if (Entry != NULL && Entry->Atom == (USHORT)Atom)
      {
@@ -642,40 +642,48 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
              *PinCount = ((Entry->Flags & RTL_ATOM_IS_PINNED) != 0);
           }
 
-        if ((AtomName != NULL) && (NameLength != NULL))
+        if (NULL != NameLength)
           {
              Length = Entry->NameLength * sizeof(WCHAR);
-
-             if (*NameLength < Length + sizeof(WCHAR))
+             if (NULL != AtomName)
                {
-                  /* prevent underflow! */
-                  if (*NameLength >= sizeof(WCHAR))
+                  if (*NameLength < Length + sizeof(WCHAR))
                     {
-                       Length = *NameLength - sizeof(WCHAR);
+                       if (*NameLength < 4)
+                         {
+                            *NameLength = Length;
+                            Status = STATUS_BUFFER_TOO_SMALL;
+                         }
+                       else
+                         {
+                            Length = *NameLength - sizeof(WCHAR);
+                         }
                     }
-                  else
+                  if (NT_SUCCESS(Status))
                     {
-                       Length = 0;
-                       Status = STATUS_BUFFER_TOO_SMALL;
+                       RtlCopyMemory(AtomName,
+                                     Entry->Name,
+                                     Length);
+                       AtomName[Length / sizeof(WCHAR)] = L'\0';
+                       *NameLength = Length;
                     }
                }
-
-             if (Length)
+             else
                {
-                  RtlCopyMemory(AtomName,
-                                Entry->Name,
-                                Length);
-                  AtomName[Length / sizeof(WCHAR)] = L'\0';
                   *NameLength = Length;
                }
           }
+        else if (NULL != AtomName)
+          {
+             Status = STATUS_INVALID_PARAMETER;
+          }
      }
    else
      {
         Status = STATUS_INVALID_HANDLE;
      }
 
-   RtlpUnlockAtomTable(AtomTable);
+   if (Unlock) RtlpUnlockAtomTable(AtomTable);
 
    return Status;
 }
@@ -684,7 +692,7 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
 /*
  * @private - only used by NtQueryInformationAtom
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 RtlQueryAtomListInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
                             IN ULONG MaxAtomCount,
                             OUT ULONG *AtomCount,