mirror of
https://github.com/reactos/reactos.git
synced 2024-09-02 08:38:28 +00:00
349 lines
8.6 KiB
C
349 lines
8.6 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)
|
|
{
|
|
PFILE_FULL_EA_INFORMATION EaBufferEnd;
|
|
ULONG NextEaBufferOffset;
|
|
LONG IntEaLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
/* Length of the rest */
|
|
IntEaLength = EaLength;
|
|
EaBufferEnd = EaBuffer;
|
|
|
|
/* The rest length of the buffer */
|
|
while (IntEaLength >= FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]))
|
|
{
|
|
/*
|
|
* The rest of buffer must greater than
|
|
* sizeof(FILE_FULL_EA_INFORMATION) + buffer
|
|
*/
|
|
NextEaBufferOffset =
|
|
EaBufferEnd->EaNameLength + EaBufferEnd->EaValueLength +
|
|
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + 1;
|
|
|
|
if ((ULONG)IntEaLength >= NextEaBufferOffset)
|
|
{
|
|
/* is the EaBufferName terminated with zero? */
|
|
if (EaBufferEnd->EaName[EaBufferEnd->EaNameLength]==0)
|
|
{
|
|
/* more EaBuffers ahead */
|
|
if (EaBufferEnd->NextEntryOffset == 0)
|
|
{
|
|
/* test the rest buffersize */
|
|
IntEaLength = IntEaLength - NextEaBufferOffset;
|
|
if (IntEaLength >= 0)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* From MSDN:
|
|
* http://msdn2.microsoft.com/en-us/library/ms795740.aspx
|
|
* For all entries except the last one, the value of
|
|
* NextEntryOffset must be greater than zero and
|
|
* must fall on a ULONG boundary.
|
|
*/
|
|
NextEaBufferOffset = ((NextEaBufferOffset + 3) & ~3);
|
|
if ((EaBufferEnd->NextEntryOffset == NextEaBufferOffset) &&
|
|
((LONG)EaBufferEnd->NextEntryOffset > 0))
|
|
{
|
|
/*
|
|
* The rest of buffer must be greater
|
|
* than the following offset.
|
|
*/
|
|
IntEaLength =
|
|
IntEaLength - EaBufferEnd->NextEntryOffset;
|
|
|
|
if (IntEaLength >= 0)
|
|
{
|
|
EaBufferEnd = (PFILE_FULL_EA_INFORMATION)
|
|
((ULONG_PTR)EaBufferEnd +
|
|
EaBufferEnd->NextEntryOffset);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ErrorOffset != NULL)
|
|
{
|
|
/* Calculate the error offset */
|
|
*ErrorOffset = (ULONG)((ULONG_PTR)EaBufferEnd - (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)
|
|
{
|
|
/* 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;
|
|
}
|