mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
353 lines
8.3 KiB
C
353 lines
8.3 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/io/iomgr/util.c
|
|
* PURPOSE: I/O Utility Functions
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
* Aleksey Bragin (aleksey@reactos.org)
|
|
* Daniel Zimmerman (netzimme@aim.com)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpGetStackLimits(PULONG_PTR StackBase,
|
|
PULONG_PTR StackLimit);
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IoComputeDesiredAccessFileObject(IN PFILE_OBJECT FileObject,
|
|
IN PACCESS_MASK DesiredAccess)
|
|
{
|
|
/* Assume failure */
|
|
*DesiredAccess = 0;
|
|
|
|
/* First check we really have a FileObject */
|
|
if (OBJECT_TO_OBJECT_HEADER(FileObject)->Type != IoFileObjectType)
|
|
{
|
|
return STATUS_OBJECT_TYPE_MISMATCH;
|
|
}
|
|
|
|
/* Then compute desired access:
|
|
* Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
|
|
* granted. However, if this is a named pipe, make sure we don't ask for
|
|
* FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
|
|
* access right!
|
|
*/
|
|
*DesiredAccess = ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
IoAcquireCancelSpinLock(OUT PKIRQL Irql)
|
|
{
|
|
/* Just acquire the internal lock */
|
|
*Irql = KeAcquireQueuedSpinLock(LockQueueIoCancelLock);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PVOID
|
|
NTAPI
|
|
IoGetInitialStack(VOID)
|
|
{
|
|
/* Return the initial stack from the TCB */
|
|
return PsGetCurrentThread()->Tcb.InitialStack;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
IoGetStackLimits(OUT PULONG_PTR LowLimit,
|
|
OUT PULONG_PTR HighLimit)
|
|
{
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
ULONG_PTR DpcStack = (ULONG_PTR)(Prcb->DpcStack);
|
|
volatile ULONG_PTR StackAddress;
|
|
|
|
/* Save our stack address so we always know it's valid */
|
|
StackAddress = (ULONG_PTR)(&StackAddress);
|
|
|
|
/* Get stack values */
|
|
RtlpGetStackLimits(LowLimit, HighLimit);
|
|
|
|
/* Check if we're outside the stack */
|
|
if ((StackAddress < *LowLimit) || (StackAddress > *HighLimit))
|
|
{
|
|
/* Check if we may be in a DPC */
|
|
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
{
|
|
/* Check if we really are in a DPC */
|
|
if ((Prcb->DpcRoutineActive) &&
|
|
(StackAddress <= DpcStack) &&
|
|
(StackAddress >= DpcStack - KERNEL_STACK_SIZE))
|
|
{
|
|
/* Use the DPC stack limits */
|
|
*HighLimit = DpcStack;
|
|
*LowLimit = DpcStack - KERNEL_STACK_SIZE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
IoIsSystemThread(IN PETHREAD Thread)
|
|
{
|
|
/* Call the Ps Function */
|
|
return PsIsSystemThread(Thread);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
IoIsWdmVersionAvailable(IN UCHAR MajorVersion,
|
|
IN UCHAR MinorVersion)
|
|
{
|
|
/* Return support for WDM 1.30 (Windows Server 2003) */
|
|
if (MajorVersion <= 1 && MinorVersion <= 0x30) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PEPROCESS
|
|
NTAPI
|
|
IoGetCurrentProcess(VOID)
|
|
{
|
|
/* Return the current thread's process */
|
|
return (PEPROCESS)PsGetCurrentThread()->Tcb.ApcState.Process;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
IoReleaseCancelSpinLock(IN KIRQL Irql)
|
|
{
|
|
/* Release the internal lock */
|
|
KeReleaseQueuedSpinLock(LockQueueIoCancelLock, Irql);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PEPROCESS
|
|
NTAPI
|
|
IoThreadToProcess(IN PETHREAD Thread)
|
|
{
|
|
/* Return the thread's process */
|
|
return Thread->ThreadsProcess;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
IoCheckDesiredAccess(IN OUT PACCESS_MASK DesiredAccess,
|
|
IN ACCESS_MASK GrantedAccess)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* Map the generic mask */
|
|
RtlMapGenericMask(DesiredAccess,
|
|
&IoFileObjectType->TypeInfo.GenericMapping);
|
|
|
|
/* Fail if the access masks don't grant full access */
|
|
if ((~(*DesiredAccess) & GrantedAccess)) return STATUS_ACCESS_DENIED;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
IoCheckEaBufferValidity(IN PFILE_FULL_EA_INFORMATION EaBuffer,
|
|
IN ULONG EaLength,
|
|
OUT PULONG ErrorOffset)
|
|
{
|
|
ULONG NextEntryOffset;
|
|
UCHAR EaNameLength;
|
|
ULONG ComputedLength;
|
|
PFILE_FULL_EA_INFORMATION Current;
|
|
|
|
PAGED_CODE();
|
|
|
|
/* We will browse all the entries */
|
|
for (Current = EaBuffer; ; Current = (PFILE_FULL_EA_INFORMATION)((ULONG_PTR)Current + NextEntryOffset))
|
|
{
|
|
/* Check that we have enough bits left for the current entry */
|
|
if (EaLength < FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName))
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
EaNameLength = Current->EaNameLength;
|
|
ComputedLength = Current->EaValueLength + EaNameLength + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + 1;
|
|
/* Check that we have enough bits left for storing the name and its value */
|
|
if (EaLength < ComputedLength)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
/* Make sure the name is null terminated */
|
|
if (Current->EaName[EaNameLength] != ANSI_NULL)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
/* Get the next entry offset */
|
|
NextEntryOffset = Current->NextEntryOffset;
|
|
/* If it's 0, it's a termination case */
|
|
if (NextEntryOffset == 0)
|
|
{
|
|
/* If we don't overflow! */
|
|
if ((LONG)(EaLength - ComputedLength) < 0)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Compare the next offset we computed with the provided one, they must match */
|
|
if (ALIGN_UP_BY(ComputedLength, sizeof(ULONG)) != NextEntryOffset)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
/* Check next entry offset value is positive */
|
|
if ((LONG)NextEntryOffset < 0)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
/* Compute the remaining bits */
|
|
EaLength -= NextEntryOffset;
|
|
/* We must have bits left */
|
|
if ((LONG)EaLength < 0)
|
|
{
|
|
goto FailPath;
|
|
}
|
|
|
|
/* Move to the next entry */
|
|
}
|
|
|
|
/* If we end here, everything went OK */
|
|
return STATUS_SUCCESS;
|
|
|
|
FailPath:
|
|
/* If we end here, we failed, set failed offset */
|
|
*ErrorOffset = (ULONG_PTR)Current - (ULONG_PTR)EaBuffer;
|
|
return STATUS_EA_LIST_INCONSISTENT;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
IoCheckFunctionAccess(IN ACCESS_MASK GrantedAccess,
|
|
IN UCHAR MajorFunction,
|
|
IN UCHAR MinorFunction,
|
|
IN ULONG IoControlCode,
|
|
IN PVOID ExtraData OPTIONAL,
|
|
IN PVOID ExtraData2 OPTIONAL)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
IoValidateDeviceIoControlAccess(IN PIRP Irp,
|
|
IN ULONG RequiredAccess)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
IoSetDeviceToVerify(IN PETHREAD Thread,
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
/* Set the pointer in the thread */
|
|
Thread->DeviceToVerify = DeviceObject;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
/* Ignore in case the IRP is not associated with any thread */
|
|
if (!Irp->Tail.Overlay.Thread)
|
|
{
|
|
DPRINT1("IoSetHardErrorOrVerifyDevice(0x%p, 0x%p): IRP has no thread, ignoring.\n",
|
|
Irp, DeviceObject);
|
|
return;
|
|
}
|
|
|
|
/* Set the pointer in the IRP */
|
|
Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PDEVICE_OBJECT
|
|
NTAPI
|
|
IoGetDeviceToVerify(IN PETHREAD Thread)
|
|
{
|
|
/* Return the pointer that was set with IoSetDeviceToVerify */
|
|
return Thread->DeviceToVerify;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
IoCheckQuerySetVolumeInformation(IN FS_INFORMATION_CLASS FsInformationClass,
|
|
IN ULONG Length,
|
|
IN BOOLEAN SetOperation)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|