3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/mup/mup.c
23 * PURPOSE: Multi UNC Provider
24 * PROGRAMMER: Eric Kohl
25 * Pierre Schweitzer (pierre@reactos.org)
28 /* INCLUDES *****************************************************************/
38 PDRIVER_OBJECT DriverObject
,
39 PUNICODE_STRING RegistryPath
52 #if defined(ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, DriverEntry)
54 #pragma alloc_text(INIT, MupInitializeData)
55 #pragma alloc_text(INIT, MupInitializeVcb)
58 ERESOURCE MupGlobalLock
;
59 ERESOURCE MupPrefixTableLock
;
60 ERESOURCE MupCcbListLock
;
62 LIST_ENTRY MupProviderList
;
63 LIST_ENTRY MupPrefixList
;
64 LIST_ENTRY MupMasterQueryList
;
65 UNICODE_PREFIX_TABLE MupPrefixTable
;
66 LARGE_INTEGER MupKnownPrefixTimeout
;
67 ULONG MupProviderCount
;
68 BOOLEAN MupOrderInitialized
;
70 PDEVICE_OBJECT mupDeviceObject
;
71 NTSTATUS MupOrderedErrorList
[] = { STATUS_UNSUCCESSFUL
,
72 STATUS_INVALID_PARAMETER
,
73 STATUS_REDIRECTOR_NOT_STARTED
,
74 STATUS_BAD_NETWORK_NAME
,
75 STATUS_BAD_NETWORK_PATH
, 0 };
77 /* FUNCTIONS ****************************************************************/
81 MupInitializeData(VOID
)
83 ExInitializeResourceLite(&MupGlobalLock
);
84 ExInitializeResourceLite(&MupPrefixTableLock
);
85 ExInitializeResourceLite(&MupCcbListLock
);
86 ExInitializeResourceLite(&MupVcbLock
);
88 InitializeListHead(&MupProviderList
);
89 InitializeListHead(&MupPrefixList
);
90 InitializeListHead(&MupMasterQueryList
);
91 RtlInitializeUnicodePrefix(&MupPrefixTable
);
92 MupKnownPrefixTimeout
.QuadPart
= 9000000000LL;
93 MupOrderInitialized
= FALSE
;
99 ExDeleteResourceLite(&MupGlobalLock
);
100 ExDeleteResourceLite(&MupPrefixTableLock
);
101 ExDeleteResourceLite(&MupCcbListLock
);
102 ExDeleteResourceLite(&MupVcbLock
);
107 MupInitializeVcb(PMUP_VCB Vcb
)
109 RtlZeroMemory(Vcb
, sizeof(MUP_VCB
));
110 Vcb
->NodeType
= NODE_TYPE_VCB
;
111 Vcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
112 Vcb
->NodeReferences
= 1;
113 Vcb
->NodeSize
= sizeof(MUP_VCB
);
117 MuppIsDfsEnabled(VOID
)
122 UNICODE_STRING KeyName
;
123 OBJECT_ATTRIBUTES ObjectAttributes
;
126 KEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
130 /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
131 KeyName
.Buffer
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
132 KeyName
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL
);
133 KeyName
.MaximumLength
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
135 /* Simply query registry to know whether we have to disable DFS.
136 * Unless explicitly stated in registry, we will try to enable DFS.
138 InitializeObjectAttributes(&ObjectAttributes
,
140 OBJ_CASE_INSENSITIVE
,
144 Status
= ZwOpenKey(&Key
, KEY_READ
, &ObjectAttributes
);
145 if (!NT_SUCCESS(Status
))
150 KeyName
.Buffer
= L
"DisableDfs";
151 KeyName
.Length
= sizeof(L
"DisableDfs") - sizeof(UNICODE_NULL
);
152 KeyName
.MaximumLength
= sizeof(L
"DisableDfs");
154 Status
= ZwQueryValueKey(Key
, &KeyName
, KeyValuePartialInformation
, &KeyQueryOutput
, sizeof(KeyQueryOutput
), &Length
);
156 if (!NT_SUCCESS(Status
) || KeyQueryOutput
.KeyInfo
.Type
!= REG_DWORD
)
161 return ((ULONG
)KeyQueryOutput
.KeyInfo
.Data
!= 1);
165 MupCalculateTimeout(PLARGE_INTEGER EntryTime
)
167 LARGE_INTEGER CurrentTime
;
169 /* Just get now + our allowed timeout */
170 KeQuerySystemTime(&CurrentTime
);
171 EntryTime
->QuadPart
= CurrentTime
.QuadPart
+ MupKnownPrefixTimeout
.QuadPart
;
179 Ccb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_CCB
), TAG_MUP
);
185 Ccb
->NodeStatus
= NODE_STATUS_HEALTHY
;
186 Ccb
->NodeReferences
= 1;
187 Ccb
->NodeType
= NODE_TYPE_CCB
;
188 Ccb
->NodeSize
= sizeof(MUP_CCB
);
198 Fcb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_FCB
), TAG_MUP
);
204 Fcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
205 Fcb
->NodeReferences
= 1;
206 Fcb
->NodeType
= NODE_TYPE_FCB
;
207 Fcb
->NodeSize
= sizeof(MUP_FCB
);
208 InitializeListHead(&Fcb
->CcbList
);
214 MupAllocateMasterIoContext(VOID
)
216 PMUP_MIC MasterIoContext
;
218 MasterIoContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MIC
), TAG_MUP
);
219 if (MasterIoContext
== NULL
)
224 MasterIoContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
225 MasterIoContext
->NodeReferences
= 1;
226 MasterIoContext
->NodeType
= NODE_TYPE_MIC
;
227 MasterIoContext
->NodeSize
= sizeof(MUP_MIC
);
229 return MasterIoContext
;
233 MupAllocateUncProvider(ULONG RedirectorDeviceNameLength
)
235 PMUP_UNC UncProvider
;
237 UncProvider
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_UNC
) + RedirectorDeviceNameLength
, TAG_MUP
);
238 if (UncProvider
== NULL
)
243 UncProvider
->NodeReferences
= 0;
244 UncProvider
->NodeType
= NODE_TYPE_UNC
;
245 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
246 UncProvider
->NodeSize
= sizeof(MUP_UNC
) + RedirectorDeviceNameLength
;
247 UncProvider
->Registered
= FALSE
;
253 MupAllocatePrefixEntry(ULONG PrefixLength
)
258 PrefixSize
= sizeof(MUP_PFX
) + PrefixLength
;
259 Prefix
= ExAllocatePoolWithTag(PagedPool
, PrefixSize
, TAG_MUP
);
265 RtlZeroMemory(Prefix
, PrefixSize
);
266 Prefix
->NodeType
= NODE_TYPE_PFX
;
267 Prefix
->NodeStatus
= NODE_STATUS_HEALTHY
;
268 Prefix
->NodeReferences
= 1;
269 Prefix
->NodeSize
= PrefixSize
;
271 /* If we got a prefix, initialize the string */
272 if (PrefixLength
!= 0)
274 Prefix
->AcceptedPrefix
.Buffer
= (PVOID
)((ULONG_PTR
)Prefix
+ sizeof(MUP_PFX
));
275 Prefix
->AcceptedPrefix
.Length
= PrefixLength
;
276 Prefix
->AcceptedPrefix
.MaximumLength
= PrefixLength
;
278 /* Otherwise, mark the fact that the allocation will be external */
281 Prefix
->ExternalAlloc
= TRUE
;
284 Prefix
->KeepExtraRef
= FALSE
;
285 /* Already init timeout to have one */
286 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
292 MupAllocateMasterQueryContext(VOID
)
294 PMUP_MQC MasterQueryContext
;
296 MasterQueryContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MQC
), TAG_MUP
);
297 if (MasterQueryContext
== NULL
)
302 MasterQueryContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
303 MasterQueryContext
->NodeReferences
= 1;
304 MasterQueryContext
->NodeType
= NODE_TYPE_MQC
;
305 MasterQueryContext
->NodeSize
= sizeof(MUP_MQC
);
306 InitializeListHead(&MasterQueryContext
->QueryPathList
);
307 InitializeListHead(&MasterQueryContext
->MQCListEntry
);
308 ExInitializeResourceLite(&MasterQueryContext
->QueryPathListLock
);
310 return MasterQueryContext
;
314 MupDecodeFileObject(PFILE_OBJECT FileObject
, PMUP_FCB
* pFcb
, PMUP_CCB
* pCcb
)
319 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
320 *pFcb
= FileObject
->FsContext
;
321 *pCcb
= FileObject
->FsContext2
;
326 ExReleaseResourceLite(&MupGlobalLock
);
330 Type
= Fcb
->NodeType
;
331 if ((Type
!= NODE_TYPE_VCB
&& Type
!= NODE_TYPE_FCB
) || (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
&& Fcb
->NodeStatus
!= NODE_STATUS_CLEANUP
))
334 ExReleaseResourceLite(&MupGlobalLock
);
338 ++Fcb
->NodeReferences
;
339 ExReleaseResourceLite(&MupGlobalLock
);
345 MupFreeNode(PVOID Node
)
347 ExFreePoolWithTag(Node
, TAG_MUP
);
351 MupDereferenceFcb(PMUP_FCB Fcb
)
353 /* Just dereference and delete if no references left */
354 if (InterlockedDecrement(&Fcb
->NodeReferences
) == 0)
361 MupDereferenceCcb(PMUP_CCB Ccb
)
363 /* Just dereference and delete (and clean) if no references left */
364 if (InterlockedDecrement(&Ccb
->NodeReferences
) == 0)
366 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
367 RemoveEntryList(&Ccb
->CcbListEntry
);
368 ExReleaseResourceLite(&MupCcbListLock
);
369 ObDereferenceObject(Ccb
->FileObject
);
370 MupDereferenceFcb(Ccb
->Fcb
);
376 MupDereferenceVcb(PMUP_VCB Vcb
)
378 /* We cannot reach the point where no references are left */
379 if (InterlockedDecrement(&Vcb
->NodeReferences
) == 0)
381 KeBugCheckEx(FILE_SYSTEM
, 3, 0, 0, 0);
386 MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext
,
391 PIO_STACK_LOCATION Stack
;
393 Status
= STATUS_SUCCESS
;
395 if (NewStatus
!= NULL
)
397 /* Save last status, depending on whether it failed or not */
398 if (!NT_SUCCESS(*NewStatus
))
400 MasterIoContext
->LastFailed
= *NewStatus
;
404 MasterIoContext
->LastSuccess
= STATUS_SUCCESS
;
408 if (InterlockedDecrement(&MasterIoContext
->NodeReferences
) != 0)
410 return STATUS_PENDING
;
413 Irp
= MasterIoContext
->Irp
;
414 Stack
= IoGetCurrentIrpStackLocation(Irp
);
415 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
417 Irp
->IoStatus
.Information
= Stack
->Parameters
.Write
.Length
;
421 Irp
->IoStatus
.Information
= 0;
424 /* In case we never had any success (init is a failure), get the last failed status */
425 if (!NT_SUCCESS(MasterIoContext
->LastSuccess
))
427 Status
= MasterIoContext
->LastFailed
;
430 Irp
->IoStatus
.Status
= Status
;
431 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
432 MupDereferenceFcb(MasterIoContext
->Fcb
);
433 MupFreeNode(MasterIoContext
);
439 MupDereferenceUncProvider(PMUP_UNC UncProvider
)
441 InterlockedExchangeAdd(&UncProvider
->NodeReferences
, -1);
445 MupDereferenceKnownPrefix(PMUP_PFX Prefix
)
447 /* Just dereference and delete (and clean) if no references left */
448 if (InterlockedDecrement(&Prefix
->NodeReferences
) == 0)
452 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
453 RemoveEntryList(&Prefix
->PrefixListEntry
);
456 if (Prefix
->ExternalAlloc
&& Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
458 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
461 if (Prefix
->UncProvider
)
463 MupDereferenceUncProvider(Prefix
->UncProvider
);
471 MupRemoveKnownPrefixEntry(PMUP_PFX Prefix
)
473 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
474 RemoveEntryList(&Prefix
->PrefixListEntry
);
475 Prefix
->InTable
= FALSE
;
476 MupDereferenceKnownPrefix(Prefix
);
480 MupInvalidatePrefixTable(VOID
)
485 /* Browse the prefix table */
486 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
487 for (Entry
= MupPrefixList
.Flink
;
488 Entry
!= &MupPrefixList
;
489 Entry
= Entry
->Flink
)
491 Prefix
= CONTAINING_RECORD(Entry
, MUP_PFX
, PrefixListEntry
);
493 /* And remove any entry in it */
496 MupRemoveKnownPrefixEntry(Prefix
);
499 ExReleaseResourceLite(&MupPrefixTableLock
);
503 MupCleanupVcb(PDEVICE_OBJECT DeviceObject
,
507 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
509 /* Check we're not doing anything wrong first */
510 if (Vcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Vcb
->NodeType
!= NODE_TYPE_VCB
)
512 ExRaiseStatus(STATUS_INVALID_HANDLE
);
515 /* Remove share access */
516 IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp
)->FileObject
, &Vcb
->ShareAccess
);
518 ExReleaseResourceLite(&MupVcbLock
);
522 MupCleanupFcb(PDEVICE_OBJECT DeviceObject
,
529 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
530 /* Check we're not doing anything wrong first */
531 if (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
533 ExRaiseStatus(STATUS_INVALID_HANDLE
);
535 Fcb
->NodeStatus
= NODE_STATUS_CLEANUP
;
536 ExReleaseResourceLite(&MupGlobalLock
);
538 /* Dereference any CCB associated with the FCB */
539 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
540 for (Entry
= Fcb
->CcbList
.Flink
;
541 Entry
!= &Fcb
->CcbList
;
542 Entry
= Entry
->Flink
)
544 Ccb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
545 ExReleaseResourceLite(&MupCcbListLock
);
546 MupDereferenceCcb(Ccb
);
547 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
549 ExReleaseResourceLite(&MupCcbListLock
);
553 CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
555 PFORWARDED_IO_CONTEXT FwdCtxt
)
559 Status
= Irp
->IoStatus
.Status
;
561 /* Just free everything we had allocated */
562 if (Irp
->MdlAddress
!= NULL
)
564 MmUnlockPages(Irp
->MdlAddress
);
565 IoFreeMdl(Irp
->MdlAddress
);
568 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
570 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
575 /* Dereference the master context
576 * The upper IRP will be completed once all the lower IRPs are done
577 * (and thus, references count reaches 0)
579 MupDereferenceCcb(FwdCtxt
->Ccb
);
580 MupDereferenceMasterIoContext(FwdCtxt
->MasterIoContext
, &Status
);
581 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
583 return STATUS_MORE_PROCESSING_REQUIRED
;
588 DeferredForwardedIoCompletionRoutine(PVOID Context
)
590 PFORWARDED_IO_CONTEXT FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
592 CommonForwardedIoCompletionRoutine(FwdCtxt
->DeviceObject
, FwdCtxt
->Irp
, Context
);
597 ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
601 PFORWARDED_IO_CONTEXT FwdCtxt
;
603 /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
604 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
606 CommonForwardedIoCompletionRoutine(DeviceObject
, Irp
, Context
);
610 FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
612 ExInitializeWorkItem(&FwdCtxt
->WorkQueueItem
, DeferredForwardedIoCompletionRoutine
, Context
);
613 ExQueueWorkItem(&FwdCtxt
->WorkQueueItem
, CriticalWorkQueue
);
616 return STATUS_MORE_PROCESSING_REQUIRED
;
620 BuildAndSubmitIrp(PIRP Irp
,
622 PMUP_MIC MasterIoContext
)
627 PIO_STACK_LOCATION Stack
;
628 PDEVICE_OBJECT DeviceObject
;
629 PFORWARDED_IO_CONTEXT FwdCtxt
;
631 Status
= STATUS_SUCCESS
;
635 /* Allocate a context for the completion routine */
636 FwdCtxt
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FORWARDED_IO_CONTEXT
), TAG_MUP
);
639 Status
= STATUS_INSUFFICIENT_RESOURCES
;
644 FwdCtxt
->DeviceObject
= NULL
;
647 /* Allocate the IRP */
648 DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
649 LowerIrp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
650 if (LowerIrp
== NULL
)
652 Status
= STATUS_INSUFFICIENT_RESOURCES
;
657 LowerIrp
->Tail
.Overlay
.OriginalFileObject
= Ccb
->FileObject
;
658 LowerIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
659 LowerIrp
->RequestorMode
= KernelMode
;
661 /* Copy the stack of the request we received to the IRP we'll pass below */
662 Stack
= IoGetNextIrpStackLocation(LowerIrp
);
663 RtlMoveMemory(Stack
, IoGetCurrentIrpStackLocation(Irp
), sizeof(IO_STACK_LOCATION
));
664 Stack
->FileObject
= Ccb
->FileObject
;
665 /* Setup flags according to the FO */
666 if (Ccb
->FileObject
->Flags
& FO_WRITE_THROUGH
)
668 Stack
->Flags
= SL_WRITE_THROUGH
;
673 /* Does the device requires we do buffered IOs? */
674 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
676 LowerIrp
->AssociatedIrp
.SystemBuffer
= NULL
;
678 if (Stack
->Parameters
.Write
.Length
== 0)
680 LowerIrp
->Flags
= IRP_BUFFERED_IO
;
682 /* If we have data to pass */
685 /* If it's coming from usermode, probe first */
686 if (Irp
->RequestorMode
== UserMode
)
688 ProbeForRead(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, sizeof(UCHAR
));
691 /* Allocate the buffer */
692 LowerIrp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned
,
693 Stack
->Parameters
.Write
.Length
,
695 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
697 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
700 /* And copy input (remember, we've to free!) */
701 RtlMoveMemory(LowerIrp
->AssociatedIrp
.SystemBuffer
, Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
);
702 LowerIrp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
707 if (!(DeviceObject
->Flags
& DO_DIRECT_IO
))
709 LowerIrp
->UserBuffer
= Irp
->UserBuffer
;
713 /* For direct IOs, allocate an MDL and pass it */
714 if (Stack
->Parameters
.Write
.Length
!= 0)
716 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, FALSE
, TRUE
, LowerIrp
);
719 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
722 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoReadAccess
);
727 /* Fix flags in the IRP */
728 if (Ccb
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
730 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
| IRP_NOCACHE
;
734 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
;
738 FwdCtxt
->MasterIoContext
= MasterIoContext
;
740 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
741 ++MasterIoContext
->NodeReferences
;
742 ExReleaseResourceLite(&MupGlobalLock
);
744 /* Set out completion routine */
745 IoSetCompletionRoutine(LowerIrp
, ForwardedIoCompletionRoutine
, FwdCtxt
, TRUE
, TRUE
, TRUE
);
746 /* And call the device with our brand new IRP */
747 Status
= IoCallDriver(Ccb
->DeviceObject
, LowerIrp
);
749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
751 Status
= _SEH2_GetExceptionCode();
756 if (!NT_SUCCESS(Status
))
760 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
763 if (LowerIrp
!= NULL
)
765 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
767 ExFreePoolWithTag(LowerIrp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
784 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject
,
792 BOOLEAN CcbLockAcquired
;
793 PMUP_MIC MasterIoContext
;
794 PIO_STACK_LOCATION Stack
;
796 /* If DFS is enabled, check if that's for DFS and is so relay */
797 if (MupEnableDfs
&& DeviceObject
->DeviceType
== FILE_DEVICE_DFS
)
799 return DfsVolumePassThrough(DeviceObject
, Irp
);
802 Stack
= IoGetCurrentIrpStackLocation(Irp
);
804 FsRtlEnterFileSystem();
806 /* Write request is only possible for a mailslot, we need a FCB */
807 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
808 if (Fcb
== NULL
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
810 FsRtlExitFileSystem();
811 Status
= STATUS_INVALID_DEVICE_REQUEST
;
815 /* Allocate a context */
816 MasterIoContext
= MupAllocateMasterIoContext();
817 if (MasterIoContext
== NULL
)
819 FsRtlExitFileSystem();
820 Status
= STATUS_INSUFFICIENT_RESOURCES
;
824 /* Mark the IRP pending and init the context */
825 IoMarkIrpPending(Irp
);
826 MasterIoContext
->Irp
= Irp
;
827 /* Init with a failure to catch if we ever succeed */
828 MasterIoContext
->LastSuccess
= STATUS_UNSUCCESSFUL
;
829 /* Init with the worth failure possible */
830 MasterIoContext
->LastFailed
= STATUS_BAD_NETWORK_PATH
;
831 MasterIoContext
->Fcb
= Fcb
;
835 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
836 CcbLockAcquired
= TRUE
;
838 /* For all the CCB (ie, the mailslots) we have */
839 for (Entry
= Fcb
->CcbList
.Flink
;
840 Entry
!= &Fcb
->CcbList
;
841 Entry
= Entry
->Flink
)
843 FcbListCcb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
844 ExReleaseResourceLite(&MupCcbListLock
);
845 CcbLockAcquired
= FALSE
;
847 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
848 ++FcbListCcb
->NodeReferences
;
849 ExReleaseResourceLite(&MupGlobalLock
);
851 /* Forward the write request */
852 BuildAndSubmitIrp(Irp
, FcbListCcb
, MasterIoContext
);
853 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
854 CcbLockAcquired
= TRUE
;
857 ExReleaseResourceLite(&MupCcbListLock
);
858 CcbLockAcquired
= FALSE
;
860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
864 ExReleaseResourceLite(&MupCcbListLock
);
870 MupDereferenceMasterIoContext(MasterIoContext
, NULL
);
871 FsRtlExitFileSystem();
873 return STATUS_PENDING
;
877 Irp
->IoStatus
.Status
= Status
;
878 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
883 AddUnregisteredProvider(PCWSTR DeviceName
,
886 PMUP_UNC UncProvider
;
887 ULONG StrLen
, NameLen
;
889 /* Just allocate the node */
890 NameLen
= wcslen(DeviceName
);
891 StrLen
= NameLen
* sizeof(WCHAR
);
892 UncProvider
= MupAllocateUncProvider(StrLen
);
893 if (UncProvider
== NULL
)
899 UncProvider
->DeviceName
.MaximumLength
= StrLen
;
900 UncProvider
->DeviceName
.Length
= StrLen
;
901 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
902 UncProvider
->ProviderOrder
= ProviderOrder
;
903 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, DeviceName
, StrLen
);
905 /* And add it to the global list
906 * We're using tail here so that when called from registry init,
907 * the providers with highest priority will be in the head of
910 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
911 InsertTailList(&MupProviderList
, &UncProvider
->ProviderListEntry
);
912 ExReleaseResourceLite(&MupGlobalLock
);
918 InitializeProvider(PCWSTR ProviderName
,
923 UNICODE_STRING Key
, Value
;
924 PKEY_VALUE_FULL_INFORMATION Info
;
925 OBJECT_ATTRIBUTES ObjectAttributes
;
926 ULONG NameLen
, StrLen
, ResultLength
;
928 /* Get the information about the provider from registry */
929 NameLen
= wcslen(ProviderName
);
930 StrLen
= NameLen
* sizeof(WCHAR
) + sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L
"\\NetworkProvider");
931 Key
.Buffer
= ExAllocatePoolWithTag(PagedPool
, StrLen
, TAG_MUP
);
932 if (Key
.Buffer
== NULL
)
937 RtlMoveMemory(Key
.Buffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
938 Key
.MaximumLength
= StrLen
;
939 Key
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL
);
940 RtlAppendUnicodeToString(&Key
, ProviderName
);
941 RtlAppendUnicodeToString(&Key
, L
"\\NetworkProvider");
943 InitializeObjectAttributes(&ObjectAttributes
,
945 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
948 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
949 ExFreePoolWithTag(Key
.Buffer
, TAG_MUP
);
950 if (!NT_SUCCESS(Status
))
955 RtlInitUnicodeString(&Value
, L
"DeviceName");
956 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
957 if (Status
== STATUS_BUFFER_TOO_SMALL
)
959 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
966 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
975 /* And create the provider
976 * It will remain unregistered until FsRTL receives a registration request and forwards
979 if (NT_SUCCESS(Status
))
981 ASSERT(Info
!= NULL
);
982 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
987 ExFreePoolWithTag(Info
, TAG_MUP
);
992 MupGetProviderInformation(VOID
)
997 PWSTR Providers
, Coma
;
998 PKEY_VALUE_FULL_INFORMATION Info
;
999 ULONG ResultLength
, ProviderCount
;
1000 OBJECT_ATTRIBUTES ObjectAttributes
;
1001 UNICODE_STRING NetworkProvider
, ProviderOrder
;
1003 /* Open the registry to get the order of the providers */
1004 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
1005 InitializeObjectAttributes(&ObjectAttributes
,
1007 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1010 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1011 if (!NT_SUCCESS(Status
))
1016 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
1017 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
1018 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1020 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1027 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1036 if (NT_SUCCESS(Status
))
1038 ASSERT(Info
!= NULL
);
1040 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1044 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1045 * The order is just the order of the list
1046 * First has highest priority (0) and then, get lower and lower priority
1047 * The highest number is the lowest priority
1051 Coma
= wcschr(Providers
, L
',');
1054 *Coma
= UNICODE_NULL
;
1061 InitializeProvider(Providers
, ProviderCount
);
1064 Providers
= Coma
+ 1;
1070 ExFreePoolWithTag(Info
, TAG_MUP
);
1075 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1078 PMUP_UNC UncProvider
;
1080 /* Browse the list of all the providers nodes we have */
1081 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1082 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1084 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1086 /* If one matches the device and is not registered, that's ours! */
1087 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1089 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1094 if (Entry
== &MupProviderList
)
1098 ExReleaseResourceLite(&MupGlobalLock
);
1104 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1113 PIO_STACK_LOCATION Stack
;
1114 IO_STATUS_BLOCK IoStatusBlock
;
1115 PMUP_UNC UncProvider
, ListEntry
;
1116 OBJECT_ATTRIBUTES ObjectAttributes
;
1117 UNICODE_STRING RedirectorDeviceName
;
1118 OBJECT_HANDLE_INFORMATION HandleInfo
;
1119 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1121 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1124 /* Check whether providers order was already initialized */
1125 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1126 if (MupOrderInitialized
)
1128 ExReleaseResourceLite(&MupGlobalLock
);
1132 /* They weren't, so do it */
1133 MupOrderInitialized
= TRUE
;
1134 ExReleaseResourceLite(&MupGlobalLock
);
1135 MupGetProviderInformation();
1138 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1140 /* This can only happen with a volume open */
1141 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1143 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1144 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1146 return STATUS_INVALID_HANDLE
;
1149 /* Get the registration information */
1150 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1153 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1154 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1155 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1157 /* Have we got already a node for it? (Like from previous init) */
1158 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1159 if (UncProvider
== NULL
)
1161 /* If we don't, allocate a new one */
1163 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1164 if (UncProvider
== NULL
)
1166 Status
= STATUS_INVALID_USER_BUFFER
;
1171 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1172 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1173 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1175 /* As it wasn't in registry for order, give the lowest priority possible */
1176 UncProvider
->ProviderOrder
= MAXLONG
;
1177 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1180 /* Continue registration */
1181 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1182 ++UncProvider
->NodeReferences
;
1184 /* Open a handle to the device */
1185 InitializeObjectAttributes(&ObjectAttributes
,
1186 &UncProvider
->DeviceName
,
1187 OBJ_CASE_INSENSITIVE
,
1190 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1194 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1195 FILE_DIRECTORY_FILE
);
1196 if (NT_SUCCESS(Status
))
1198 Status
= IoStatusBlock
.Status
;
1201 /* And return the provider (as CCB) */
1202 if (NT_SUCCESS(Status
))
1204 Stack
->FileObject
->FsContext2
= UncProvider
;
1205 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1206 if (!NT_SUCCESS(Status
))
1208 NtClose(UncProvider
->DeviceHandle
);
1212 if (!NT_SUCCESS(Status
))
1214 MupDereferenceUncProvider(UncProvider
);
1218 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1220 /* Now, insert the provider in our global list
1221 * They are sorted by order
1223 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1227 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1229 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1231 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1237 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1239 UncProvider
->Registered
= TRUE
;
1240 ExReleaseResourceLite(&MupGlobalLock
);
1241 Status
= STATUS_SUCCESS
;
1243 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1248 if (_abnormal_termination())
1250 Status
= STATUS_INVALID_USER_BUFFER
;
1253 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1255 Irp
->IoStatus
.Status
= Status
;
1256 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1265 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1269 PIO_STACK_LOCATION Stack
;
1271 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1275 /* MUP only understands a single FSCTL code: registering UNC provider */
1276 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1278 /* It obviously has to come from a driver/kernelmode thread */
1279 if (Irp
->RequestorMode
== UserMode
)
1281 Status
= STATUS_ACCESS_DENIED
;
1283 Irp
->IoStatus
.Status
= Status
;
1284 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1289 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1293 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1296 Status
= STATUS_INVALID_PARAMETER
;
1298 Irp
->IoStatus
.Status
= Status
;
1299 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1304 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1309 Status
= _SEH2_GetExceptionCode();
1317 MupSetFileObject(PFILE_OBJECT FileObject
,
1321 FileObject
->FsContext
= Fcb
;
1322 FileObject
->FsContext2
= Ccb
;
1326 MupRerouteOpen(PFILE_OBJECT FileObject
,
1327 PMUP_UNC UncProvider
)
1332 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1334 /* Get the full path name (device name first, and requested file name appended) */
1335 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1336 if (TotalLength
> MAXUSHORT
)
1338 return STATUS_NAME_TOO_LONG
;
1341 /* Allocate a buffer big enough */
1342 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1343 if (FullPath
== NULL
)
1345 return STATUS_INSUFFICIENT_RESOURCES
;
1348 /* Create the full path */
1349 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1350 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1352 /* And redo the path in the file object */
1353 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1354 FileObject
->FileName
.Buffer
= FullPath
;
1355 FileObject
->FileName
.MaximumLength
= TotalLength
;
1356 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1358 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1359 return STATUS_REPARSE
;
1363 BroadcastOpen(PIRP Irp
)
1368 PMUP_CCB Ccb
= NULL
;
1369 PMUP_UNC UncProvider
;
1370 UNICODE_STRING FullPath
;
1371 PFILE_OBJECT FileObject
;
1372 PIO_STACK_LOCATION Stack
;
1373 NTSTATUS Status
, LastFailed
;
1374 ULONG TotalLength
, LastOrder
;
1375 IO_STATUS_BLOCK IoStatusBlock
;
1376 OBJECT_ATTRIBUTES ObjectAttributes
;
1377 OBJECT_HANDLE_INFORMATION HandleInfo
;
1378 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1380 Fcb
= MupCreateFcb();
1383 return STATUS_INSUFFICIENT_RESOURCES
;
1386 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1387 FileObject
= Stack
->FileObject
;
1390 CcbInitialized
= FALSE
;
1391 LastFailed
= STATUS_NO_SUCH_FILE
;
1392 LastOrder
= (ULONG
)-1;
1396 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1399 /* Associate our FCB with the FO */
1400 MupSetFileObject(FileObject
, Fcb
, NULL
);
1401 Fcb
->FileObject
= FileObject
;
1403 /* Now, broadcast the open to any UNC provider that supports mailslots */
1404 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1406 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1407 ++UncProvider
->NodeReferences
;
1410 ExReleaseResourceLite(&MupGlobalLock
);
1413 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1414 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1416 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1417 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1418 if (FullPath
.Buffer
== NULL
)
1420 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1423 FullPath
.Length
= TotalLength
;
1424 FullPath
.MaximumLength
= TotalLength
;
1425 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1426 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1427 FileObject
->FileName
.Buffer
,
1428 FileObject
->FileName
.Length
);
1430 /* And just forward the creation request */
1431 InitializeObjectAttributes(&ObjectAttributes
,
1433 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1436 Status
= IoCreateFile(&Handle
,
1437 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1441 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1442 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1444 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1449 IO_NO_PARAMETER_CHECKING
);
1451 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1453 /* If opening succeed */
1454 if (NT_SUCCESS(Status
))
1456 Status
= IoStatusBlock
.Status
;
1459 Ccb
= MupCreateCcb();
1462 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1465 /* And associated a FO to it */
1466 if (NT_SUCCESS(Status
))
1468 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1473 /* If we failed, remember the last failed status of the higher priority provider */
1474 if (!NT_SUCCESS(Status
))
1476 if (UncProvider
->ProviderOrder
<= LastOrder
)
1478 LastOrder
= UncProvider
->ProviderOrder
;
1479 LastFailed
= Status
;
1482 /* Otherwise, properly attach our CCB to the mailslot */
1485 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1488 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1490 ++Fcb
->NodeReferences
;
1491 ExReleaseResourceLite(&MupGlobalLock
);
1493 CcbInitialized
= TRUE
;
1495 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1499 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1501 MupDereferenceUncProvider(UncProvider
);
1505 ExReleaseResourceLite(&MupGlobalLock
);
1508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1510 Status
= _SEH2_GetExceptionCode();
1514 /* If we at least opened one mailslot, return success */
1515 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1519 MupDereferenceUncProvider(UncProvider
);
1524 ExReleaseResourceLite(&MupGlobalLock
);
1527 /* In case of failure, don't leak CCB */
1528 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1537 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1539 ULONG MajorFunction
,
1542 ULONG InputBufferSize
,
1544 ULONG OutputBufferSize
,
1545 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1548 PIO_STACK_LOCATION Stack
;
1549 PDEVICE_OBJECT DeviceObject
;
1551 if (InputBuffer
== NULL
)
1556 /* Get the device object */
1557 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1558 /* Allocate the IRP (with one more location for us */
1559 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1565 /* Skip our location */
1566 IoSetNextIrpStackLocation(Irp
);
1568 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1569 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1570 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1572 /* Setup the stack */
1573 Stack
= IoGetNextIrpStackLocation(Irp
);
1574 Stack
->MajorFunction
= MajorFunction
;
1575 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1576 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1577 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1578 Stack
->MinorFunction
= 0;
1579 Stack
->FileObject
= FileObject
;
1580 Stack
->DeviceObject
= DeviceObject
;
1582 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1584 case METHOD_BUFFERED
:
1585 /* If it's buffered, just pass the buffers we got */
1586 Irp
->MdlAddress
= NULL
;
1587 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1588 Irp
->UserBuffer
= OutputBuffer
;
1589 Irp
->Flags
= IRP_BUFFERED_IO
;
1591 if (OutputBuffer
!= NULL
)
1593 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1597 case METHOD_IN_DIRECT
:
1598 case METHOD_OUT_DIRECT
:
1599 /* Otherwise, allocate an MDL */
1600 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1606 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1607 Irp
->Flags
= IRP_BUFFERED_IO
;
1608 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1611 case METHOD_NEITHER
:
1612 /* Or pass the buffers */
1613 Irp
->UserBuffer
= OutputBuffer
;
1614 Irp
->MdlAddress
= NULL
;
1615 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1616 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1624 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1626 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1627 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1631 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1635 BOOLEAN KeepExtraRef
;
1637 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1638 --MasterQueryContext
->NodeReferences
;
1639 References
= MasterQueryContext
->NodeReferences
;
1640 ExReleaseResourceLite(&MupGlobalLock
);
1642 if (References
!= 0)
1644 DPRINT("Still having refs (%ld)\n", References
);
1645 return STATUS_PENDING
;
1648 /* We HAVE an IRP to complete. It cannot be NULL
1649 * Please, help preserving kittens, don't provide NULL IRPs.
1651 if (MasterQueryContext
->Irp
== NULL
)
1653 KeBugCheck(FILE_SYSTEM
);
1656 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1657 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1658 ExReleaseResourceLite(&MupGlobalLock
);
1660 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1661 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1662 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1664 /* We found a provider? */
1665 if (MasterQueryContext
->LatestProvider
!= NULL
)
1667 /* With a successful status? */
1668 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1670 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1673 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1676 ExReleaseResourceLite(&MupPrefixTableLock
);
1677 /* Reroute & complete :-) */
1678 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1683 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1687 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1688 ExReleaseResourceLite(&MupPrefixTableLock
);
1690 /* Return the highest failed status we had */
1691 Status
= MasterQueryContext
->LatestStatus
;
1694 /* In finally, complete the IRP for real! */
1695 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1696 IoCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1698 MasterQueryContext
->Irp
= NULL
;
1699 MupFreeMasterQueryContext(MasterQueryContext
);
1706 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1711 ULONG LatestPos
, Pos
;
1712 PWSTR AcceptedPrefix
;
1713 PMUP_MQC MasterQueryContext
;
1714 NTSTATUS Status
, TableStatus
;
1715 PQUERY_PATH_CONTEXT QueryContext
;
1716 PQUERY_PATH_RESPONSE QueryResponse
;
1718 /* Get all the data from our query to the provider */
1719 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1720 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1721 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1722 Status
= Irp
->IoStatus
.Status
;
1724 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1726 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1727 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1729 /* If the driver returned a success, and an acceptance length */
1730 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1732 Prefix
= MasterQueryContext
->Prefix
;
1734 /* Check if we already found a provider from a previous iteration */
1735 if (MasterQueryContext
->LatestProvider
!= NULL
)
1737 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1738 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1740 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1744 /* Otherwise, if the prefix was in the prefix table, just drop it:
1745 * we have a provider which supersedes the accepted prefix, so leave
1746 * room for the new prefix/provider
1748 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1749 if (Prefix
->InTable
)
1751 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1752 RemoveEntryList(&Prefix
->PrefixListEntry
);
1753 Prefix
->InTable
= FALSE
;
1755 ExReleaseResourceLite(&MupPrefixTableLock
);
1757 Prefix
->KeepExtraRef
= FALSE
;
1759 /* Release data associated with the current prefix, if any
1760 * We'll renew them with the new accepted prefix
1762 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1764 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1765 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1766 Prefix
->AcceptedPrefix
.Length
= 0;
1767 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1768 Prefix
->ExternalAlloc
= FALSE
;
1771 /* If there was also a provider, drop it, the new one
1774 if (Prefix
->UncProvider
!= NULL
)
1776 MupDereferenceUncProvider(Prefix
->UncProvider
);
1777 Prefix
->UncProvider
= NULL
;
1781 /* Now, set our information about the provider that accepted the prefix */
1782 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1783 MasterQueryContext
->LatestStatus
= Status
;
1785 if (MasterQueryContext
->FileObject
->FsContext2
!= (PVOID
)DFS_DOWNLEVEL_OPEN_CONTEXT
)
1787 /* Allocate a buffer for the prefix */
1788 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1789 if (AcceptedPrefix
== NULL
)
1791 Prefix
->InTable
= FALSE
;
1795 /* Set it up to the accepted length */
1796 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1797 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1798 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1799 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1800 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1801 Prefix
->ExternalAlloc
= TRUE
;
1803 /* Insert the accepted prefix in the table of known prefixes */
1804 DPRINT1("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1805 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1806 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1808 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1809 Prefix
->InTable
= TRUE
;
1810 Prefix
->KeepExtraRef
= TRUE
;
1814 Prefix
->InTable
= FALSE
;
1816 ExReleaseResourceLite(&MupPrefixTableLock
);
1822 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1824 /* We failed and didn't find any provider over the latest iterations */
1825 if (MasterQueryContext
->LatestProvider
== NULL
)
1827 /* If we had a success though (broken provider?) set our failed status */
1828 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1830 MasterQueryContext
->LatestStatus
= Status
;
1834 TableStatus
= MupOrderedErrorList
[0];
1837 /* Otherwise, time to compare statuses, between the latest failed
1838 * and the current failure.
1839 * We have an order table of failed status: the deeper you go in the
1840 * table, the more the error is critical.
1841 * Our goal is to return the most critical status that was returned by
1842 * any of the providers
1845 /* Look for latest status position */
1846 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1849 TableStatus
= MupOrderedErrorList
[LatestPos
];
1852 /* If at pos 0, the new status is likely more critical */
1855 MasterQueryContext
->LatestStatus
= Status
;
1859 /* Otherwise, find position of the new status in the table */
1863 if (Status
== MupOrderedErrorList
[Pos
])
1870 while (Pos
< LatestPos
);
1872 /* If it has a higher position (more critical), return it */
1873 if (Pos
>= LatestPos
)
1875 MasterQueryContext
->LatestStatus
= Status
;
1883 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1884 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1887 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1888 MupDereferenceMasterQueryContext(MasterQueryContext
);
1890 return STATUS_MORE_PROCESSING_REQUIRED
;
1894 CreateRedirectedFile(PIRP Irp
,
1895 PFILE_OBJECT FileObject
,
1896 PIO_SECURITY_CONTEXT SecurityContext
)
1905 PMUP_UNC UncProvider
;
1906 PIO_STACK_LOCATION Stack
;
1907 LARGE_INTEGER CurrentTime
;
1908 PMUP_MQC MasterQueryContext
;
1909 PQUERY_PATH_CONTEXT QueryContext
;
1910 PQUERY_PATH_REQUEST QueryPathRequest
;
1911 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1912 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1914 /* We cannot open a file without a name */
1915 if (FileObject
->FileName
.Length
== 0)
1917 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1918 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1920 return STATUS_INVALID_DEVICE_REQUEST
;
1923 DPRINT1("Request for opening: %wZ\n", &FileObject
->FileName
);
1926 BreakOnFirst
= TRUE
;
1927 Status
= STATUS_BAD_NETWORK_PATH
;
1929 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1930 /* First, try to see if that's a prefix we already know */
1931 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1932 if (TableEntry
!= NULL
)
1934 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1936 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1938 /* If so, check whether the prefix is still valid */
1939 KeQuerySystemTime(&CurrentTime
);
1940 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1942 /* It is: so, update its validity period and reroute file opening */
1943 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1944 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1945 ExReleaseResourceLite(&MupPrefixTableLock
);
1947 if (Status
== STATUS_REPARSE
)
1949 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1952 Irp
->IoStatus
.Status
= Status
;
1953 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1958 /* When here, we found a matching prefix, but expired, remove it from the table
1959 * We'll redo a full search
1961 if (Prefix
->InTable
)
1963 MupRemoveKnownPrefixEntry(Prefix
);
1966 ExReleaseResourceLite(&MupPrefixTableLock
);
1968 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1969 /* First of all, start looking for a mailslot */
1970 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
1972 Name
= &FileObject
->FileName
.Buffer
[1];
1973 Len
= FileObject
->FileName
.Length
;
1975 /* Skip the remote destination name */
1978 Len
-= sizeof(WCHAR
);
1986 } while (Cur
!= L
'\\');
1987 Len
-= sizeof(WCHAR
);
1989 /* If we still have room for "Mailslot" to fit */
1990 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
1992 /* Get the len in terms of chars count */
1993 Len
/= sizeof(WCHAR
);
1994 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
1996 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
1999 /* It's indeed a mailslot opening! */
2000 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
2002 /* Broadcast open */
2003 Status
= BroadcastOpen(Irp
);
2004 if (Status
== STATUS_REPARSE
)
2006 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
2009 Irp
->IoStatus
.Status
= Status
;
2010 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2017 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
2018 if (!MupEnableDfs
|| FileObject
->FsContext2
== (PVOID
)DFS_DOWNLEVEL_OPEN_CONTEXT
)
2020 /* We won't complete immediately */
2021 IoMarkIrpPending(Irp
);
2023 /* Allocate a new prefix for our search */
2024 Prefix
= MupAllocatePrefixEntry(0);
2027 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2028 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2030 return STATUS_PENDING
;
2033 /* Allocate a context for our search */
2034 MasterQueryContext
= MupAllocateMasterQueryContext();
2035 if (MasterQueryContext
== NULL
)
2037 MupFreeNode(Prefix
);
2039 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2040 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2042 return STATUS_PENDING
;
2045 MasterQueryContext
->Irp
= Irp
;
2046 MasterQueryContext
->FileObject
= FileObject
;
2047 MasterQueryContext
->LatestProvider
= NULL
;
2048 MasterQueryContext
->Prefix
= Prefix
;
2049 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2050 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2051 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2052 ++Prefix
->NodeReferences
;
2053 ExReleaseResourceLite(&MupGlobalLock
);
2057 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2060 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2061 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2063 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2065 ++UncProvider
->NodeReferences
;
2068 ExReleaseResourceLite(&MupGlobalLock
);
2071 /* We will obviously only query registered providers */
2072 if (UncProvider
->Registered
)
2074 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2075 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2076 if (QueryPathRequest
== NULL
)
2078 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2081 /* Allocate a context for IRP completion routine
2082 * In case a prefix matches the path, the reroute will happen
2083 * in the completion routine, when we have return from the provider
2085 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2086 if (QueryContext
== NULL
)
2088 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2089 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2092 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2093 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2094 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2095 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2096 QueryPathRequest
->SecurityContext
= SecurityContext
;
2097 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2099 /* Build our IRP for the query */
2100 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2102 IRP_MJ_DEVICE_CONTROL
,
2103 IOCTL_REDIR_QUERY_PATH
,
2105 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2107 sizeof(QUERY_PATH_RESPONSE
),
2108 QueryPathCompletionRoutine
);
2109 if (QueryIrp
== NULL
)
2111 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2112 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2113 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2116 QueryIrp
->RequestorMode
= KernelMode
;
2117 QueryContext
->UncProvider
= UncProvider
;
2118 QueryContext
->Irp
= QueryIrp
;
2120 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2121 ++UncProvider
->NodeReferences
;
2122 ++MasterQueryContext
->NodeReferences
;
2123 ExReleaseResourceLite(&MupGlobalLock
);
2125 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2126 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2127 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2129 /* Query the provider !*/
2130 DPRINT1("Requesting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2131 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2132 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2135 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2138 /* We're done with that provider */
2139 MupDereferenceUncProvider(UncProvider
);
2142 /* If query went fine on the first request, just break and leave */
2143 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2148 BreakOnFirst
= FALSE
;
2153 if (_abnormal_termination())
2155 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2160 MupDereferenceUncProvider(UncProvider
);
2165 ExReleaseResourceLite(&MupGlobalLock
);
2168 MupDereferenceMasterQueryContext(MasterQueryContext
);
2170 Status
= STATUS_PENDING
;
2177 Status
= STATUS_NOT_IMPLEMENTED
;
2184 OpenMupFileSystem(PMUP_VCB Vcb
,
2185 PFILE_OBJECT FileObject
,
2186 ACCESS_MASK DesiredAccess
,
2191 DPRINT1("Opening MUP\n");
2193 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2196 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2197 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2198 if (NT_SUCCESS(Status
))
2200 ++Vcb
->NodeReferences
;
2201 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2202 Status
= STATUS_SUCCESS
;
2207 ExReleaseResourceLite(&MupVcbLock
);
2216 MupCreate(PDEVICE_OBJECT DeviceObject
,
2220 PIO_STACK_LOCATION Stack
;
2221 PFILE_OBJECT FileObject
, RelatedFileObject
;
2223 FsRtlEnterFileSystem();
2227 /* If DFS is enabled, check if that's for DFS and is so relay */
2228 if (MupEnableDfs
&& (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
))
2230 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2234 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2235 FileObject
= Stack
->FileObject
;
2236 RelatedFileObject
= FileObject
->RelatedFileObject
;
2238 /* 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 */
2239 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2241 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2243 /* Otherwise, it's just a volume open */
2246 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2248 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2249 Stack
->Parameters
.Create
.ShareAccess
);
2251 Irp
->IoStatus
.Information
= FILE_OPENED
;
2252 Irp
->IoStatus
.Status
= Status
;
2253 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2259 Status
= _SEH2_GetExceptionCode();
2261 Irp
->IoStatus
.Status
= Status
;
2262 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2266 FsRtlExitFileSystem();
2272 MupCloseUncProvider(PMUP_UNC UncProvider
)
2274 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2276 /* If the node was still valid, reregister the UNC provider */
2277 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2279 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2280 UncProvider
->Registered
= FALSE
;
2281 ExReleaseResourceLite(&MupGlobalLock
);
2283 if (UncProvider
->FileObject
!= NULL
)
2285 ZwClose(UncProvider
->DeviceHandle
);
2286 ObDereferenceObject(UncProvider
->FileObject
);
2291 ExReleaseResourceLite(&MupGlobalLock
);
2297 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2304 PIO_STACK_LOCATION Stack
;
2306 /* If DFS is enabled, check if that's for DFS and is so relay */
2309 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2311 return DfsFsdCleanup(DeviceObject
, Irp
);
2315 FsRtlEnterFileSystem();
2319 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2320 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2324 /* If we got a VCB, clean it up */
2325 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2327 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2328 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2330 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2332 /* If Ccb is not null, then, it's a UNC provider node */
2335 /* Close it, and dereference */
2336 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2337 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2338 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2340 ExReleaseResourceLite(&MupGlobalLock
);
2343 Status
= STATUS_SUCCESS
;
2347 /* If the node wasn't already cleaned, do it */
2348 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2350 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2351 Status
= STATUS_SUCCESS
;
2355 Status
= STATUS_INVALID_HANDLE
;
2358 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2359 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2361 MupDereferenceFcb(Fcb
);
2365 Status
= STATUS_INVALID_HANDLE
;
2367 Irp
->IoStatus
.Status
= Status
;
2368 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2375 Status
= _SEH2_GetExceptionCode();
2379 FsRtlExitFileSystem();
2385 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2388 PFILE_OBJECT FileObject
)
2390 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2392 /* Remove FCB, UNC from FO */
2393 MupSetFileObject(FileObject
, NULL
, NULL
);
2394 MupDereferenceVcb(Vcb
);
2396 ExReleaseResourceLite(&MupGlobalLock
);
2398 return STATUS_SUCCESS
;
2402 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2405 PFILE_OBJECT FileObject
)
2407 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2409 /* Remove FCB, CCB from FO */
2410 MupSetFileObject(FileObject
, NULL
, NULL
);
2411 MupDereferenceFcb(Fcb
);
2413 ExReleaseResourceLite(&MupGlobalLock
);
2415 return STATUS_SUCCESS
;
2420 MupClose(PDEVICE_OBJECT DeviceObject
,
2426 PIO_STACK_LOCATION Stack
;
2428 /* If DFS is enabled, check if that's for DFS and is so relay */
2431 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2433 return DfsFsdClose(DeviceObject
, Irp
);
2437 FsRtlEnterFileSystem();
2441 /* Get our internal structures from FO */
2442 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2443 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2446 Status
= STATUS_INVALID_HANDLE
;
2448 Irp
->IoStatus
.Status
= Status
;
2449 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2454 /* If we got the VCB, that's a volume close */
2455 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2457 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2459 /* Otherwise close the FCB */
2460 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2462 MupDereferenceFcb(Fcb
);
2463 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2467 Status
= STATUS_INVALID_HANDLE
;
2469 Irp
->IoStatus
.Status
= Status
;
2470 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2475 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2476 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2480 Status
= _SEH2_GetExceptionCode();
2484 FsRtlExitFileSystem();
2491 MupUnload(PDRIVER_OBJECT DriverObject
)
2493 IoDeleteDevice(mupDeviceObject
);
2497 DfsUnload(DriverObject
);
2500 MupUninitializeData();
2504 * FUNCTION: Called by the system to initialize the driver
2506 * DriverObject = object describing this driver
2507 * RegistryPath = path to our configuration entries
2508 * RETURNS: Success or failure
2513 DriverEntry(PDRIVER_OBJECT DriverObject
,
2514 PUNICODE_STRING RegistryPath
)
2517 UNICODE_STRING MupString
;
2518 PDEVICE_OBJECT DeviceObject
;
2520 /* Only initialize global state of the driver
2521 * Other inits will happen when required
2523 MupInitializeData();
2525 /* Check if DFS is disabled */
2526 MupEnableDfs
= MuppIsDfsEnabled();
2527 /* If it's not disabled but when cannot init, disable it */
2528 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2530 MupEnableDfs
= FALSE
;
2533 /* Create the MUP device */
2534 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2535 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2536 if (!NT_SUCCESS(Status
))
2540 DfsUnload(DriverObject
);
2543 MupUninitializeData();
2549 DriverObject
->DriverUnload
= MupUnload
;
2550 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2551 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2552 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2553 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2554 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2555 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2556 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2558 /* And finish init */
2559 mupDeviceObject
= DeviceObject
;
2560 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2562 return STATUS_SUCCESS
;