windows-nt/Source/XPSP1/NT/base/ntos/ex/exatom.c
2020-09-26 16:20:57 +08:00

489 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
exatom.c
Abstract:
This file contains functions for manipulating global atom tables
stored in kernel space.
Author:
Steve Wood (stevewo) 13-Dec-1995
Revision History:
--*/
#include "exp.h"
#pragma hdrstop
//
// Local Procedure prototype
//
PVOID
ExpGetGlobalAtomTable (
);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, NtAddAtom)
#pragma alloc_text(PAGE, NtFindAtom)
#pragma alloc_text(PAGE, NtDeleteAtom)
#pragma alloc_text(PAGE, NtQueryInformationAtom)
#pragma alloc_text(PAGE, ExpGetGlobalAtomTable)
#endif
#define COPY_STACK_SIZE 128
NTSYSAPI
NTSTATUS
NTAPI
NtAddAtom (
IN PWSTR AtomName,
IN ULONG Length,
OUT PRTL_ATOM Atom OPTIONAL
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
RTL_ATOM ReturnAtom;
PVOID AtomTable = ExpGetGlobalAtomTable();
KPROCESSOR_MODE PreviousMode;
PWSTR CapturedAtomNameBuffer;
ULONG AllocLength;
UCHAR StackArray[COPY_STACK_SIZE];
PAGED_CODE();
if (AtomTable == NULL) {
return STATUS_ACCESS_DENIED;
}
if (Length > (RTL_ATOM_MAXIMUM_NAME_LENGTH * sizeof(WCHAR))) {
return STATUS_INVALID_PARAMETER;
}
PreviousMode = KeGetPreviousMode();
CapturedAtomNameBuffer = AtomName;
Status = STATUS_SUCCESS;
if (PreviousMode != KernelMode) {
if (ARGUMENT_PRESENT (Atom)) {
try {
ProbeForWriteUshort( Atom );
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
}
if (ARGUMENT_PRESENT (AtomName)) {
AllocLength = (Length + sizeof( UNICODE_NULL ))&~(sizeof (WCHAR)-1);
try {
ProbeForRead( AtomName, Length, sizeof( WCHAR ) );
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
if (AllocLength <= COPY_STACK_SIZE) {
CapturedAtomNameBuffer = (PWSTR) StackArray;
}
else {
CapturedAtomNameBuffer = ExAllocatePoolWithTag (PagedPool, AllocLength, 'motA');
if (CapturedAtomNameBuffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
try {
RtlCopyMemory( CapturedAtomNameBuffer, AtomName, Length );
} except (EXCEPTION_EXECUTE_HANDLER) {
if (CapturedAtomNameBuffer != (PWSTR) StackArray) {
ExFreePool (CapturedAtomNameBuffer);
}
return GetExceptionCode();
}
CapturedAtomNameBuffer[Length / sizeof (WCHAR)] = '\0';
}
}
if (NT_SUCCESS (Status)) {
Status = RtlAddAtomToAtomTable (AtomTable, CapturedAtomNameBuffer, &ReturnAtom);
if ((ARGUMENT_PRESENT (Atom)) && (NT_SUCCESS (Status))) {
if (PreviousMode != KernelMode) {
try {
*Atom = ReturnAtom;
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
}
else {
*Atom = ReturnAtom;
}
}
}
if ((CapturedAtomNameBuffer != AtomName) &&
(CapturedAtomNameBuffer != (PWSTR) StackArray)) {
ExFreePool (CapturedAtomNameBuffer);
}
return Status;
}
NTSYSAPI
NTSTATUS
NTAPI
NtFindAtom (
IN PWSTR AtomName,
IN ULONG Length,
OUT PRTL_ATOM Atom OPTIONAL
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
RTL_ATOM ReturnAtom;
PVOID AtomTable = ExpGetGlobalAtomTable();
KPROCESSOR_MODE PreviousMode;
PWSTR CapturedAtomNameBuffer;
ULONG AllocLength;
UCHAR StackArray[COPY_STACK_SIZE];
PAGED_CODE();
if (AtomTable == NULL) {
return STATUS_ACCESS_DENIED;
}
if (Length > (RTL_ATOM_MAXIMUM_NAME_LENGTH * sizeof(WCHAR))) {
return STATUS_INVALID_PARAMETER;
}
PreviousMode = KeGetPreviousMode();
CapturedAtomNameBuffer = AtomName;
Status = STATUS_SUCCESS;
if (PreviousMode != KernelMode) {
if (ARGUMENT_PRESENT (Atom)) {
try {
ProbeForWriteUshort (Atom);
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
}
if (ARGUMENT_PRESENT (AtomName)) {
AllocLength = (Length + sizeof( UNICODE_NULL ))&~(sizeof (WCHAR)-1);
try {
ProbeForRead (AtomName, Length, sizeof (WCHAR));
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
if (AllocLength <= COPY_STACK_SIZE) {
CapturedAtomNameBuffer = (PWSTR) StackArray;
}
else {
CapturedAtomNameBuffer = ExAllocatePoolWithTag (PagedPool, AllocLength, 'motA');
if (CapturedAtomNameBuffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
try {
RtlCopyMemory (CapturedAtomNameBuffer, AtomName, Length);
} except (EXCEPTION_EXECUTE_HANDLER) {
if (CapturedAtomNameBuffer != (PWSTR) StackArray) {
ExFreePool (CapturedAtomNameBuffer);
}
return GetExceptionCode();
}
CapturedAtomNameBuffer[Length / sizeof (WCHAR)] = '\0';
}
}
if (NT_SUCCESS( Status )) {
Status = RtlLookupAtomInAtomTable (AtomTable, CapturedAtomNameBuffer, &ReturnAtom);
if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(Atom)) {
try {
*Atom = ReturnAtom;
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
}
}
if ((CapturedAtomNameBuffer != AtomName) &&
(CapturedAtomNameBuffer != (PWSTR) StackArray)) {
ExFreePool (CapturedAtomNameBuffer);
}
return Status;
}
NTSYSAPI
NTSTATUS
NTAPI
NtDeleteAtom (
IN RTL_ATOM Atom
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PVOID AtomTable = ExpGetGlobalAtomTable();
PAGED_CODE();
if (AtomTable == NULL) {
return STATUS_ACCESS_DENIED;
}
Status = RtlDeleteAtomFromAtomTable( AtomTable, Atom );
return Status;
}
NTSYSAPI
NTSTATUS
NTAPI
NtQueryInformationAtom(
IN RTL_ATOM Atom,
IN ATOM_INFORMATION_CLASS AtomInformationClass,
OUT PVOID AtomInformation,
IN ULONG AtomInformationLength,
OUT PULONG ReturnLength OPTIONAL
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
ULONG RequiredLength;
ULONG UsageCount;
ULONG NameLength;
ULONG AtomFlags;
PATOM_BASIC_INFORMATION BasicInfo;
PATOM_TABLE_INFORMATION TableInfo;
PVOID AtomTable = ExpGetGlobalAtomTable();
PAGED_CODE();
if (AtomTable == NULL) {
return STATUS_ACCESS_DENIED;
}
//
// Assume successful completion.
//
Status = STATUS_SUCCESS;
try {
//
// Get previous processor mode and probe output argument if necessary.
//
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode) {
ProbeForWrite( AtomInformation,
AtomInformationLength,
sizeof( ULONG ));
if (ARGUMENT_PRESENT( ReturnLength )) {
ProbeForWriteUlong( ReturnLength );
}
}
RequiredLength = 0;
switch (AtomInformationClass) {
case AtomBasicInformation:
RequiredLength = FIELD_OFFSET( ATOM_BASIC_INFORMATION, Name );
if (AtomInformationLength < RequiredLength) {
return STATUS_INFO_LENGTH_MISMATCH;
}
BasicInfo = (PATOM_BASIC_INFORMATION)AtomInformation;
UsageCount = 0;
NameLength = AtomInformationLength - RequiredLength;
BasicInfo->Name[ 0 ] = UNICODE_NULL;
Status = RtlQueryAtomInAtomTable( AtomTable,
Atom,
&UsageCount,
&AtomFlags,
&BasicInfo->Name[0],
&NameLength );
if (NT_SUCCESS(Status)) {
BasicInfo->UsageCount = (USHORT)UsageCount;
BasicInfo->Flags = (USHORT)AtomFlags;
BasicInfo->NameLength = (USHORT)NameLength;
RequiredLength += NameLength + sizeof( UNICODE_NULL );
}
break;
case AtomTableInformation:
RequiredLength = FIELD_OFFSET( ATOM_TABLE_INFORMATION, Atoms );
if (AtomInformationLength < RequiredLength) {
return STATUS_INFO_LENGTH_MISMATCH;
}
TableInfo = (PATOM_TABLE_INFORMATION)AtomInformation;
Status = RtlQueryAtomsInAtomTable( AtomTable,
(AtomInformationLength - RequiredLength) / sizeof( RTL_ATOM ),
&TableInfo->NumberOfAtoms,
&TableInfo->Atoms[0] );
if (NT_SUCCESS(Status)) {
RequiredLength += TableInfo->NumberOfAtoms * sizeof( RTL_ATOM );
}
break;
default:
Status = STATUS_INVALID_INFO_CLASS;
break;
}
if (ARGUMENT_PRESENT( ReturnLength )) {
*ReturnLength = RequiredLength;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
return Status;
}
//
// Local support routine
//
PKWIN32_GLOBALATOMTABLE_CALLOUT ExGlobalAtomTableCallout;
PVOID
ExpGetGlobalAtomTable (
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
if (ExGlobalAtomTableCallout != NULL) {
return ((*ExGlobalAtomTableCallout)());
}
#if DBG
DbgPrint( "EX: ExpGetGlobalAtomTable is about to return NULL!\n" );
DbgBreakPoint();
#endif
return NULL;
}