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 *****************************************************************/
35 ERESOURCE MupGlobalLock
;
36 ERESOURCE MupPrefixTableLock
;
37 ERESOURCE MupCcbListLock
;
39 LIST_ENTRY MupProviderList
;
40 LIST_ENTRY MupPrefixList
;
41 LIST_ENTRY MupMasterQueryList
;
42 UNICODE_PREFIX_TABLE MupPrefixTable
;
43 LARGE_INTEGER MupKnownPrefixTimeout
;
44 ULONG MupProviderCount
;
45 BOOLEAN MupOrderInitialized
;
47 PDEVICE_OBJECT mupDeviceObject
;
48 NTSTATUS MupOrderedErrorList
[] = { STATUS_UNSUCCESSFUL
,
49 STATUS_INVALID_PARAMETER
,
50 STATUS_REDIRECTOR_NOT_STARTED
,
51 STATUS_BAD_NETWORK_NAME
,
52 STATUS_BAD_NETWORK_PATH
, 0 };
54 /* FUNCTIONS ****************************************************************/
59 ExInitializeResourceLite(&MupGlobalLock
);
60 ExInitializeResourceLite(&MupPrefixTableLock
);
61 ExInitializeResourceLite(&MupCcbListLock
);
62 ExInitializeResourceLite(&MupVcbLock
);
64 InitializeListHead(&MupProviderList
);
65 InitializeListHead(&MupPrefixList
);
66 InitializeListHead(&MupMasterQueryList
);
67 RtlInitializeUnicodePrefix(&MupPrefixTable
);
68 MupKnownPrefixTimeout
.QuadPart
= 9000000000LL;
69 MupOrderInitialized
= FALSE
;
75 ExDeleteResourceLite(&MupGlobalLock
);
76 ExDeleteResourceLite(&MupPrefixTableLock
);
77 ExDeleteResourceLite(&MupCcbListLock
);
78 ExDeleteResourceLite(&MupVcbLock
);
82 MupInitializeVcb(PMUP_VCB Vcb
)
84 RtlZeroMemory(Vcb
, sizeof(MUP_VCB
));
85 Vcb
->NodeType
= NODE_TYPE_VCB
;
86 Vcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
87 Vcb
->NodeReferences
= 1;
88 Vcb
->NodeSize
= sizeof(MUP_VCB
);
92 MuppIsDfsEnabled(VOID
)
97 UNICODE_STRING KeyName
;
98 OBJECT_ATTRIBUTES ObjectAttributes
;
101 KEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
105 /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
106 KeyName
.Buffer
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
107 KeyName
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL
);
108 KeyName
.MaximumLength
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
110 /* Simply query registry to know whether we have to disable DFS.
111 * Unless explicitely stated in registry, we will try to enable DFS.
113 InitializeObjectAttributes(&ObjectAttributes
,
115 OBJ_CASE_INSENSITIVE
,
119 Status
= ZwOpenKey(&Key
, KEY_READ
, &ObjectAttributes
);
120 if (!NT_SUCCESS(Status
))
125 KeyName
.Buffer
= L
"DisableDfs";
126 KeyName
.Length
= sizeof(L
"DisableDfs") - sizeof(UNICODE_NULL
);
127 KeyName
.MaximumLength
= sizeof(L
"DisableDfs");
129 Status
= ZwQueryValueKey(Key
, &KeyName
, KeyValuePartialInformation
, &KeyQueryOutput
, sizeof(KeyQueryOutput
), &Length
);
131 if (!NT_SUCCESS(Status
) || KeyQueryOutput
.KeyInfo
.Type
!= REG_DWORD
)
136 return ((ULONG
)KeyQueryOutput
.KeyInfo
.Data
!= 1);
140 MupCalculateTimeout(PLARGE_INTEGER EntryTime
)
142 LARGE_INTEGER CurrentTime
;
144 /* Just get now + our allowed timeout */
145 KeQuerySystemTime(&CurrentTime
);
146 EntryTime
->QuadPart
= CurrentTime
.QuadPart
+ MupKnownPrefixTimeout
.QuadPart
;
154 Ccb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_CCB
), TAG_MUP
);
160 Ccb
->NodeStatus
= NODE_STATUS_HEALTHY
;
161 Ccb
->NodeReferences
= 1;
162 Ccb
->NodeType
= NODE_TYPE_CCB
;
163 Ccb
->NodeSize
= sizeof(MUP_CCB
);
173 Fcb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_FCB
), TAG_MUP
);
179 Fcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
180 Fcb
->NodeReferences
= 1;
181 Fcb
->NodeType
= NODE_TYPE_FCB
;
182 Fcb
->NodeSize
= sizeof(MUP_FCB
);
183 InitializeListHead(&Fcb
->CcbList
);
189 MupAllocateMasterIoContext(VOID
)
191 PMUP_MIC MasterIoContext
;
193 MasterIoContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MIC
), TAG_MUP
);
194 if (MasterIoContext
== NULL
)
199 MasterIoContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
200 MasterIoContext
->NodeReferences
= 1;
201 MasterIoContext
->NodeType
= NODE_TYPE_MIC
;
202 MasterIoContext
->NodeSize
= sizeof(MUP_MIC
);
204 return MasterIoContext
;
208 MupAllocateUncProvider(ULONG RedirectorDeviceNameLength
)
210 PMUP_UNC UncProvider
;
212 UncProvider
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_UNC
) + RedirectorDeviceNameLength
, TAG_MUP
);
213 if (UncProvider
== NULL
)
218 UncProvider
->NodeReferences
= 0;
219 UncProvider
->NodeType
= NODE_TYPE_UNC
;
220 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
221 UncProvider
->NodeSize
= sizeof(MUP_UNC
) + RedirectorDeviceNameLength
;
222 UncProvider
->Registered
= FALSE
;
228 MupAllocatePrefixEntry(ULONG PrefixLength
)
233 PrefixSize
= sizeof(MUP_PFX
) + PrefixLength
;
234 Prefix
= ExAllocatePoolWithTag(PagedPool
, PrefixSize
, TAG_MUP
);
240 RtlZeroMemory(Prefix
, PrefixSize
);
241 Prefix
->NodeType
= NODE_TYPE_PFX
;
242 Prefix
->NodeStatus
= NODE_STATUS_HEALTHY
;
243 Prefix
->NodeReferences
= 1;
244 Prefix
->NodeSize
= PrefixSize
;
246 /* If we got a prefix, initialize the string */
247 if (PrefixLength
!= 0)
249 Prefix
->AcceptedPrefix
.Buffer
= (PVOID
)((ULONG_PTR
)Prefix
+ sizeof(MUP_PFX
));
250 Prefix
->AcceptedPrefix
.Length
= PrefixLength
;
251 Prefix
->AcceptedPrefix
.MaximumLength
= PrefixLength
;
253 /* Otherwise, mark the fact that the allocation will be external */
256 Prefix
->ExternalAlloc
= TRUE
;
259 Prefix
->KeepExtraRef
= FALSE
;
260 /* Already init timeout to have one */
261 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
267 MupAllocateMasterQueryContext(VOID
)
269 PMUP_MQC MasterQueryContext
;
271 MasterQueryContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MQC
), TAG_MUP
);
272 if (MasterQueryContext
== NULL
)
277 MasterQueryContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
278 MasterQueryContext
->NodeReferences
= 1;
279 MasterQueryContext
->NodeType
= NODE_TYPE_MQC
;
280 MasterQueryContext
->NodeSize
= sizeof(MUP_MQC
);
281 InitializeListHead(&MasterQueryContext
->QueryPathList
);
282 InitializeListHead(&MasterQueryContext
->MQCListEntry
);
283 ExInitializeResourceLite(&MasterQueryContext
->QueryPathListLock
);
285 return MasterQueryContext
;
289 MupDecodeFileObject(PFILE_OBJECT FileObject
, PMUP_FCB
* pFcb
, PMUP_CCB
* pCcb
)
294 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
295 *pFcb
= FileObject
->FsContext
;
296 *pCcb
= FileObject
->FsContext2
;
301 ExReleaseResourceLite(&MupGlobalLock
);
305 Type
= Fcb
->NodeType
;
306 if ((Type
!= NODE_TYPE_VCB
&& Type
!= NODE_TYPE_FCB
) || (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
&& Fcb
->NodeStatus
!= NODE_STATUS_CLEANUP
))
309 ExReleaseResourceLite(&MupGlobalLock
);
313 ++Fcb
->NodeReferences
;
314 ExReleaseResourceLite(&MupGlobalLock
);
320 MupFreeNode(PVOID Node
)
322 ExFreePoolWithTag(Node
, TAG_MUP
);
326 MupDereferenceFcb(PMUP_FCB Fcb
)
328 /* Just dereference and delete if no references left */
329 if (InterlockedDecrement(&Fcb
->NodeReferences
) == 0)
336 MupDereferenceCcb(PMUP_CCB Ccb
)
338 /* Just dereference and delete (and clean) if no references left */
339 if (InterlockedDecrement(&Ccb
->NodeReferences
) == 0)
341 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
342 RemoveEntryList(&Ccb
->CcbListEntry
);
343 ExReleaseResourceLite(&MupCcbListLock
);
344 ObDereferenceObject(Ccb
->FileObject
);
345 MupDereferenceFcb(Ccb
->Fcb
);
351 MupDereferenceVcb(PMUP_VCB Vcb
)
353 /* We cannot reach the point where no references are left */
354 if (InterlockedDecrement(&Vcb
->NodeReferences
) == 0)
356 KeBugCheckEx(FILE_SYSTEM
, 3, 0, 0, 0);
361 MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext
,
366 PIO_STACK_LOCATION Stack
;
368 Status
= STATUS_SUCCESS
;
370 if (NewStatus
!= NULL
)
372 /* Save last status, depending on whether it failed or not */
373 if (!NT_SUCCESS(*NewStatus
))
375 MasterIoContext
->LastFailed
= *NewStatus
;
379 MasterIoContext
->LastSuccess
= STATUS_SUCCESS
;
383 if (InterlockedDecrement(&MasterIoContext
->NodeReferences
) != 0)
385 return STATUS_PENDING
;
388 Irp
= MasterIoContext
->Irp
;
389 Stack
= IoGetCurrentIrpStackLocation(Irp
);
390 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
392 Irp
->IoStatus
.Information
= Stack
->Parameters
.Write
.Length
;
396 Irp
->IoStatus
.Information
= 0;
399 /* In case we never had any success (init is a failure), get the last failed status */
400 if (!NT_SUCCESS(MasterIoContext
->LastSuccess
))
402 Status
= MasterIoContext
->LastFailed
;
405 Irp
->IoStatus
.Status
= Status
;
406 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
407 MupDereferenceFcb(MasterIoContext
->Fcb
);
408 MupFreeNode(MasterIoContext
);
414 MupDereferenceUncProvider(PMUP_UNC UncProvider
)
416 InterlockedExchangeAdd(&UncProvider
->NodeReferences
, -1);
420 MupDereferenceKnownPrefix(PMUP_PFX Prefix
)
422 /* Just dereference and delete (and clean) if no references left */
423 if (InterlockedDecrement(&Prefix
->NodeReferences
) == 0)
427 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
428 RemoveEntryList(&Prefix
->PrefixListEntry
);
431 if (Prefix
->ExternalAlloc
&& Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
433 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
436 if (Prefix
->UncProvider
)
438 MupDereferenceUncProvider(Prefix
->UncProvider
);
446 MupRemoveKnownPrefixEntry(PMUP_PFX Prefix
)
448 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
449 RemoveEntryList(&Prefix
->PrefixListEntry
);
450 Prefix
->InTable
= FALSE
;
451 MupDereferenceKnownPrefix(Prefix
);
455 MupInvalidatePrefixTable(VOID
)
460 /* Browse the prefix table */
461 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
462 for (Entry
= MupPrefixList
.Flink
;
463 Entry
!= &MupPrefixList
;
464 Entry
= Entry
->Flink
)
466 Prefix
= CONTAINING_RECORD(Entry
, MUP_PFX
, PrefixListEntry
);
468 /* And remove any entry in it */
471 MupRemoveKnownPrefixEntry(Prefix
);
474 ExReleaseResourceLite(&MupPrefixTableLock
);
478 MupCleanupVcb(PDEVICE_OBJECT DeviceObject
,
482 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
484 /* Check we're not doing anything wrong first */
485 if (Vcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Vcb
->NodeType
!= NODE_TYPE_VCB
)
487 ExRaiseStatus(STATUS_INVALID_HANDLE
);
490 /* Remove share access */
491 IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp
)->FileObject
, &Vcb
->ShareAccess
);
493 ExReleaseResourceLite(&MupVcbLock
);
497 MupCleanupFcb(PDEVICE_OBJECT DeviceObject
,
504 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
505 /* Check we're not doing anything wrong first */
506 if (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
508 ExRaiseStatus(STATUS_INVALID_HANDLE
);
510 Fcb
->NodeStatus
= NODE_STATUS_CLEANUP
;
511 ExReleaseResourceLite(&MupGlobalLock
);
513 /* Dereference any CCB associated with the FCB */
514 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
515 for (Entry
= Fcb
->CcbList
.Flink
;
516 Entry
!= &Fcb
->CcbList
;
517 Entry
= Entry
->Flink
)
519 Ccb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
520 ExReleaseResourceLite(&MupCcbListLock
);
521 MupDereferenceCcb(Ccb
);
522 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
524 ExReleaseResourceLite(&MupCcbListLock
);
528 CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
530 PFORWARDED_IO_CONTEXT FwdCtxt
)
534 Status
= Irp
->IoStatus
.Status
;
536 /* Just free everything we had allocated */
537 if (Irp
->MdlAddress
!= NULL
)
539 MmUnlockPages(Irp
->MdlAddress
);
540 IoFreeMdl(Irp
->MdlAddress
);
543 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
545 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
550 /* Dereference the master context
551 * The upper IRP will be completed once all the lower IRPs are done
552 * (and thus, references count reaches 0)
554 MupDereferenceCcb(FwdCtxt
->Ccb
);
555 MupDereferenceMasterIoContext(FwdCtxt
->MasterIoContext
, &Status
);
556 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
558 return STATUS_MORE_PROCESSING_REQUIRED
;
563 DeferredForwardedIoCompletionRoutine(PVOID Context
)
565 PFORWARDED_IO_CONTEXT FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
567 CommonForwardedIoCompletionRoutine(FwdCtxt
->DeviceObject
, FwdCtxt
->Irp
, Context
);
572 ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
576 PFORWARDED_IO_CONTEXT FwdCtxt
;
578 /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
579 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
581 CommonForwardedIoCompletionRoutine(DeviceObject
, Irp
, Context
);
585 FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
587 ExInitializeWorkItem(&FwdCtxt
->WorkQueueItem
, DeferredForwardedIoCompletionRoutine
, Context
);
588 ExQueueWorkItem(&FwdCtxt
->WorkQueueItem
, CriticalWorkQueue
);
591 return STATUS_MORE_PROCESSING_REQUIRED
;
595 BuildAndSubmitIrp(PIRP Irp
,
597 PMUP_MIC MasterIoContext
)
602 PIO_STACK_LOCATION Stack
;
603 PDEVICE_OBJECT DeviceObject
;
604 PFORWARDED_IO_CONTEXT FwdCtxt
;
606 Status
= STATUS_SUCCESS
;
610 /* Allocate a context for the completion routine */
611 FwdCtxt
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FORWARDED_IO_CONTEXT
), TAG_MUP
);
614 Status
= STATUS_INSUFFICIENT_RESOURCES
;
619 FwdCtxt
->DeviceObject
= NULL
;
622 /* Allocate the IRP */
623 DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
624 LowerIrp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
625 if (LowerIrp
== NULL
)
627 Status
= STATUS_INSUFFICIENT_RESOURCES
;
632 LowerIrp
->Tail
.Overlay
.OriginalFileObject
= Ccb
->FileObject
;
633 LowerIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
634 LowerIrp
->RequestorMode
= KernelMode
;
636 /* Copy the stack of the request we received to the IRP we'll pass below */
637 Stack
= IoGetNextIrpStackLocation(LowerIrp
);
638 RtlMoveMemory(Stack
, IoGetCurrentIrpStackLocation(Irp
), sizeof(IO_STACK_LOCATION
));
639 Stack
->FileObject
= Ccb
->FileObject
;
640 /* Setup flags according to the FO */
641 if (Ccb
->FileObject
->Flags
& FO_WRITE_THROUGH
)
643 Stack
->Flags
= SL_WRITE_THROUGH
;
648 /* Does the device requires we do buffered IOs? */
649 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
651 LowerIrp
->AssociatedIrp
.SystemBuffer
= NULL
;
653 if (Stack
->Parameters
.Write
.Length
== 0)
655 LowerIrp
->Flags
= IRP_BUFFERED_IO
;
657 /* If we have data to pass */
660 /* If it's coming from usermode, probe first */
661 if (Irp
->RequestorMode
== UserMode
)
663 ProbeForRead(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, sizeof(UCHAR
));
666 /* Allocate the buffer */
667 LowerIrp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned
,
668 Stack
->Parameters
.Write
.Length
,
670 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
672 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
675 /* And copy input (remember, we've to free!) */
676 RtlMoveMemory(LowerIrp
->AssociatedIrp
.SystemBuffer
, Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
);
677 LowerIrp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
682 if (!(DeviceObject
->Flags
& DO_DIRECT_IO
))
684 LowerIrp
->UserBuffer
= Irp
->UserBuffer
;
688 /* For direct IOs, allocate an MDL and pass it */
689 if (Stack
->Parameters
.Write
.Length
!= 0)
691 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, FALSE
, TRUE
, LowerIrp
);
694 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
697 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoReadAccess
);
702 /* Fix flags in the IRP */
703 if (Ccb
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
705 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
| IRP_NOCACHE
;
709 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
;
713 FwdCtxt
->MasterIoContext
= MasterIoContext
;
715 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
716 ++MasterIoContext
->NodeReferences
;
717 ExReleaseResourceLite(&MupGlobalLock
);
719 /* Set out completion routine */
720 IoSetCompletionRoutine(LowerIrp
, ForwardedIoCompletionRoutine
, FwdCtxt
, TRUE
, TRUE
, TRUE
);
721 /* And call the device with our brand new IRP */
722 Status
= IoCallDriver(Ccb
->DeviceObject
, LowerIrp
);
724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
726 Status
= _SEH2_GetExceptionCode();
731 if (!NT_SUCCESS(Status
))
735 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
738 if (LowerIrp
!= NULL
)
740 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
742 ExFreePoolWithTag(LowerIrp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
759 DfsVolumePassThrough(PDEVICE_OBJECT DeviceObject
,
762 return STATUS_NOT_IMPLEMENTED
;
767 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject
,
775 BOOLEAN CcbLockAcquired
;
776 PMUP_MIC MasterIoContext
;
777 PIO_STACK_LOCATION Stack
;
779 /* If DFS is enabled, check if that's for DFS and is so relay */
780 if (MupEnableDfs
&& DeviceObject
->DeviceType
== FILE_DEVICE_DFS
)
782 return DfsVolumePassThrough(DeviceObject
, Irp
);
785 Stack
= IoGetCurrentIrpStackLocation(Irp
);
787 FsRtlEnterFileSystem();
789 /* Write request is only possible for a mailslot, we need a FCB */
790 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
791 if (Fcb
== NULL
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
793 FsRtlExitFileSystem();
794 Status
= STATUS_INVALID_DEVICE_REQUEST
;
798 /* Allocate a context */
799 MasterIoContext
= MupAllocateMasterIoContext();
800 if (MasterIoContext
== NULL
)
802 FsRtlExitFileSystem();
803 Status
= STATUS_INSUFFICIENT_RESOURCES
;
807 /* Mark the IRP pending and init the context */
808 IoMarkIrpPending(Irp
);
809 MasterIoContext
->Irp
= Irp
;
810 /* Init with a failure to catch if we ever succeed */
811 MasterIoContext
->LastSuccess
= STATUS_UNSUCCESSFUL
;
812 /* Init with the worth failure possible */
813 MasterIoContext
->LastFailed
= STATUS_BAD_NETWORK_PATH
;
814 MasterIoContext
->Fcb
= Fcb
;
818 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
819 CcbLockAcquired
= TRUE
;
821 /* For all the CCB (ie, the mailslots) we have */
822 for (Entry
= Fcb
->CcbList
.Flink
;
823 Entry
!= &Fcb
->CcbList
;
824 Entry
= Entry
->Flink
)
826 FcbListCcb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
827 ExReleaseResourceLite(&MupCcbListLock
);
828 CcbLockAcquired
= FALSE
;
830 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
831 ++FcbListCcb
->NodeReferences
;
832 ExReleaseResourceLite(&MupGlobalLock
);
834 /* Forward the write request */
835 BuildAndSubmitIrp(Irp
, FcbListCcb
, MasterIoContext
);
836 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
837 CcbLockAcquired
= TRUE
;
840 ExReleaseResourceLite(&MupCcbListLock
);
841 CcbLockAcquired
= FALSE
;
843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
847 ExReleaseResourceLite(&MupCcbListLock
);
853 MupDereferenceMasterIoContext(MasterIoContext
, NULL
);
854 FsRtlExitFileSystem();
856 return STATUS_PENDING
;
860 Irp
->IoStatus
.Status
= Status
;
861 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
866 AddUnregisteredProvider(PCWSTR DeviceName
,
869 PMUP_UNC UncProvider
;
870 ULONG StrLen
, NameLen
;
872 /* Just allocate the node */
873 NameLen
= wcslen(DeviceName
);
874 StrLen
= NameLen
* sizeof(WCHAR
);
875 UncProvider
= MupAllocateUncProvider(StrLen
);
876 if (UncProvider
== NULL
)
882 UncProvider
->DeviceName
.MaximumLength
= StrLen
;
883 UncProvider
->DeviceName
.Length
= StrLen
;
884 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
885 UncProvider
->ProviderOrder
= ProviderOrder
;
886 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, DeviceName
, StrLen
);
888 /* And add it to the global list
889 * We're using tail here so that when called from registry init,
890 * the providers with highest priority will be in the head of
893 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
894 InsertTailList(&MupProviderList
, &UncProvider
->ProviderListEntry
);
895 ExReleaseResourceLite(&MupGlobalLock
);
901 InitializeProvider(PCWSTR ProviderName
,
906 UNICODE_STRING Key
, Value
;
907 PKEY_VALUE_FULL_INFORMATION Info
;
908 OBJECT_ATTRIBUTES ObjectAttributes
;
909 ULONG NameLen
, StrLen
, ResultLength
;
911 /* Get the information about the provider from registry */
912 NameLen
= wcslen(ProviderName
);
913 StrLen
= NameLen
* sizeof(WCHAR
) + sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L
"\\NetworkProvider");
914 Key
.Buffer
= ExAllocatePoolWithTag(PagedPool
, StrLen
, TAG_MUP
);
915 if (Key
.Buffer
== NULL
)
920 RtlMoveMemory(Key
.Buffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
921 Key
.MaximumLength
= StrLen
;
922 Key
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL
);
923 RtlAppendUnicodeToString(&Key
, ProviderName
);
924 RtlAppendUnicodeToString(&Key
, L
"\\NetworkProvider");
926 InitializeObjectAttributes(&ObjectAttributes
,
928 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
931 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
932 ExFreePoolWithTag(Key
.Buffer
, TAG_MUP
);
933 if (!NT_SUCCESS(Status
))
938 RtlInitUnicodeString(&Value
, L
"DeviceName");
939 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
940 if (Status
== STATUS_BUFFER_TOO_SMALL
)
942 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
949 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
954 /* And create the provider
955 * It will remain unregistered until FsRTL receives a registration request and forwards
958 if (NT_SUCCESS(Status
))
960 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
965 ExFreePoolWithTag(Info
, TAG_MUP
);
970 MupGetProviderInformation(VOID
)
975 PWSTR Providers
, Coma
;
976 PKEY_VALUE_FULL_INFORMATION Info
;
977 ULONG ResultLength
, ProviderCount
;
978 OBJECT_ATTRIBUTES ObjectAttributes
;
979 UNICODE_STRING NetworkProvider
, ProviderOrder
;
981 /* Open the registry to get the order of the providers */
982 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
983 InitializeObjectAttributes(&ObjectAttributes
,
985 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
988 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
989 if (!NT_SUCCESS(Status
))
994 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
995 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
996 if (Status
== STATUS_BUFFER_TOO_SMALL
)
998 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1005 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1010 if (NT_SUCCESS(Status
))
1012 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1016 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1017 * The order is just the order of the list
1018 * First has highest priority (0) and then, get lower and lower priority
1019 * The highest number is the lowest priority
1023 Coma
= wcschr(Providers
, L
',');
1026 *Coma
= UNICODE_NULL
;
1033 InitializeProvider(Providers
, ProviderCount
);
1036 Providers
= Coma
+ 1;
1042 ExFreePoolWithTag(Info
, TAG_MUP
);
1047 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1050 PMUP_UNC UncProvider
;
1052 /* Browse the list of all the providers nodes we have */
1053 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1054 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1056 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1058 /* If one matches the device and is not registered, that's ours! */
1059 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1061 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1066 if (Entry
== &MupProviderList
)
1070 ExReleaseResourceLite(&MupGlobalLock
);
1076 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1085 PIO_STACK_LOCATION Stack
;
1086 IO_STATUS_BLOCK IoStatusBlock
;
1087 PMUP_UNC UncProvider
, ListEntry
;
1088 OBJECT_ATTRIBUTES ObjectAttributes
;
1089 UNICODE_STRING RedirectorDeviceName
;
1090 OBJECT_HANDLE_INFORMATION HandleInfo
;
1091 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1093 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1096 /* Check whether providers order was already initialized */
1097 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1098 if (MupOrderInitialized
)
1100 ExReleaseResourceLite(&MupGlobalLock
);
1104 /* They weren't, so do it */
1105 MupOrderInitialized
= TRUE
;
1106 ExReleaseResourceLite(&MupGlobalLock
);
1107 MupGetProviderInformation();
1110 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1112 /* This can only happen with a volume open */
1113 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1115 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1116 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1118 return STATUS_INVALID_HANDLE
;
1121 /* Get the registration information */
1122 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1125 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1126 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1127 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1129 /* Have we got already a node for it? (Like from previous init) */
1130 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1131 if (UncProvider
== NULL
)
1133 /* If we don't, allocate a new one */
1135 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1136 if (UncProvider
== NULL
)
1138 Status
= STATUS_INVALID_USER_BUFFER
;
1143 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1144 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1145 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1147 /* As it wasn't in registry for order, give the lowest priority possible */
1148 UncProvider
->ProviderOrder
= MAXLONG
;
1149 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1152 /* Continue registration */
1153 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1154 ++UncProvider
->NodeReferences
;
1156 /* Open a handle to the device */
1157 InitializeObjectAttributes(&ObjectAttributes
,
1158 &UncProvider
->DeviceName
,
1159 OBJ_CASE_INSENSITIVE
,
1162 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1166 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1167 FILE_DIRECTORY_FILE
);
1168 if (NT_SUCCESS(Status
))
1170 Status
= IoStatusBlock
.Status
;
1173 /* And return the provider (as CCB) */
1174 if (NT_SUCCESS(Status
))
1176 Stack
->FileObject
->FsContext2
= UncProvider
;
1177 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1178 if (!NT_SUCCESS(Status
))
1180 NtClose(UncProvider
->DeviceHandle
);
1184 if (!NT_SUCCESS(Status
))
1186 MupDereferenceUncProvider(UncProvider
);
1190 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1192 /* Now, insert the provider in our global list
1193 * They are sorted by order
1195 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1199 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1201 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1203 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1209 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1211 UncProvider
->Registered
= TRUE
;
1212 ExReleaseResourceLite(&MupGlobalLock
);
1213 Status
= STATUS_SUCCESS
;
1215 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1220 if (_abnormal_termination())
1222 Status
= STATUS_INVALID_USER_BUFFER
;
1225 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1227 Irp
->IoStatus
.Status
= Status
;
1228 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1236 DfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject
,
1239 return STATUS_NOT_IMPLEMENTED
;
1244 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1248 PIO_STACK_LOCATION Stack
;
1250 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1254 /* MUP only understands a single FSCTL code: registering UNC provider */
1255 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1257 /* It obviously has to come from a driver/kernelmode thread */
1258 if (Irp
->RequestorMode
== UserMode
)
1260 Status
= STATUS_ACCESS_DENIED
;
1262 Irp
->IoStatus
.Status
= Status
;
1263 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1268 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1272 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1275 Status
= STATUS_INVALID_PARAMETER
;
1277 Irp
->IoStatus
.Status
= Status
;
1278 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1283 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1288 Status
= _SEH2_GetExceptionCode();
1296 MupSetFileObject(PFILE_OBJECT FileObject
,
1300 FileObject
->FsContext
= Fcb
;
1301 FileObject
->FsContext2
= Ccb
;
1305 MupRerouteOpen(PFILE_OBJECT FileObject
,
1306 PMUP_UNC UncProvider
)
1311 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1313 /* Get the full path name (device name first, and requested file name appended) */
1314 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1315 if (TotalLength
> MAXUSHORT
)
1317 return STATUS_NAME_TOO_LONG
;
1320 /* Allocate a buffer big enough */
1321 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1322 if (FullPath
== NULL
)
1324 return STATUS_INSUFFICIENT_RESOURCES
;
1327 /* Create the full path */
1328 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1329 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1331 /* And redo the path in the file oject */
1332 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1333 FileObject
->FileName
.Buffer
= FullPath
;
1334 FileObject
->FileName
.MaximumLength
= TotalLength
;
1335 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1337 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1338 return STATUS_REPARSE
;
1342 BroadcastOpen(PIRP Irp
)
1348 PMUP_UNC UncProvider
;
1349 UNICODE_STRING FullPath
;
1350 PFILE_OBJECT FileObject
;
1351 PIO_STACK_LOCATION Stack
;
1352 NTSTATUS Status
, LastFailed
;
1353 ULONG TotalLength
, LastOrder
;
1354 IO_STATUS_BLOCK IoStatusBlock
;
1355 OBJECT_ATTRIBUTES ObjectAttributes
;
1356 OBJECT_HANDLE_INFORMATION HandleInfo
;
1357 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1359 Fcb
= MupCreateFcb();
1362 return STATUS_INSUFFICIENT_RESOURCES
;
1365 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1366 FileObject
= Stack
->FileObject
;
1369 CcbInitialized
= FALSE
;
1370 LastFailed
= STATUS_NO_SUCH_FILE
;
1371 LastOrder
= (ULONG
)-1;
1375 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1378 /* Associate our FCB with the FO */
1379 MupSetFileObject(FileObject
, Fcb
, NULL
);
1380 Fcb
->FileObject
= FileObject
;
1382 /* Now, broadcast the open to any UNC provider that supports mailslots */
1383 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1385 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1386 ++UncProvider
->NodeReferences
;
1389 ExReleaseResourceLite(&MupGlobalLock
);
1392 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1393 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1395 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1396 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1397 if (FullPath
.Buffer
== NULL
)
1399 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1402 FullPath
.Length
= TotalLength
;
1403 FullPath
.MaximumLength
= TotalLength
;
1404 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1405 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1406 FileObject
->FileName
.Buffer
,
1407 FileObject
->FileName
.Length
);
1409 /* And just forward the creation request */
1410 InitializeObjectAttributes(&ObjectAttributes
,
1412 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1415 Status
= IoCreateFile(&Handle
,
1416 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1420 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1421 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1423 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1428 IO_NO_PARAMETER_CHECKING
);
1430 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1432 /* If opening succeed */
1433 if (NT_SUCCESS(Status
))
1435 Status
= IoStatusBlock
.Status
;
1438 Ccb
= MupCreateCcb();
1441 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1444 /* And associated a FO to it */
1445 if (NT_SUCCESS(Status
))
1447 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1452 /* If we failed, remember the last failed status of the higher priority provider */
1453 if (!NT_SUCCESS(Status
))
1455 if (UncProvider
->ProviderOrder
<= LastOrder
)
1457 LastOrder
= UncProvider
->ProviderOrder
;
1458 LastFailed
= Status
;
1461 /* Otherwise, properly attach our CCB to the mailslot */
1464 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1467 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1469 ++Fcb
->NodeReferences
;
1470 ExReleaseResourceLite(&MupGlobalLock
);
1472 CcbInitialized
= TRUE
;
1474 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1478 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1480 MupDereferenceUncProvider(UncProvider
);
1484 ExReleaseResourceLite(&MupGlobalLock
);
1487 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1489 Status
= _SEH2_GetExceptionCode();
1493 /* If we at least opened one mailslot, return success */
1494 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1498 MupDereferenceUncProvider(UncProvider
);
1503 ExReleaseResourceLite(&MupGlobalLock
);
1506 /* In case of failure, don't leak CCB */
1507 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1516 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1518 ULONG MajorFunction
,
1521 ULONG InputBufferSize
,
1523 ULONG OutputBufferSize
,
1524 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1527 PIO_STACK_LOCATION Stack
;
1528 PDEVICE_OBJECT DeviceObject
;
1530 if (InputBuffer
== NULL
)
1535 /* Get the device object */
1536 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1537 /* Allocate the IRP (with one more location for us */
1538 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1544 /* Skip our location */
1545 IoSetNextIrpStackLocation(Irp
);
1547 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1548 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1549 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1551 /* Setup the stack */
1552 Stack
= IoGetNextIrpStackLocation(Irp
);
1553 Stack
->MajorFunction
= MajorFunction
;
1554 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1555 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1556 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1557 Stack
->MinorFunction
= 0;
1558 Stack
->FileObject
= FileObject
;
1559 Stack
->DeviceObject
= DeviceObject
;
1561 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1563 case METHOD_BUFFERED
:
1564 /* If it's buffered, just pass the buffers we got */
1565 Irp
->MdlAddress
= NULL
;
1566 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1567 Irp
->UserBuffer
= OutputBuffer
;
1568 Irp
->Flags
= IRP_BUFFERED_IO
;
1570 if (OutputBuffer
!= NULL
)
1572 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1576 case METHOD_IN_DIRECT
:
1577 case METHOD_OUT_DIRECT
:
1578 /* Otherwise, allocate an MDL */
1579 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1585 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1586 Irp
->Flags
= IRP_BUFFERED_IO
;
1587 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1590 case METHOD_NEITHER
:
1591 /* Or pass the buffers */
1592 Irp
->UserBuffer
= OutputBuffer
;
1593 Irp
->MdlAddress
= NULL
;
1594 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1595 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1603 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1605 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1606 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1610 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1614 BOOLEAN KeepExtraRef
;
1616 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1617 --MasterQueryContext
->NodeReferences
;
1618 References
= MasterQueryContext
->NodeReferences
;
1619 ExReleaseResourceLite(&MupGlobalLock
);
1621 if (References
!= 0)
1623 DPRINT("Still having refs (%ld)\n", References
);
1624 return STATUS_PENDING
;
1627 /* We HAVE an IRP to complete. It cannot be NULL
1628 * Please, help preserving kittens, don't provide NULL IRPs.
1630 if (MasterQueryContext
->Irp
== NULL
)
1632 KeBugCheck(FILE_SYSTEM
);
1635 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1636 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1637 ExReleaseResourceLite(&MupGlobalLock
);
1639 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1640 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1641 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1643 /* We found a provider? */
1644 if (MasterQueryContext
->LatestProvider
!= NULL
)
1646 /* With a successful status? */
1647 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1649 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1652 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1655 ExReleaseResourceLite(&MupPrefixTableLock
);
1656 /* Reroute & complete :-) */
1657 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1662 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1666 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1667 ExReleaseResourceLite(&MupPrefixTableLock
);
1669 /* Return the highest failed status we had */
1670 Status
= MasterQueryContext
->LatestStatus
;
1673 /* In finally, complete the IRP for real! */
1674 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1675 IofCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1677 MasterQueryContext
->Irp
= NULL
;
1678 MupFreeMasterQueryContext(MasterQueryContext
);
1685 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1690 ULONG LatestPos
, Pos
;
1691 PWSTR AcceptedPrefix
;
1692 PMUP_MQC MasterQueryContext
;
1693 NTSTATUS Status
, TableStatus
;
1694 PQUERY_PATH_CONTEXT QueryContext
;
1695 PQUERY_PATH_RESPONSE QueryResponse
;
1697 /* Get all the data from our query to the provider */
1698 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1699 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1700 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1701 Status
= Irp
->IoStatus
.Status
;
1703 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1705 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1706 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1708 /* If the driver returned a success, and an acceptance length */
1709 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1711 Prefix
= MasterQueryContext
->Prefix
;
1713 /* Check if we already found a provider from a previous iteration */
1714 if (MasterQueryContext
->LatestProvider
!= NULL
)
1716 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1717 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1719 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1723 /* Otherwise, if the prefix was in the prefix table, just drop it:
1724 * we have a provider which superseeds the accepted prefix, so leave
1725 * room for the new prefix/provider
1727 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1728 if (Prefix
->InTable
)
1730 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1731 RemoveEntryList(&Prefix
->PrefixListEntry
);
1732 Prefix
->InTable
= FALSE
;
1734 ExReleaseResourceLite(&MupPrefixTableLock
);
1736 Prefix
->KeepExtraRef
= FALSE
;
1738 /* Release data associated with the current prefix, if any
1739 * We'll renew them with the new accepted prefix
1741 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1743 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1744 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1745 Prefix
->AcceptedPrefix
.Length
= 0;
1746 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1747 Prefix
->ExternalAlloc
= FALSE
;
1750 /* If there was also a provider, drop it, the new one
1753 if (Prefix
->UncProvider
!= NULL
)
1755 MupDereferenceUncProvider(Prefix
->UncProvider
);
1756 Prefix
->UncProvider
= NULL
;
1760 /* Now, set our information about the provider that accepted the prefix */
1761 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1762 MasterQueryContext
->LatestStatus
= Status
;
1764 if (MasterQueryContext
->FileObject
->FsContext2
!= DFS_MAGIC_CCB
)
1766 /* Allocate a buffer for the prefix */
1767 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1768 if (AcceptedPrefix
== NULL
)
1770 Prefix
->InTable
= FALSE
;
1774 /* Set it up to the accepted length */
1775 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1776 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1777 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1778 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1779 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1780 Prefix
->ExternalAlloc
= TRUE
;
1782 /* Insert the accepted prefix in the table of known prefixes */
1783 DPRINT1("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1784 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1785 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1787 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1788 Prefix
->InTable
= TRUE
;
1789 Prefix
->KeepExtraRef
= TRUE
;
1793 Prefix
->InTable
= FALSE
;
1795 ExReleaseResourceLite(&MupPrefixTableLock
);
1801 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1803 /* We failed and didn't find any provider over the latest iterations */
1804 if (MasterQueryContext
->LatestProvider
== NULL
)
1806 /* If we had a success though (broken provider?) set our failed status */
1807 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1809 MasterQueryContext
->LatestStatus
= Status
;
1813 TableStatus
= MupOrderedErrorList
[0];
1816 /* Otherwise, time to compare statuteses, between the latest failed
1817 * and the current failure.
1818 * We have an order table of failed status: the deeper you go in the
1819 * table, the more the error is critical.
1820 * Our goal is to return the most critical status that was returned by
1821 * any of the providers
1824 /* Look for latest status position */
1825 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1828 TableStatus
= MupOrderedErrorList
[LatestPos
];
1831 /* If at pos 0, the new status is likely more critical */
1834 MasterQueryContext
->LatestStatus
= Status
;
1838 /* Otherwise, find position of the new status in the table */
1842 if (Status
== MupOrderedErrorList
[Pos
])
1849 while (Pos
< LatestPos
);
1851 /* If it has a higher position (more critical), return it */
1852 if (Pos
>= LatestPos
)
1854 MasterQueryContext
->LatestStatus
= Status
;
1862 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1863 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1866 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1867 MupDereferenceMasterQueryContext(MasterQueryContext
);
1869 return STATUS_MORE_PROCESSING_REQUIRED
;
1873 DfsFsdCreate(PDEVICE_OBJECT DeviceObject
,
1877 return STATUS_NOT_IMPLEMENTED
;
1881 CreateRedirectedFile(PIRP Irp
,
1882 PFILE_OBJECT FileObject
,
1883 PIO_SECURITY_CONTEXT SecurityContext
)
1892 PMUP_UNC UncProvider
;
1893 PIO_STACK_LOCATION Stack
;
1894 LARGE_INTEGER CurrentTime
;
1895 PMUP_MQC MasterQueryContext
;
1896 PQUERY_PATH_CONTEXT QueryContext
;
1897 PQUERY_PATH_REQUEST QueryPathRequest
;
1898 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1899 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1901 /* We cannot open a file without a name */
1902 if (FileObject
->FileName
.Length
== 0)
1904 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1905 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1907 return STATUS_INVALID_DEVICE_REQUEST
;
1910 DPRINT1("Request for opening: %wZ\n", &FileObject
->FileName
);
1913 BreakOnFirst
= TRUE
;
1914 Status
= STATUS_BAD_NETWORK_PATH
;
1916 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1917 /* First, try to see if that's a prefix we already know */
1918 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1919 if (TableEntry
!= NULL
)
1921 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1923 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1925 /* If so, check whether the prefix is still valid */
1926 KeQuerySystemTime(&CurrentTime
);
1927 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1929 /* It is: so, update its validity period and reroute file opening */
1930 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1931 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1932 ExReleaseResourceLite(&MupPrefixTableLock
);
1934 if (Status
== STATUS_REPARSE
)
1936 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1939 Irp
->IoStatus
.Status
= Status
;
1940 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1945 /* When here, we found a matching prefix, but expired, remove it from the table
1946 * We'll redo a full search
1948 if (Prefix
->InTable
)
1950 MupRemoveKnownPrefixEntry(Prefix
);
1953 ExReleaseResourceLite(&MupPrefixTableLock
);
1955 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1956 /* First of all, start looking for a mailslot */
1957 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
1959 Name
= &FileObject
->FileName
.Buffer
[1];
1960 Len
= FileObject
->FileName
.Length
;
1962 /* Skip the remote destination name */
1965 Len
-= sizeof(WCHAR
);
1973 } while (Cur
!= L
'\\');
1974 Len
-= sizeof(WCHAR
);
1976 /* If we still have room for "Mailslot" to fit */
1977 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
1979 /* Get the len in terms of chars count */
1980 Len
/= sizeof(WCHAR
);
1981 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
1983 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
1986 /* It's indeed a mailslot opening! */
1987 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
1989 /* Broadcast open */
1990 Status
= BroadcastOpen(Irp
);
1991 if (Status
== STATUS_REPARSE
)
1993 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1996 Irp
->IoStatus
.Status
= Status
;
1997 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2004 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
2005 if (!MupEnableDfs
|| FileObject
->FsContext2
== DFS_MAGIC_CCB
)
2007 /* We won't complete immediately */
2008 IoMarkIrpPending(Irp
);
2010 /* Allocate a new prefix for our search */
2011 Prefix
= MupAllocatePrefixEntry(0);
2014 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2015 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2017 return STATUS_PENDING
;
2020 /* Allocate a context for our search */
2021 MasterQueryContext
= MupAllocateMasterQueryContext();
2022 if (MasterQueryContext
== NULL
)
2024 MupFreeNode(Prefix
);
2026 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2027 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2029 return STATUS_PENDING
;
2032 MasterQueryContext
->Irp
= Irp
;
2033 MasterQueryContext
->FileObject
= FileObject
;
2034 MasterQueryContext
->LatestProvider
= NULL
;
2035 MasterQueryContext
->Prefix
= Prefix
;
2036 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2037 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2038 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2039 ++Prefix
->NodeReferences
;
2040 ExReleaseResourceLite(&MupGlobalLock
);
2044 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2047 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2048 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2050 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2052 ++UncProvider
->NodeReferences
;
2055 ExReleaseResourceLite(&MupGlobalLock
);
2058 /* We will obviously only query registered providers */
2059 if (UncProvider
->Registered
)
2061 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2062 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2063 if (QueryPathRequest
== NULL
)
2065 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2068 /* Allocate a context for IRP completion routine
2069 * In case a prefix matches the path, the reroute will happen
2070 * in the completion routine, when we have return from the provider
2072 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2073 if (QueryContext
== NULL
)
2075 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2076 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2079 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2080 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2081 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2082 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2083 QueryPathRequest
->SecurityContext
= SecurityContext
;
2084 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2086 /* Build our IRP for the query */
2087 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2089 IRP_MJ_DEVICE_CONTROL
,
2090 IOCTL_REDIR_QUERY_PATH
,
2092 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2094 sizeof(QUERY_PATH_RESPONSE
),
2095 QueryPathCompletionRoutine
);
2096 if (QueryIrp
== NULL
)
2098 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2099 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2100 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2103 QueryIrp
->RequestorMode
= KernelMode
;
2104 QueryContext
->UncProvider
= UncProvider
;
2105 QueryContext
->Irp
= QueryIrp
;
2107 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2108 ++UncProvider
->NodeReferences
;
2109 ++MasterQueryContext
->NodeReferences
;
2110 ExReleaseResourceLite(&MupGlobalLock
);
2112 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2113 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2114 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2116 /* Query the provider !*/
2117 DPRINT1("Requeting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2118 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2119 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2122 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2125 /* We're done with that provider */
2126 MupDereferenceUncProvider(UncProvider
);
2129 /* If query went fine on the first request, just break and leave */
2130 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2135 BreakOnFirst
= FALSE
;
2140 if (_abnormal_termination())
2142 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2147 MupDereferenceUncProvider(UncProvider
);
2152 ExReleaseResourceLite(&MupGlobalLock
);
2155 MupDereferenceMasterQueryContext(MasterQueryContext
);
2157 Status
= STATUS_PENDING
;
2164 Status
= STATUS_NOT_IMPLEMENTED
;
2171 OpenMupFileSystem(PMUP_VCB Vcb
,
2172 PFILE_OBJECT FileObject
,
2173 ACCESS_MASK DesiredAccess
,
2178 DPRINT1("Opening MUP\n");
2180 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2183 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2184 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2185 if (NT_SUCCESS(Status
))
2187 ++Vcb
->NodeReferences
;
2188 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2189 Status
= STATUS_SUCCESS
;
2194 ExReleaseResourceLite(&MupVcbLock
);
2203 MupCreate(PDEVICE_OBJECT DeviceObject
,
2207 PIO_STACK_LOCATION Stack
;
2208 PFILE_OBJECT FileObject
, RelatedFileObject
;
2210 FsRtlEnterFileSystem();
2214 /* If DFS is enabled, check if that's for DFS and is so relay */
2217 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2219 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2224 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2225 FileObject
= Stack
->FileObject
;
2226 RelatedFileObject
= FileObject
->RelatedFileObject
;
2228 /* 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 */
2229 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2231 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2233 /* Otherwise, it's just a volume open */
2236 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2238 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2239 Stack
->Parameters
.Create
.ShareAccess
);
2241 Irp
->IoStatus
.Information
= FILE_OPENED
;
2242 Irp
->IoStatus
.Status
= Status
;
2243 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2247 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2249 Status
= _SEH2_GetExceptionCode();
2251 Irp
->IoStatus
.Status
= Status
;
2252 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2256 FsRtlExitFileSystem();
2262 MupCloseUncProvider(PMUP_UNC UncProvider
)
2264 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2266 /* If the node was still valid, reregister the UNC provider */
2267 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2269 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2270 UncProvider
->Registered
= FALSE
;
2271 ExReleaseResourceLite(&MupGlobalLock
);
2273 if (UncProvider
->FileObject
!= NULL
)
2275 ZwClose(UncProvider
->DeviceHandle
);
2276 ObDereferenceObject(UncProvider
->FileObject
);
2281 ExReleaseResourceLite(&MupGlobalLock
);
2286 DfsFsdCleanup(PDEVICE_OBJECT DeviceObject
,
2290 return STATUS_NOT_IMPLEMENTED
;
2295 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2302 PIO_STACK_LOCATION Stack
;
2304 /* If DFS is enabled, check if that's for DFS and is so relay */
2307 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2309 return DfsFsdCleanup(DeviceObject
, Irp
);
2313 FsRtlEnterFileSystem();
2317 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2318 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2322 /* If we got a VCB, clean it up */
2323 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2325 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2326 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2328 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2330 /* If Ccb is not null, then, it's a UNC provider node */
2333 /* Close it, and dereference */
2334 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2335 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2336 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2338 ExReleaseResourceLite(&MupGlobalLock
);
2341 Status
= STATUS_SUCCESS
;
2345 /* If the node wasn't already cleaned, do it */
2346 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2348 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2349 Status
= STATUS_SUCCESS
;
2353 Status
= STATUS_INVALID_HANDLE
;
2356 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2357 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2359 MupDereferenceFcb(Fcb
);
2363 Status
= STATUS_INVALID_HANDLE
;
2365 Irp
->IoStatus
.Status
= Status
;
2366 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2373 Status
= _SEH2_GetExceptionCode();
2377 FsRtlExitFileSystem();
2383 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2386 PFILE_OBJECT FileObject
)
2388 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2390 /* Remove FCB, UNC from FO */
2391 MupSetFileObject(FileObject
, NULL
, NULL
);
2392 MupDereferenceVcb(Vcb
);
2394 ExReleaseResourceLite(&MupGlobalLock
);
2396 return STATUS_SUCCESS
;
2400 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2403 PFILE_OBJECT FileObject
)
2405 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2407 /* Remove FCB, CCB from FO */
2408 MupSetFileObject(FileObject
, NULL
, NULL
);
2409 MupDereferenceFcb(Fcb
);
2411 ExReleaseResourceLite(&MupGlobalLock
);
2413 return STATUS_SUCCESS
;
2417 DfsFsdClose(PDEVICE_OBJECT DeviceObject
,
2421 return STATUS_NOT_IMPLEMENTED
;
2426 MupClose(PDEVICE_OBJECT DeviceObject
,
2432 PIO_STACK_LOCATION Stack
;
2434 /* If DFS is enabled, check if that's for DFS and is so relay */
2437 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2439 return DfsFsdClose(DeviceObject
, Irp
);
2443 FsRtlEnterFileSystem();
2447 /* Get our internal structures from FO */
2448 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2449 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2452 Status
= STATUS_INVALID_HANDLE
;
2454 Irp
->IoStatus
.Status
= Status
;
2455 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2460 /* If we got the VCB, that's a volume close */
2461 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2463 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2465 /* Otherwise close the FCB */
2466 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2468 MupDereferenceFcb(Fcb
);
2469 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2473 Status
= STATUS_INVALID_HANDLE
;
2475 Irp
->IoStatus
.Status
= Status
;
2476 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2481 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2482 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2486 Status
= _SEH2_GetExceptionCode();
2490 FsRtlExitFileSystem();
2496 DfsUnload(PDRIVER_OBJECT DriverObject
)
2503 MupUnload(PDRIVER_OBJECT DriverObject
)
2505 IoDeleteDevice(mupDeviceObject
);
2509 DfsUnload(DriverObject
);
2512 MupUninitializeData();
2516 DfsDriverEntry(PDRIVER_OBJECT DriverObject
,
2517 PUNICODE_STRING RegistryPath
)
2519 /* We don't support DFS yet, so
2520 * fail to make sure it remains disabled
2523 return STATUS_NOT_IMPLEMENTED
;
2527 * FUNCTION: Called by the system to initialize the driver
2529 * DriverObject = object describing this driver
2530 * RegistryPath = path to our configuration entries
2531 * RETURNS: Success or failure
2535 DriverEntry(PDRIVER_OBJECT DriverObject
,
2536 PUNICODE_STRING RegistryPath
)
2539 UNICODE_STRING MupString
;
2540 PDEVICE_OBJECT DeviceObject
;
2542 /* Only initialize global state of the driver
2543 * Other inits will happen when required
2545 MupInitializeData();
2547 /* Check if DFS is disabled */
2548 MupEnableDfs
= MuppIsDfsEnabled();
2549 /* If it's not disabled but when cannot init, disable it */
2550 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2552 MupEnableDfs
= FALSE
;
2555 /* Create the MUP device */
2556 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2557 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2558 if (!NT_SUCCESS(Status
))
2562 DfsUnload(DriverObject
);
2565 MupUninitializeData();
2571 DriverObject
->DriverUnload
= MupUnload
;
2572 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2573 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2574 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2575 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2576 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2577 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2578 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2580 /* And finish init */
2581 mupDeviceObject
= DeviceObject
;
2582 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2584 return STATUS_SUCCESS
;