reactos/ntoskrnl/ob/obref.c
Joachim Henze 688875e411 [0.4.7][CDFS_NEW/NTOSKRNL/NDK] Switch from our old CDFS to MS-PL CDFS_NEW
The main motivation to switch to that newer driver is, that our old one
simply can not read all isos. Especially complex ones made trouble and were
only shown as empty in explorer.
It is still possible to build and use the old driver when needed, only thing
that needs to be done for that is to revert 0.4.8-dev-164-g ec6b3ecbe4

Porting back the state up to 0.4.8-release-100-g8f947b5 implies:

Fixing the following JIRA-IDs (or avoid introducing them):
CORE-18029 "Mute noisy DPRINT 'SectionObject has ImageSection'"
CORE-17405 "Fix a macro-copy-paste and shrink the binary size"
CORE-15659 "Unable to build the gcc Release version in Windows using RosBE 2.1.6 (module cdfs fails)"
CORE-14315 "CDFS_NEW assertion during first stage setup due to new CcPerformReadAhead"
CORE-14128 "Avast! Free Antivirus 7.0 hangs the system when trying to detect a newly created virus"
CORE-14067 "CDFS_NEW assertions and exceptions"
CORE-14003 "Shutting down LiveCD asserts since introduction of MS PL CDFS_NEW"
CORE-13184 "Restore ability to install from disk-image"

by picking the following commits:
0.4.8-release-100-g 8f947b5322 [NTOSKRNL] Mute noisy DPRINT 'SectionObject has ImageSection' CORE-18029
0.4.8-release-80-g eb1ea19588 [CDFS_NEW] == 0.4.15-dev-1456-g 889eab7 CORE-17405
0.4.8-release-62-g 8c07aad4a8 [CDFS_NEW/XDK] == 0.4.11-dev-39-g a2f9762 + 0.4.11-dev-40-g 6d7ec8c CORE-14067
0.4.8-release-3-g 5d976d04e8 [CDFS_NEW] == 0.4.12-dev-431-g bccad87f3c + 0.4.12-dev-432-g 3463b2db9f CORE-15659
0.4.8-RC-3-g 51f9494d48 [CDFS_NEW] superseded later by the proper fix 0.4.8-release-62-g 8c07aad4a8 CORE-14067
0.4.8-dev-1069-g a5e89014dc [CDFS_NEW] CORE-14315
0.4.8-dev-475-g a59d4674de [NTOSKRNL] io/iomgr/device.c (forgotten assert) CORE-14128
0.4.8-dev-221-g 9d67a24799 [CDFS_NEW]
0.4.8-dev-220-g 67a7e45e35 [CDFS_NEW/DOC]
0.4.8-dev-219-g 6a3bbf24e0 [CDFS_NEW]
0.4.8-dev-218-g ec26cde4a1 [CDFS_NEW]
0.4.8-dev-217-g bc2378a356 [CDFS_NEW]
0.4.8-dev-216-g 5429771b99 [CDFS_NEW]
0.4.8-dev-215-g fd34548263 [CDFS_NEW] Sync with MS-PL driver
0.4.8-dev-164-g ec6b3ecbe4 [FILESYSTEMS] switch from CDFS to CDFS_NEW in CMakeLists.txt
0.4.8-dev-160-g 2b217e4ecf [NTOSKRNL] Mute spam CcSetReadAheadGranularity()
0.4.8-dev-159-g 64cb138a67 [NTOSKRNL] Mute spam CcPurgeCacheSection()
0.4.8-dev-150-g f723d230a0 [CDFS_NEW]
0.4.8-dev-133-g faee3753ea [CDFS_NEW] CORE-14003
0.4.8-dev-132-g 1d777ffab5 [NTOSKRNL] iofunc.c CORE-14003
0.4.8-dev-131-g c3d5a3f2bd [NTOSKRNL] iofunc.c CORE-14003
0.4.8-dev-130-g 3b64f7f8fb [NTOSKRNL] ob/obref.c & co CORE-14003
0.4.8-dev-129-g 7eefe70294 [NTOSKRNL] io/iomgr.c & co CORE-14003
0.4.8-dev-127-g 5f255827d3 [CDFS_NEW]
0.4.8-dev-126-g 1bef48796e [NTOSKRNL] just a comment, superseded later
0.4.8-dev-125-g cbf0430b56 [CDFS_NEW]
0.4.8-dev-123-g f88fe43abd [NTOSKRNL] io/iomgr/device.c (forbidden DPRINT)
0.4.8-dev-122-g 6c73385625 [CDFS_NEW] CORE-13184
0.4.8-dev-97-g 94298313c0 [CDFS_NEW]
0.4.8-dev-95-g e88eeb21af [CDFS_NEW/NTOSKRNL] CcWaitForCurrentLazyWriterActivity() stub return Success
0.4.8-dev-94-g 03d5be6437 [CDFS_NEW]
0.4.8-dev-93-g fa1c60db50 [CDFS_NEW]
0.4.8-dev-92-g 8b2fd60829 [CDFS_NEW]
0.4.8-dev-91-g e4da7ecc50 [CDFS_NEW]
0.4.8-dev-90-g 7b19676e2b [CDFS_NEW]
0.4.8-dev-89-g 3d4b8783fd [CDFS_NEW]
0.4.8-dev-88-g 818025ecc8 [CDFS_NEW]
0.4.8-dev-87-g 2639dd6736 [CDFS_NEW]
0.4.8-dev-86-g 755bdb5d0b [CDFS_NEW]
0.4.8-dev-85-g 3cbcb1bade [CDFS_NEW]

