mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 22:02:18 +00:00
272 lines
7.1 KiB
C
272 lines
7.1 KiB
C
/*
|
|
* PROJECT: Filesystem Filter Manager
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/filters/fltmgr/Object.c
|
|
* PURPOSE: Miscellaneous library functions
|
|
* PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org)
|
|
*/
|
|
|
|
// NOTE: Split this file into filter object and device object functions
|
|
// when the code base grows sufficiently
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "fltmgr.h"
|
|
#include "fltmgrint.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* DATA *********************************************************************/
|
|
|
|
#define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
|
|
|
|
//
|
|
// Pushlock bits
|
|
//
|
|
#define EX_PUSH_LOCK_LOCK_V ((ULONG_PTR)0x0)
|
|
#define EX_PUSH_LOCK_LOCK ((ULONG_PTR)0x1)
|
|
#define EX_PUSH_LOCK_WAITING ((ULONG_PTR)0x2)
|
|
#define EX_PUSH_LOCK_WAKING ((ULONG_PTR)0x4)
|
|
#define EX_PUSH_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
|
|
#define EX_PUSH_LOCK_SHARE_INC ((ULONG_PTR)0x10)
|
|
#define EX_PUSH_LOCK_PTR_BITS ((ULONG_PTR)0xf)
|
|
|
|
/* EXPORTED FUNCTIONS ******************************************************/
|
|
|
|
|
|
NTSTATUS
|
|
FLTAPI
|
|
FltObjectReference(_Inout_ PVOID Object)
|
|
{
|
|
if (!FltpExAcquireRundownProtection(&((PFLT_OBJECT)Object)->RundownRef))
|
|
{
|
|
return STATUS_FLT_DELETING_OBJECT;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
FLTAPI
|
|
FltObjectDereference(_Inout_ PVOID Object)
|
|
{
|
|
FltpExReleaseRundownProtection(&((PFLT_OBJECT)Object)->RundownRef);
|
|
}
|
|
|
|
|
|
_Acquires_lock_(_Global_critical_region_)
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
VOID
|
|
FLTAPI
|
|
FltAcquirePushLockExclusive(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
|
|
{
|
|
KeEnterCriticalRegion();
|
|
|
|
/* Try acquiring the lock */
|
|
if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
|
|
{
|
|
/* Someone changed it, use the slow path */
|
|
ExfAcquirePushLockExclusive(PushLock);
|
|
}
|
|
|
|
/* Sanity check */
|
|
FLT_ASSERT(PushLock->Locked);
|
|
}
|
|
|
|
|
|
_Acquires_lock_(_Global_critical_region_)
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
VOID
|
|
FLTAPI
|
|
FltAcquirePushLockShared(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
|
|
{
|
|
EX_PUSH_LOCK NewValue;
|
|
|
|
KeEnterCriticalRegion();
|
|
|
|
/* Try acquiring the lock */
|
|
NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
|
|
if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
|
|
{
|
|
/* Someone changed it, use the slow path */
|
|
ExfAcquirePushLockShared(PushLock);
|
|
}
|
|
|
|
/* Sanity checks */
|
|
ASSERT(PushLock->Locked);
|
|
}
|
|
|
|
_Releases_lock_(_Global_critical_region_)
|
|
_IRQL_requires_max_(APC_LEVEL)
|
|
VOID
|
|
FLTAPI
|
|
FltReleasePushLock(_Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
|
|
{
|
|
EX_PUSH_LOCK OldValue = *PushLock;
|
|
EX_PUSH_LOCK NewValue;
|
|
|
|
/* Sanity checks */
|
|
FLT_ASSERT(OldValue.Locked);
|
|
|
|
/* Check if the pushlock is shared */
|
|
if (OldValue.Shared > 1)
|
|
{
|
|
/* Decrease the share count */
|
|
NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
|
|
}
|
|
else
|
|
{
|
|
/* Clear the pushlock entirely */
|
|
NewValue.Value = 0;
|
|
}
|
|
|
|
/* Check if nobody is waiting on us and try clearing the lock here */
|
|
if ((OldValue.Waiting) ||
|
|
(ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
|
|
OldValue.Ptr))
|
|
{
|
|
/* We have waiters, use the long path */
|
|
ExfReleasePushLock(PushLock);
|
|
}
|
|
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
|
|
|
|
/* INTERNAL FUNCTIONS ******************************************************/
|
|
|
|
VOID
|
|
FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)
|
|
{
|
|
ExInitializeRundownProtection(RundownRef);
|
|
}
|
|
|
|
BOOLEAN
|
|
FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
|
|
{
|
|
return ExAcquireRundownProtection(RundownRef);
|
|
}
|
|
|
|
BOOLEAN
|
|
FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
|
|
{
|
|
ExReleaseRundownProtection(RundownRef);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)
|
|
{
|
|
return _InterlockedExchange((PLONG)RundownRef, 1);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)
|
|
{
|
|
//return FltpExWaitForRundownProtectionRelease(RundownRef);
|
|
return 0;
|
|
}
|
|
|
|
NTSTATUS
|
|
FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,
|
|
_Inout_ PUNICODE_STRING ObjectName)
|
|
{
|
|
PDEVICE_OBJECT BaseDeviceObject;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* Get the lowest device object on the stack, which may be the
|
|
* object we were passed, and lookup the name for that object
|
|
*/
|
|
BaseDeviceObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
|
|
Status = FltpGetObjectName(BaseDeviceObject, ObjectName);
|
|
ObDereferenceObject(BaseDeviceObject);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
FltpGetObjectName(_In_ PVOID Object,
|
|
_Inout_ PUNICODE_STRING ObjectName)
|
|
{
|
|
POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
|
|
OBJECT_NAME_INFORMATION LocalNameInfo;
|
|
ULONG ReturnLength;
|
|
NTSTATUS Status;
|
|
|
|
if (ObjectName == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Get the size of the buffer required to hold the nameinfo */
|
|
Status = ObQueryNameString(Object,
|
|
&LocalNameInfo,
|
|
sizeof(LocalNameInfo),
|
|
&ReturnLength);
|
|
if (Status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
|
|
ReturnLength,
|
|
FM_TAG_UNICODE_STRING);
|
|
if (ObjectNameInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Get the actual name info now we have the buffer to hold it */
|
|
Status = ObQueryNameString(Object,
|
|
ObjectNameInfo,
|
|
ReturnLength,
|
|
&ReturnLength);
|
|
}
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Make sure the buffer we were passed is large enough to hold the string */
|
|
if (ObjectName->MaximumLength < ObjectNameInfo->Name.Length)
|
|
{
|
|
/* It wasn't, let's enlarge the buffer */
|
|
Status = FltpReallocateUnicodeString(ObjectName,
|
|
ObjectNameInfo->Name.Length,
|
|
FALSE);
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Copy the object name into the callers buffer */
|
|
RtlCopyUnicodeString(ObjectName, &ObjectNameInfo->Name);
|
|
}
|
|
}
|
|
|
|
if (ObjectNameInfo)
|
|
{
|
|
ExFreePoolWithTag(ObjectNameInfo, FM_TAG_UNICODE_STRING);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
FltpObjectPointerReference(_In_ PFLT_OBJECT Object)
|
|
{
|
|
PULONG Result;
|
|
|
|
/* Store the old count and increment */
|
|
Result = &Object->PointerCount;
|
|
InterlockedIncrement((PLONG)&Object->PointerCount);
|
|
|
|
/* Return the initial value */
|
|
return *Result;
|
|
}
|
|
|
|
VOID
|
|
FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)
|
|
{
|
|
if (!InterlockedDecrement((PLONG)Object->PointerCount))
|
|
{
|
|
// Cleanup
|
|
FLT_ASSERT(FALSE);
|
|
}
|
|
} |