|
|
/*++
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; }
|