From cf56f16a98daf0e77976ac5d1f8173f3c053523a Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 29 Dec 2005 08:43:45 +0000 Subject: [PATCH 1/1] Fix kernel-mode executive atom implementation (mostly add SEH and tidy up the code). Then fix kernel32 implementation which was sending incorrect sizes, and also re-factored the entire code, since most functions were quatriplicated. now there are 3 main functions instead of 12. Also fixed a bug in RtlCreateAtomTable. svn path=/trunk/; revision=20414 --- reactos/lib/kernel32/misc/atom.c | 977 +++++++++++++++---------------- reactos/lib/rtl/atom.c | 8 +- reactos/ntoskrnl/ex/atom.c | 324 +++++++--- 3 files changed, 700 insertions(+), 609 deletions(-) diff --git a/reactos/lib/kernel32/misc/atom.c b/reactos/lib/kernel32/misc/atom.c index 7a4a916f37b..1f8cc1c3405 100644 --- a/reactos/lib/kernel32/misc/atom.c +++ b/reactos/lib/kernel32/misc/atom.c @@ -1,635 +1,584 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/kernel32/misc/atom.c * PURPOSE: Atom functions - * PROGRAMMER: Eric Kohl ( ariadne@xs4all.nl) - * UPDATE HISTORY: - * Created 01/11/98 - * Full rewrite 27/05/2001 + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ +/* INCLUDES ******************************************************************/ #include #define NDEBUG #include "../include/debug.h" - /* GLOBALS *******************************************************************/ -static PRTL_ATOM_TABLE LocalAtomTable = NULL; +PRTL_ATOM_TABLE BaseLocalAtomTable = NULL; -static PRTL_ATOM_TABLE GetLocalAtomTable(VOID); +/* FUNCTIONS *****************************************************************/ +PVOID +WINAPI +InternalInitAtomTable(VOID) +{ + /* Create or return the local table */ + if (!BaseLocalAtomTable) RtlCreateAtomTable(0, &BaseLocalAtomTable); + return BaseLocalAtomTable; +} + +ATOM +WINAPI +InternalAddAtom(BOOLEAN Local, + BOOLEAN Unicode, + LPCSTR AtomName) +{ + NTSTATUS Status; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + PUNICODE_STRING AtomNameString; + ATOM Atom = INVALID_ATOM; + + /* Check if it's an integer atom */ + if ((ULONG_PTR)AtomName <= 0xFFFF) + { + /* Convert the name to an atom */ + Atom = (ATOM)PtrToShort((PVOID)AtomName); + if (Atom >= MAXINTATOM) + { + /* Fail, atom number too large */ + SetLastErrorByStatus(STATUS_INVALID_PARAMETER); + return INVALID_ATOM; + } + + /* Return it */ + return Atom; + } + else + { + /* Check if this is a unicode atom */ + if (Unicode) + { + /* Use a unicode string */ + AtomNameString = &UnicodeString; + RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName); + Status = STATUS_SUCCESS; + } + else + { + /* Use an ansi string */ + RtlInitAnsiString(&AnsiString, AtomName ); + + /* Check if we can abuse the TEB */ + if (AnsiString.MaximumLength > 260) + { + /* We can't, allocate a new string */ + AtomNameString = &UnicodeString; + Status = RtlAnsiStringToUnicodeString(AtomNameString, + &AnsiString, + TRUE); + } + else + { + /* We can! Use the TEB */ + AtomNameString = &NtCurrentTeb()->StaticUnicodeString; + Status = RtlAnsiStringToUnicodeString(AtomNameString, + &AnsiString, + FALSE); + } + } + + /* Check for failure */ + if (!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + return Atom; + } + } + + /* Check if we're doing local add */ + if (Local) + { + /* Do a local add */ + Status = RtlAddAtomToAtomTable(InternalInitAtomTable(), + AtomNameString->Buffer, + &Atom); + } + else + { + /* Do a global add */ + Status = NtAddAtom(AtomNameString->Buffer, + AtomNameString->Length, + &Atom); + } + + /* Check for failure */ + if (!NT_SUCCESS(Status)) SetLastErrorByStatus(Status); + + /* Check if we were non-static ANSI */ + if (!(Unicode) && (AtomNameString == &UnicodeString)) + { + /* Free the allocated buffer */ + RtlFreeUnicodeString(AtomNameString); + } + + /* Return the atom */ + return Atom; +} + +ATOM +WINAPI +InternalFindAtom(BOOLEAN Local, + BOOLEAN Unicode, + LPCSTR AtomName) +{ + NTSTATUS Status; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + PUNICODE_STRING AtomNameString; + ATOM Atom = INVALID_ATOM; + + /* Check if it's an integer atom */ + if ((ULONG_PTR)AtomName <= 0xFFFF) + { + /* Convert the name to an atom */ + Atom = (ATOM)PtrToShort((PVOID)AtomName); + if (Atom >= MAXINTATOM) + { + /* Fail, atom number too large */ + SetLastErrorByStatus(STATUS_INVALID_PARAMETER); + DPRINT1("Invalid atom\n"); + } + + /* Return it */ + return Atom; + } + else + { + /* Check if this is a unicode atom */ + if (Unicode) + { + /* Use a unicode string */ + AtomNameString = &UnicodeString; + RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName); + Status = STATUS_SUCCESS; + } + else + { + /* Use an ansi string */ + RtlInitAnsiString(&AnsiString, AtomName); + + /* Check if we can abuse the TEB */ + if (AnsiString.MaximumLength > 260) + { + /* We can't, allocate a new string */ + AtomNameString = &UnicodeString; + Status = RtlAnsiStringToUnicodeString(AtomNameString, + &AnsiString, + TRUE); + } + else + { + /* We can! Use the TEB */ + AtomNameString = &NtCurrentTeb()->StaticUnicodeString; + Status = RtlAnsiStringToUnicodeString(AtomNameString, + &AnsiString, + FALSE); + } + } + + /* Check for failure */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed\n"); + SetLastErrorByStatus(Status); + return Atom; + } + } + + /* Check if we're doing local lookup */ + if (Local) + { + /* Do a local lookup */ + Status = RtlLookupAtomInAtomTable(InternalInitAtomTable(), + AtomNameString->Buffer, + &Atom); + } + else + { + /* Do a global search */ + if (!AtomNameString->Length) + { + /* This is illegal in win32 */ + DPRINT1("No name given\n"); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else + { + /* Call the global function */ + Status = NtFindAtom(AtomNameString->Buffer, + AtomNameString->Length, + &Atom); + } + } + + /* Check for failure */ + if (!NT_SUCCESS(Status)) SetLastErrorByStatus(Status); + + /* Check if we were non-static ANSI */ + if (!(Unicode) && (AtomNameString == &UnicodeString)) + { + /* Free the allocated buffer */ + RtlFreeUnicodeString(AtomNameString); + } + + /* Return the atom */ + return Atom; +} + +ATOM +WINAPI +InternalDeleteAtom(BOOLEAN Local, + ATOM Atom) +{ + NTSTATUS Status; + + /* Validate it */ + if (Atom >= MAXINTATOM) + { + /* Check if it's a local delete */ + if (Local) + { + /* Delete it locally */ + Status = RtlDeleteAtomFromAtomTable(InternalInitAtomTable(), Atom); + } + else + { + /* Delete it globall */ + Status = NtDeleteAtom(Atom); + } + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + /* Fail */ + SetLastErrorByStatus(Status); + return INVALID_ATOM; + } + } + + /* Return failure */ + return 0; +} + +UINT +WINAPI +InternalGetAtomName(BOOLEAN Local, + BOOLEAN Unicode, + ATOM Atom, + LPSTR AtomName, + DWORD Size) +{ + NTSTATUS Status; + DWORD RetVal = 0; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + PVOID TempBuffer = NULL; + PWSTR AtomNameString; + ULONG AtomInfoLength; + ULONG AtomNameLength; + PATOM_BASIC_INFORMATION AtomInfo; + + /* Normalize the size as not to overflow */ + if (!Unicode && Size > 0x7000) Size = 0x7000; + + /* Make sure it's valid too */ + if (!Size) + { + SetLastErrorByStatus(STATUS_BUFFER_OVERFLOW); + return 0; + } + + /* Check if this is a global query */ + if (Local) + { + /* Set the query length */ + AtomNameLength = Size * sizeof(WCHAR); + + /* If it's unicode, just keep the name */ + if (Unicode) + { + AtomNameString = (PWSTR)AtomName; + } + else + { + /* Allocate memory for the ansi buffer */ + TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + AtomNameLength); + AtomNameString = TempBuffer; + } + + /* Query the name */ + Status = RtlQueryAtomInAtomTable(InternalInitAtomTable(), + Atom, + NULL, + NULL, + AtomNameString, + &AtomNameLength); + } + else + { + /* We're going to do a global query, so allocate a buffer */ + AtomInfoLength = sizeof(ATOM_BASIC_INFORMATION) + + (Size * sizeof(WCHAR)); + AtomInfo = TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + AtomInfoLength); + + /* Query the name */ + Status = NtQueryInformationAtom(Atom, + AtomBasicInformation, + AtomInfo, + AtomInfoLength, + &AtomInfoLength); + if (NT_SUCCESS(Status)) + { + /* Success. Update the length and get the name */ + AtomNameLength = (ULONG)AtomInfo->NameLength; + AtomNameString = AtomInfo->Name; + } + } + + /* Check for global success */ + if (NT_SUCCESS(Status)) + { + /* Check if it was unicode */ + if (Unicode) + { + /* We return the length in chars */ + RetVal = AtomNameLength / sizeof(WCHAR); + + /* Copy the memory if this was a global query */ + if (AtomNameString != (PWSTR)AtomName) + { + RtlMoveMemory(AtomName, AtomNameString, AtomNameLength); + } + + /* And null-terminate it if the buffer was too large */ + if (RetVal < Size) + { + ((PWCHAR)AtomName)[RetVal] = UNICODE_NULL; + } + } + else + { + /* First create a unicode string with our data */ + UnicodeString.Buffer = AtomNameString; + UnicodeString.Length = (USHORT)AtomNameLength; + UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + + sizeof(WCHAR)); + + /* Now prepare an ansi string for conversion */ + AnsiString.Buffer = AtomName; + AnsiString.Length = 0; + AnsiString.MaximumLength = (USHORT)Size; + + /* Convert it */ + Status = RtlUnicodeStringToAnsiString(&AnsiString, + &UnicodeString, + FALSE); + + /* Return the length */ + if (NT_SUCCESS(Status)) RetVal = AnsiString.Length; + } + } + + /* Free the temporary buffer if we have one */ + if (TempBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, TempBuffer); + + /* Check for failure */ + if (!NT_SUCCESS(Status)) + { + /* Fail */ + DPRINT1("Failed: %lx\n", Status); + SetLastErrorByStatus(Status); + } + + /* Return length */ + return RetVal; +} /* FUNCTIONS *****************************************************************/ /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI GlobalAddAtomA(LPCSTR lpString) { - UNICODE_STRING AtomName; - NTSTATUS Status; - ATOM Atom; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - if (lstrlenA(lpString) > 255) - { - /* This limit does not exist with NtAddAtom so the limit is probably - * added for compability. -Gunnar - */ - SetLastError(ERROR_INVALID_PARAMETER); - return (ATOM)0; - } - - RtlCreateUnicodeStringFromAsciiz(&AtomName, - (LPSTR)lpString); - - Status = NtAddAtom(AtomName.Buffer, - AtomName.Length, - &Atom); - RtlFreeUnicodeString(&AtomName); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalAddAtom(FALSE, FALSE, lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI GlobalAddAtomW(LPCWSTR lpString) { - ATOM Atom; - NTSTATUS Status; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - if (lstrlenW(lpString) > 255) - { - /* This limit does not exist with NtAddAtom so the limit is probably - * added for compability. -Gunnar - */ - SetLastError(ERROR_INVALID_PARAMETER); - return (ATOM)0; - } - - Status = NtAddAtom((LPWSTR)lpString, - wcslen(lpString), - &Atom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI GlobalDeleteAtom(ATOM nAtom) { - NTSTATUS Status; - - if (nAtom < 0xC000) - { - return 0; - } - - Status = NtDeleteAtom(nAtom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return nAtom; - } - - return 0; + return InternalDeleteAtom(FALSE, nAtom); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI GlobalFindAtomA(LPCSTR lpString) { - UNICODE_STRING AtomName; - NTSTATUS Status; - ATOM Atom; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - if (lstrlenA(lpString) > 255) - { - /* This limit does not exist with NtAddAtom so the limit is probably - * added for compability. -Gunnar - */ - SetLastError(ERROR_INVALID_PARAMETER); - return (ATOM)0; - } - - RtlCreateUnicodeStringFromAsciiz(&AtomName, - (LPSTR)lpString); - Status = NtFindAtom(AtomName.Buffer, - AtomName.Length, - &Atom); - RtlFreeUnicodeString(&AtomName); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalFindAtom(FALSE, FALSE, lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI GlobalFindAtomW(LPCWSTR lpString) { - ATOM Atom; - NTSTATUS Status; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - if (lstrlenW(lpString) > 255) - { - /* This limit does not exist with NtAddAtom so the limit is probably - * added for compability. -Gunnar - */ - SetLastError(ERROR_INVALID_PARAMETER); - return (ATOM)0; - } - - Status = NtFindAtom((LPWSTR)lpString, - wcslen(lpString), - &Atom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString); } - -UINT STDCALL +/* + * @implemented + */ +UINT +WINAPI GlobalGetAtomNameA(ATOM nAtom, - LPSTR lpBuffer, - int nSize) + LPSTR lpBuffer, + int nSize) { - PATOM_BASIC_INFORMATION Buffer; - UNICODE_STRING AtomNameU; - ANSI_STRING AtomName; - ULONG BufferSize; - ULONG ReturnLength; - NTSTATUS Status; - - BufferSize = sizeof(ATOM_BASIC_INFORMATION) + nSize * sizeof(WCHAR); - Buffer = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - BufferSize); - if (Buffer == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - Status = NtQueryInformationAtom(nAtom, - AtomBasicInformation, - Buffer, - BufferSize, - &ReturnLength); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - SetLastErrorByStatus(Status); - return 0; - } - - RtlInitUnicodeString(&AtomNameU, - Buffer->Name); - AtomName.Buffer = lpBuffer; - AtomName.Length = 0; - AtomName.MaximumLength = nSize; - RtlUnicodeStringToAnsiString(&AtomName, - &AtomNameU, - FALSE); - - ReturnLength = AtomName.Length; - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - - return ReturnLength; + return InternalGetAtomName(FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize); } - /* * @implemented */ -UINT STDCALL +UINT +WINAPI GlobalGetAtomNameW(ATOM nAtom, - LPWSTR lpBuffer, - int nSize) -{ - PATOM_BASIC_INFORMATION Buffer; - ULONG BufferSize; - ULONG ReturnLength; - NTSTATUS Status; - - BufferSize = sizeof(ATOM_BASIC_INFORMATION) + nSize * sizeof(WCHAR); - Buffer = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - BufferSize); - if (Buffer == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - Status = NtQueryInformationAtom(nAtom, - AtomBasicInformation, - Buffer, - BufferSize, - &ReturnLength); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - SetLastErrorByStatus(Status); - return 0; - } - - memcpy(lpBuffer, Buffer->Name, Buffer->NameLength); - ReturnLength = Buffer->NameLength / sizeof(WCHAR); - *(lpBuffer + ReturnLength) = 0; - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - - return ReturnLength; -} - - -static PRTL_ATOM_TABLE -GetLocalAtomTable(VOID) + LPWSTR lpBuffer, + int nSize) { - if (LocalAtomTable != NULL) - { - return LocalAtomTable; - } - RtlCreateAtomTable(37, - &LocalAtomTable); - return LocalAtomTable; + return InternalGetAtomName(FALSE, + TRUE, + nAtom, + (LPSTR)lpBuffer, + (DWORD)nSize); } - /* * @implemented */ -BOOL STDCALL +BOOL +WINAPI InitAtomTable(DWORD nSize) { - NTSTATUS Status; + /* Normalize size */ + if (nSize < 4 || nSize > 511) nSize = 37; - /* nSize should be a prime number */ - - if ( nSize < 4 || nSize >= 512 ) - { - nSize = 37; - } - - if (LocalAtomTable == NULL) - { - Status = RtlCreateAtomTable(nSize, - &LocalAtomTable); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return FALSE; - } - } - - return TRUE; + DPRINT("Here\n"); + return NT_SUCCESS(RtlCreateAtomTable(nSize, &BaseLocalAtomTable)); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI AddAtomA(LPCSTR lpString) { - PRTL_ATOM_TABLE AtomTable; - UNICODE_STRING AtomName; - NTSTATUS Status; - ATOM Atom; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - AtomTable = GetLocalAtomTable(); - - RtlCreateUnicodeStringFromAsciiz(&AtomName, - (LPSTR)lpString); - - Status = RtlAddAtomToAtomTable(AtomTable, - AtomName.Buffer, - &Atom); - RtlFreeUnicodeString(&AtomName); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalAddAtom(TRUE, FALSE, lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI AddAtomW(LPCWSTR lpString) { - PRTL_ATOM_TABLE AtomTable; - ATOM Atom; - NTSTATUS Status; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - AtomTable = GetLocalAtomTable(); - - Status = RtlAddAtomToAtomTable(AtomTable, - (LPWSTR)lpString, - &Atom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI DeleteAtom(ATOM nAtom) { - PRTL_ATOM_TABLE AtomTable; - NTSTATUS Status; - - if (nAtom < 0xC000) - { - return 0; - } - - AtomTable = GetLocalAtomTable(); - - Status = RtlDeleteAtomFromAtomTable(AtomTable, - nAtom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return nAtom; - } - - return 0; + return InternalDeleteAtom(TRUE, nAtom); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI FindAtomA(LPCSTR lpString) { - PRTL_ATOM_TABLE AtomTable; - UNICODE_STRING AtomName; - NTSTATUS Status; - ATOM Atom; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - AtomTable = GetLocalAtomTable(); - RtlCreateUnicodeStringFromAsciiz(&AtomName, - (LPSTR)lpString); - Status = RtlLookupAtomInAtomTable(AtomTable, - AtomName.Buffer, - &Atom); - RtlFreeUnicodeString(&AtomName); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; + return InternalFindAtom(TRUE, FALSE, lpString); } - /* * @implemented */ -ATOM STDCALL +ATOM +WINAPI FindAtomW(LPCWSTR lpString) { - PRTL_ATOM_TABLE AtomTable; - ATOM Atom; - NTSTATUS Status; - - if (HIWORD((ULONG)lpString) == 0) - { - if ((ULONG)lpString >= 0xC000) - { - SetLastErrorByStatus(STATUS_INVALID_PARAMETER); - return (ATOM)0; - } - return (ATOM)LOWORD((ULONG)lpString); - } - - AtomTable = GetLocalAtomTable(); - - Status = RtlLookupAtomInAtomTable(AtomTable, - (LPWSTR)lpString, - &Atom); - if (!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return (ATOM)0; - } - - return Atom; -} + return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString); +} /* * @implemented */ -UINT STDCALL +UINT +WINAPI GetAtomNameA(ATOM nAtom, - LPSTR lpBuffer, - int nSize) + LPSTR lpBuffer, + int nSize) { - PRTL_ATOM_TABLE AtomTable; - PWCHAR Buffer; - UNICODE_STRING AtomNameU; - ANSI_STRING AtomName; - ULONG NameLength; - NTSTATUS Status; - - AtomTable = GetLocalAtomTable(); - - NameLength = nSize * sizeof(WCHAR); - Buffer = RtlAllocateHeap(RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - NameLength); - if (Buffer == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - Status = RtlQueryAtomInAtomTable(AtomTable, - nAtom, - NULL, - NULL, - Buffer, - &NameLength); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - SetLastErrorByStatus(Status); - return 0; - } - - RtlInitUnicodeString(&AtomNameU, - Buffer); - AtomName.Buffer = lpBuffer; - AtomName.Length = 0; - AtomName.MaximumLength = nSize; - RtlUnicodeStringToAnsiString(&AtomName, - &AtomNameU, - FALSE); - - NameLength = AtomName.Length; - RtlFreeHeap(RtlGetProcessHeap(), - 0, - Buffer); - - return NameLength; + return InternalGetAtomName(TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize); } - /* * @implemented */ -UINT STDCALL +UINT +WINAPI GetAtomNameW(ATOM nAtom, - LPWSTR lpBuffer, - int nSize) + LPWSTR lpBuffer, + int nSize) { - PRTL_ATOM_TABLE AtomTable; - ULONG NameLength; - NTSTATUS Status; - - AtomTable = GetLocalAtomTable(); - - NameLength = nSize * sizeof(WCHAR); - Status = RtlQueryAtomInAtomTable(AtomTable, - nAtom, - NULL, - NULL, - lpBuffer, - &NameLength); - if (!NT_SUCCESS(Status)) - { - return 0; - } - - return(NameLength / sizeof(WCHAR)); + return InternalGetAtomName(TRUE, + TRUE, + nAtom, + (LPSTR)lpBuffer, + (DWORD)nSize); } - /* EOF */ diff --git a/reactos/lib/rtl/atom.c b/reactos/lib/rtl/atom.c index 166b9796dd1..1c643df3d95 100644 --- a/reactos/lib/rtl/atom.c +++ b/reactos/lib/rtl/atom.c @@ -150,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)); @@ -507,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; } diff --git a/reactos/ntoskrnl/ex/atom.c b/reactos/ntoskrnl/ex/atom.c index be573da2263..0326d51b5c9 100644 --- a/reactos/ntoskrnl/ex/atom.c +++ b/reactos/ntoskrnl/ex/atom.c @@ -13,6 +13,8 @@ #define NDEBUG #include +#define TAG_ATOM TAG('A', 't', 'o', 'm') + /* GLOBALS ****************************************************************/ /* @@ -45,79 +47,6 @@ ExpGetGlobalAtomTable(VOID) return GlobalAtomTable; } -NTSTATUS -NTAPI -RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable, - RTL_ATOM Atom, - PATOM_BASIC_INFORMATION AtomInformation, - ULONG AtomInformationLength, - PULONG ReturnLength) -{ - NTSTATUS Status; - ULONG UsageCount; - ULONG Flags; - ULONG NameLength; - - NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR); - Status = RtlQueryAtomInAtomTable(AtomTable, - Atom, - &UsageCount, - &Flags, - AtomInformation->Name, - &NameLength); - - if (!NT_SUCCESS(Status)) return Status; - DPRINT("NameLength: %lu\n", NameLength); - - if (ReturnLength != NULL) - { - *ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION); - } - - if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - AtomInformation->UsageCount = (USHORT)UsageCount; - AtomInformation->Flags = (USHORT)Flags; - AtomInformation->NameLength = (USHORT)NameLength; - - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable, - RTL_ATOM Atom, - PATOM_TABLE_INFORMATION AtomInformation, - ULONG AtomInformationLength, - PULONG ReturnLength) -{ - ULONG Length; - NTSTATUS Status; - - Length = sizeof(ATOM_TABLE_INFORMATION); - DPRINT("RequiredLength: %lu\n", Length); - - if (ReturnLength) *ReturnLength = Length; - - if (Length > AtomInformationLength) return STATUS_INFO_LENGTH_MISMATCH; - - Status = RtlQueryAtomListInAtomTable(AtomTable, - (AtomInformationLength - Length) / - sizeof(RTL_ATOM), - &AtomInformation->NumberOfAtoms, - AtomInformation->Atoms); - if (NT_SUCCESS(Status)) - { - ReturnLength += AtomInformation->NumberOfAtoms * sizeof(RTL_ATOM); - if (ReturnLength != NULL) *ReturnLength = Length; - } - - return Status; -} - /* FUNCTIONS ****************************************************************/ /* @@ -130,14 +59,96 @@ NtAddAtom(IN PWSTR AtomName, OUT PRTL_ATOM Atom) { PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); + NTSTATUS Status = STATUS_SUCCESS; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + LPWSTR CapturedName = NULL; + ULONG CapturedSize; + RTL_ATOM SafeAtom; + PAGED_CODE(); /* Check for the table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED; - /* FIXME: SEH! */ + /* Check for valid name */ + if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) + { + /* Fail */ + DPRINT1("Atom name too long\n"); + return STATUS_INVALID_PARAMETER; + } - /* Call the worker function */ - return RtlAddAtomToAtomTable(AtomTable, AtomName, Atom); + /* Check if we're called from user-mode*/ + if (PreviousMode != KernelMode) + { + /* Enter SEH */ + _SEH_TRY + { + /* Check if we have a name */ + if (AtomName) + { + /* Probe the atom */ + ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); + + /* Allocate an aligned buffer + the null char */ + CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~ + (sizeof(WCHAR) -1)); + CapturedName = ExAllocatePoolWithTag(PagedPool, + CapturedSize, + TAG_ATOM); + if (!CapturedName) + { + /* Fail the call */ + Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + /* Copy the name and null-terminate it */ + RtlMoveMemory(CapturedName, AtomName, AtomNameLength); + CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; + } + + /* Probe the atom too */ + if (Atom) ProbeForWriteUshort(Atom); + } + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + else + { + /* Simplify code and re-use one variable */ + if (AtomName) CapturedName = AtomName; + } + + /* Make sure probe worked */ + if (NT_SUCCESS(Status)) + { + /* Call the runtime function */ + Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom); + if (NT_SUCCESS(Status) && (Atom)) + { + /* Success and caller wants the atom back.. .enter SEH */ + _SEH_TRY + { + /* Return the atom */ + *Atom = SafeAtom; + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + + /* If we captured anything, free it */ + if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName); + + /* Return to caller */ + return Status; } /* @@ -148,6 +159,7 @@ NTAPI NtDeleteAtom(IN RTL_ATOM Atom) { PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); + PAGED_CODE(); /* Check for valid table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED; @@ -166,14 +178,96 @@ NtFindAtom(IN PWSTR AtomName, OUT PRTL_ATOM Atom) { PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); + NTSTATUS Status = STATUS_SUCCESS; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + LPWSTR CapturedName = NULL; + ULONG CapturedSize; + RTL_ATOM SafeAtom; + PAGED_CODE(); - /* Check for valid table */ + /* Check for the table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED; - /* FIXME: SEH!!! */ + /* Check for valid name */ + if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) + { + /* Fail */ + DPRINT1("Atom name too long\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Check if we're called from user-mode*/ + if (PreviousMode != KernelMode) + { + /* Enter SEH */ + _SEH_TRY + { + /* Check if we have a name */ + if (AtomName) + { + /* Probe the atom */ + ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); + + /* Allocate an aligned buffer + the null char */ + CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~ + (sizeof(WCHAR) -1)); + CapturedName = ExAllocatePoolWithTag(PagedPool, + CapturedSize, + TAG_ATOM); + if (!CapturedName) + { + /* Fail the call */ + Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + /* Copy the name and null-terminate it */ + RtlMoveMemory(CapturedName, AtomName, AtomNameLength); + CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; + } + + /* Probe the atom too */ + if (Atom) ProbeForWriteUshort(Atom); + } + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + else + { + /* Simplify code and re-use one variable */ + if (AtomName) CapturedName = AtomName; + } - /* Call worker function */ - return RtlLookupAtomInAtomTable(AtomTable, AtomName, Atom); + /* Make sure probe worked */ + if (NT_SUCCESS(Status)) + { + /* Call the runtime function */ + Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom); + if (NT_SUCCESS(Status) && (Atom)) + { + /* Success and caller wants the atom back.. .enter SEH */ + _SEH_TRY + { + /* Return the atom */ + *Atom = SafeAtom; + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + + /* If we captured anything, free it */ + if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName); + + /* Return to caller */ + return Status; } /* @@ -188,7 +282,10 @@ NtQueryInformationAtom(RTL_ATOM Atom, PULONG ReturnLength) { PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); + PATOM_BASIC_INFORMATION BasicInformation = AtomInformation; + PATOM_TABLE_INFORMATION TableInformation = AtomInformation; NTSTATUS Status; + ULONG Flags, UsageCount, NameLength; /* Check for valid table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED; @@ -198,23 +295,70 @@ NtQueryInformationAtom(RTL_ATOM Atom, /* Choose class */ switch (AtomInformationClass) { + /* Caller requested info about an atom */ case AtomBasicInformation: - Status = RtlpQueryAtomInformation(AtomTable, - Atom, - AtomInformation, - AtomInformationLength, - ReturnLength); + + /* Size check */ + *ReturnLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name); + if (*ReturnLength > AtomInformationLength) + { + /* Fail */ + DPRINT1("Buffer too small\n"); + return STATUS_INFO_LENGTH_MISMATCH; + } + + /* Prepare query */ + UsageCount = 0; + NameLength = AtomInformationLength - *ReturnLength; + BasicInformation->Name[0] = UNICODE_NULL; + + /* Query the data */ + Status = RtlQueryAtomInAtomTable(AtomTable, + Atom, + &UsageCount, + &Flags, + BasicInformation->Name, + &NameLength); + if (NT_SUCCESS(Status)) + { + /* Return data */ + BasicInformation->UsageCount = (USHORT)UsageCount; + BasicInformation->Flags = (USHORT)Flags; + BasicInformation->NameLength = (USHORT)NameLength; + *ReturnLength += NameLength + sizeof(WCHAR); + } break; + /* Caller requested info about an Atom Table */ case AtomTableInformation: - Status = RtlpQueryAtomTableInformation(AtomTable, - Atom, - AtomInformation, - AtomInformationLength, - ReturnLength); + + /* Size check */ + *ReturnLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms); + if (*ReturnLength > AtomInformationLength) + { + /* Fail */ + DPRINT1("Buffer too small\n"); + return STATUS_INFO_LENGTH_MISMATCH; + } + + /* Query the data */ + Status = RtlQueryAtomListInAtomTable(AtomTable, + (AtomInformationLength - *ReturnLength) / + sizeof(RTL_ATOM), + &TableInformation->NumberOfAtoms, + TableInformation->Atoms); + if (NT_SUCCESS(Status)) + { + /* Update the return length */ + *ReturnLength += TableInformation->NumberOfAtoms * + sizeof(RTL_ATOM); + } break; + /* Caller was on crack */ default: + + /* Unrecognized class */ Status = STATUS_INVALID_INFO_CLASS; } -- 2.17.1