Author: pschweitzer
Date: Tue Aug 18 20:17:22 2015
New Revision: 68757
URL:
http://svn.reactos.org/svn/reactos?rev=68757&view=rev
Log:
[MUP]
Implement the MUP driver for ReactOS. It only supports Multiple UNC Providers so far
Stub support for DFS
Removed:
trunk/reactos/drivers/filesystems/mup/create.c
Modified:
trunk/reactos/drivers/filesystems/mup/CMakeLists.txt
trunk/reactos/drivers/filesystems/mup/mup.c
trunk/reactos/drivers/filesystems/mup/mup.h
Modified: trunk/reactos/drivers/filesystems/mup/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/mup/CM…
==============================================================================
--- trunk/reactos/drivers/filesystems/mup/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/mup/CMakeLists.txt [iso-8859-1] Tue Aug 18 20:17:22
2015
@@ -1,11 +1,11 @@
list(APPEND SOURCE
- create.c
- mup.c
- mup.h)
+ mup.c
+ mup.h)
add_library(mup SHARED ${SOURCE} mup.rc)
set_module_type(mup kernelmodedriver)
+target_link_libraries(mup ${PSEH_LIB})
add_importlibs(mup ntoskrnl hal)
add_pch(mup mup.h SOURCE)
add_cd_file(TARGET mup DESTINATION reactos/system32/drivers FOR all)
Removed: trunk/reactos/drivers/filesystems/mup/create.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/mup/cr…
==============================================================================
--- trunk/reactos/drivers/filesystems/mup/create.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/mup/create.c (removed)
@@ -1,66 +0,0 @@
-/*
- * ReactOS kernel
- * Copyright (C) 2002 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: drivers/fs/mup/create.c
- * PURPOSE: Multi UNC Provider
- * PROGRAMMER: Eric Kohl
- */
-
-/* INCLUDES *****************************************************************/
-
-#include "mup.h"
-
-#define NDEBUG
-#include <debug.h>
-
-/* FUNCTIONS ****************************************************************/
-
-NTSTATUS NTAPI
-MupCreate(PDEVICE_OBJECT DeviceObject,
- PIRP Irp)
-{
- PDEVICE_EXTENSION DeviceExt;
- PIO_STACK_LOCATION Stack;
- PFILE_OBJECT FileObject;
- NTSTATUS Status;
-
- DPRINT("MupCreate() called\n");
-
- DeviceExt = DeviceObject->DeviceExtension;
- ASSERT(DeviceExt);
- Stack = IoGetCurrentIrpStackLocation (Irp);
- ASSERT(Stack);
-
- FileObject = Stack->FileObject;
-
- DPRINT1("MUP - Unimplemented (FileName: '%wZ')\n",
&FileObject->FileName);
- Status = STATUS_OBJECT_NAME_INVALID; // STATUS_BAD_NETWORK_PATH;
-
- Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0;
- Irp->IoStatus.Status = Status;
-
- IoCompleteRequest(Irp,
- IO_NO_INCREMENT);
-
- return Status;
-}
-
-/* EOF */
Modified: trunk/reactos/drivers/filesystems/mup/mup.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/mup/mu…
==============================================================================
--- trunk/reactos/drivers/filesystems/mup/mup.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/mup/mup.c [iso-8859-1] Tue Aug 18 20:17:22 2015
@@ -19,9 +19,10 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: drivers/fs/mup/mup.c
+ * FILE: drivers/filesystems/mup/mup.c
* PURPOSE: Multi UNC Provider
* PROGRAMMER: Eric Kohl
+ * Pierre Schweitzer (pierre(a)reactos.org)
*/
/* INCLUDES *****************************************************************/
@@ -31,7 +32,2496 @@
#define NDEBUG
#include <debug.h>
+ERESOURCE MupGlobalLock;
+ERESOURCE MupPrefixTableLock;
+ERESOURCE MupCcbListLock;
+ERESOURCE MupVcbLock;
+LIST_ENTRY MupProviderList;
+LIST_ENTRY MupPrefixList;
+LIST_ENTRY MupMasterQueryList;
+UNICODE_PREFIX_TABLE MupPrefixTable;
+LARGE_INTEGER MupKnownPrefixTimeout;
+ULONG MupProviderCount;
+BOOLEAN MupOrderInitialized;
+BOOLEAN MupEnableDfs;
+PDEVICE_OBJECT mupDeviceObject;
+NTSTATUS MupOrderedErrorList[] = { STATUS_UNSUCCESSFUL,
+ STATUS_INVALID_PARAMETER,
+ STATUS_REDIRECTOR_NOT_STARTED,
+ STATUS_BAD_NETWORK_NAME,
+ STATUS_BAD_NETWORK_PATH, 0 };
+
/* FUNCTIONS ****************************************************************/
+
+VOID
+MupInitializeData()
+{
+ ExInitializeResourceLite(&MupGlobalLock);
+ ExInitializeResourceLite(&MupPrefixTableLock);
+ ExInitializeResourceLite(&MupCcbListLock);
+ ExInitializeResourceLite(&MupVcbLock);
+ MupProviderCount = 0;
+ InitializeListHead(&MupProviderList);
+ InitializeListHead(&MupPrefixList);
+ InitializeListHead(&MupMasterQueryList);
+ RtlInitializeUnicodePrefix(&MupPrefixTable);
+ MupKnownPrefixTimeout.QuadPart = 9000000000LL;
+ MupOrderInitialized = FALSE;
+}
+
+VOID
+MupUninitializeData()
+{
+ ExDeleteResourceLite(&MupGlobalLock);
+ ExDeleteResourceLite(&MupPrefixTableLock);
+ ExDeleteResourceLite(&MupCcbListLock);
+ ExDeleteResourceLite(&MupVcbLock);
+}
+
+VOID
+MupInitializeVcb(PMUP_VCB Vcb)
+{
+ RtlZeroMemory(Vcb, sizeof(MUP_VCB));
+ Vcb->NodeType = NODE_TYPE_VCB;
+ Vcb->NodeStatus = NODE_STATUS_HEALTHY;
+ Vcb->NodeReferences = 1;
+ Vcb->NodeSize = sizeof(MUP_VCB);
+}
+
+BOOLEAN
+MuppIsDfsEnabled(VOID)
+{
+ HANDLE Key;
+ ULONG Length;
+ NTSTATUS Status;
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ struct
+ {
+ KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+ ULONG KeyValue;
+ } KeyQueryOutput;
+
+ /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
+ KeyName.Buffer =
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
+ KeyName.Length =
sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") -
sizeof(UNICODE_NULL);
+ KeyName.MaximumLength =
sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
+
+ /* Simply query registry to know whether we have to disable DFS.
+ * Unless explicitely stated in registry, we will try to enable DFS.
+ */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ return TRUE;
+ }
+
+ KeyName.Buffer = L"DisableDfs";
+ KeyName.Length = sizeof(L"DisableDfs") - sizeof(UNICODE_NULL);
+ KeyName.MaximumLength = sizeof(L"DisableDfs");
+
+ Status = ZwQueryValueKey(Key, &KeyName, KeyValuePartialInformation,
&KeyQueryOutput, sizeof(KeyQueryOutput), &Length);
+ ZwClose(Key);
+ if (!NT_SUCCESS(Status) || KeyQueryOutput.KeyInfo.Type != REG_DWORD)
+ {
+ return TRUE;
+ }
+
+ return ((ULONG)KeyQueryOutput.KeyInfo.Data != 1);
+}
+
+VOID
+MupCalculateTimeout(PLARGE_INTEGER EntryTime)
+{
+ LARGE_INTEGER CurrentTime;
+
+ /* Just get now + our allowed timeout */
+ KeQuerySystemTime(&CurrentTime);
+ EntryTime->QuadPart = CurrentTime.QuadPart + MupKnownPrefixTimeout.QuadPart;
+}
+
+PMUP_CCB
+MupCreateCcb(VOID)
+{
+ PMUP_CCB Ccb;
+
+ Ccb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_CCB), TAG_MUP);
+ if (Ccb == NULL)
+ {
+ return NULL;
+ }
+
+ Ccb->NodeStatus = NODE_STATUS_HEALTHY;
+ Ccb->NodeReferences = 1;
+ Ccb->NodeType = NODE_TYPE_CCB;
+ Ccb->NodeSize = sizeof(MUP_CCB);
+
+ return Ccb;
+}
+
+PMUP_FCB
+MupCreateFcb(VOID)
+{
+ PMUP_FCB Fcb;
+
+ Fcb = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_FCB), TAG_MUP);
+ if (Fcb == NULL)
+ {
+ return NULL;
+ }
+
+ Fcb->NodeStatus = NODE_STATUS_HEALTHY;
+ Fcb->NodeReferences = 1;
+ Fcb->NodeType = NODE_TYPE_FCB;
+ Fcb->NodeSize = sizeof(MUP_FCB);
+ InitializeListHead(&Fcb->CcbList);
+
+ return Fcb;
+}
+
+PMUP_MIC
+MupAllocateMasterIoContext(VOID)
+{
+ PMUP_MIC MasterIoContext;
+
+ MasterIoContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MIC), TAG_MUP);
+ if (MasterIoContext == NULL)
+ {
+ return NULL;
+ }
+
+ MasterIoContext->NodeStatus = NODE_STATUS_HEALTHY;
+ MasterIoContext->NodeReferences = 1;
+ MasterIoContext->NodeType = NODE_TYPE_MIC;
+ MasterIoContext->NodeSize = sizeof(MUP_MIC);
+
+ return MasterIoContext;
+}
+
+PMUP_UNC
+MupAllocateUncProvider(ULONG RedirectorDeviceNameLength)
+{
+ PMUP_UNC UncProvider;
+
+ UncProvider = ExAllocatePoolWithTag(PagedPool, sizeof(MUP_UNC) +
RedirectorDeviceNameLength, TAG_MUP);
+ if (UncProvider == NULL)
+ {
+ return NULL;
+ }
+
+ UncProvider->NodeReferences = 0;
+ UncProvider->NodeType = NODE_TYPE_UNC;
+ UncProvider->NodeStatus = NODE_STATUS_HEALTHY;
+ UncProvider->NodeSize = sizeof(MUP_UNC) + RedirectorDeviceNameLength;
+ UncProvider->Registered = FALSE;
+
+ return UncProvider;
+}
+
+PMUP_PFX
+MupAllocatePrefixEntry(ULONG PrefixLength)
+{
+ PMUP_PFX Prefix;
+ ULONG PrefixSize;
+
+ PrefixSize = sizeof(MUP_PFX) + PrefixLength;
+ Prefix = ExAllocatePoolWithTag(PagedPool, PrefixSize, TAG_MUP);
+ if (Prefix == NULL)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(Prefix, PrefixSize);
+ Prefix->NodeType = NODE_TYPE_PFX;
+ Prefix->NodeStatus = NODE_STATUS_HEALTHY;
+ Prefix->NodeReferences = 1;
+ Prefix->NodeSize = PrefixSize;
+
+ /* If we got a prefix, initialize the string */
+ if (PrefixLength != 0)
+ {
+ Prefix->AcceptedPrefix.Buffer = (PVOID)((ULONG_PTR)Prefix + sizeof(MUP_PFX));
+ Prefix->AcceptedPrefix.Length = PrefixLength;
+ Prefix->AcceptedPrefix.MaximumLength = PrefixLength;
+ }
+ /* Otherwise, mark the fact that the allocation will be external */
+ else
+ {
+ Prefix->ExternalAlloc = TRUE;
+ }
+
+ Prefix->KeepExtraRef = FALSE;
+ /* Already init timeout to have one */
+ MupCalculateTimeout(&Prefix->ValidityTimeout);
+
+ return Prefix;
+}
+
+PMUP_MQC
+MupAllocateMasterQueryContext(VOID)
+{
+ PMUP_MQC MasterQueryContext;
+
+ MasterQueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(MUP_MQC), TAG_MUP);
+ if (MasterQueryContext == NULL)
+ {
+ return NULL;
+ }
+
+ MasterQueryContext->NodeStatus = NODE_STATUS_HEALTHY;
+ MasterQueryContext->NodeReferences = 1;
+ MasterQueryContext->NodeType = NODE_TYPE_MQC;
+ MasterQueryContext->NodeSize = sizeof(MUP_MQC);
+ InitializeListHead(&MasterQueryContext->QueryPathList);
+ InitializeListHead(&MasterQueryContext->MQCListEntry);
+ ExInitializeResourceLite(&MasterQueryContext->QueryPathListLock);
+
+ return MasterQueryContext;
+}
+
+ULONG
+MupDecodeFileObject(PFILE_OBJECT FileObject, PMUP_FCB * pFcb, PMUP_CCB * pCcb)
+{
+ ULONG Type;
+ PMUP_FCB Fcb;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ *pFcb = FileObject->FsContext;
+ *pCcb = FileObject->FsContext2;
+ Fcb = *pFcb;
+
+ if (Fcb == NULL)
+ {
+ ExReleaseResourceLite(&MupGlobalLock);
+ return 0;
+ }
+
+ Type = Fcb->NodeType;
+ if ((Type != NODE_TYPE_VCB && Type != NODE_TYPE_FCB) || (Fcb->NodeStatus
!= NODE_STATUS_HEALTHY && Fcb->NodeStatus != NODE_STATUS_CLEANUP))
+ {
+ *pFcb = 0;
+ ExReleaseResourceLite(&MupGlobalLock);
+ return 0;
+ }
+
+ ++Fcb->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ return Type;
+}
+
+VOID
+MupFreeNode(PVOID Node)
+{
+ ExFreePoolWithTag(Node, TAG_MUP);
+}
+
+VOID
+MupDereferenceFcb(PMUP_FCB Fcb)
+{
+ /* Just dereference and delete if no references left */
+ if (InterlockedDecrement(&Fcb->NodeReferences) == 0)
+ {
+ MupFreeNode(Fcb);
+ }
+}
+
+VOID
+MupDereferenceCcb(PMUP_CCB Ccb)
+{
+ /* Just dereference and delete (and clean) if no references left */
+ if (InterlockedDecrement(&Ccb->NodeReferences) == 0)
+ {
+ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
+ RemoveEntryList(&Ccb->CcbListEntry);
+ ExReleaseResourceLite(&MupCcbListLock);
+ ObDereferenceObject(Ccb->FileObject);
+ MupDereferenceFcb(Ccb->Fcb);
+ MupFreeNode(Ccb);
+ }
+}
+
+VOID
+MupDereferenceVcb(PMUP_VCB Vcb)
+{
+ /* We cannot reach the point where no references are left */
+ if (InterlockedDecrement(&Vcb->NodeReferences) == 0)
+ {
+ KeBugCheckEx(FILE_SYSTEM, 3, 0, 0, 0);
+ }
+}
+
+NTSTATUS
+MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext,
+ PNTSTATUS NewStatus)
+{
+ PIRP Irp;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+
+ Status = STATUS_SUCCESS;
+
+ if (NewStatus != NULL)
+ {
+ /* Save last status, depending on whether it failed or not */
+ if (!NT_SUCCESS(*NewStatus))
+ {
+ MasterIoContext->LastFailed = *NewStatus;
+ }
+ else
+ {
+ MasterIoContext->LastSuccess = STATUS_SUCCESS;
+ }
+ }
+
+ if (InterlockedDecrement(&MasterIoContext->NodeReferences) != 0)
+ {
+ return STATUS_PENDING;
+ }
+
+ Irp = MasterIoContext->Irp;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->MajorFunction == IRP_MJ_WRITE)
+ {
+ Irp->IoStatus.Information = Stack->Parameters.Write.Length;
+ }
+ else
+ {
+ Irp->IoStatus.Information = 0;
+ }
+
+ /* In case we never had any success (init is a failure), get the last failed status
*/
+ if (!NT_SUCCESS(MasterIoContext->LastSuccess))
+ {
+ Status = MasterIoContext->LastFailed;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ MupDereferenceFcb(MasterIoContext->Fcb);
+ MupFreeNode(MasterIoContext);
+
+ return Status;
+}
+
+VOID
+MupDereferenceUncProvider(PMUP_UNC UncProvider)
+{
+ InterlockedExchangeAdd(&UncProvider->NodeReferences, -1);
+}
+
+VOID
+MupDereferenceKnownPrefix(PMUP_PFX Prefix)
+{
+ /* Just dereference and delete (and clean) if no references left */
+ if (InterlockedDecrement(&Prefix->NodeReferences) == 0)
+ {
+ if (Prefix->InTable)
+ {
+ RtlRemoveUnicodePrefix(&MupPrefixTable,
&Prefix->PrefixTableEntry);
+ RemoveEntryList(&Prefix->PrefixListEntry);
+ }
+
+ if (Prefix->ExternalAlloc && Prefix->AcceptedPrefix.Buffer !=
NULL)
+ {
+ ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP);
+ }
+
+ if (Prefix->UncProvider)
+ {
+ MupDereferenceUncProvider(Prefix->UncProvider);
+ }
+
+ MupFreeNode(Prefix);
+ }
+}
+
+VOID
+MupRemoveKnownPrefixEntry(PMUP_PFX Prefix)
+{
+ RtlRemoveUnicodePrefix(&MupPrefixTable, &Prefix->PrefixTableEntry);
+ RemoveEntryList(&Prefix->PrefixListEntry);
+ Prefix->InTable = FALSE;
+ MupDereferenceKnownPrefix(Prefix);
+}
+
+VOID
+MupInvalidatePrefixTable(VOID)
+{
+ PMUP_PFX Prefix;
+ PLIST_ENTRY Entry;
+
+ /* Browse the prefix table */
+ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
+ for (Entry = MupPrefixList.Flink;
+ Entry != &MupPrefixList;
+ Entry = Entry->Flink)
+ {
+ Prefix = CONTAINING_RECORD(Entry, MUP_PFX, PrefixListEntry);
+
+ /* And remove any entry in it */
+ if (Prefix->InTable)
+ {
+ MupRemoveKnownPrefixEntry(Prefix);
+ }
+ }
+ ExReleaseResourceLite(&MupPrefixTableLock);
+}
+
+VOID
+MupCleanupVcb(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PMUP_VCB Vcb)
+{
+ ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE);
+
+ /* Check we're not doing anything wrong first */
+ if (Vcb->NodeStatus != NODE_STATUS_HEALTHY || Vcb->NodeType != NODE_TYPE_VCB)
+ {
+ ExRaiseStatus(STATUS_INVALID_HANDLE);
+ }
+
+ /* Remove share access */
+ IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp)->FileObject,
&Vcb->ShareAccess);
+
+ ExReleaseResourceLite(&MupVcbLock);
+}
+
+VOID
+MupCleanupFcb(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PMUP_FCB Fcb)
+{
+ PLIST_ENTRY Entry;
+ PMUP_CCB Ccb;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ /* Check we're not doing anything wrong first */
+ if (Fcb->NodeStatus != NODE_STATUS_HEALTHY || Fcb->NodeType != NODE_TYPE_FCB)
+ {
+ ExRaiseStatus(STATUS_INVALID_HANDLE);
+ }
+ Fcb->NodeStatus = NODE_STATUS_CLEANUP;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ /* Dereference any CCB associated with the FCB */
+ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
+ for (Entry = Fcb->CcbList.Flink;
+ Entry != &Fcb->CcbList;
+ Entry = Entry->Flink)
+ {
+ Ccb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry);
+ ExReleaseResourceLite(&MupCcbListLock);
+ MupDereferenceCcb(Ccb);
+ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
+ }
+ ExReleaseResourceLite(&MupCcbListLock);
+}
+
+NTSTATUS
+CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PFORWARDED_IO_CONTEXT FwdCtxt)
+{
+ NTSTATUS Status;
+
+ Status = Irp->IoStatus.Status;
+
+ /* Just free everything we had allocated */
+ if (Irp->MdlAddress != NULL)
+ {
+ MmUnlockPages(Irp->MdlAddress);
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
+ {
+ ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_MUP);
+ }
+
+ IoFreeIrp(Irp);
+
+ /* Dereference the master context
+ * The upper IRP will be completed once all the lower IRPs are done
+ * (and thus, references count reaches 0)
+ */
+ MupDereferenceCcb(FwdCtxt->Ccb);
+ MupDereferenceMasterIoContext(FwdCtxt->MasterIoContext, &Status);
+ ExFreePoolWithTag(FwdCtxt, TAG_MUP);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+VOID
+NTAPI
+DeferredForwardedIoCompletionRoutine(PVOID Context)
+{
+ PFORWARDED_IO_CONTEXT FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
+
+ CommonForwardedIoCompletionRoutine(FwdCtxt->DeviceObject, FwdCtxt->Irp,
Context);
+}
+
+NTSTATUS
+NTAPI
+ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context)
+{
+ PFORWARDED_IO_CONTEXT FwdCtxt;
+
+ /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
+ if (KeGetCurrentIrql() < DISPATCH_LEVEL)
+ {
+ CommonForwardedIoCompletionRoutine(DeviceObject, Irp, Context);
+ }
+ else
+ {
+ FwdCtxt = (PFORWARDED_IO_CONTEXT)Context;
+
+ ExInitializeWorkItem(&FwdCtxt->WorkQueueItem,
DeferredForwardedIoCompletionRoutine, Context);
+ ExQueueWorkItem(&FwdCtxt->WorkQueueItem, CriticalWorkQueue);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+BuildAndSubmitIrp(PIRP Irp,
+ PMUP_CCB Ccb,
+ PMUP_MIC MasterIoContext)
+{
+ PMDL Mdl;
+ PIRP LowerIrp;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+ PDEVICE_OBJECT DeviceObject;
+ PFORWARDED_IO_CONTEXT FwdCtxt;
+
+ Status = STATUS_SUCCESS;
+ LowerIrp = NULL;
+ Mdl = NULL;
+
+ /* Allocate a context for the completion routine */
+ FwdCtxt = ExAllocatePoolWithTag(NonPagedPool, sizeof(FORWARDED_IO_CONTEXT),
TAG_MUP);
+ if (FwdCtxt == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ /* Init it */
+ FwdCtxt->DeviceObject = NULL;
+ FwdCtxt->Irp = NULL;
+
+ /* Allocate the IRP */
+ DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject);
+ LowerIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
+ if (LowerIrp == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ /* Initialize it */
+ LowerIrp->Tail.Overlay.OriginalFileObject = Ccb->FileObject;
+ LowerIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
+ LowerIrp->RequestorMode = KernelMode;
+
+ /* Copy the stack of the request we received to the IRP we'll pass below */
+ Stack = IoGetNextIrpStackLocation(LowerIrp);
+ RtlMoveMemory(Stack, IoGetCurrentIrpStackLocation(Irp), sizeof(IO_STACK_LOCATION));
+ Stack->FileObject = Ccb->FileObject;
+ /* Setup flags according to the FO */
+ if (Ccb->FileObject->Flags & FO_WRITE_THROUGH)
+ {
+ Stack->Flags = SL_WRITE_THROUGH;
+ }
+
+ _SEH2_TRY
+ {
+ /* Does the device requires we do buffered IOs? */
+ if (DeviceObject->Flags & DO_BUFFERED_IO)
+ {
+ LowerIrp->AssociatedIrp.SystemBuffer = NULL;
+
+ if (Stack->Parameters.Write.Length == 0)
+ {
+ LowerIrp->Flags = IRP_BUFFERED_IO;
+ }
+ /* If we have data to pass */
+ else
+ {
+ /* If it's coming from usermode, probe first */
+ if (Irp->RequestorMode == UserMode)
+ {
+ ProbeForRead(Irp->UserBuffer, Stack->Parameters.Write.Length,
sizeof(UCHAR));
+ }
+
+ /* Allocate the buffer */
+ LowerIrp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned,
+
Stack->Parameters.Write.Length,
+
TAG_MUP);
+ if (LowerIrp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ /* And copy input (remember, we've to free!) */
+ RtlMoveMemory(LowerIrp->AssociatedIrp.SystemBuffer,
Irp->UserBuffer, Stack->Parameters.Write.Length);
+ LowerIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ }
+ }
+ else
+ {
+ if (!(DeviceObject->Flags & DO_DIRECT_IO))
+ {
+ LowerIrp->UserBuffer = Irp->UserBuffer;
+ }
+ else
+ {
+ /* For direct IOs, allocate an MDL and pass it */
+ if (Stack->Parameters.Write.Length != 0)
+ {
+ Mdl = IoAllocateMdl(Irp->UserBuffer,
Stack->Parameters.Write.Length, FALSE, TRUE, LowerIrp);
+ if (Mdl == NULL)
+ {
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoReadAccess);
+ }
+ }
+ }
+
+ /* Fix flags in the IRP */
+ if (Ccb->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+ {
+ LowerIrp->Flags |= IRP_WRITE_OPERATION | IRP_NOCACHE;
+ }
+ else
+ {
+ LowerIrp->Flags |= IRP_WRITE_OPERATION;
+ }
+
+ FwdCtxt->Ccb = Ccb;
+ FwdCtxt->MasterIoContext = MasterIoContext;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ ++MasterIoContext->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ /* Set out completion routine */
+ IoSetCompletionRoutine(LowerIrp, ForwardedIoCompletionRoutine, FwdCtxt, TRUE,
TRUE, TRUE);
+ /* And call the device with our brand new IRP */
+ Status = IoCallDriver(Ccb->DeviceObject, LowerIrp);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+Cleanup:
+ if (!NT_SUCCESS(Status))
+ {
+ if (FwdCtxt != NULL)
+ {
+ ExFreePoolWithTag(FwdCtxt, TAG_MUP);
+ }
+
+ if (LowerIrp != NULL)
+ {
+ if (LowerIrp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ ExFreePoolWithTag(LowerIrp->AssociatedIrp.SystemBuffer, TAG_MUP);
+ }
+
+ IoFreeIrp(LowerIrp);
+ }
+
+ if (Mdl != NULL)
+ {
+ IoFreeMdl(Mdl);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+DfsVolumePassThrough(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+MupForwardIoRequest(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PMUP_FCB Fcb;
+ PMUP_CCB Ccb;
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PMUP_CCB FcbListCcb;
+ BOOLEAN CcbLockAcquired;
+ PMUP_MIC MasterIoContext;
+ PIO_STACK_LOCATION Stack;
+
+ /* If DFS is enabled, check if that's for DFS and is so relay */
+ if (MupEnableDfs && DeviceObject->DeviceType == FILE_DEVICE_DFS)
+ {
+ return DfsVolumePassThrough(DeviceObject, Irp);
+ }
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ FsRtlEnterFileSystem();
+
+ /* Write request is only possible for a mailslot, we need a FCB */
+ MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
+ if (Fcb == NULL || Fcb->NodeType != NODE_TYPE_FCB)
+ {
+ FsRtlExitFileSystem();
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ goto Complete;
+ }
+
+ /* Allocate a context */
+ MasterIoContext = MupAllocateMasterIoContext();
+ if (MasterIoContext == NULL)
+ {
+ FsRtlExitFileSystem();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Complete;
+ }
+
+ /* Mark the IRP pending and init the context */
+ IoMarkIrpPending(Irp);
+ MasterIoContext->Irp = Irp;
+ /* Init with a failure to catch if we ever succeed */
+ MasterIoContext->LastSuccess = STATUS_UNSUCCESSFUL;
+ /* Init with the worth failure possible */
+ MasterIoContext->LastFailed = STATUS_BAD_NETWORK_PATH;
+ MasterIoContext->Fcb = Fcb;
+
+ _SEH2_TRY
+ {
+ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
+ CcbLockAcquired = TRUE;
+
+ /* For all the CCB (ie, the mailslots) we have */
+ for (Entry = Fcb->CcbList.Flink;
+ Entry != &Fcb->CcbList;
+ Entry = Entry->Flink)
+ {
+ FcbListCcb = CONTAINING_RECORD(Entry, MUP_CCB, CcbListEntry);
+ ExReleaseResourceLite(&MupCcbListLock);
+ CcbLockAcquired = FALSE;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ ++FcbListCcb->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ /* Forward the write request */
+ BuildAndSubmitIrp(Irp, FcbListCcb, MasterIoContext);
+ ExAcquireResourceExclusiveLite(&MupCcbListLock, TRUE);
+ CcbLockAcquired = TRUE;
+ }
+
+ ExReleaseResourceLite(&MupCcbListLock);
+ CcbLockAcquired = FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (CcbLockAcquired)
+ {
+ ExReleaseResourceLite(&MupCcbListLock);
+ }
+ }
+ _SEH2_END;
+
+ /* And done */
+ MupDereferenceMasterIoContext(MasterIoContext, NULL);
+ FsRtlExitFileSystem();
+
+ return STATUS_PENDING;
+
+Complete:
+ /* Failure case */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ return Status;
+}
+
+PMUP_UNC
+AddUnregisteredProvider(PCWSTR DeviceName,
+ ULONG ProviderOrder)
+{
+ PMUP_UNC UncProvider;
+ ULONG StrLen, NameLen;
+
+ /* Just allocate the node */
+ NameLen = wcslen(DeviceName);
+ StrLen = NameLen * sizeof(WCHAR);
+ UncProvider = MupAllocateUncProvider(StrLen);
+ if (UncProvider == NULL)
+ {
+ return NULL;
+ }
+
+ /* And init it */
+ UncProvider->DeviceName.MaximumLength = StrLen;
+ UncProvider->DeviceName.Length = StrLen;
+ UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider +
sizeof(MUP_UNC));
+ UncProvider->ProviderOrder = ProviderOrder;
+ RtlMoveMemory(UncProvider->DeviceName.Buffer, DeviceName, StrLen);
+
+ /* And add it to the global list
+ * We're using tail here so that when called from registry init,
+ * the providers with highest priority will be in the head of
+ * the list
+ */
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ InsertTailList(&MupProviderList, &UncProvider->ProviderListEntry);
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ return UncProvider;
+}
+
+VOID
+InitializeProvider(PCWSTR ProviderName,
+ ULONG ProviderOrder)
+{
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ UNICODE_STRING Key, Value;
+ PKEY_VALUE_FULL_INFORMATION Info;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG NameLen, StrLen, ResultLength;
+
+ /* Get the information about the provider from registry */
+ NameLen = wcslen(ProviderName);
+ StrLen = NameLen * sizeof(WCHAR) +
sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") +
sizeof(L"\\NetworkProvider");
+ Key.Buffer = ExAllocatePoolWithTag(PagedPool, StrLen, TAG_MUP);
+ if (Key.Buffer == NULL)
+ {
+ return;
+ }
+
+ RtlMoveMemory(Key.Buffer,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
+ Key.MaximumLength = StrLen;
+ Key.Length =
sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") -
sizeof(UNICODE_NULL);
+ RtlAppendUnicodeToString(&Key, ProviderName);
+ RtlAppendUnicodeToString(&Key, L"\\NetworkProvider");
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Key,
+ OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
+ ExFreePoolWithTag(Key.Buffer, TAG_MUP);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ RtlInitUnicodeString(&Value, L"DeviceName");
+ Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, NULL, 0,
&ResultLength);
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL),
TAG_MUP);
+ if (Info == NULL)
+ {
+ ZwClose(KeyHandle);
+ return;
+ }
+
+ Status = ZwQueryValueKey(KeyHandle, &Value, KeyValueFullInformation, Info,
ResultLength, &ResultLength);
+ }
+
+ ZwClose(KeyHandle);
+
+ /* And create the provider
+ * It will remain unregistered until FsRTL receives a registration request and
forwards
+ * it to MUP
+ */
+ if (NT_SUCCESS(Status))
+ {
+ AddUnregisteredProvider((PWSTR)((ULONG_PTR)Info + Info->DataOffset),
ProviderOrder);
+ }
+
+ if (Info != NULL)
+ {
+ ExFreePoolWithTag(Info, TAG_MUP);
+ }
+}
+
+VOID
+MupGetProviderInformation(VOID)
+{
+ BOOLEAN End;
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ PWSTR Providers, Coma;
+ PKEY_VALUE_FULL_INFORMATION Info;
+ ULONG ResultLength, ProviderCount;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING NetworkProvider, ProviderOrder;
+
+ /* Open the registry to get the order of the providers */
+ RtlInitUnicodeString(&NetworkProvider,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NetworkProvider,
+ OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ RtlInitUnicodeString(&ProviderOrder, L"ProviderOrder");
+ Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation,
NULL, 0, &ResultLength);
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ Info = ExAllocatePoolWithTag(PagedPool, ResultLength + sizeof(UNICODE_NULL),
TAG_MUP);
+ if (Info == NULL)
+ {
+ ZwClose(KeyHandle);
+ return;
+ }
+
+ Status = ZwQueryValueKey(KeyHandle, &ProviderOrder, KeyValueFullInformation,
Info, ResultLength, &ResultLength);
+ }
+
+ ZwClose(KeyHandle);
+
+ if (NT_SUCCESS(Status))
+ {
+ Providers = (PWSTR)((ULONG_PTR)Info + Info->DataOffset);
+ End = FALSE;
+ ProviderCount = 0;
+
+ /* For all the providers we got (coma-separated list), just create a provider
node with the right order
+ * The order is just the order of the list
+ * First has highest priority (0) and then, get lower and lower priority
+ * The highest number is the lowest priority
+ */
+ do
+ {
+ Coma = wcschr(Providers, L',');
+ if (Coma != NULL)
+ {
+ *Coma = UNICODE_NULL;
+ }
+ else
+ {
+ End = TRUE;
+ }
+
+ InitializeProvider(Providers, ProviderCount);
+ ++ProviderCount;
+
+ Providers = Coma + 1;
+ } while (!End);
+ }
+
+ if (Info != NULL)
+ {
+ ExFreePoolWithTag(Info, TAG_MUP);
+ }
+}
+
+PMUP_UNC
+MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName)
+{
+ PLIST_ENTRY Entry;
+ PMUP_UNC UncProvider;
+
+ /* Browse the list of all the providers nodes we have */
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry =
Entry->Flink)
+ {
+ UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
+
+ /* If one matches the device and is not registered, that's ours! */
+ if (!UncProvider->Registered &&
RtlEqualUnicodeString(RedirectorDeviceName, &UncProvider->DeviceName, TRUE))
+ {
+ UncProvider->NodeStatus = NODE_STATUS_HEALTHY;
+ break;
+ }
+ }
+
+ if (Entry == &MupProviderList)
+ {
+ UncProvider = NULL;
+ }
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ return UncProvider;
+}
+
+NTSTATUS
+RegisterUncProvider(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+
+{
+ BOOLEAN New;
+ PMUP_FCB Fcb;
+ PMUP_CCB Ccb;
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PIO_STACK_LOCATION Stack;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PMUP_UNC UncProvider, ListEntry;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING RedirectorDeviceName;
+ OBJECT_HANDLE_INFORMATION HandleInfo;
+ PMUP_PROVIDER_REGISTRATION_INFO RegInfo;
+
+ DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject, Irp);
+ New = FALSE;
+
+ /* Check whether providers order was already initialized */
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ if (MupOrderInitialized)
+ {
+ ExReleaseResourceLite(&MupGlobalLock);
+ }
+ else
+ {
+ /* They weren't, so do it */
+ MupOrderInitialized = TRUE;
+ ExReleaseResourceLite(&MupGlobalLock);
+ MupGetProviderInformation();
+ }
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* This can only happen with a volume open */
+ if (MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb) != NODE_TYPE_VCB)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_HANDLE;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ /* Get the registration information */
+ RegInfo = (PMUP_PROVIDER_REGISTRATION_INFO)Irp->AssociatedIrp.SystemBuffer;
+ _SEH2_TRY
+ {
+ RedirectorDeviceName.Length = RegInfo->RedirectorDeviceNameLength;
+ RedirectorDeviceName.MaximumLength = RedirectorDeviceName.Length;
+ RedirectorDeviceName.Buffer = (PWSTR)((ULONG_PTR)RegInfo +
RegInfo->RedirectorDeviceNameOffset);
+
+ /* Have we got already a node for it? (Like from previous init) */
+ UncProvider = MupCheckForUnregisteredProvider(&RedirectorDeviceName);
+ if (UncProvider == NULL)
+ {
+ /* If we don't, allocate a new one */
+ New = TRUE;
+ UncProvider =
MupAllocateUncProvider(RegInfo->RedirectorDeviceNameLength);
+ if (UncProvider == NULL)
+ {
+ Status = STATUS_INVALID_USER_BUFFER;
+ _SEH2_LEAVE;
+ }
+
+ /* Set it up */
+ UncProvider->DeviceName.Length = RedirectorDeviceName.Length;
+ UncProvider->DeviceName.MaximumLength =
RedirectorDeviceName.MaximumLength;
+ UncProvider->DeviceName.Buffer = (PWSTR)((ULONG_PTR)UncProvider +
sizeof(MUP_UNC));
+
+ /* As it wasn't in registry for order, give the lowest priority possible
*/
+ UncProvider->ProviderOrder = MAXLONG;
+ RtlMoveMemory(UncProvider->DeviceName.Buffer, (PWSTR)((ULONG_PTR)RegInfo +
RegInfo->RedirectorDeviceNameOffset), RegInfo->RedirectorDeviceNameLength);
+ }
+
+ /* Continue registration */
+ UncProvider->MailslotsSupported = RegInfo->MailslotsSupported;
+ ++UncProvider->NodeReferences;
+
+ /* Open a handle to the device */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &UncProvider->DeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenFile(&UncProvider->DeviceHandle,
+ FILE_TRAVERSE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE);
+ if (NT_SUCCESS(Status))
+ {
+ Status = IoStatusBlock.Status;
+ }
+
+ /* And return the provider (as CCB) */
+ if (NT_SUCCESS(Status))
+ {
+ Stack->FileObject->FsContext2 = UncProvider;
+ Status = ObReferenceObjectByHandle(UncProvider->DeviceHandle, 0, NULL,
KernelMode, (PVOID *)&UncProvider->FileObject, &HandleInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(UncProvider->DeviceHandle);
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ MupDereferenceUncProvider(UncProvider);
+ }
+ else
+ {
+ UncProvider->DeviceObject =
IoGetRelatedDeviceObject(UncProvider->FileObject);
+
+ /* Now, insert the provider in our global list
+ * They are sorted by order
+ */
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ ++MupProviderCount;
+ if (New)
+ {
+ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry
= Entry->Flink)
+ {
+ ListEntry = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
+
+ if (UncProvider->ProviderOrder < ListEntry->ProviderOrder)
+ {
+ break;
+ }
+ }
+
+ InsertTailList(Entry, &UncProvider->ProviderListEntry);
+ }
+ UncProvider->Registered = TRUE;
+ ExReleaseResourceLite(&MupGlobalLock);
+ Status = STATUS_SUCCESS;
+
+ DPRINT1("UNC provider %wZ registered\n",
&UncProvider->DeviceName);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (_abnormal_termination())
+ {
+ Status = STATUS_INVALID_USER_BUFFER;
+ }
+
+ MupDereferenceVcb((PMUP_VCB)Fcb);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+DfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+MupFsControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ _SEH2_TRY
+ {
+ /* MUP only understands a single FSCTL code: registering UNC provider */
+ if (Stack->Parameters.FileSystemControl.FsControlCode ==
FSCTL_MUP_REGISTER_PROVIDER)
+ {
+ /* It obviously has to come from a driver/kernelmode thread */
+ if (Irp->RequestorMode == UserMode)
+ {
+ Status = STATUS_ACCESS_DENIED;
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ _SEH2_LEAVE;
+ }
+
+ Status = RegisterUncProvider(DeviceObject, Irp);
+ }
+ else
+ {
+ /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
+ if (!MupEnableDfs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ _SEH2_LEAVE;
+ }
+
+ Status = DfsFsdFileSystemControl(DeviceObject, Irp);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+VOID
+MupSetFileObject(PFILE_OBJECT FileObject,
+ PMUP_FCB Fcb,
+ PMUP_CCB Ccb)
+{
+ FileObject->FsContext = Fcb;
+ FileObject->FsContext2 = Ccb;
+}
+
+NTSTATUS
+MupRerouteOpen(PFILE_OBJECT FileObject,
+ PMUP_UNC UncProvider)
+{
+ PWSTR FullPath;
+ ULONG TotalLength;
+
+ DPRINT1("Rerouting %wZ with %wZ\n", &FileObject->FileName,
&UncProvider->DeviceName);
+
+ /* Get the full path name (device name first, and requested file name appended) */
+ TotalLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
+ if (TotalLength > MAXUSHORT)
+ {
+ return STATUS_NAME_TOO_LONG;
+ }
+
+ /* Allocate a buffer big enough */
+ FullPath = ExAllocatePoolWithTag(PagedPool, TotalLength, TAG_MUP);
+ if (FullPath == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Create the full path */
+ RtlMoveMemory(FullPath, UncProvider->DeviceName.Buffer,
UncProvider->DeviceName.Length);
+ RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath + UncProvider->DeviceName.Length),
FileObject->FileName.Buffer, FileObject->FileName.Length);
+
+ /* And redo the path in the file oject */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
+ FileObject->FileName.Buffer = FullPath;
+ FileObject->FileName.MaximumLength = TotalLength;
+ FileObject->FileName.Length = FileObject->FileName.MaximumLength;
+
+ /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
+ return STATUS_REPARSE;
+}
+
+NTSTATUS
+BroadcastOpen(PIRP Irp)
+{
+ PMUP_FCB Fcb;
+ PMUP_CCB Ccb;
+ HANDLE Handle;
+ PLIST_ENTRY Entry;
+ PMUP_UNC UncProvider;
+ UNICODE_STRING FullPath;
+ PFILE_OBJECT FileObject;
+ PIO_STACK_LOCATION Stack;
+ NTSTATUS Status, LastFailed;
+ ULONG TotalLength, LastOrder;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_HANDLE_INFORMATION HandleInfo;
+ BOOLEAN Locked, Referenced, CcbInitialized;
+
+ Fcb = MupCreateFcb();
+ if (Fcb == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ FileObject = Stack->FileObject;
+ Locked = FALSE;
+ Referenced = FALSE;
+ CcbInitialized = FALSE;
+ LastFailed = STATUS_NO_SUCH_FILE;
+ LastOrder = (ULONG)-1;
+
+ _SEH2_TRY
+ {
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ Locked = TRUE;
+
+ /* Associate our FCB with the FO */
+ MupSetFileObject(FileObject, Fcb, NULL);
+ Fcb->FileObject = FileObject;
+
+ /* Now, broadcast the open to any UNC provider that supports mailslots */
+ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry =
Entry->Flink)
+ {
+ UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
+ ++UncProvider->NodeReferences;
+ Referenced = TRUE;
+
+ ExReleaseResourceLite(&MupGlobalLock);
+ Locked = FALSE;
+
+ TotalLength = UncProvider->DeviceName.Length +
FileObject->FileName.Length;
+ if (UncProvider->MailslotsSupported && TotalLength <=
MAXUSHORT)
+ {
+ /* Provide the correct name for the mailslot (ie, happened the device
name of the provider) */
+ FullPath.Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength,
TAG_MUP);
+ if (FullPath.Buffer == NULL)
+ {
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ FullPath.Length = TotalLength;
+ FullPath.MaximumLength = TotalLength;
+ RtlMoveMemory(FullPath.Buffer, UncProvider->DeviceName.Buffer,
UncProvider->DeviceName.Length);
+ RtlMoveMemory((PWSTR)((ULONG_PTR)FullPath.Buffer +
UncProvider->DeviceName.Length),
+ FileObject->FileName.Buffer,
+ FileObject->FileName.Length);
+
+ /* And just forward the creation request */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &FullPath,
+ OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = IoCreateFile(&Handle,
+
Stack->Parameters.Create.SecurityContext->DesiredAccess &
FILE_SIMPLE_RIGHTS_MASK,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ Stack->Parameters.Create.FileAttributes &
FILE_ATTRIBUTE_VALID_FLAGS,
+ Stack->Parameters.Create.ShareAccess &
FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN,
+ Stack->Parameters.Create.Options &
FILE_VALID_SET_FLAGS,
+ NULL,
+ 0,
+ CreateFileTypeNone,
+ NULL,
+ IO_NO_PARAMETER_CHECKING);
+
+ ExFreePoolWithTag(FullPath.Buffer, TAG_MUP);
+
+ /* If opening succeed */
+ if (NT_SUCCESS(Status))
+ {
+ Status = IoStatusBlock.Status;
+
+ /* Create a CCB */
+ Ccb = MupCreateCcb();
+ if (Ccb == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* And associated a FO to it */
+ if (NT_SUCCESS(Status))
+ {
+ Status = ObReferenceObjectByHandle(Handle, 0, 0, 0, (PVOID
*)&Ccb->FileObject, &HandleInfo);
+ ZwClose(Handle);
+ }
+ }
+
+ /* If we failed, remember the last failed status of the higher priority
provider */
+ if (!NT_SUCCESS(Status))
+ {
+ if (UncProvider->ProviderOrder <= LastOrder)
+ {
+ LastOrder = UncProvider->ProviderOrder;
+ LastFailed = Status;
+ }
+ }
+ /* Otherwise, properly attach our CCB to the mailslot */
+ else
+ {
+ Ccb->DeviceObject = IoGetRelatedDeviceObject(Ccb->FileObject);
+ Ccb->Fcb = Fcb;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ Locked = TRUE;
+ ++Fcb->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+ Locked = FALSE;
+ CcbInitialized = TRUE;
+
+ InsertTailList(&Fcb->CcbList, &Ccb->CcbListEntry);
+ }
+ }
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ Locked = TRUE;
+ MupDereferenceUncProvider(UncProvider);
+ Referenced = FALSE;
+ }
+
+ ExReleaseResourceLite(&MupGlobalLock);
+ Locked = FALSE;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* If we at least opened one mailslot, return success */
+ Status = (CcbInitialized ? STATUS_SUCCESS : LastFailed);
+
+ if (Referenced)
+ {
+ MupDereferenceUncProvider(UncProvider);
+ }
+
+ if (Locked)
+ {
+ ExReleaseResourceLite(&MupGlobalLock);
+ }
+
+ /* In case of failure, don't leak CCB */
+ if (!NT_SUCCESS(Status) && Ccb != NULL)
+ {
+ MupFreeNode(Ccb);
+ }
+
+ return Status;
+}
+
+PIRP
+MupBuildIoControlRequest(PFILE_OBJECT FileObject,
+ PVOID Context,
+ ULONG MajorFunction,
+ ULONG IoctlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferSize,
+ PVOID OutputBuffer,
+ ULONG OutputBufferSize,
+ PIO_COMPLETION_ROUTINE CompletionRoutine)
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION Stack;
+ PDEVICE_OBJECT DeviceObject;
+
+ if (InputBuffer == NULL)
+ {
+ return NULL;
+ }
+
+ /* Get the device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ /* Allocate the IRP (with one more location for us */
+ Irp = IoAllocateIrp(DeviceObject->StackSize + 1, FALSE);
+ if (Irp == NULL)
+ {
+ return NULL;
+ }
+
+ /* Skip our location */
+ IoSetNextIrpStackLocation(Irp);
+ /* Setup the IRP */
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ IoSetCompletionRoutine(Irp, CompletionRoutine, Context, TRUE, TRUE, TRUE);
+
+ /* Setup the stack */
+ Stack = IoGetNextIrpStackLocation(Irp);
+ Stack->MajorFunction = MajorFunction;
+ Stack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferSize;
+ Stack->Parameters.DeviceIoControl.InputBufferLength = InputBufferSize;
+ Stack->Parameters.DeviceIoControl.IoControlCode = IoctlCode;
+ Stack->MinorFunction = 0;
+ Stack->FileObject = FileObject;
+ Stack->DeviceObject = DeviceObject;
+
+ switch (IO_METHOD_FROM_CTL_CODE(IoctlCode))
+ {
+ case METHOD_BUFFERED:
+ /* If it's buffered, just pass the buffers we got */
+ Irp->MdlAddress = NULL;
+ Irp->AssociatedIrp.SystemBuffer = InputBuffer;
+ Irp->UserBuffer = OutputBuffer;
+ Irp->Flags = IRP_BUFFERED_IO;
+
+ if (OutputBuffer != NULL)
+ {
+ Irp->Flags |= IRP_INPUT_OPERATION;
+ }
+ break;
+
+ case METHOD_IN_DIRECT:
+ case METHOD_OUT_DIRECT:
+ /* Otherwise, allocate an MDL */
+ if (IoAllocateMdl(InputBuffer, InputBufferSize, FALSE, FALSE, Irp) == NULL)
+ {
+ IoFreeIrp(Irp);
+ return NULL;
+ }
+
+ Irp->AssociatedIrp.SystemBuffer = InputBuffer;
+ Irp->Flags = IRP_BUFFERED_IO;
+ MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoReadAccess);
+ break;
+
+ case METHOD_NEITHER:
+ /* Or pass the buffers */
+ Irp->UserBuffer = OutputBuffer;
+ Irp->MdlAddress = NULL;
+ Irp->AssociatedIrp.SystemBuffer = NULL;
+ Stack->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
+ break;
+ }
+
+ return Irp;
+}
+
+VOID
+MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext)
+{
+ ExDeleteResourceLite(&MasterQueryContext->QueryPathListLock);
+ ExFreePoolWithTag(MasterQueryContext, TAG_MUP);
+}
+
+NTSTATUS
+MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext)
+{
+ LONG References;
+ NTSTATUS Status;
+ BOOLEAN KeepExtraRef;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ --MasterQueryContext->NodeReferences;
+ References = MasterQueryContext->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ if (References != 0)
+ {
+ DPRINT1("Still having refs (%ld)\n", References);
+ return STATUS_PENDING;
+ }
+
+ /* We HAVE an IRP to complete. It cannot be NULL
+ * Please, help preserving kittens, don't provide NULL IRPs.
+ */
+ if (MasterQueryContext->Irp == NULL)
+ {
+ KeBugCheck(FILE_SYSTEM);
+ }
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ RemoveEntryList(&MasterQueryContext->MQCListEntry);
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
+ KeepExtraRef = MasterQueryContext->Prefix->KeepExtraRef;
+ MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
+
+ /* We found a provider? */
+ if (MasterQueryContext->LatestProvider != NULL)
+ {
+ /* With a successful status? */
+ if (MasterQueryContext->LatestStatus == STATUS_SUCCESS)
+ {
+ /* Then, it's time to reroute, someone accepted to handle the file
creation request! */
+ if (!KeepExtraRef)
+ {
+ MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
+ }
+
+ ExReleaseResourceLite(&MupPrefixTableLock);
+ /* Reroute & complete :-) */
+ Status = MupRerouteOpen(MasterQueryContext->FileObject,
MasterQueryContext->LatestProvider);
+ goto Complete;
+ }
+ else
+ {
+ MupDereferenceUncProvider(MasterQueryContext->LatestProvider);
+ }
+ }
+
+ MupDereferenceKnownPrefix(MasterQueryContext->Prefix);
+ ExReleaseResourceLite(&MupPrefixTableLock);
+
+ /* Return the highest failed status we had */
+ Status = MasterQueryContext->LatestStatus;
+
+Complete:
+ /* In finally, complete the IRP for real! */
+ MasterQueryContext->Irp->IoStatus.Status = Status;
+ IofCompleteRequest(MasterQueryContext->Irp, IO_DISK_INCREMENT);
+
+ MasterQueryContext->Irp = NULL;
+ MupFreeMasterQueryContext(MasterQueryContext);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context)
+{
+ PMUP_PFX Prefix;
+ ULONG LatestPos, Pos;
+ PWSTR AcceptedPrefix;
+ PMUP_MQC MasterQueryContext;
+ NTSTATUS Status, TableStatus;
+ PQUERY_PATH_CONTEXT QueryContext;
+ PQUERY_PATH_RESPONSE QueryResponse;
+
+ /* Get all the data from our query to the provider */
+ QueryContext = (PQUERY_PATH_CONTEXT)Context;
+ QueryResponse = (PQUERY_PATH_RESPONSE)QueryContext->QueryPathRequest;
+ MasterQueryContext = QueryContext->MasterQueryContext;
+ Status = Irp->IoStatus.Status;
+
+ DPRINT1("Reply from %wZ: %u (Status: %lx)\n",
&QueryContext->UncProvider->DeviceName, QueryResponse->LengthAccepted,
Status);
+
+ ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE);
+ RemoveEntryList(&QueryContext->QueryPathListEntry);
+
+ /* If the driver returned a success, and an acceptance length */
+ if (NT_SUCCESS(Status) && QueryResponse->LengthAccepted > 0)
+ {
+ Prefix = MasterQueryContext->Prefix;
+
+ /* Check if we already found a provider from a previous iteration */
+ if (MasterQueryContext->LatestProvider != NULL)
+ {
+ /* If the current provider has a lower priority (ie, a greater order), then,
bailout and keep previous one */
+ if (QueryContext->UncProvider->ProviderOrder >=
MasterQueryContext->LatestProvider->ProviderOrder)
+ {
+ MupDereferenceUncProvider(QueryContext->UncProvider);
+ goto Cleanup;
+ }
+
+ /* Otherwise, if the prefix was in the prefix table, just drop it:
+ * we have a provider which superseeds the accepted prefix, so leave
+ * room for the new prefix/provider
+ */
+ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
+ if (Prefix->InTable)
+ {
+ RtlRemoveUnicodePrefix(&MupPrefixTable,
&Prefix->PrefixTableEntry);
+ RemoveEntryList(&Prefix->PrefixListEntry);
+ Prefix->InTable = FALSE;
+ }
+ ExReleaseResourceLite(&MupPrefixTableLock);
+
+ Prefix->KeepExtraRef = FALSE;
+
+ /* Release data associated with the current prefix, if any
+ * We'll renew them with the new accepted prefix
+ */
+ if (Prefix->AcceptedPrefix.Length != 0 &&
Prefix->AcceptedPrefix.Buffer != NULL)
+ {
+ ExFreePoolWithTag(Prefix->AcceptedPrefix.Buffer, TAG_MUP);
+ Prefix->AcceptedPrefix.MaximumLength = 0;
+ Prefix->AcceptedPrefix.Length = 0;
+ Prefix->AcceptedPrefix.Buffer = NULL;
+ Prefix->ExternalAlloc = FALSE;
+ }
+
+ /* If there was also a provider, drop it, the new one
+ * is different
+ */
+ if (Prefix->UncProvider != NULL)
+ {
+ MupDereferenceUncProvider(Prefix->UncProvider);
+ Prefix->UncProvider = NULL;
+ }
+ }
+
+ /* Now, set our information about the provider that accepted the prefix */
+ MasterQueryContext->LatestProvider = QueryContext->UncProvider;
+ MasterQueryContext->LatestStatus = Status;
+
+ if (MasterQueryContext->FileObject->FsContext2 != DFS_MAGIC_CCB)
+ {
+ /* Allocate a buffer for the prefix */
+ AcceptedPrefix = ExAllocatePoolWithTag(PagedPool,
QueryResponse->LengthAccepted, TAG_MUP);
+ if (AcceptedPrefix == NULL)
+ {
+ Prefix->InTable = FALSE;
+ }
+ else
+ {
+ /* Set it up to the accepted length */
+ RtlMoveMemory(AcceptedPrefix,
MasterQueryContext->FileObject->FileName.Buffer, QueryResponse->LengthAccepted);
+ Prefix->UncProvider = MasterQueryContext->LatestProvider;
+ Prefix->AcceptedPrefix.Buffer = AcceptedPrefix;
+ Prefix->AcceptedPrefix.Length = QueryResponse->LengthAccepted;
+ Prefix->AcceptedPrefix.MaximumLength =
QueryResponse->LengthAccepted;
+ Prefix->ExternalAlloc = TRUE;
+
+ /* Insert the accepted prefix in the table of known prefixes */
+ DPRINT1("%wZ accepted %wZ\n",
&Prefix->UncProvider->DeviceName, &Prefix->AcceptedPrefix);
+ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
+ if (RtlInsertUnicodePrefix(&MupPrefixTable,
&Prefix->AcceptedPrefix, &Prefix->PrefixTableEntry))
+ {
+ InsertHeadList(&MupPrefixList, &Prefix->PrefixListEntry);
+ Prefix->InTable = TRUE;
+ Prefix->KeepExtraRef = TRUE;
+ }
+ else
+ {
+ Prefix->InTable = FALSE;
+ }
+ ExReleaseResourceLite(&MupPrefixTableLock);
+ }
+ }
+ }
+ else
+ {
+ MupDereferenceUncProvider(QueryContext->UncProvider);
+
+ /* We failed and didn't find any provider over the latest iterations */
+ if (MasterQueryContext->LatestProvider == NULL)
+ {
+ /* If we had a success though (broken provider?) set our failed status */
+ if (NT_SUCCESS(MasterQueryContext->LatestStatus))
+ {
+ MasterQueryContext->LatestStatus = Status;
+ }
+ else
+ {
+ TableStatus = MupOrderedErrorList[0];
+ LatestPos = 0;
+
+ /* Otherwise, time to compare statuteses, between the latest failed
+ * and the current failure.
+ * We have an order table of failed status: the deeper you go in the
+ * table, the more the error is critical.
+ * Our goal is to return the most critical status that was returned by
+ * any of the providers
+ */
+
+ /* Look for latest status position */
+ while (TableStatus != 0 && TableStatus !=
MasterQueryContext->LatestStatus)
+ {
+ ++LatestPos;
+ TableStatus = MupOrderedErrorList[LatestPos];
+ }
+
+ /* If at pos 0, the new status is likely more critical */
+ if (LatestPos == 0)
+ {
+ MasterQueryContext->LatestStatus = Status;
+ }
+ else
+ {
+ /* Otherwise, find position of the new status in the table */
+ Pos = 0;
+ do
+ {
+ if (Status == MupOrderedErrorList[Pos])
+ {
+ break;
+ }
+
+ ++Pos;
+ }
+ while (Pos < LatestPos);
+
+ /* If it has a higher position (more critical), return it */
+ if (Pos >= LatestPos)
+ {
+ MasterQueryContext->LatestStatus = Status;
+ }
+ }
+ }
+ }
+ }
+
+Cleanup:
+ ExFreePoolWithTag(QueryResponse, TAG_MUP);
+ ExFreePoolWithTag(QueryContext, TAG_MUP);
+ IoFreeIrp(Irp);
+
+ ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock);
+ MupDereferenceMasterQueryContext(MasterQueryContext);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+DfsFsdCreate(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+CreateRedirectedFile(PIRP Irp,
+ PFILE_OBJECT FileObject,
+ PIO_SECURITY_CONTEXT SecurityContext)
+{
+ LONG Len;
+ WCHAR Cur;
+ PWSTR Name;
+ PIRP QueryIrp;
+ NTSTATUS Status;
+ PMUP_PFX Prefix;
+ PLIST_ENTRY Entry;
+ PMUP_UNC UncProvider;
+ PIO_STACK_LOCATION Stack;
+ LARGE_INTEGER CurrentTime;
+ PMUP_MQC MasterQueryContext;
+ PQUERY_PATH_CONTEXT QueryContext;
+ PQUERY_PATH_REQUEST QueryPathRequest;
+ PUNICODE_PREFIX_TABLE_ENTRY TableEntry;
+ BOOLEAN Locked, Referenced, BreakOnFirst;
+
+ /* We cannot open a file without a name */
+ if (FileObject->FileName.Length == 0)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ DPRINT1("Request for opening: %wZ\n", &FileObject->FileName);
+
+ Referenced = FALSE;
+ BreakOnFirst = TRUE;
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ ExAcquireResourceExclusiveLite(&MupPrefixTableLock, TRUE);
+ /* First, try to see if that's a prefix we already know */
+ TableEntry = RtlFindUnicodePrefix(&MupPrefixTable, &FileObject->FileName,
1);
+ if (TableEntry != NULL)
+ {
+ Prefix = CONTAINING_RECORD(TableEntry, MUP_PFX, PrefixTableEntry);
+
+ DPRINT1("Matching prefix found: %wZ\n",
&Prefix->AcceptedPrefix);
+
+ /* If so, check whether the prefix is still valid */
+ KeQuerySystemTime(&CurrentTime);
+ if (Prefix->ValidityTimeout.QuadPart < CurrentTime.QuadPart)
+ {
+ /* It is: so, update its validity period and reroute file opening */
+ MupCalculateTimeout(&Prefix->ValidityTimeout);
+ Status = MupRerouteOpen(FileObject, Prefix->UncProvider);
+ ExReleaseResourceLite(&MupPrefixTableLock);
+
+ if (Status == STATUS_REPARSE)
+ {
+ Irp->IoStatus.Information = FILE_SUPERSEDED;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return Status;
+ }
+
+ /* When here, we found a matching prefix, but expired, remove it from the table
+ * We'll redo a full search
+ */
+ if (Prefix->InTable)
+ {
+ MupRemoveKnownPrefixEntry(Prefix);
+ }
+ }
+ ExReleaseResourceLite(&MupPrefixTableLock);
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ /* First of all, start looking for a mailslot */
+ if (FileObject->FileName.Buffer[0] == L'\\' &&
Stack->MajorFunction != IRP_MJ_CREATE)
+ {
+ Name = &FileObject->FileName.Buffer[1];
+ Len = FileObject->FileName.Length;
+
+ /* Skip the remote destination name */
+ do
+ {
+ Len -= sizeof(WCHAR);
+ if (Len <= 0)
+ {
+ break;
+ }
+
+ Cur = *Name;
+ ++Name;
+ } while (Cur != L'\\');
+ Len -= sizeof(WCHAR);
+
+ /* If we still have room for "Mailslot" to fit */
+ if (Len >= (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)))
+ {
+ /* Get the len in terms of chars count */
+ Len /= sizeof(WCHAR);
+ if (Len > ((sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) /
sizeof(WCHAR)))
+ {
+ Len = (sizeof(L"Mailslot") - sizeof(UNICODE_NULL)) /
sizeof(WCHAR);
+ }
+
+ /* It's indeed a mailslot opening! */
+ if (_wcsnicmp(Name, L"Mailslot", Len) == 0)
+ {
+ /* Broadcast open */
+ Status = BroadcastOpen(Irp);
+ if (Status == STATUS_REPARSE)
+ {
+ Irp->IoStatus.Information = FILE_SUPERSEDED;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return Status;
+ }
+ }
+ }
+
+ /* Ok, at that point, that's a regular MUP opening (if no DFS) */
+ if (!MupEnableDfs || FileObject->FsContext2 == DFS_MAGIC_CCB)
+ {
+ /* We won't complete immediately */
+ IoMarkIrpPending(Irp);
+
+ /* Allocate a new prefix for our search */
+ Prefix = MupAllocatePrefixEntry(0);
+ if (Prefix == NULL)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return STATUS_PENDING;
+ }
+
+ /* Allocate a context for our search */
+ MasterQueryContext = MupAllocateMasterQueryContext();
+ if (MasterQueryContext == NULL)
+ {
+ MupFreeNode(Prefix);
+
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return STATUS_PENDING;
+ }
+
+ MasterQueryContext->Irp = Irp;
+ MasterQueryContext->FileObject = FileObject;
+ MasterQueryContext->LatestProvider = NULL;
+ MasterQueryContext->Prefix = Prefix;
+ MasterQueryContext->LatestStatus = STATUS_BAD_NETWORK_PATH;
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ InsertTailList(&MupMasterQueryList,
&MasterQueryContext->MQCListEntry);
+ ++Prefix->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ _SEH2_TRY
+ {
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ Locked = TRUE;
+
+ /* Now, we will browse all the providers we know, to ask for their accepted
prefix regarding the path */
+ for (Entry = MupProviderList.Flink; Entry != &MupProviderList; Entry =
Entry->Flink)
+ {
+ UncProvider = CONTAINING_RECORD(Entry, MUP_UNC, ProviderListEntry);
+
+ ++UncProvider->NodeReferences;
+ Referenced = TRUE;
+
+ ExReleaseResourceLite(&MupGlobalLock);
+ Locked = FALSE;
+
+ /* We will obviously only query registered providers */
+ if (UncProvider->Registered)
+ {
+ /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer
*/
+ QueryPathRequest = ExAllocatePoolWithTag(PagedPool,
FileObject->FileName.Length + sizeof(QUERY_PATH_REQUEST), TAG_MUP);
+ if (QueryPathRequest == NULL)
+ {
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ /* Allocate a context for IRP completion routine
+ * In case a prefix matches the path, the reroute will happen
+ * in the completion routine, when we have return from the provider
+ */
+ QueryContext = ExAllocatePoolWithTag(PagedPool,
sizeof(QUERY_PATH_CONTEXT), TAG_MUP);
+ if (QueryContext == NULL)
+ {
+ ExFreePoolWithTag(QueryPathRequest, TAG_MUP);
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ InitializeListHead(&QueryContext->QueryPathListEntry);
+ QueryContext->MasterQueryContext = MasterQueryContext;
+ QueryContext->QueryPathRequest = QueryPathRequest;
+ QueryPathRequest->PathNameLength =
FileObject->FileName.Length;
+ QueryPathRequest->SecurityContext = SecurityContext;
+ RtlMoveMemory(QueryPathRequest->FilePathName,
FileObject->FileName.Buffer, FileObject->FileName.Length);
+
+ /* Build our IRP for the query */
+ QueryIrp = MupBuildIoControlRequest(UncProvider->FileObject,
+ QueryContext,
+ IRP_MJ_DEVICE_CONTROL,
+ IOCTL_REDIR_QUERY_PATH,
+ QueryPathRequest,
+ FileObject->FileName.Length +
sizeof(QUERY_PATH_REQUEST),
+ QueryPathRequest,
+ sizeof(QUERY_PATH_RESPONSE),
+ QueryPathCompletionRoutine);
+ if (QueryIrp == NULL)
+ {
+ ExFreePoolWithTag(QueryContext, TAG_MUP);
+ ExFreePoolWithTag(QueryPathRequest, TAG_MUP);
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ QueryIrp->RequestorMode = KernelMode;
+ QueryContext->UncProvider = UncProvider;
+ QueryContext->Irp = QueryIrp;
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ ++UncProvider->NodeReferences;
+ ++MasterQueryContext->NodeReferences;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+
ExAcquireResourceExclusiveLite(&MasterQueryContext->QueryPathListLock, TRUE);
+ InsertTailList(&MasterQueryContext->QueryPathList,
&QueryContext->QueryPathListEntry);
+
ExReleaseResourceLite(&MasterQueryContext->QueryPathListLock);
+
+ /* Query the provider !*/
+ DPRINT1("Requeting UNC provider: %wZ\n",
&UncProvider->DeviceName);
+ DPRINT1("Calling: %wZ\n",
&UncProvider->DeviceObject->DriverObject->DriverName);
+ Status = IoCallDriver(UncProvider->DeviceObject, QueryIrp);
+ }
+
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ Locked = TRUE;
+
+ /* We're done with that provider */
+ MupDereferenceUncProvider(UncProvider);
+ Referenced = FALSE;
+
+ /* If query went fine on the first request, just break and leave */
+ if (BreakOnFirst && Status == STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ BreakOnFirst = FALSE;
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (_abnormal_termination())
+ {
+ MasterQueryContext->LatestStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (Referenced)
+ {
+ MupDereferenceUncProvider(UncProvider);
+ }
+
+ if (Locked)
+ {
+ ExReleaseResourceLite(&MupGlobalLock);
+ }
+
+ MupDereferenceMasterQueryContext(MasterQueryContext);
+
+ Status = STATUS_PENDING;
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+OpenMupFileSystem(PMUP_VCB Vcb,
+ PFILE_OBJECT FileObject,
+ ACCESS_MASK DesiredAccess,
+ USHORT ShareAccess)
+{
+ NTSTATUS Status;
+
+ DPRINT1("Opening MUP\n");
+
+ ExAcquireResourceExclusiveLite(&MupVcbLock, TRUE);
+ _SEH2_TRY
+ {
+ /* Update share access, increase reference count, and associated VCB to the FO,
that's it! */
+ Status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject,
&Vcb->ShareAccess, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ ++Vcb->NodeReferences;
+ MupSetFileObject(FileObject, (PMUP_FCB)Vcb, NULL);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ _SEH2_FINALLY
+ {
+ ExReleaseResourceLite(&MupVcbLock);
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MupCreate(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+ PFILE_OBJECT FileObject, RelatedFileObject;
+
+ FsRtlEnterFileSystem();
+
+ _SEH2_TRY
+ {
+ /* If DFS is enabled, check if that's for DFS and is so relay */
+ if (MupEnableDfs)
+ {
+ if (DeviceObject->DeviceType == FILE_DEVICE_DFS ||
DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM)
+ {
+ Status = DfsFsdCreate(DeviceObject, Irp);
+ }
+ }
+ else
+ {
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ FileObject = Stack->FileObject;
+ RelatedFileObject = FileObject->RelatedFileObject;
+
+ /* If we have a file name or if the associated FCB of the related FO
isn't the VCB, then, it's a regular opening */
+ if (FileObject->FileName.Length != 0 || (RelatedFileObject != NULL
&& ((PMUP_FCB)(RelatedFileObject->FsContext))->NodeType != NODE_TYPE_VCB))
+ {
+ Status = CreateRedirectedFile(Irp, FileObject,
Stack->Parameters.Create.SecurityContext);
+ }
+ /* Otherwise, it's just a volume open */
+ else
+ {
+ Status = OpenMupFileSystem(DeviceObject->DeviceExtension,
+ FileObject,
+
Stack->Parameters.Create.SecurityContext->DesiredAccess,
+ Stack->Parameters.Create.ShareAccess);
+
+ Irp->IoStatus.Information = FILE_OPENED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
+ _SEH2_END;
+
+ FsRtlExitFileSystem();
+
+ return Status;
+}
+
+VOID
+MupCloseUncProvider(PMUP_UNC UncProvider)
+{
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+
+ /* If the node was still valid, reregister the UNC provider */
+ if (UncProvider->NodeStatus == NODE_STATUS_HEALTHY)
+ {
+ UncProvider->NodeStatus = NODE_STATUS_CLEANUP;
+ UncProvider->Registered = FALSE;
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ if (UncProvider->FileObject != NULL)
+ {
+ ZwClose(UncProvider->DeviceHandle);
+ ObDereferenceObject(UncProvider->FileObject);
+ }
+ }
+ else
+ {
+ ExReleaseResourceLite(&MupGlobalLock);
+ }
+}
+
+NTSTATUS
+DfsFsdCleanup(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+MupCleanup(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ ULONG Type;
+ PMUP_FCB Fcb;
+ PMUP_CCB Ccb;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+
+ /* If DFS is enabled, check if that's for DFS and is so relay */
+ if (MupEnableDfs)
+ {
+ if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM)
+ {
+ return DfsFsdCleanup(DeviceObject, Irp);
+ }
+ }
+
+ FsRtlEnterFileSystem();
+
+ _SEH2_TRY
+ {
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ Type = MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
+ switch (Type)
+ {
+ case NODE_TYPE_VCB:
+ /* If we got a VCB, clean it up */
+ MupCleanupVcb(DeviceObject, Irp, (PMUP_VCB)Fcb);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ MupDereferenceVcb((PMUP_VCB)Fcb);
+
+ /* If Ccb is not null, then, it's a UNC provider node */
+ if (Ccb)
+ {
+ /* Close it, and dereference */
+ MupCloseUncProvider((PMUP_UNC)Ccb);
+ MupDereferenceUncProvider((PMUP_UNC)Ccb);
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+ --MupProviderCount;
+ ExReleaseResourceLite(&MupGlobalLock);
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case NODE_TYPE_FCB:
+ /* If the node wasn't already cleaned, do it */
+ if (Fcb->NodeStatus == NODE_STATUS_HEALTHY)
+ {
+ MupCleanupFcb(DeviceObject, Irp, Fcb);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ MupDereferenceFcb(Fcb);
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ break;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ FsRtlExitFileSystem();
+
+ return Status;
+}
+
+NTSTATUS
+MupCloseVcb(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PMUP_VCB Vcb,
+ PFILE_OBJECT FileObject)
+{
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+
+ /* Remove FCB, UNC from FO */
+ MupSetFileObject(FileObject, NULL, NULL);
+ MupDereferenceVcb(Vcb);
+
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MupCloseFcb(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PMUP_FCB Fcb,
+ PFILE_OBJECT FileObject)
+{
+ ExAcquireResourceExclusiveLite(&MupGlobalLock, TRUE);
+
+ /* Remove FCB, CCB from FO */
+ MupSetFileObject(FileObject, NULL, NULL);
+ MupDereferenceFcb(Fcb);
+
+ ExReleaseResourceLite(&MupGlobalLock);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+DfsFsdClose(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+MupClose(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PMUP_FCB Fcb;
+ PMUP_CCB Ccb;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+
+ /* If DFS is enabled, check if that's for DFS and is so relay */
+ if (MupEnableDfs)
+ {
+ if (DeviceObject->DeviceType == FILE_DEVICE_DFS || DeviceObject->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM)
+ {
+ return DfsFsdClose(DeviceObject, Irp);
+ }
+ }
+
+ FsRtlEnterFileSystem();
+
+ _SEH2_TRY
+ {
+ /* Get our internal structures from FO */
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ MupDecodeFileObject(Stack->FileObject, &Fcb, &Ccb);
+ if (Fcb == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ _SEH2_LEAVE;
+ }
+
+ /* If we got the VCB, that's a volume close */
+ if (Fcb->NodeType == NODE_TYPE_VCB)
+ {
+ Status = MupCloseVcb(DeviceObject, Irp, (PMUP_VCB)Fcb,
Stack->FileObject);
+ }
+ /* Otherwise close the FCB */
+ else if (Fcb->NodeType == NODE_TYPE_FCB)
+ {
+ MupDereferenceFcb(Fcb);
+ Status = MupCloseFcb(DeviceObject, Irp, Fcb, Stack->FileObject);
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ _SEH2_LEAVE;
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ FsRtlExitFileSystem();
+
+ return Status;
+}
+
+VOID
+DfsUnload(PDRIVER_OBJECT DriverObject)
+{
+ UNIMPLEMENTED;
+}
+
+VOID
+NTAPI
+MupUnload(PDRIVER_OBJECT DriverObject)
+{
+ IoDeleteDevice(mupDeviceObject);
+
+ if (MupEnableDfs)
+ {
+ DfsUnload(DriverObject);
+ }
+
+ MupUninitializeData();
+}
+
+NTSTATUS
+DfsDriverEntry(PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath)
+{
+ /* We don't support DFS yet, so
+ * fail to make sure it remains disabled
+ */
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
/*
* FUNCTION: Called by the system to initialize the driver
@@ -40,60 +2530,56 @@
* RegistryPath = path to our configuration entries
* RETURNS: Success or failure
*/
-NTSTATUS NTAPI
+NTSTATUS
+NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
+ NTSTATUS Status;
+ UNICODE_STRING MupString;
PDEVICE_OBJECT DeviceObject;
- NTSTATUS Status;
- UNICODE_STRING DeviceName;
-
- UNREFERENCED_PARAMETER(RegistryPath);
-
- DPRINT("MUP 0.0.1\n");
-
- RtlInitUnicodeString(&DeviceName,
- L"\\Device\\Mup");
- Status = IoCreateDevice(DriverObject,
- sizeof(DEVICE_EXTENSION),
- &DeviceName,
- FILE_DEVICE_MULTI_UNC_PROVIDER,
- 0,
- FALSE,
- &DeviceObject);
+
+ /* Only initialize global state of the driver
+ * Other inits will happen when required
+ */
+ MupInitializeData();
+
+ /* Check if DFS is disabled */
+ MupEnableDfs = MuppIsDfsEnabled();
+ /* If it's not disabled but when cannot init, disable it */
+ if (MupEnableDfs && !NT_SUCCESS(DfsDriverEntry(DriverObject, RegistryPath)))
+ {
+ MupEnableDfs = FALSE;
+ }
+
+ /* Create the MUP device */
+ RtlInitUnicodeString(&MupString, L"\\Device\\Mup");
+ Status = IoCreateDevice(DriverObject, sizeof(MUP_VCB), &MupString,
FILE_DEVICE_MULTI_UNC_PROVIDER, 0, FALSE, &DeviceObject);
if (!NT_SUCCESS(Status))
{
+ if (MupEnableDfs)
+ {
+ DfsUnload(DriverObject);
+ }
+
+ MupUninitializeData();
+
return Status;
}
- /* Initialize driver data */
- DeviceObject->Flags |= DO_DIRECT_IO;
-// DriverObject->MajorFunction[IRP_MJ_CLOSE] = NtfsClose;
+ /* Set our MJ */
+ DriverObject->DriverUnload = MupUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = MupCreate;
DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = MupCreate;
DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = MupCreate;
-// DriverObject->MajorFunction[IRP_MJ_READ] = NtfsRead;
-// DriverObject->MajorFunction[IRP_MJ_WRITE] = NtfsWrite;
-// DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
-// NtfsFileSystemControl;
-// DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
-// NtfsDirectoryControl;
-// DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
-// NtfsQueryInformation;
-// DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
-// NtfsQueryVolumeInformation;
-// DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
-// NtfsSetVolumeInformation;
-
- DriverObject->DriverUnload = NULL;
-
-
- /* Initialize global data */
-// DeviceExtensionNtfsGlobalData = DeviceObject->DeviceExtension;
-// RtlZeroMemory(NtfsGlobalData,
-// sizeof(NTFS_GLOBAL_DATA));
-// NtfsGlobalData->DriverObject = DriverObject;
-// NtfsGlobalData->DeviceObject = DeviceObject;
+ DriverObject->MajorFunction[IRP_MJ_WRITE] = MupForwardIoRequest;
+ DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = MupFsControl;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MupCleanup;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = MupClose;
+
+ /* And finish init */
+ mupDeviceObject = DeviceObject;
+ MupInitializeVcb(DeviceObject->DeviceExtension);
return STATUS_SUCCESS;
}
Modified: trunk/reactos/drivers/filesystems/mup/mup.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/mup/mu…
==============================================================================
--- trunk/reactos/drivers/filesystems/mup/mup.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/mup/mup.h [iso-8859-1] Tue Aug 18 20:17:22 2015
@@ -2,24 +2,138 @@
#define _MUP_PCH_
#include <wdm.h>
+#include <ntifs.h>
+#include <pseh/pseh2.h>
+#include <ndk/muptypes.h>
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
+#define IO_METHOD_FROM_CTL_CODE(C) (C & 0x00000003)
-typedef struct
+#define TAG_MUP ' puM'
+
+#define DFS_MAGIC_CCB (PVOID)0x11444653
+#define FILE_SIMPLE_RIGHTS_MASK (FILE_ALL_ACCESS & ~STANDARD_RIGHTS_REQUIRED &~
SYNCHRONIZE)
+
+#define NODE_TYPE_VCB 0x1
+#define NODE_TYPE_UNC 0x2
+#define NODE_TYPE_PFX 0x3
+#define NODE_TYPE_FCB 0x4
+#define NODE_TYPE_CCB 0x5
+#define NODE_TYPE_MIC 0x6
+#define NODE_TYPE_MQC 0x8
+
+#define NODE_STATUS_HEALTHY 0x1
+#define NODE_STATUS_CLEANUP 0x2
+
+typedef struct _MUP_VCB
{
- ULONG Dummy;
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ SHARE_ACCESS ShareAccess;
+} MUP_VCB, *PMUP_VCB;
-} DEVICE_EXTENSION, *PDEVICE_EXTENSION, VCB, *PVCB;
+typedef struct _MUP_FCB
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ PFILE_OBJECT FileObject;
+ LIST_ENTRY CcbList;
+} MUP_FCB, *PMUP_FCB;
-/* create.c */
-DRIVER_DISPATCH MupCreate;
-NTSTATUS NTAPI
-MupCreate(PDEVICE_OBJECT DeviceObject,
- PIRP Irp);
+typedef struct _MUP_CCB
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ PMUP_FCB Fcb;
+ LIST_ENTRY CcbListEntry;
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+} MUP_CCB, *PMUP_CCB;
-/* mup.c */
-NTSTATUS NTAPI
-DriverEntry(PDRIVER_OBJECT DriverObject,
- PUNICODE_STRING RegistryPath);
+typedef struct _MUP_MIC
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ PIRP Irp;
+ NTSTATUS LastSuccess;
+ NTSTATUS LastFailed;
+ PMUP_FCB Fcb;
+} MUP_MIC, *PMUP_MIC;
+
+typedef struct _MUP_UNC
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ LIST_ENTRY ProviderListEntry;
+ UNICODE_STRING DeviceName;
+ HANDLE DeviceHandle;
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+ ULONG ProviderOrder;
+ BOOLEAN MailslotsSupported;
+ BOOLEAN Registered;
+} MUP_UNC, *PMUP_UNC;
+
+typedef struct _MUP_PFX
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ UNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry;
+ UNICODE_STRING AcceptedPrefix;
+ ULONG Reserved;
+ LARGE_INTEGER ValidityTimeout;
+ PMUP_UNC UncProvider;
+ BOOLEAN ExternalAlloc;
+ BOOLEAN InTable;
+ BOOLEAN KeepExtraRef;
+ BOOLEAN Padding;
+ LIST_ENTRY PrefixListEntry;
+} MUP_PFX, *PMUP_PFX;
+
+typedef struct _MUP_MQC
+{
+ ULONG NodeType;
+ ULONG NodeStatus;
+ LONG NodeReferences;
+ ULONG NodeSize;
+ PIRP Irp;
+ PFILE_OBJECT FileObject;
+ PMUP_UNC LatestProvider;
+ ERESOURCE QueryPathListLock;
+ PMUP_PFX Prefix;
+ NTSTATUS LatestStatus;
+ LIST_ENTRY QueryPathList;
+ LIST_ENTRY MQCListEntry;
+} MUP_MQC, *PMUP_MQC;
+
+typedef struct _FORWARDED_IO_CONTEXT
+{
+ PMUP_CCB Ccb;
+ PMUP_MIC MasterIoContext;
+ WORK_QUEUE_ITEM WorkQueueItem;
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
+} FORWARDED_IO_CONTEXT, *PFORWARDED_IO_CONTEXT;
+
+typedef struct _QUERY_PATH_CONTEXT
+{
+ PMUP_MQC MasterQueryContext;
+ PMUP_UNC UncProvider;
+ PQUERY_PATH_REQUEST QueryPathRequest;
+ LIST_ENTRY QueryPathListEntry;
+ PIRP Irp;
+} QUERY_PATH_CONTEXT, *PQUERY_PATH_CONTEXT;
#endif /* _MUP_PCH_ */