Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489/* * 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 */
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* GLOBALS ****************************************************************/
/* * 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;
/* PRIVATE FUNCTIONS *********************************************************/
/*++ * @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_TABLENTAPIExpGetGlobalAtomTable(VOID){ NTSTATUS Status;
/* Return it if we have one */ if (GlobalAtomTable) return GlobalAtomTable;
/* Create it */ Status = RtlCreateAtomTable(37, &GlobalAtomTable);
/* If we couldn't create it, return NULL */ if (!NT_SUCCESS(Status)) return NULL;
/* Return the newly created one */ return GlobalAtomTable;}
/* FUNCTIONS ****************************************************************/
/*++ * @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 * *--*/NTSTATUSNTAPINtAddAtom(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();
/* Check for the table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
/* 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 or kernel-mode */ if (PreviousMode == KernelMode) { /* Re-use the given name if kernel mode */ CapturedName = AtomName; } else { /* Check if we have a name */ if (AtomName) { /* 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 */ return STATUS_INSUFFICIENT_RESOURCES; }
/* Enter SEH */ _SEH2_TRY { /* Probe the atom */ ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
/* Copy the name and null-terminate it */ RtlCopyMemory(CapturedName, AtomName, AtomNameLength); CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Probe the atom too */ if (Atom) ProbeForWriteUshort(Atom); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* No name */ CapturedName = NULL; } }
/* Call the runtime function */ Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom); if (NT_SUCCESS(Status) && (Atom)) { /* Success and caller wants the atom back.. .enter SEH */ _SEH2_TRY { /* Return the atom */ *Atom = SafeAtom; } _SEH2_EXCEPT(ExSystemExceptionFilter()) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
/* If we captured anything, free it */ if ((CapturedName != NULL) && (CapturedName != AtomName)) ExFreePoolWithTag(CapturedName, TAG_ATOM);
/* Return to caller */ 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 * *--*/NTSTATUSNTAPINtDeleteAtom(IN RTL_ATOM Atom){ PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); PAGED_CODE();
/* Check for valid table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
/* Call worker function */ 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 * *--*/NTSTATUSNTAPINtFindAtom(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();
/* Check for the table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
/* Check for valid name */ if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) { /* Fail */ DPRINT1("Atom name too long\n"); return STATUS_INVALID_PARAMETER; }
/* Re-use the given name if kernel mode or no atom name */ CapturedName = AtomName;
/* Check if we're called from user-mode*/ if (PreviousMode != KernelMode) { /* Enter SEH */ _SEH2_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 = ExAllocatePoolWithQuotaTag(PagedPool, CapturedSize, TAG_ATOM); /* Copy the name and null-terminate it */ RtlCopyMemory(CapturedName, AtomName, AtomNameLength); CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Probe the atom too */ if (Atom) ProbeForWriteUshort(Atom); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { if (CapturedName != AtomName) { ExFreePoolWithTag(CapturedName, TAG_ATOM); }
/* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Call the runtime function */ Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom); if (NT_SUCCESS(Status) && (Atom)) { /* Success and caller wants the atom back... enter SEH */ _SEH2_TRY { /* Return the atom */ *Atom = SafeAtom; } _SEH2_EXCEPT(ExSystemExceptionFilter()) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
/* If we captured anything, free it */ if ((CapturedName) && (CapturedName != AtomName)) ExFreePoolWithTag(CapturedName, TAG_ATOM);
/* Return to caller */ 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 * *--*/NTSTATUSNTAPINtQueryInformationAtom(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();
/* Check for valid table */ if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
PreviousMode = ExGetPreviousMode();
_SEH2_TRY { /* Probe the parameters */ if (PreviousMode != KernelMode) { ProbeForWrite(AtomInformation, AtomInformationLength, sizeof(ULONG));
if (ReturnLength != NULL) { ProbeForWriteUlong(ReturnLength); } }
/* Choose class */ switch (AtomInformationClass) { /* Caller requested info about an atom */ case AtomBasicInformation:
/* Size check */ RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name); if (RequiredLength > AtomInformationLength) { /* Fail */ DPRINT1("Buffer too small\n"); Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; }
/* Prepare query */ UsageCount = 0; NameLength = AtomInformationLength - RequiredLength; 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; RequiredLength += NameLength + sizeof(WCHAR); } break;
/* Caller requested info about an Atom Table */ case AtomTableInformation:
/* Size check */ RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms); if (RequiredLength > AtomInformationLength) { /* Fail */ DPRINT1("Buffer too small\n"); Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; }
/* Query the data */ Status = RtlQueryAtomListInAtomTable(AtomTable, (AtomInformationLength - RequiredLength) / sizeof(RTL_ATOM), &TableInformation->NumberOfAtoms, TableInformation->Atoms); if (NT_SUCCESS(Status)) { /* Update the return length */ RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM); } break;
/* Caller was on crack */ default:
/* Unrecognized class */ Status = STATUS_INVALID_INFO_CLASS; break; }
/* Return the required size */ if (ReturnLength != NULL) { *ReturnLength = RequiredLength; } } _SEH2_EXCEPT(ExSystemExceptionFilter()) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* Return to caller */ return Status;}
/* EOF */