* PROJECT: ReactOS Kernel
* COPYRIGHT: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ex/atom.c
* PURPOSE: Executive Atom Functions
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Gunnar Dalsnes
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
* FIXME: this is WRONG! The global atom table should live in the WinSta struct
* and accessed through a win32k callout (received in PsEstablishWin32Callouts)
* NOTE: There is a session/win32k global atom table also, but its private to
* win32k. Its used for RegisterWindowMessage() and for window classes.
* -Gunnar
*/
PRTL_ATOM_TABLE GlobalAtomTable;
* @name ExpGetGlobalAtomTable
*
* Gets pointer to a global atom table, creates it if not already created
*
* @return Pointer to the RTL_ATOM_TABLE, or NULL if it's impossible
* to create atom table
*
* @remarks Internal function
*
*--*/
PRTL_ATOM_TABLE
NTAPI
ExpGetGlobalAtomTable(VOID)
{
NTSTATUS Status;
if (GlobalAtomTable) return GlobalAtomTable;
Status = RtlCreateAtomTable(37, &GlobalAtomTable);
if (!NT_SUCCESS(Status)) return NULL;
return GlobalAtomTable;
}
* @name NtAddAtom
* @implemented
*
* Function NtAddAtom creates new Atom in Global Atom Table. If Atom
* with the same name already exist, internal Atom counter is incremented.
* See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtAddAtom.html
*
* @param AtomName
* Atom name in Unicode
*
* @param AtomNameLength
* Length of the atom name
*
* @param Atom
* Pointer to RTL_ATOM
*
* @return STATUS_SUCCESS in case of success, proper error code
* otherwise.
*
* @remarks None
*
*--*/
NTSTATUS
NTAPI
NtAddAtom(IN PWSTR AtomName,
IN ULONG AtomNameLength,
OUT PRTL_ATOM Atom)
{
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LPWSTR CapturedName;
ULONG CapturedSize;
RTL_ATOM SafeAtom;
PAGED_CODE();
if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
{
DPRINT1("Atom name too long\n");
return STATUS_INVALID_PARAMETER;
}
if (PreviousMode == KernelMode)
{
CapturedName = AtomName;
}
else
{
if (AtomName)
{
CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &
~(sizeof(WCHAR) -1));
CapturedName = ExAllocatePoolWithTag(PagedPool,
CapturedSize,
TAG_ATOM);
if (!CapturedName)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
_SEH2_TRY
{
ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
if (Atom) ProbeForWriteUshort(Atom);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
CapturedName = NULL;
}
}
Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom);
if (NT_SUCCESS(Status) && (Atom))
{
_SEH2_TRY
{
*Atom = SafeAtom;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
if ((CapturedName != NULL) && (CapturedName != AtomName))
ExFreePoolWithTag(CapturedName, TAG_ATOM);
return Status;
}
* @name NtDeleteAtom
* @implemented
*
* Removes Atom from Global Atom Table. If Atom's reference counter
* is greater then 1, function decrements this counter, but Atom
* stayed in Global Atom Table.
* See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html
*
* @param Atom
* Atom identifier
*
* @return STATUS_SUCCESS in case of success, proper error code
* otherwise.
*
* @remarks None
*
*--*/
NTSTATUS
NTAPI
NtDeleteAtom(IN RTL_ATOM Atom)
{
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
PAGED_CODE();
if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
return RtlDeleteAtomFromAtomTable(AtomTable, Atom);
}
* @name NtFindAtom
* @implemented
*
* Retrieves existing Atom's identifier without incrementing Atom's
* internal counter
* See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html
*
* @param AtomName
* Atom name in Unicode
*
* @param AtomNameLength
* Length of the atom name
*
* @param Atom
* Pointer to RTL_ATOM
*
* @return STATUS_SUCCESS in case of success, proper error code
* otherwise.
*
* @remarks None
*
*--*/
NTSTATUS
NTAPI
NtFindAtom(IN PWSTR AtomName,
IN ULONG AtomNameLength,
OUT PRTL_ATOM Atom)
{
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
_SEH2_VOLATILE LPWSTR CapturedName;
ULONG CapturedSize;
RTL_ATOM SafeAtom;
PAGED_CODE();
if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
{
DPRINT1("Atom name too long\n");
return STATUS_INVALID_PARAMETER;
}
CapturedName = AtomName;
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
if (AtomName)
{
ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
(sizeof(WCHAR) -1));
CapturedName = ExAllocatePoolWithQuotaTag(PagedPool,
CapturedSize,
TAG_ATOM);
RtlCopyMemory(CapturedName, AtomName, AtomNameLength);
CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
if (Atom) ProbeForWriteUshort(Atom);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
if (CapturedName != AtomName)
{
ExFreePoolWithTag(CapturedName, TAG_ATOM);
}
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom);
if (NT_SUCCESS(Status) && (Atom))
{
_SEH2_TRY
{
*Atom = SafeAtom;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
if ((CapturedName) && (CapturedName != AtomName))
ExFreePoolWithTag(CapturedName, TAG_ATOM);
return Status;
}
* @name NtQueryInformationAtom
* @implemented
*
* Gets single Atom properties or reads Global Atom Table
* See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html
*
* @param Atom
* Atom to query. If AtomInformationClass parameter is
* AtomTableInformation, Atom parameter is not used.
*
* @param AtomInformationClass
* See ATOM_INFORMATION_CLASS enumeration type for details
*
* @param AtomInformation
* Result of call - pointer to user's allocated buffer for data
*
* @param AtomInformationLength
* Size of AtomInformation buffer, in bytes
*
* @param ReturnLength
* Pointer to ULONG value containing required AtomInformation
* buffer size
*
* @return STATUS_SUCCESS in case of success, proper error code
* otherwise.
*
* @remarks None
*
*--*/
NTSTATUS
NTAPI
NtQueryInformationAtom(RTL_ATOM Atom,
ATOM_INFORMATION_CLASS AtomInformationClass,
PVOID AtomInformation,
ULONG AtomInformationLength,
PULONG ReturnLength)
{
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
PATOM_BASIC_INFORMATION BasicInformation = AtomInformation;
PATOM_TABLE_INFORMATION TableInformation = AtomInformation;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Flags, UsageCount, NameLength, RequiredLength = 0;
KPROCESSOR_MODE PreviousMode;
PAGED_CODE();
if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
PreviousMode = ExGetPreviousMode();
_SEH2_TRY
{
if (PreviousMode != KernelMode)
{
ProbeForWrite(AtomInformation,
AtomInformationLength,
sizeof(ULONG));
if (ReturnLength != NULL)
{
ProbeForWriteUlong(ReturnLength);
}
}
switch (AtomInformationClass)
{
case AtomBasicInformation:
RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name);
if (RequiredLength > AtomInformationLength)
{
DPRINT1("Buffer too small\n");
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
UsageCount = 0;
NameLength = AtomInformationLength - RequiredLength;
BasicInformation->Name[0] = UNICODE_NULL;
Status = RtlQueryAtomInAtomTable(AtomTable,
Atom,
&UsageCount,
&Flags,
BasicInformation->Name,
&NameLength);
if (NT_SUCCESS(Status))
{
BasicInformation->UsageCount = (USHORT)UsageCount;
BasicInformation->Flags = (USHORT)Flags;
BasicInformation->NameLength = (USHORT)NameLength;
RequiredLength += NameLength + sizeof(WCHAR);
}
break;
case AtomTableInformation:
RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms);
if (RequiredLength > AtomInformationLength)
{
DPRINT1("Buffer too small\n");
Status = STATUS_INFO_LENGTH_MISMATCH;
_SEH2_LEAVE;
}
Status = RtlQueryAtomListInAtomTable(AtomTable,
(AtomInformationLength - RequiredLength) /
sizeof(RTL_ATOM),
&TableInformation->NumberOfAtoms,
TableInformation->Atoms);
if (NT_SUCCESS(Status))
{
RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM);
}
break;
default:
Status = STATUS_INVALID_INFO_CLASS;
break;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
return Status;
}