and mute spam in opcode INSTEAD of picking:
0.4.8-dev-165-g 2284a457a3 [NTOSKRNL] oplock.c Fixup
0.4.8-dev-163-g d3d5853956 [NTOSKRNL] oplock.c Implement oplock-support
0.4.12-dev-232-g f488102c86 [CDFS] was also left out for now

I am aware, that the backport introduces white-space-glitches within CDFS_NEW.
I decided to live with them in favor of better sync to master and newer releases.
2022-01-27 21:11:23 +01:00

710 lines
21 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ob/obref.c
* PURPOSE: Manages the referencing and de-referencing of all Objects,
* as well as the Object Fast Reference implementation.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Thomas Weidenmueller (w3seek@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
extern ULONG ObpAccessProtectCloseBit;
/* PRIVATE FUNCTIONS *********************************************************/
BOOLEAN
FASTCALL
ObReferenceObjectSafe(IN PVOID Object)
{
POBJECT_HEADER ObjectHeader;
LONG OldValue, NewValue;
/* Get the object header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
/* Get the current reference count and fail if it's zero */
OldValue = ObjectHeader->PointerCount;
if (!OldValue) return FALSE;
/* Start reference loop */
do
{
/* Increase the reference count */
NewValue = InterlockedCompareExchange(&ObjectHeader->PointerCount,
OldValue + 1,
OldValue);
if (OldValue == NewValue) return TRUE;
/* Keep looping */
OldValue = NewValue;
} while (OldValue);
/* If we got here, then the reference count is now 0 */
return FALSE;
}
VOID
NTAPI
ObpDeferObjectDeletion(IN POBJECT_HEADER Header)
{
PVOID Entry;
/* Loop while trying to update the list */
do
{
/* Get the current entry */
Entry = ObpReaperList;
/* Link our object to the list */
Header->NextToFree = Entry;
/* Update the list */
} while (InterlockedCompareExchangePointer(&ObpReaperList,
Header,
Entry) != Entry);
/* Queue the work item if needed */
if (!Entry) ExQueueWorkItem(&ObpReaperWorkItem, CriticalWorkQueue);
}
LONG
FASTCALL
ObReferenceObjectEx(IN PVOID Object,
IN LONG Count)
{
/* Increment the reference count and return the count now */
return InterlockedExchangeAdd(&OBJECT_TO_OBJECT_HEADER(Object)->
PointerCount,
Count) + Count;
}
LONG
FASTCALL
ObDereferenceObjectEx(IN PVOID Object,
IN LONG Count)
{
POBJECT_HEADER Header;
LONG NewCount;
/* Extract the object header */
Header = OBJECT_TO_OBJECT_HEADER(Object);
/* Check whether the object can now be deleted. */
NewCount = InterlockedExchangeAdd(&Header->PointerCount, -Count) - Count;
if (!NewCount) ObpDeferObjectDeletion(Header);
/* Return the current count */
return NewCount;
}
VOID
FASTCALL
ObInitializeFastReference(IN PEX_FAST_REF FastRef,
IN PVOID Object OPTIONAL)
{
/* Check if we were given an object and reference it 7 times */
if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Setup the fast reference */
ExInitializeFastReference(FastRef, Object);
}
PVOID
FASTCALL
ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef)
{
PVOID Object;
EX_FAST_REF OldValue = *FastRef;
/* Get the object and reference it slowly */
Object = ExGetObjectFastReference(OldValue);
if (Object) ObReferenceObject(Object);
return Object;
}
PVOID
FASTCALL
ObFastReferenceObject(IN PEX_FAST_REF FastRef)
{
EX_FAST_REF OldValue;
ULONG_PTR Count;
PVOID Object;
/* Reference the object and get it pointer */
OldValue = ExAcquireFastReference(FastRef);
Object = ExGetObjectFastReference(OldValue);
/* Check how many references are left */
Count = ExGetCountFastReference(OldValue);
/* Check if the reference count is over 1 */
if (Count > 1) return Object;
/* Check if the reference count has reached 0 */
if (!Count) return NULL;
/* Otherwise, reference the object 7 times */
ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Now update the reference count */
if (!ExInsertFastReference(FastRef, Object))
{
/* We failed: completely dereference the object */
ObDereferenceObjectEx(Object, MAX_FAST_REFS);
}
/* Return the Object */
return Object;
}
VOID
FASTCALL
ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
IN PVOID Object)
{
/* Release a fast reference. If this failed, use the slow path */
if (!ExReleaseFastReference(FastRef, Object)) ObDereferenceObject(Object);
}
PVOID
FASTCALL
ObFastReplaceObject(IN PEX_FAST_REF FastRef,
PVOID Object)
{
EX_FAST_REF OldValue;
PVOID OldObject;
ULONG Count;
/* Check if we were given an object and reference it 7 times */
if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
/* Do the swap */
OldValue = ExSwapFastReference(FastRef, Object);
OldObject = ExGetObjectFastReference(OldValue);
/* Check if we had an active object and dereference it */
Count = ExGetCountFastReference(OldValue);
if ((OldObject) && (Count)) ObDereferenceObjectEx(OldObject, Count);
/* Return the old object */
return OldObject;
}
NTSTATUS
NTAPI
ObReferenceFileObjectForWrite(IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode,
OUT PFILE_OBJECT *FileObject,
OUT POBJECT_HANDLE_INFORMATION HandleInformation)
{
NTSTATUS Status;
PHANDLE_TABLE HandleTable;
POBJECT_HEADER ObjectHeader;
PHANDLE_TABLE_ENTRY HandleEntry;
ACCESS_MASK GrantedAccess, DesiredAccess;
/* Assume failure */
*FileObject = NULL;
/* Check if this is a special handle */
if (HandleToLong(Handle) < 0)
{
/* Make sure we have a valid kernel handle */
if (AccessMode != KernelMode || Handle == NtCurrentProcess() || Handle == NtCurrentThread())
{
return STATUS_INVALID_HANDLE;
}
/* Use the kernel handle table and get the actual handle value */
Handle = ObKernelHandleToHandle(Handle);
HandleTable = ObpKernelHandleTable;
}
else
{
/* Otherwise use this process's handle table */
HandleTable = PsGetCurrentProcess()->ObjectTable;
}
ASSERT(HandleTable != NULL);
KeEnterCriticalRegion();
/* Get the handle entry */
HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
if (HandleEntry)
{
/* Get the object header and validate the type*/
ObjectHeader = ObpGetHandleObject(HandleEntry);
/* Get the desired access from the file object */
if (!NT_SUCCESS(IoComputeDesiredAccessFileObject((PFILE_OBJECT)&ObjectHeader->Body,
&DesiredAccess)))
{
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
else
{
/* Extract the granted access from the handle entry */
if (BooleanFlagOn(NtGlobalFlag, FLG_KERNEL_STACK_TRACE_DB))
{
/* FIXME: Translate granted access */
GrantedAccess = HandleEntry->GrantedAccess;
}
else
{
GrantedAccess = HandleEntry->GrantedAccess & ~ObpAccessProtectCloseBit;
}
/* FIXME: Get handle information for audit */
HandleInformation->GrantedAccess = GrantedAccess;
/* FIXME: Get handle attributes */
HandleInformation->HandleAttributes = 0;
/* Do granted and desired access match? */
if (GrantedAccess & DesiredAccess)
{
/* FIXME: Audit access if required */
/* Reference the object directly since we have its header */
InterlockedIncrement(&ObjectHeader->PointerCount);
/* Unlock the handle */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
KeLeaveCriticalRegion();
*FileObject = (PFILE_OBJECT)&ObjectHeader->Body;
/* Return success */
ASSERT(*FileObject != NULL);
return STATUS_SUCCESS;
}
/* No match, deny write access */
Status = STATUS_ACCESS_DENIED;
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
}
}
else
{
Status = STATUS_INVALID_HANDLE;
}
/* Return failure status */
KeLeaveCriticalRegion();
return Status;
}
/* PUBLIC FUNCTIONS *********************************************************/
LONG_PTR
FASTCALL
ObfReferenceObject(IN PVOID Object)
{
ASSERT(Object);
/* Get the header and increment the reference count */
return InterlockedIncrement(&OBJECT_TO_OBJECT_HEADER(Object)->PointerCount);
}
LONG_PTR
FASTCALL
ObfDereferenceObject(IN PVOID Object)
{
POBJECT_HEADER Header;
LONG_PTR OldCount;
/* Extract the object header */
Header = OBJECT_TO_OBJECT_HEADER(Object);
if (Header->PointerCount < Header->HandleCount)
{
DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name);
return Header->PointerCount;
}
/* Check whether the object can now be deleted. */
OldCount = InterlockedDecrement(&Header->PointerCount);
if (!OldCount)
{
/* Sanity check */
ASSERT(Header->HandleCount == 0);
/* Check if APCs are still active */
if (!KeAreAllApcsDisabled())
{
/* Remove the object */
ObpDeleteObject(Object, FALSE);
}
else
{
/* Add us to the deferred deletion list */
ObpDeferObjectDeletion(Header);
}
}
/* Return the old count */
return OldCount;
}
VOID
NTAPI
ObDereferenceObjectDeferDelete(IN PVOID Object)
{
POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
/* Check whether the object can now be deleted. */
if (!InterlockedDecrement(&Header->PointerCount))
{
/* Add us to the deferred deletion list */
ObpDeferObjectDeletion(Header);
}
}
#undef ObDereferenceObject
VOID
NTAPI
ObDereferenceObject(IN PVOID Object)
{
/* Call the fastcall function */
ObfDereferenceObject(Object);
}
NTSTATUS
NTAPI
ObReferenceObjectByPointer(IN PVOID Object,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode)
{
POBJECT_HEADER Header;
/* Get the header */
Header = OBJECT_TO_OBJECT_HEADER(Object);
/*
* Validate object type if the call is for UserMode.
* NOTE: Unless it's a symbolic link (Caz Yokoyama [MSFT])
*/
if ((Header->Type != ObjectType) && ((AccessMode != KernelMode) ||
(ObjectType == ObSymbolicLinkType)))
{
/* Invalid type */
return STATUS_OBJECT_TYPE_MISMATCH;
}
/* Increment the reference count and return success */
InterlockedIncrement(&Header->PointerCount);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext,
OUT PVOID* ObjectPtr)
{
PVOID Object = NULL;
UNICODE_STRING ObjectName;
NTSTATUS Status;
OBP_LOOKUP_CONTEXT Context;
AUX_ACCESS_DATA AuxData;
ACCESS_STATE AccessState;
PAGED_CODE();
/* Fail quickly */
if (!ObjectPath) return STATUS_OBJECT_NAME_INVALID;
/* Capture the name */
Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/* We also need a valid name after capture */
if (!ObjectName.Length) return STATUS_OBJECT_NAME_INVALID;
/* Check if we didn't get an access state */
if (!PassedAccessState)
{
/* Use our built-in access state */
PassedAccessState = &AccessState;
Status = SeCreateAccessState(&AccessState,
&AuxData,
DesiredAccess,
&ObjectType->TypeInfo.GenericMapping);
if (!NT_SUCCESS(Status)) goto Quickie;
}
/* Find the object */
*ObjectPtr = NULL;
Status = ObpLookupObjectName(NULL,
&ObjectName,
Attributes,
ObjectType,
AccessMode,
ParseContext,
NULL,
NULL,
PassedAccessState,
&Context,
&Object);
/* Cleanup after lookup */
ObpReleaseLookupContext(&Context);
/* Check if the lookup succeeded */
if (NT_SUCCESS(Status))
{
/* Check if access is allowed */
if (ObpCheckObjectReference(Object,
PassedAccessState,
FALSE,
AccessMode,
&Status))
{
/* Return the object */
*ObjectPtr = Object;
}
}
/* Free the access state */
if (PassedAccessState == &AccessState)
{
SeDeleteAccessState(PassedAccessState);
}
Quickie:
/* Free the captured name if we had one, and return status */
ObpFreeObjectNameBuffer(&ObjectName);
return Status;
}
NTSTATUS
NTAPI
ObReferenceObjectByHandle(IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID* Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
PHANDLE_TABLE_ENTRY HandleEntry;
POBJECT_HEADER ObjectHeader;
ACCESS_MASK GrantedAccess;
ULONG Attributes;
PEPROCESS CurrentProcess;
PVOID HandleTable;
PETHREAD CurrentThread;
NTSTATUS Status;
PAGED_CODE();
/* Assume failure */
*Object = NULL;
/* Check if this is a special handle */
if (HandleToLong(Handle) < 0)
{
/* Check if this is the current process */
if (Handle == NtCurrentProcess())
{
/* Check if this is the right object type */
if ((ObjectType == PsProcessType) || !(ObjectType))
{
/* Get the current process and granted access */
CurrentProcess = PsGetCurrentProcess();
GrantedAccess = CurrentProcess->GrantedAccess;
/* Validate access */
/* ~GrantedAccess = RefusedAccess.*/
/* ~GrantedAccess & DesiredAccess = list of refused bits. */
/* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
if ((AccessMode == KernelMode) ||
!(~GrantedAccess & DesiredAccess))
{
/* Check if the caller wanted handle information */
if (HandleInformation)
{
/* Return it */
HandleInformation->HandleAttributes = 0;
HandleInformation->GrantedAccess = GrantedAccess;
}
/* Reference ourselves */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentProcess);
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
/* Return the pointer */
*Object = CurrentProcess;
ASSERT(*Object != NULL);
Status = STATUS_SUCCESS;
}
else
{
/* Access denied */
Status = STATUS_ACCESS_DENIED;
}
}
else
{
/* The caller used this special handle value with a non-process type */
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
/* Return the status */
return Status;
}
else if (Handle == NtCurrentThread())
{
/* Check if this is the right object type */
if ((ObjectType == PsThreadType) || !(ObjectType))
{
/* Get the current process and granted access */
CurrentThread = PsGetCurrentThread();
GrantedAccess = CurrentThread->GrantedAccess;
/* Validate access */
/* ~GrantedAccess = RefusedAccess.*/
/* ~GrantedAccess & DesiredAccess = list of refused bits. */
/* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
if ((AccessMode == KernelMode) ||
!(~GrantedAccess & DesiredAccess))
{
/* Check if the caller wanted handle information */
if (HandleInformation)
{
/* Return it */
HandleInformation->HandleAttributes = 0;
HandleInformation->GrantedAccess = GrantedAccess;
}
/* Reference ourselves */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentThread);
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
/* Return the pointer */
*Object = CurrentThread;
ASSERT(*Object != NULL);
Status = STATUS_SUCCESS;
}
else
{
/* Access denied */
Status = STATUS_ACCESS_DENIED;
}
}
else
{
/* The caller used this special handle value with a non-process type */
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
/* Return the status */
return Status;
}
else if (AccessMode == KernelMode)
{
/* Use the kernel handle table and get the actual handle value */
Handle = ObKernelHandleToHandle(Handle);
HandleTable = ObpKernelHandleTable;
}
else
{
/* Invalid access, fail */
return STATUS_INVALID_HANDLE;
}
}
else
{
/* Otherwise use this process's handle table */
HandleTable = PsGetCurrentProcess()->ObjectTable;
}
/* Enter a critical region while we touch the handle table */
ASSERT(HandleTable != NULL);
KeEnterCriticalRegion();
/* Get the handle entry */
HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
if (HandleEntry)
{
/* Get the object header and validate the type*/
ObjectHeader = ObpGetHandleObject(HandleEntry);
if (!(ObjectType) || (ObjectType == ObjectHeader->Type))
{
/* Get the granted access and validate it */
GrantedAccess = HandleEntry->GrantedAccess;
/* Validate access */
/* ~GrantedAccess = RefusedAccess.*/
/* ~GrantedAccess & DesiredAccess = list of refused bits. */
/* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
if ((AccessMode == KernelMode) ||
!(~GrantedAccess & DesiredAccess))
{
/* Reference the object directly since we have its header */
InterlockedIncrement(&ObjectHeader->PointerCount);
/* Mask out the internal attributes */
Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
/* Check if the caller wants handle information */
if (HandleInformation)
{
/* Fill out the information */
HandleInformation->HandleAttributes = Attributes;
HandleInformation->GrantedAccess = GrantedAccess;
}
/* Return the pointer */
*Object = &ObjectHeader->Body;
/* Unlock the handle */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
KeLeaveCriticalRegion();
/* Return success */
ASSERT(*Object != NULL);
return STATUS_SUCCESS;
}
else
{
/* Requested access failed */
DPRINT("Rights not granted: %x\n", ~GrantedAccess & DesiredAccess);
Status = STATUS_ACCESS_DENIED;
}
}
else
{
/* Invalid object type */
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
/* Unlock the entry */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
}
else
{
/* Invalid handle */
Status = STATUS_INVALID_HANDLE;
}
/* Return failure status */
KeLeaveCriticalRegion();
*Object = NULL;
return Status;
}
/* EOF */