mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
1159 lines
32 KiB
C
1159 lines
32 KiB
C
/**
|
|
* @file sys/util.c
|
|
*
|
|
* @copyright 2015-2018 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of WinFsp.
|
|
*
|
|
* You can redistribute it and/or modify it under the terms of the GNU
|
|
* General Public License version 3 as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Licensees holding a valid commercial license may use this file in
|
|
* accordance with the commercial license agreement provided with the
|
|
* software.
|
|
*/
|
|
|
|
#include <sys/driver.h>
|
|
|
|
NTSTATUS FspCreateGuid(GUID *Guid);
|
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject);
|
|
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length);
|
|
static NTSTATUS FspSendSetInformationIrpCompletion(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0);
|
|
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
|
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation);
|
|
NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags);
|
|
NTSTATUS FspCcInitializeCacheMap(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes,
|
|
BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS Callbacks, PVOID CallbackContext);
|
|
NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes);
|
|
NTSTATUS FspCcCopyRead(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
BOOLEAN Wait, PVOID Buffer, PIO_STATUS_BLOCK IoStatus);
|
|
NTSTATUS FspCcCopyWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
BOOLEAN Wait, PVOID Buffer);
|
|
NTSTATUS FspCcMdlRead(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus);
|
|
NTSTATUS FspCcMdlReadComplete(PFILE_OBJECT FileObject, PMDL MdlChain);
|
|
NTSTATUS FspCcPrepareMdlWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus);
|
|
NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain);
|
|
NTSTATUS FspCcFlushCache(PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
PLARGE_INTEGER FileOffset, ULONG Length, PIO_STATUS_BLOCK IoStatus);
|
|
NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength,
|
|
PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor);
|
|
NTSTATUS FspNotifyInitializeSync(PNOTIFY_SYNC *NotifySync);
|
|
NTSTATUS FspNotifyFullChangeDirectory(
|
|
PNOTIFY_SYNC NotifySync,
|
|
PLIST_ENTRY NotifyList,
|
|
PVOID FsContext,
|
|
PSTRING FullDirectoryName,
|
|
BOOLEAN WatchTree,
|
|
BOOLEAN IgnoreBuffer,
|
|
ULONG CompletionFilter,
|
|
PIRP NotifyIrp,
|
|
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback,
|
|
PSECURITY_SUBJECT_CONTEXT SubjectContext);
|
|
NTSTATUS FspNotifyFullReportChange(
|
|
PNOTIFY_SYNC NotifySync,
|
|
PLIST_ENTRY NotifyList,
|
|
PSTRING FullTargetName,
|
|
USHORT TargetNameOffset,
|
|
PSTRING StreamName,
|
|
PSTRING NormalizedParentName,
|
|
ULONG FilterMatch,
|
|
ULONG Action,
|
|
PVOID TargetContext);
|
|
NTSTATUS FspOplockBreakH(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG Flags,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
|
NTSTATUS FspCheckOplock(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
|
NTSTATUS FspCheckOplockEx(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG Flags,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine);
|
|
NTSTATUS FspOplockFsctrl(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG OpenCount);
|
|
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
|
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
|
static WORKER_THREAD_ROUTINE FspExecuteSynchronousWorkItemRoutine;
|
|
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
|
VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay);
|
|
static KDEFERRED_ROUTINE FspQueueDelayedWorkItemDPC;
|
|
BOOLEAN FspSafeMdlCheck(PMDL Mdl);
|
|
NTSTATUS FspSafeMdlCreate(PMDL UserMdl, LOCK_OPERATION Operation, FSP_SAFE_MDL **PSafeMdl);
|
|
VOID FspSafeMdlCopyBack(FSP_SAFE_MDL *SafeMdl);
|
|
VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl);
|
|
NTSTATUS FspIrpHook(PIRP Irp, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID OwnContext);
|
|
VOID FspIrpHookReset(PIRP Irp);
|
|
PVOID FspIrpHookContext(PVOID Context);
|
|
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, FspCreateGuid)
|
|
#pragma alloc_text(PAGE, FspGetDeviceObjectPointer)
|
|
#pragma alloc_text(PAGE, FspSendSetInformationIrp)
|
|
#pragma alloc_text(PAGE, FspBufferUserBuffer)
|
|
#pragma alloc_text(PAGE, FspLockUserBuffer)
|
|
#pragma alloc_text(PAGE, FspMapLockedPagesInUserMode)
|
|
#pragma alloc_text(PAGE, FspCcInitializeCacheMap)
|
|
#pragma alloc_text(PAGE, FspCcSetFileSizes)
|
|
#pragma alloc_text(PAGE, FspCcCopyRead)
|
|
#pragma alloc_text(PAGE, FspCcCopyWrite)
|
|
#pragma alloc_text(PAGE, FspCcMdlRead)
|
|
#pragma alloc_text(PAGE, FspCcMdlReadComplete)
|
|
#pragma alloc_text(PAGE, FspCcPrepareMdlWrite)
|
|
#pragma alloc_text(PAGE, FspCcMdlWriteComplete)
|
|
#pragma alloc_text(PAGE, FspCcFlushCache)
|
|
#pragma alloc_text(PAGE, FspQuerySecurityDescriptorInfo)
|
|
#pragma alloc_text(PAGE, FspNotifyInitializeSync)
|
|
#pragma alloc_text(PAGE, FspNotifyFullChangeDirectory)
|
|
#pragma alloc_text(PAGE, FspNotifyFullReportChange)
|
|
#pragma alloc_text(PAGE, FspOplockBreakH)
|
|
#pragma alloc_text(PAGE, FspCheckOplock)
|
|
#pragma alloc_text(PAGE, FspCheckOplockEx)
|
|
#pragma alloc_text(PAGE, FspOplockFsctrl)
|
|
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
|
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
|
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
|
#pragma alloc_text(PAGE, FspInitializeDelayedWorkItem)
|
|
#pragma alloc_text(PAGE, FspQueueDelayedWorkItem)
|
|
#pragma alloc_text(PAGE, FspSafeMdlCheck)
|
|
#pragma alloc_text(PAGE, FspSafeMdlCreate)
|
|
#pragma alloc_text(PAGE, FspSafeMdlCopyBack)
|
|
#pragma alloc_text(PAGE, FspSafeMdlDelete)
|
|
#pragma alloc_text(PAGE, FspIrpHook)
|
|
#pragma alloc_text(PAGE, FspIrpHookReset)
|
|
// !#pragma alloc_text(PAGE, FspIrpHookContext)
|
|
// !#pragma alloc_text(PAGE, FspIrpHookNext)
|
|
#endif
|
|
|
|
static const LONG Delays[] =
|
|
{
|
|
10/*ms*/ * -10000,
|
|
10/*ms*/ * -10000,
|
|
50/*ms*/ * -10000,
|
|
50/*ms*/ * -10000,
|
|
100/*ms*/ * -10000,
|
|
100/*ms*/ * -10000,
|
|
300/*ms*/ * -10000,
|
|
};
|
|
|
|
PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
PVOID Result;
|
|
LARGE_INTEGER Delay;
|
|
|
|
for (ULONG i = 0, n = sizeof(Delays) / sizeof(Delays[0]);; i++)
|
|
{
|
|
Result = DEBUGTEST(99) ? ExAllocatePoolWithTag(PoolType, Size, Tag) : 0;
|
|
if (0 != Result)
|
|
return Result;
|
|
|
|
Delay.QuadPart = n > i ? Delays[i] : Delays[n - 1];
|
|
KeDelayExecutionThread(KernelMode, FALSE, &Delay);
|
|
}
|
|
}
|
|
|
|
PVOID FspAllocateIrpMustSucceed(CCHAR StackSize)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
PIRP Result;
|
|
LARGE_INTEGER Delay;
|
|
|
|
for (ULONG i = 0, n = sizeof(Delays) / sizeof(Delays[0]);; i++)
|
|
{
|
|
Result = DEBUGTEST(99) ? IoAllocateIrp(StackSize, FALSE) : 0;
|
|
if (0 != Result)
|
|
return Result;
|
|
|
|
Delay.QuadPart = n > i ? Delays[i] : Delays[n - 1];
|
|
KeDelayExecutionThread(KernelMode, FALSE, &Delay);
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCreateGuid(GUID *Guid)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
int Retries = 3;
|
|
do
|
|
{
|
|
Result = ExUuidCreate(Guid);
|
|
} while (!NT_SUCCESS(Result) && 0 < --Retries);
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess,
|
|
PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
UNICODE_STRING PartialName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Handle;
|
|
NTSTATUS Result;
|
|
|
|
PartialName.Length = 0;
|
|
PartialName.MaximumLength = ObjectName->Length;
|
|
PartialName.Buffer = ObjectName->Buffer;
|
|
|
|
Result = STATUS_NO_SUCH_DEVICE;
|
|
while (PartialName.MaximumLength > PartialName.Length)
|
|
{
|
|
while (PartialName.MaximumLength > PartialName.Length &&
|
|
L'\\' == PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
|
|
PartialName.Length += sizeof(WCHAR);
|
|
while (PartialName.MaximumLength > PartialName.Length &&
|
|
L'\\' != PartialName.Buffer[PartialName.Length / sizeof(WCHAR)])
|
|
PartialName.Length += sizeof(WCHAR);
|
|
|
|
Result = IoGetDeviceObjectPointer(&PartialName, DesiredAccess, PFileObject, PDeviceObject);
|
|
if (NT_SUCCESS(Result))
|
|
{
|
|
*PFileNameIndex = PartialName.Length;
|
|
break;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &PartialName, OBJ_KERNEL_HANDLE, 0, 0);
|
|
Result = ZwOpenDirectoryObject(&Handle, 0, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
Result = ZwOpenSymbolicLinkObject(&Handle, 0, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
Result = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
}
|
|
ZwClose(Handle);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
IO_STATUS_BLOCK IoStatus;
|
|
KEVENT Event;
|
|
} FSP_SEND_SET_INFORMATION_IRP_CONTEXT;
|
|
|
|
NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|
FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT(
|
|
FileAllocationInformation == FileInformationClass ||
|
|
FileEndOfFileInformation == FileInformationClass);
|
|
|
|
NTSTATUS Result;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
FSP_SEND_SET_INFORMATION_IRP_CONTEXT Context;
|
|
|
|
if (0 == DeviceObject)
|
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
if (0 == Irp)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
|
Irp->RequestorMode = KernelMode;
|
|
Irp->AssociatedIrp.SystemBuffer = FileInformation;
|
|
IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
|
|
IrpSp->FileObject = FileObject;
|
|
IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
|
|
IrpSp->Parameters.SetFile.Length = FileInformationClass;
|
|
|
|
IoSetCompletionRoutine(Irp, FspSendSetInformationIrpCompletion, &Context, TRUE, TRUE, TRUE);
|
|
|
|
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
|
|
Result = IoCallDriver(DeviceObject, Irp);
|
|
if (STATUS_PENDING == Result)
|
|
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0);
|
|
|
|
return NT_SUCCESS(Result) ? Context.IoStatus.Status : Result;
|
|
}
|
|
|
|
static NTSTATUS FspSendSetInformationIrpCompletion(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
FSP_SEND_SET_INFORMATION_IRP_CONTEXT *Context = Context0;
|
|
|
|
Context->IoStatus = Irp->IoStatus;
|
|
KeSetEvent(&Context->Event, 1, FALSE);
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (0 == Length || 0 != Irp->AssociatedIrp.SystemBuffer)
|
|
return STATUS_SUCCESS;
|
|
|
|
PVOID SystemBuffer = FspAllocNonPagedExternal(Length);
|
|
if (0 == SystemBuffer)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (IoReadAccess == Operation)
|
|
{
|
|
try
|
|
{
|
|
RtlCopyMemory(SystemBuffer, Irp->UserBuffer, Length);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
FspFree(SystemBuffer);
|
|
|
|
NTSTATUS Result = GetExceptionCode();
|
|
return FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
|
|
}
|
|
}
|
|
else
|
|
RtlZeroMemory(SystemBuffer, Length);
|
|
|
|
Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
|
|
Irp->Flags |= (IoReadAccess == Operation ? 0 : IRP_INPUT_OPERATION) |
|
|
IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS FspLockUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (0 == Length || 0 != Irp->MdlAddress)
|
|
return STATUS_SUCCESS;
|
|
|
|
PMDL Mdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, 0);
|
|
if (0 == Mdl)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
try
|
|
{
|
|
MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
IoFreeMdl(Mdl);
|
|
|
|
NTSTATUS Result = GetExceptionCode();
|
|
return FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
|
|
}
|
|
|
|
Irp->MdlAddress = Mdl;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress, ULONG ExtraPriorityFlags)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
*PAddress = MmMapLockedPagesSpecifyCache(Mdl, UserMode, MmCached, 0, FALSE,
|
|
NormalPagePriority | ExtraPriorityFlags);
|
|
return 0 != *PAddress ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
*PAddress = 0;
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcInitializeCacheMap(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes,
|
|
BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS Callbacks, PVOID CallbackContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcInitializeCacheMap(FileObject, FileSizes, PinAccess, Callbacks, CallbackContext);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcSetFileSizes(FileObject, FileSizes);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcCopyRead(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
BOOLEAN Wait, PVOID Buffer, PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
BOOLEAN Success = CcCopyRead(FileObject, FileOffset, Length, Wait, Buffer, IoStatus);
|
|
Result = Success ? STATUS_SUCCESS : STATUS_PENDING;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
IoStatus->Information = 0;
|
|
IoStatus->Status = Result;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspCcCopyWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
BOOLEAN Wait, PVOID Buffer)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
BOOLEAN Success = CcCopyWrite(FileObject, FileOffset, Length, Wait, Buffer);
|
|
return Success ? STATUS_SUCCESS : STATUS_PENDING;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcMdlRead(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcMdlRead(FileObject, FileOffset, Length, PMdlChain, IoStatus);
|
|
return IoStatus->Status;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcMdlReadComplete(PFILE_OBJECT FileObject, PMDL MdlChain)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcMdlReadComplete(FileObject, MdlChain);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcPrepareMdlWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length,
|
|
PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcPrepareMdlWrite(FileObject, FileOffset, Length, PMdlChain, IoStatus);
|
|
return IoStatus->Status;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
try
|
|
{
|
|
CcMdlWriteComplete(FileObject, FileOffset, MdlChain);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
CcMdlWriteAbort(FileObject, MdlChain);
|
|
return GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
NTSTATUS FspCcFlushCache(PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
PLARGE_INTEGER FileOffset, ULONG Length, PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
CcFlushCache(SectionObjectPointer, FileOffset, Length, IoStatus);
|
|
Result = IoStatus->Status;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
|
|
IoStatus->Information = 0;
|
|
IoStatus->Status = Result;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation,
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength,
|
|
PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
Result = SeQuerySecurityDescriptorInfo(&SecurityInformation,
|
|
SecurityDescriptor, PLength, &ObjectsSecurityDescriptor);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result;
|
|
}
|
|
|
|
return STATUS_BUFFER_TOO_SMALL == Result ? STATUS_BUFFER_OVERFLOW : Result;
|
|
}
|
|
|
|
NTSTATUS FspNotifyInitializeSync(PNOTIFY_SYNC *NotifySync)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
FsRtlNotifyInitializeSync(NotifySync);
|
|
Result = STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspNotifyFullChangeDirectory(
|
|
PNOTIFY_SYNC NotifySync,
|
|
PLIST_ENTRY NotifyList,
|
|
PVOID FsContext,
|
|
PSTRING FullDirectoryName,
|
|
BOOLEAN WatchTree,
|
|
BOOLEAN IgnoreBuffer,
|
|
ULONG CompletionFilter,
|
|
PIRP NotifyIrp,
|
|
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback,
|
|
PSECURITY_SUBJECT_CONTEXT SubjectContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
FsRtlNotifyFullChangeDirectory(
|
|
NotifySync,
|
|
NotifyList,
|
|
FsContext,
|
|
FullDirectoryName,
|
|
WatchTree,
|
|
IgnoreBuffer,
|
|
CompletionFilter,
|
|
NotifyIrp,
|
|
TraverseCallback,
|
|
SubjectContext);
|
|
Result = STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspNotifyFullReportChange(
|
|
PNOTIFY_SYNC NotifySync,
|
|
PLIST_ENTRY NotifyList,
|
|
PSTRING FullTargetName,
|
|
USHORT TargetNameOffset,
|
|
PSTRING StreamName,
|
|
PSTRING NormalizedParentName,
|
|
ULONG FilterMatch,
|
|
ULONG Action,
|
|
PVOID TargetContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
FsRtlNotifyFullReportChange(
|
|
NotifySync,
|
|
NotifyList,
|
|
FullTargetName,
|
|
TargetNameOffset,
|
|
StreamName,
|
|
NormalizedParentName,
|
|
FilterMatch,
|
|
Action,
|
|
TargetContext);
|
|
Result = STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspOplockBreakH(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG Flags,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
Result = FsRtlOplockBreakH(
|
|
Oplock,
|
|
Irp,
|
|
Flags,
|
|
Context,
|
|
CompletionRoutine,
|
|
PostIrpRoutine);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspCheckOplock(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
Result = FsRtlCheckOplock(
|
|
Oplock,
|
|
Irp,
|
|
Context,
|
|
CompletionRoutine,
|
|
PostIrpRoutine);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspCheckOplockEx(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG Flags,
|
|
PVOID Context,
|
|
POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine,
|
|
POPLOCK_FS_PREPOST_IRP PostIrpRoutine)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
Result = FsRtlCheckOplockEx(
|
|
Oplock,
|
|
Irp,
|
|
Flags,
|
|
Context,
|
|
CompletionRoutine,
|
|
PostIrpRoutine);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspOplockFsctrl(
|
|
POPLOCK Oplock,
|
|
PIRP Irp,
|
|
ULONG OpenCount)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
|
|
try
|
|
{
|
|
Result = FsRtlOplockFsctrl(
|
|
Oplock,
|
|
Irp,
|
|
OpenCount);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = GetExceptionCode();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
|
SynchronousWorkItem->Routine = Routine;
|
|
SynchronousWorkItem->Context = Context;
|
|
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
|
|
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
|
|
}
|
|
|
|
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
|
|
|
NTSTATUS Result;
|
|
Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, FALSE, 0);
|
|
ASSERT(STATUS_SUCCESS == Result);
|
|
}
|
|
|
|
static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
|
|
SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
|
|
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
|
|
}
|
|
|
|
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
KeInitializeTimer(&DelayedWorkItem->Timer);
|
|
KeInitializeDpc(&DelayedWorkItem->Dpc, FspQueueDelayedWorkItemDPC, DelayedWorkItem);
|
|
ExInitializeWorkItem(&DelayedWorkItem->WorkQueueItem, Routine, Context);
|
|
}
|
|
|
|
VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
KeSetTimer(&DelayedWorkItem->Timer, Delay, &DelayedWorkItem->Dpc);
|
|
}
|
|
|
|
static VOID FspQueueDelayedWorkItemDPC(PKDPC Dpc,
|
|
PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
FSP_DELAYED_WORK_ITEM *DelayedWorkItem = DeferredContext;
|
|
|
|
ExQueueWorkItem(&DelayedWorkItem->WorkQueueItem, DelayedWorkQueue);
|
|
}
|
|
|
|
BOOLEAN FspSafeMdlCheck(PMDL Mdl)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return 0 == MmGetMdlByteOffset(Mdl) && 0 == BYTE_OFFSET(MmGetMdlByteCount(Mdl));
|
|
}
|
|
|
|
NTSTATUS FspSafeMdlCreate(PMDL UserMdl, LOCK_OPERATION Operation, FSP_SAFE_MDL **PSafeMdl)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
*PSafeMdl = 0;
|
|
|
|
PVOID VirtualAddress = MmGetSystemAddressForMdlSafe(UserMdl, NormalPagePriority);
|
|
if (0 == VirtualAddress)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
NTSTATUS Result;
|
|
ULONG ByteCount = MmGetMdlByteCount(UserMdl);
|
|
ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ByteCount);
|
|
FSP_SAFE_MDL *SafeMdl;
|
|
PMDL TempMdl;
|
|
PPFN_NUMBER UserPfnArray, SafePfnArray, TempPfnArray;
|
|
ULONG ByteOffsetBgn0, ByteOffsetEnd0, ByteOffsetEnd1;
|
|
BOOLEAN Buffer0, Buffer1;
|
|
ULONG BufferPageCount;
|
|
|
|
ASSERT(0 != PageCount);
|
|
ASSERT(FlagOn(UserMdl->MdlFlags, MDL_SOURCE_IS_NONPAGED_POOL | MDL_PAGES_LOCKED));
|
|
|
|
SafeMdl = FspAllocNonPaged(sizeof *SafeMdl);
|
|
if (0 == SafeMdl)
|
|
{
|
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
RtlZeroMemory(SafeMdl, sizeof *SafeMdl);
|
|
SafeMdl->Operation = Operation;
|
|
|
|
SafeMdl->Mdl = IoAllocateMdl(VirtualAddress, ByteCount, FALSE, FALSE, 0);
|
|
if (0 == SafeMdl->Mdl)
|
|
{
|
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
#pragma prefast(suppress:28145, "We are a filesystem: ok to access MdlFlags")
|
|
SafeMdl->Mdl->MdlFlags |= MDL_PAGES_LOCKED;
|
|
UserPfnArray = MmGetMdlPfnArray(UserMdl);
|
|
SafePfnArray = MmGetMdlPfnArray(SafeMdl->Mdl);
|
|
RtlCopyMemory(SafePfnArray, UserPfnArray, PageCount * sizeof(PFN_NUMBER));
|
|
|
|
/*
|
|
* Possible cases:
|
|
*
|
|
* ----+---------+---------+----
|
|
*
|
|
* *---------* +
|
|
* + *----* +
|
|
* *----* + +
|
|
* + *---* + +
|
|
* *--------...--------*
|
|
* + *---...--------*
|
|
* *--------...---* +
|
|
* + *---...---* +
|
|
*/
|
|
if (1 == PageCount)
|
|
{
|
|
ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress);
|
|
ByteOffsetEnd0 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount - 1) + 1;
|
|
ByteOffsetEnd1 = 0;
|
|
Buffer0 = 0 != ByteOffsetBgn0 || PAGE_SIZE != ByteOffsetEnd0;
|
|
Buffer1 = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress);
|
|
ByteOffsetEnd0 = PAGE_SIZE;
|
|
ByteOffsetEnd1 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount - 1) + 1;
|
|
Buffer0 = 0 != ByteOffsetBgn0;
|
|
Buffer1 = PAGE_SIZE != ByteOffsetEnd1;
|
|
}
|
|
BufferPageCount = Buffer0 + Buffer1;
|
|
|
|
if (0 < BufferPageCount)
|
|
{
|
|
SafeMdl->Buffer = FspAllocNonPaged(PAGE_SIZE * BufferPageCount);
|
|
if (0 == SafeMdl->Buffer)
|
|
{
|
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
TempMdl = IoAllocateMdl(SafeMdl->Buffer, PAGE_SIZE * BufferPageCount, FALSE, FALSE, 0);
|
|
if (0 == TempMdl)
|
|
{
|
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool(TempMdl);
|
|
|
|
TempPfnArray = MmGetMdlPfnArray(TempMdl);
|
|
if (IoReadAccess == Operation)
|
|
{
|
|
if (Buffer0)
|
|
{
|
|
RtlZeroMemory((PUINT8)SafeMdl->Buffer, ByteOffsetBgn0);
|
|
RtlCopyMemory((PUINT8)SafeMdl->Buffer + ByteOffsetBgn0,
|
|
(PUINT8)VirtualAddress, ByteOffsetEnd0 - ByteOffsetBgn0);
|
|
RtlZeroMemory((PUINT8)SafeMdl->Buffer + ByteOffsetEnd0, PAGE_SIZE - ByteOffsetEnd0);
|
|
SafePfnArray[0] = TempPfnArray[0];
|
|
}
|
|
if (Buffer1)
|
|
{
|
|
RtlCopyMemory((PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE,
|
|
PAGE_ALIGN((PUINT8)VirtualAddress + (PageCount - 1) * PAGE_SIZE), ByteOffsetEnd1);
|
|
RtlZeroMemory((PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE + ByteOffsetEnd1,
|
|
PAGE_SIZE - ByteOffsetEnd1);
|
|
SafePfnArray[PageCount - 1] = TempPfnArray[BufferPageCount - 1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RtlZeroMemory((PUINT8)SafeMdl->Buffer, PAGE_SIZE * BufferPageCount);
|
|
if (Buffer0)
|
|
SafePfnArray[0] = TempPfnArray[0];
|
|
if (Buffer1)
|
|
SafePfnArray[PageCount - 1] = TempPfnArray[BufferPageCount - 1];
|
|
}
|
|
|
|
IoFreeMdl(TempMdl);
|
|
}
|
|
|
|
SafeMdl->UserMdl = UserMdl;
|
|
*PSafeMdl = SafeMdl;
|
|
|
|
Result = STATUS_SUCCESS;
|
|
|
|
exit:
|
|
if (!NT_SUCCESS(Result) && 0 != SafeMdl)
|
|
{
|
|
if (0 != SafeMdl->Buffer)
|
|
FspFree(SafeMdl->Buffer);
|
|
if (0 != SafeMdl->Mdl)
|
|
IoFreeMdl(SafeMdl->Mdl);
|
|
FspFree(SafeMdl);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID FspSafeMdlCopyBack(FSP_SAFE_MDL *SafeMdl)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IoReadAccess == SafeMdl->Operation)
|
|
return;
|
|
|
|
PVOID VirtualAddress = MmGetSystemAddressForMdlSafe(SafeMdl->UserMdl, NormalPagePriority);
|
|
if (0 == VirtualAddress)
|
|
return; /* should never happen, already checked in FspSafeMdlCreate */
|
|
|
|
ULONG ByteCount = MmGetMdlByteCount(SafeMdl->UserMdl);
|
|
ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ByteCount);
|
|
ULONG ByteOffsetBgn0, ByteOffsetEnd0, ByteOffsetEnd1;
|
|
BOOLEAN Buffer0, Buffer1;
|
|
ULONG BufferPageCount;
|
|
|
|
/*
|
|
* Possible cases:
|
|
*
|
|
* ----+---------+---------+----
|
|
*
|
|
* *---------* +
|
|
* + *----* +
|
|
* *----* + +
|
|
* + *---* + +
|
|
* *--------...--------*
|
|
* + *---...--------*
|
|
* *--------...---* +
|
|
* + *---...---* +
|
|
*/
|
|
if (1 == PageCount)
|
|
{
|
|
ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress);
|
|
ByteOffsetEnd0 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount - 1) + 1;
|
|
ByteOffsetEnd1 = 0;
|
|
Buffer0 = 0 != ByteOffsetBgn0 || PAGE_SIZE != ByteOffsetEnd0;
|
|
Buffer1 = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress);
|
|
ByteOffsetEnd0 = PAGE_SIZE;
|
|
ByteOffsetEnd1 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount - 1) + 1;
|
|
Buffer0 = 0 != ByteOffsetBgn0;
|
|
Buffer1 = PAGE_SIZE != ByteOffsetEnd1;
|
|
}
|
|
BufferPageCount = Buffer0 + Buffer1;
|
|
|
|
if (0 < BufferPageCount)
|
|
{
|
|
if (Buffer0)
|
|
RtlCopyMemory((PUINT8)VirtualAddress,
|
|
(PUINT8)SafeMdl->Buffer + ByteOffsetBgn0, ByteOffsetEnd0 - ByteOffsetBgn0);
|
|
if (Buffer1)
|
|
RtlCopyMemory(PAGE_ALIGN((PUINT8)VirtualAddress + (PageCount - 1) * PAGE_SIZE),
|
|
(PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE, ByteOffsetEnd1);
|
|
}
|
|
}
|
|
|
|
VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (0 != SafeMdl->Buffer)
|
|
FspFree(SafeMdl->Buffer);
|
|
if (0 != SafeMdl->Mdl)
|
|
IoFreeMdl(SafeMdl->Mdl);
|
|
FspFree(SafeMdl);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
PIO_COMPLETION_ROUTINE CompletionRoutine;
|
|
PVOID Context;
|
|
ULONG Control;
|
|
PVOID OwnContext;
|
|
} FSP_IRP_HOOK_CONTEXT;
|
|
|
|
NTSTATUS FspIrpHook(PIRP Irp, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID OwnContext)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
FSP_IRP_HOOK_CONTEXT *HookContext = 0;
|
|
|
|
if (0 != IrpSp->CompletionRoutine || 0 != OwnContext)
|
|
{
|
|
HookContext = FspAllocNonPaged(sizeof *HookContext);
|
|
if (0 == HookContext)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
HookContext->CompletionRoutine = IrpSp->CompletionRoutine;
|
|
HookContext->Context = IrpSp->Context;
|
|
HookContext->Control = FlagOn(IrpSp->Control,
|
|
SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL);
|
|
HookContext->OwnContext = OwnContext;
|
|
}
|
|
|
|
IrpSp->CompletionRoutine = CompletionRoutine;
|
|
IrpSp->Context = HookContext;
|
|
SetFlag(IrpSp->Control, SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID FspIrpHookReset(PIRP Irp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
FSP_IRP_HOOK_CONTEXT *HookContext = IrpSp->Context;
|
|
|
|
if (0 != HookContext)
|
|
{
|
|
IrpSp->CompletionRoutine = HookContext->CompletionRoutine;
|
|
IrpSp->Context = HookContext->Context;
|
|
ClearFlag(IrpSp->Control, SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL);
|
|
SetFlag(IrpSp->Control, HookContext->Control);
|
|
|
|
FspFree(HookContext);
|
|
}
|
|
else
|
|
{
|
|
IrpSp->CompletionRoutine = 0;
|
|
IrpSp->Context = 0;
|
|
ClearFlag(IrpSp->Control, SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL);
|
|
}
|
|
}
|
|
|
|
PVOID FspIrpHookContext(PVOID Context)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
FSP_IRP_HOOK_CONTEXT *HookContext = Context;
|
|
return 0 != HookContext ? HookContext->OwnContext : 0;
|
|
}
|
|
|
|
NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
|
|
{
|
|
// !PAGED_CODE();
|
|
|
|
FSP_IRP_HOOK_CONTEXT *HookContext = Context;
|
|
NTSTATUS Result;
|
|
|
|
if (0 != HookContext && 0 != HookContext->CompletionRoutine && (
|
|
(NT_SUCCESS(Irp->IoStatus.Status) && FlagOn(HookContext->Control, SL_INVOKE_ON_SUCCESS)) ||
|
|
(!NT_SUCCESS(Irp->IoStatus.Status) && FlagOn(HookContext->Control, SL_INVOKE_ON_ERROR)) ||
|
|
(Irp->Cancel && FlagOn(HookContext->Control, SL_INVOKE_ON_CANCEL))))
|
|
{
|
|
Result = HookContext->CompletionRoutine(DeviceObject, Irp, HookContext->Context);
|
|
}
|
|
else
|
|
{
|
|
if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount)
|
|
IoMarkIrpPending(Irp);
|
|
|
|
Result = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (0 != HookContext)
|
|
FspFree(HookContext);
|
|
|
|
return Result;
|
|
}
|