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 ****************************************************************/
58 MupInitializeData(VOID
)
60 ExInitializeResourceLite(&MupGlobalLock
);
61 ExInitializeResourceLite(&MupPrefixTableLock
);
62 ExInitializeResourceLite(&MupCcbListLock
);
63 ExInitializeResourceLite(&MupVcbLock
);
65 InitializeListHead(&MupProviderList
);
66 InitializeListHead(&MupPrefixList
);
67 InitializeListHead(&MupMasterQueryList
);
68 RtlInitializeUnicodePrefix(&MupPrefixTable
);
69 MupKnownPrefixTimeout
.QuadPart
= 9000000000LL;
70 MupOrderInitialized
= FALSE
;
76 ExDeleteResourceLite(&MupGlobalLock
);
77 ExDeleteResourceLite(&MupPrefixTableLock
);
78 ExDeleteResourceLite(&MupCcbListLock
);
79 ExDeleteResourceLite(&MupVcbLock
);
84 MupInitializeVcb(PMUP_VCB Vcb
)
86 RtlZeroMemory(Vcb
, sizeof(MUP_VCB
));
87 Vcb
->NodeType
= NODE_TYPE_VCB
;
88 Vcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
89 Vcb
->NodeReferences
= 1;
90 Vcb
->NodeSize
= sizeof(MUP_VCB
);
94 MuppIsDfsEnabled(VOID
)
99 UNICODE_STRING KeyName
;
100 OBJECT_ATTRIBUTES ObjectAttributes
;
103 KEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
107 /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
108 KeyName
.Buffer
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
109 KeyName
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL
);
110 KeyName
.MaximumLength
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
112 /* Simply query registry to know whether we have to disable DFS.
113 * Unless explicitly stated in registry, we will try to enable DFS.
115 InitializeObjectAttributes(&ObjectAttributes
,
117 OBJ_CASE_INSENSITIVE
,
121 Status
= ZwOpenKey(&Key
, KEY_READ
, &ObjectAttributes
);
122 if (!NT_SUCCESS(Status
))
127 KeyName
.Buffer
= L
"DisableDfs";
128 KeyName
.Length
= sizeof(L
"DisableDfs") - sizeof(UNICODE_NULL
);
129 KeyName
.MaximumLength
= sizeof(L
"DisableDfs");
131 Status
= ZwQueryValueKey(Key
, &KeyName
, KeyValuePartialInformation
, &KeyQueryOutput
, sizeof(KeyQueryOutput
), &Length
);
133 if (!NT_SUCCESS(Status
) || KeyQueryOutput
.KeyInfo
.Type
!= REG_DWORD
)
138 return ((ULONG_PTR
)KeyQueryOutput
.KeyInfo
.Data
!= 1);
142 MupCalculateTimeout(PLARGE_INTEGER EntryTime
)
144 LARGE_INTEGER CurrentTime
;
146 /* Just get now + our allowed timeout */
147 KeQuerySystemTime(&CurrentTime
);
148 EntryTime
->QuadPart
= CurrentTime
.QuadPart
+ MupKnownPrefixTimeout
.QuadPart
;
156 Ccb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_CCB
), TAG_MUP
);
162 Ccb
->NodeStatus
= NODE_STATUS_HEALTHY
;
163 Ccb
->NodeReferences
= 1;
164 Ccb
->NodeType
= NODE_TYPE_CCB
;
165 Ccb
->NodeSize
= sizeof(MUP_CCB
);
175 Fcb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_FCB
), TAG_MUP
);
181 Fcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
182 Fcb
->NodeReferences
= 1;
183 Fcb
->NodeType
= NODE_TYPE_FCB
;
184 Fcb
->NodeSize
= sizeof(MUP_FCB
);
185 InitializeListHead(&Fcb
->CcbList
);
191 MupAllocateMasterIoContext(VOID
)
193 PMUP_MIC MasterIoContext
;
195 MasterIoContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MIC
), TAG_MUP
);
196 if (MasterIoContext
== NULL
)
201 MasterIoContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
202 MasterIoContext
->NodeReferences
= 1;
203 MasterIoContext
->NodeType
= NODE_TYPE_MIC
;
204 MasterIoContext
->NodeSize
= sizeof(MUP_MIC
);
206 return MasterIoContext
;
210 MupAllocateUncProvider(ULONG RedirectorDeviceNameLength
)
212 PMUP_UNC UncProvider
;
214 UncProvider
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_UNC
) + RedirectorDeviceNameLength
, TAG_MUP
);
215 if (UncProvider
== NULL
)
220 UncProvider
->NodeReferences
= 0;
221 UncProvider
->NodeType
= NODE_TYPE_UNC
;
222 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
223 UncProvider
->NodeSize
= sizeof(MUP_UNC
) + RedirectorDeviceNameLength
;
224 UncProvider
->Registered
= FALSE
;
230 MupAllocatePrefixEntry(ULONG PrefixLength
)
235 PrefixSize
= sizeof(MUP_PFX
) + PrefixLength
;
236 Prefix
= ExAllocatePoolWithTag(PagedPool
, PrefixSize
, TAG_MUP
);
242 RtlZeroMemory(Prefix
, PrefixSize
);
243 Prefix
->NodeType
= NODE_TYPE_PFX
;
244 Prefix
->NodeStatus
= NODE_STATUS_HEALTHY
;
245 Prefix
->NodeReferences
= 1;
246 Prefix
->NodeSize
= PrefixSize
;
248 /* If we got a prefix, initialize the string */
249 if (PrefixLength
!= 0)
251 Prefix
->AcceptedPrefix
.Buffer
= (PVOID
)((ULONG_PTR
)Prefix
+ sizeof(MUP_PFX
));
252 Prefix
->AcceptedPrefix
.Length
= PrefixLength
;
253 Prefix
->AcceptedPrefix
.MaximumLength
= PrefixLength
;
255 /* Otherwise, mark the fact that the allocation will be external */
258 Prefix
->ExternalAlloc
= TRUE
;
261 Prefix
->KeepExtraRef
= FALSE
;
262 /* Already init timeout to have one */
263 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
269 MupAllocateMasterQueryContext(VOID
)
271 PMUP_MQC MasterQueryContext
;
273 MasterQueryContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MQC
), TAG_MUP
);
274 if (MasterQueryContext
== NULL
)
279 MasterQueryContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
280 MasterQueryContext
->NodeReferences
= 1;
281 MasterQueryContext
->NodeType
= NODE_TYPE_MQC
;
282 MasterQueryContext
->NodeSize
= sizeof(MUP_MQC
);
283 InitializeListHead(&MasterQueryContext
->QueryPathList
);
284 InitializeListHead(&MasterQueryContext
->MQCListEntry
);
285 ExInitializeResourceLite(&MasterQueryContext
->QueryPathListLock
);
287 return MasterQueryContext
;
291 MupDecodeFileObject(PFILE_OBJECT FileObject
, PMUP_FCB
* pFcb
, PMUP_CCB
* pCcb
)
296 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
297 *pFcb
= FileObject
->FsContext
;
298 *pCcb
= FileObject
->FsContext2
;
303 ExReleaseResourceLite(&MupGlobalLock
);
307 Type
= Fcb
->NodeType
;
308 if ((Type
!= NODE_TYPE_VCB
&& Type
!= NODE_TYPE_FCB
) || (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
&& Fcb
->NodeStatus
!= NODE_STATUS_CLEANUP
))
311 ExReleaseResourceLite(&MupGlobalLock
);
315 ++Fcb
->NodeReferences
;
316 ExReleaseResourceLite(&MupGlobalLock
);
322 MupFreeNode(PVOID Node
)
324 ExFreePoolWithTag(Node
, TAG_MUP
);
328 MupDereferenceFcb(PMUP_FCB Fcb
)
330 /* Just dereference and delete if no references left */
331 if (InterlockedDecrement(&Fcb
->NodeReferences
) == 0)
338 MupDereferenceCcb(PMUP_CCB Ccb
)
340 /* Just dereference and delete (and clean) if no references left */
341 if (InterlockedDecrement(&Ccb
->NodeReferences
) == 0)
343 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
344 RemoveEntryList(&Ccb
->CcbListEntry
);
345 ExReleaseResourceLite(&MupCcbListLock
);
346 ObDereferenceObject(Ccb
->FileObject
);
347 MupDereferenceFcb(Ccb
->Fcb
);
353 MupDereferenceVcb(PMUP_VCB Vcb
)
355 /* We cannot reach the point where no references are left */
356 if (InterlockedDecrement(&Vcb
->NodeReferences
) == 0)
358 KeBugCheckEx(FILE_SYSTEM
, 3, 0, 0, 0);
363 MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext
,
368 PIO_STACK_LOCATION Stack
;
370 Status
= STATUS_SUCCESS
;
372 if (NewStatus
!= NULL
)
374 /* Save last status, depending on whether it failed or not */
375 if (!NT_SUCCESS(*NewStatus
))
377 MasterIoContext
->LastFailed
= *NewStatus
;
381 MasterIoContext
->LastSuccess
= STATUS_SUCCESS
;
385 if (InterlockedDecrement(&MasterIoContext
->NodeReferences
) != 0)
387 return STATUS_PENDING
;
390 Irp
= MasterIoContext
->Irp
;
391 Stack
= IoGetCurrentIrpStackLocation(Irp
);
392 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
394 Irp
->IoStatus
.Information
= Stack
->Parameters
.Write
.Length
;
398 Irp
->IoStatus
.Information
= 0;
401 /* In case we never had any success (init is a failure), get the last failed status */
402 if (!NT_SUCCESS(MasterIoContext
->LastSuccess
))
404 Status
= MasterIoContext
->LastFailed
;
407 Irp
->IoStatus
.Status
= Status
;
408 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
409 MupDereferenceFcb(MasterIoContext
->Fcb
);
410 MupFreeNode(MasterIoContext
);
416 MupDereferenceUncProvider(PMUP_UNC UncProvider
)
418 InterlockedExchangeAdd(&UncProvider
->NodeReferences
, -1);
422 MupDereferenceKnownPrefix(PMUP_PFX Prefix
)
424 /* Just dereference and delete (and clean) if no references left */
425 if (InterlockedDecrement(&Prefix
->NodeReferences
) == 0)
429 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
430 RemoveEntryList(&Prefix
->PrefixListEntry
);
433 if (Prefix
->ExternalAlloc
&& Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
435 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
438 if (Prefix
->UncProvider
)
440 MupDereferenceUncProvider(Prefix
->UncProvider
);
448 MupRemoveKnownPrefixEntry(PMUP_PFX Prefix
)
450 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
451 RemoveEntryList(&Prefix
->PrefixListEntry
);
452 Prefix
->InTable
= FALSE
;
453 MupDereferenceKnownPrefix(Prefix
);
457 MupInvalidatePrefixTable(VOID
)
462 /* Browse the prefix table */
463 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
464 for (Entry
= MupPrefixList
.Flink
;
465 Entry
!= &MupPrefixList
;
466 Entry
= Entry
->Flink
)
468 Prefix
= CONTAINING_RECORD(Entry
, MUP_PFX
, PrefixListEntry
);
470 /* And remove any entry in it */
473 MupRemoveKnownPrefixEntry(Prefix
);
476 ExReleaseResourceLite(&MupPrefixTableLock
);
480 MupCleanupVcb(PDEVICE_OBJECT DeviceObject
,
484 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
486 /* Check we're not doing anything wrong first */
487 if (Vcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Vcb
->NodeType
!= NODE_TYPE_VCB
)
489 ExRaiseStatus(STATUS_INVALID_HANDLE
);
492 /* Remove share access */
493 IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp
)->FileObject
, &Vcb
->ShareAccess
);
495 ExReleaseResourceLite(&MupVcbLock
);
499 MupCleanupFcb(PDEVICE_OBJECT DeviceObject
,
506 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
507 /* Check we're not doing anything wrong first */
508 if (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
510 ExRaiseStatus(STATUS_INVALID_HANDLE
);
512 Fcb
->NodeStatus
= NODE_STATUS_CLEANUP
;
513 ExReleaseResourceLite(&MupGlobalLock
);
515 /* Dereference any CCB associated with the FCB */
516 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
517 for (Entry
= Fcb
->CcbList
.Flink
;
518 Entry
!= &Fcb
->CcbList
;
519 Entry
= Entry
->Flink
)
521 Ccb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
522 ExReleaseResourceLite(&MupCcbListLock
);
523 MupDereferenceCcb(Ccb
);
524 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
526 ExReleaseResourceLite(&MupCcbListLock
);
530 CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
532 PFORWARDED_IO_CONTEXT FwdCtxt
)
536 Status
= Irp
->IoStatus
.Status
;
538 /* Just free everything we had allocated */
539 if (Irp
->MdlAddress
!= NULL
)
541 MmUnlockPages(Irp
->MdlAddress
);
542 IoFreeMdl(Irp
->MdlAddress
);
545 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
547 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
552 /* Dereference the master context
553 * The upper IRP will be completed once all the lower IRPs are done
554 * (and thus, references count reaches 0)
556 MupDereferenceCcb(FwdCtxt
->Ccb
);
557 MupDereferenceMasterIoContext(FwdCtxt
->MasterIoContext
, &Status
);
558 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
560 return STATUS_MORE_PROCESSING_REQUIRED
;
565 DeferredForwardedIoCompletionRoutine(PVOID Context
)
567 PFORWARDED_IO_CONTEXT FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
569 CommonForwardedIoCompletionRoutine(FwdCtxt
->DeviceObject
, FwdCtxt
->Irp
, Context
);
574 ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
578 PFORWARDED_IO_CONTEXT FwdCtxt
;
580 /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
581 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
583 CommonForwardedIoCompletionRoutine(DeviceObject
, Irp
, Context
);
587 FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
589 ExInitializeWorkItem(&FwdCtxt
->WorkQueueItem
, DeferredForwardedIoCompletionRoutine
, Context
);
590 ExQueueWorkItem(&FwdCtxt
->WorkQueueItem
, CriticalWorkQueue
);
593 return STATUS_MORE_PROCESSING_REQUIRED
;
597 BuildAndSubmitIrp(PIRP Irp
,
599 PMUP_MIC MasterIoContext
)
604 PIO_STACK_LOCATION Stack
;
605 PDEVICE_OBJECT DeviceObject
;
606 PFORWARDED_IO_CONTEXT FwdCtxt
;
608 Status
= STATUS_SUCCESS
;
612 /* Allocate a context for the completion routine */
613 FwdCtxt
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FORWARDED_IO_CONTEXT
), TAG_MUP
);
616 Status
= STATUS_INSUFFICIENT_RESOURCES
;
621 FwdCtxt
->DeviceObject
= NULL
;
624 /* Allocate the IRP */
625 DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
626 LowerIrp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
627 if (LowerIrp
== NULL
)
629 Status
= STATUS_INSUFFICIENT_RESOURCES
;
634 LowerIrp
->Tail
.Overlay
.OriginalFileObject
= Ccb
->FileObject
;
635 LowerIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
636 LowerIrp
->RequestorMode
= KernelMode
;
638 /* Copy the stack of the request we received to the IRP we'll pass below */
639 Stack
= IoGetNextIrpStackLocation(LowerIrp
);
640 RtlMoveMemory(Stack
, IoGetCurrentIrpStackLocation(Irp
), sizeof(IO_STACK_LOCATION
));
641 Stack
->FileObject
= Ccb
->FileObject
;
642 /* Setup flags according to the FO */
643 if (Ccb
->FileObject
->Flags
& FO_WRITE_THROUGH
)
645 Stack
->Flags
= SL_WRITE_THROUGH
;
650 /* Does the device requires we do buffered IOs? */
651 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
653 LowerIrp
->AssociatedIrp
.SystemBuffer
= NULL
;
655 if (Stack
->Parameters
.Write
.Length
== 0)
657 LowerIrp
->Flags
= IRP_BUFFERED_IO
;
659 /* If we have data to pass */
662 /* If it's coming from usermode, probe first */
663 if (Irp
->RequestorMode
== UserMode
)
665 ProbeForRead(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, sizeof(UCHAR
));
668 /* Allocate the buffer */
669 LowerIrp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned
,
670 Stack
->Parameters
.Write
.Length
,
672 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
674 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
677 /* And copy input (remember, we've to free!) */
678 RtlMoveMemory(LowerIrp
->AssociatedIrp
.SystemBuffer
, Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
);
679 LowerIrp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
684 if (!(DeviceObject
->Flags
& DO_DIRECT_IO
))
686 LowerIrp
->UserBuffer
= Irp
->UserBuffer
;
690 /* For direct IOs, allocate an MDL and pass it */
691 if (Stack
->Parameters
.Write
.Length
!= 0)
693 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, FALSE
, TRUE
, LowerIrp
);
696 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
699 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoReadAccess
);
704 /* Fix flags in the IRP */
705 if (Ccb
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
707 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
| IRP_NOCACHE
;
711 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
;
715 FwdCtxt
->MasterIoContext
= MasterIoContext
;
717 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
718 ++MasterIoContext
->NodeReferences
;
719 ExReleaseResourceLite(&MupGlobalLock
);
721 /* Set out completion routine */
722 IoSetCompletionRoutine(LowerIrp
, ForwardedIoCompletionRoutine
, FwdCtxt
, TRUE
, TRUE
, TRUE
);
723 /* And call the device with our brand new IRP */
724 Status
= IoCallDriver(Ccb
->DeviceObject
, LowerIrp
);
726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
728 Status
= _SEH2_GetExceptionCode();
733 if (!NT_SUCCESS(Status
))
737 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
740 if (LowerIrp
!= NULL
)
742 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
744 ExFreePoolWithTag(LowerIrp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
761 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject
,
769 BOOLEAN CcbLockAcquired
;
770 PMUP_MIC MasterIoContext
;
771 PIO_STACK_LOCATION Stack
;
773 /* If DFS is enabled, check if that's for DFS and is so relay */
774 if (MupEnableDfs
&& DeviceObject
->DeviceType
== FILE_DEVICE_DFS
)
776 return DfsVolumePassThrough(DeviceObject
, Irp
);
779 Stack
= IoGetCurrentIrpStackLocation(Irp
);
781 FsRtlEnterFileSystem();
783 /* Write request is only possible for a mailslot, we need a FCB */
784 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
785 if (Fcb
== NULL
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
787 FsRtlExitFileSystem();
788 Status
= STATUS_INVALID_DEVICE_REQUEST
;
792 /* Allocate a context */
793 MasterIoContext
= MupAllocateMasterIoContext();
794 if (MasterIoContext
== NULL
)
796 FsRtlExitFileSystem();
797 Status
= STATUS_INSUFFICIENT_RESOURCES
;
801 /* Mark the IRP pending and init the context */
802 IoMarkIrpPending(Irp
);
803 MasterIoContext
->Irp
= Irp
;
804 /* Init with a failure to catch if we ever succeed */
805 MasterIoContext
->LastSuccess
= STATUS_UNSUCCESSFUL
;
806 /* Init with the worth failure possible */
807 MasterIoContext
->LastFailed
= STATUS_BAD_NETWORK_PATH
;
808 MasterIoContext
->Fcb
= Fcb
;
812 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
813 CcbLockAcquired
= TRUE
;
815 /* For all the CCB (ie, the mailslots) we have */
816 for (Entry
= Fcb
->CcbList
.Flink
;
817 Entry
!= &Fcb
->CcbList
;
818 Entry
= Entry
->Flink
)
820 FcbListCcb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
821 ExReleaseResourceLite(&MupCcbListLock
);
822 CcbLockAcquired
= FALSE
;
824 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
825 ++FcbListCcb
->NodeReferences
;
826 ExReleaseResourceLite(&MupGlobalLock
);
828 /* Forward the write request */
829 BuildAndSubmitIrp(Irp
, FcbListCcb
, MasterIoContext
);
830 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
831 CcbLockAcquired
= TRUE
;
834 ExReleaseResourceLite(&MupCcbListLock
);
835 CcbLockAcquired
= FALSE
;
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
841 ExReleaseResourceLite(&MupCcbListLock
);
847 MupDereferenceMasterIoContext(MasterIoContext
, NULL
);
848 FsRtlExitFileSystem();
850 return STATUS_PENDING
;
854 Irp
->IoStatus
.Status
= Status
;
855 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
860 AddUnregisteredProvider(PCWSTR DeviceName
,
863 PMUP_UNC UncProvider
;
864 ULONG StrLen
, NameLen
;
866 /* Just allocate the node */
867 NameLen
= wcslen(DeviceName
);
868 StrLen
= NameLen
* sizeof(WCHAR
);
869 UncProvider
= MupAllocateUncProvider(StrLen
);
870 if (UncProvider
== NULL
)
876 UncProvider
->DeviceName
.MaximumLength
= StrLen
;
877 UncProvider
->DeviceName
.Length
= StrLen
;
878 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
879 UncProvider
->ProviderOrder
= ProviderOrder
;
880 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, DeviceName
, StrLen
);
882 /* And add it to the global list
883 * We're using tail here so that when called from registry init,
884 * the providers with highest priority will be in the head of
887 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
888 InsertTailList(&MupProviderList
, &UncProvider
->ProviderListEntry
);
889 ExReleaseResourceLite(&MupGlobalLock
);
895 InitializeProvider(PCWSTR ProviderName
,
900 UNICODE_STRING Key
, Value
;
901 PKEY_VALUE_FULL_INFORMATION Info
;
902 OBJECT_ATTRIBUTES ObjectAttributes
;
903 ULONG NameLen
, StrLen
, ResultLength
;
905 /* Get the information about the provider from registry */
906 NameLen
= wcslen(ProviderName
);
907 StrLen
= NameLen
* sizeof(WCHAR
) + sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L
"\\NetworkProvider");
908 Key
.Buffer
= ExAllocatePoolWithTag(PagedPool
, StrLen
, TAG_MUP
);
909 if (Key
.Buffer
== NULL
)
914 RtlMoveMemory(Key
.Buffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
915 Key
.MaximumLength
= StrLen
;
916 Key
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL
);
917 RtlAppendUnicodeToString(&Key
, ProviderName
);
918 RtlAppendUnicodeToString(&Key
, L
"\\NetworkProvider");
920 InitializeObjectAttributes(&ObjectAttributes
,
922 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
925 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
926 ExFreePoolWithTag(Key
.Buffer
, TAG_MUP
);
927 if (!NT_SUCCESS(Status
))
932 RtlInitUnicodeString(&Value
, L
"DeviceName");
933 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
934 if (Status
== STATUS_BUFFER_TOO_SMALL
)
936 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
943 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
952 /* And create the provider
953 * It will remain unregistered until FsRTL receives a registration request and forwards
956 if (NT_SUCCESS(Status
))
958 ASSERT(Info
!= NULL
);
959 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
964 ExFreePoolWithTag(Info
, TAG_MUP
);
969 MupGetProviderInformation(VOID
)
974 PWSTR Providers
, Coma
;
975 PKEY_VALUE_FULL_INFORMATION Info
;
976 ULONG ResultLength
, ProviderCount
;
977 OBJECT_ATTRIBUTES ObjectAttributes
;
978 UNICODE_STRING NetworkProvider
, ProviderOrder
;
980 /* Open the registry to get the order of the providers */
981 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
982 InitializeObjectAttributes(&ObjectAttributes
,
984 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
987 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
988 if (!NT_SUCCESS(Status
))
993 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
994 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
995 if (Status
== STATUS_BUFFER_TOO_SMALL
)
997 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1004 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1013 if (NT_SUCCESS(Status
))
1015 ASSERT(Info
!= NULL
);
1017 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1021 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1022 * The order is just the order of the list
1023 * First has highest priority (0) and then, get lower and lower priority
1024 * The highest number is the lowest priority
1028 Coma
= wcschr(Providers
, L
',');
1031 *Coma
= UNICODE_NULL
;
1038 InitializeProvider(Providers
, ProviderCount
);
1041 Providers
= Coma
+ 1;
1047 ExFreePoolWithTag(Info
, TAG_MUP
);
1052 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1055 PMUP_UNC UncProvider
;
1057 /* Browse the list of all the providers nodes we have */
1058 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1059 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1061 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1063 /* If one matches the device and is not registered, that's ours! */
1064 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1066 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1071 if (Entry
== &MupProviderList
)
1075 ExReleaseResourceLite(&MupGlobalLock
);
1081 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1090 PIO_STACK_LOCATION Stack
;
1091 IO_STATUS_BLOCK IoStatusBlock
;
1092 PMUP_UNC UncProvider
, ListEntry
;
1093 OBJECT_ATTRIBUTES ObjectAttributes
;
1094 UNICODE_STRING RedirectorDeviceName
;
1095 OBJECT_HANDLE_INFORMATION HandleInfo
;
1096 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1098 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1101 /* Check whether providers order was already initialized */
1102 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1103 if (MupOrderInitialized
)
1105 ExReleaseResourceLite(&MupGlobalLock
);
1109 /* They weren't, so do it */
1110 MupOrderInitialized
= TRUE
;
1111 ExReleaseResourceLite(&MupGlobalLock
);
1112 MupGetProviderInformation();
1115 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1117 /* This can only happen with a volume open */
1118 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1120 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1121 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1123 return STATUS_INVALID_HANDLE
;
1126 /* Get the registration information */
1127 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1130 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1131 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1132 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1134 /* Have we got already a node for it? (Like from previous init) */
1135 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1136 if (UncProvider
== NULL
)
1138 /* If we don't, allocate a new one */
1140 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1141 if (UncProvider
== NULL
)
1143 Status
= STATUS_INVALID_USER_BUFFER
;
1148 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1149 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1150 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1152 /* As it wasn't in registry for order, give the lowest priority possible */
1153 UncProvider
->ProviderOrder
= MAXLONG
;
1154 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1157 /* Continue registration */
1158 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1159 ++UncProvider
->NodeReferences
;
1161 /* Open a handle to the device */
1162 InitializeObjectAttributes(&ObjectAttributes
,
1163 &UncProvider
->DeviceName
,
1164 OBJ_CASE_INSENSITIVE
,
1167 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1171 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1172 FILE_DIRECTORY_FILE
);
1173 if (NT_SUCCESS(Status
))
1175 Status
= IoStatusBlock
.Status
;
1178 /* And return the provider (as CCB) */
1179 if (NT_SUCCESS(Status
))
1181 Stack
->FileObject
->FsContext2
= UncProvider
;
1182 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1183 if (!NT_SUCCESS(Status
))
1185 NtClose(UncProvider
->DeviceHandle
);
1189 if (!NT_SUCCESS(Status
))
1191 MupDereferenceUncProvider(UncProvider
);
1195 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1197 /* Now, insert the provider in our global list
1198 * They are sorted by order
1200 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1204 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1206 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1208 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1214 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1216 UncProvider
->Registered
= TRUE
;
1217 ExReleaseResourceLite(&MupGlobalLock
);
1218 Status
= STATUS_SUCCESS
;
1220 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1225 if (_SEH2_AbnormalTermination())
1227 Status
= STATUS_INVALID_USER_BUFFER
;
1230 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1232 Irp
->IoStatus
.Status
= Status
;
1233 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1242 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1246 PIO_STACK_LOCATION Stack
;
1248 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1252 /* MUP only understands a single FSCTL code: registering UNC provider */
1253 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1255 /* It obviously has to come from a driver/kernelmode thread */
1256 if (Irp
->RequestorMode
== UserMode
)
1258 Status
= STATUS_ACCESS_DENIED
;
1260 Irp
->IoStatus
.Status
= Status
;
1261 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1266 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1270 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1273 Status
= STATUS_INVALID_PARAMETER
;
1275 Irp
->IoStatus
.Status
= Status
;
1276 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1281 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1286 Status
= _SEH2_GetExceptionCode();
1294 MupSetFileObject(PFILE_OBJECT FileObject
,
1298 FileObject
->FsContext
= Fcb
;
1299 FileObject
->FsContext2
= Ccb
;
1303 MupRerouteOpen(PFILE_OBJECT FileObject
,
1304 PMUP_UNC UncProvider
)
1309 DPRINT("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1311 /* Get the full path name (device name first, and requested file name appended) */
1312 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1313 if (TotalLength
> MAXUSHORT
)
1315 return STATUS_NAME_TOO_LONG
;
1318 /* Allocate a buffer big enough */
1319 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1320 if (FullPath
== NULL
)
1322 return STATUS_INSUFFICIENT_RESOURCES
;
1325 /* Create the full path */
1326 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1327 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1329 /* And redo the path in the file object */
1330 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1331 FileObject
->FileName
.Buffer
= FullPath
;
1332 FileObject
->FileName
.MaximumLength
= TotalLength
;
1333 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1335 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1336 return STATUS_REPARSE
;
1340 BroadcastOpen(PIRP Irp
)
1345 PMUP_CCB Ccb
= NULL
;
1346 PMUP_UNC UncProvider
;
1347 UNICODE_STRING FullPath
;
1348 PFILE_OBJECT FileObject
;
1349 PIO_STACK_LOCATION Stack
;
1350 NTSTATUS Status
, LastFailed
;
1351 ULONG TotalLength
, LastOrder
;
1352 IO_STATUS_BLOCK IoStatusBlock
;
1353 OBJECT_ATTRIBUTES ObjectAttributes
;
1354 OBJECT_HANDLE_INFORMATION HandleInfo
;
1355 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1357 Fcb
= MupCreateFcb();
1360 return STATUS_INSUFFICIENT_RESOURCES
;
1363 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1364 FileObject
= Stack
->FileObject
;
1367 CcbInitialized
= FALSE
;
1368 LastFailed
= STATUS_NO_SUCH_FILE
;
1369 LastOrder
= (ULONG
)-1;
1373 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1376 /* Associate our FCB with the FO */
1377 MupSetFileObject(FileObject
, Fcb
, NULL
);
1378 Fcb
->FileObject
= FileObject
;
1380 /* Now, broadcast the open to any UNC provider that supports mailslots */
1381 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1383 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1384 ++UncProvider
->NodeReferences
;
1387 ExReleaseResourceLite(&MupGlobalLock
);
1390 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1391 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1393 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1394 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1395 if (FullPath
.Buffer
== NULL
)
1397 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1400 FullPath
.Length
= TotalLength
;
1401 FullPath
.MaximumLength
= TotalLength
;
1402 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1403 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1404 FileObject
->FileName
.Buffer
,
1405 FileObject
->FileName
.Length
);
1407 /* And just forward the creation request */
1408 InitializeObjectAttributes(&ObjectAttributes
,
1410 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1413 Status
= IoCreateFile(&Handle
,
1414 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1418 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1419 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1421 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1426 IO_NO_PARAMETER_CHECKING
);
1428 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1430 /* If opening succeed */
1431 if (NT_SUCCESS(Status
))
1433 Status
= IoStatusBlock
.Status
;
1436 Ccb
= MupCreateCcb();
1439 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1442 /* And associated a FO to it */
1443 if (NT_SUCCESS(Status
))
1445 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1450 /* If we failed, remember the last failed status of the higher priority provider */
1451 if (!NT_SUCCESS(Status
))
1453 if (UncProvider
->ProviderOrder
<= LastOrder
)
1455 LastOrder
= UncProvider
->ProviderOrder
;
1456 LastFailed
= Status
;
1459 /* Otherwise, properly attach our CCB to the mailslot */
1462 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1465 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1467 ++Fcb
->NodeReferences
;
1468 ExReleaseResourceLite(&MupGlobalLock
);
1470 CcbInitialized
= TRUE
;
1472 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1476 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1478 MupDereferenceUncProvider(UncProvider
);
1482 ExReleaseResourceLite(&MupGlobalLock
);
1485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1487 Status
= _SEH2_GetExceptionCode();
1491 /* If we at least opened one mailslot, return success */
1492 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1496 MupDereferenceUncProvider(UncProvider
);
1501 ExReleaseResourceLite(&MupGlobalLock
);
1504 /* In case of failure, don't leak CCB */
1505 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1514 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1516 ULONG MajorFunction
,
1519 ULONG InputBufferSize
,
1521 ULONG OutputBufferSize
,
1522 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1525 PIO_STACK_LOCATION Stack
;
1526 PDEVICE_OBJECT DeviceObject
;
1528 if (InputBuffer
== NULL
)
1533 /* Get the device object */
1534 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1535 /* Allocate the IRP (with one more location for us */
1536 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1542 /* Skip our location */
1543 IoSetNextIrpStackLocation(Irp
);
1545 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1546 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1547 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1549 /* Setup the stack */
1550 Stack
= IoGetNextIrpStackLocation(Irp
);
1551 Stack
->MajorFunction
= MajorFunction
;
1552 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1553 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1554 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1555 Stack
->MinorFunction
= 0;
1556 Stack
->FileObject
= FileObject
;
1557 Stack
->DeviceObject
= DeviceObject
;
1559 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1561 case METHOD_BUFFERED
:
1562 /* If it's buffered, just pass the buffers we got */
1563 Irp
->MdlAddress
= NULL
;
1564 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1565 Irp
->UserBuffer
= OutputBuffer
;
1566 Irp
->Flags
= IRP_BUFFERED_IO
;
1568 if (OutputBuffer
!= NULL
)
1570 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1574 case METHOD_IN_DIRECT
:
1575 case METHOD_OUT_DIRECT
:
1576 /* Otherwise, allocate an MDL */
1577 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1583 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1584 Irp
->Flags
= IRP_BUFFERED_IO
;
1585 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1588 case METHOD_NEITHER
:
1589 /* Or pass the buffers */
1590 Irp
->UserBuffer
= OutputBuffer
;
1591 Irp
->MdlAddress
= NULL
;
1592 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1593 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1601 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1603 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1604 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1608 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1612 BOOLEAN KeepExtraRef
;
1614 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1615 --MasterQueryContext
->NodeReferences
;
1616 References
= MasterQueryContext
->NodeReferences
;
1617 ExReleaseResourceLite(&MupGlobalLock
);
1619 if (References
!= 0)
1621 DPRINT("Still having refs (%ld)\n", References
);
1622 return STATUS_PENDING
;
1625 /* We HAVE an IRP to complete. It cannot be NULL
1626 * Please, help preserving kittens, don't provide NULL IRPs.
1628 if (MasterQueryContext
->Irp
== NULL
)
1630 KeBugCheck(FILE_SYSTEM
);
1633 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1634 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1635 ExReleaseResourceLite(&MupGlobalLock
);
1637 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1638 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1639 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1641 /* We found a provider? */
1642 if (MasterQueryContext
->LatestProvider
!= NULL
)
1644 /* With a successful status? */
1645 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1647 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1650 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1653 ExReleaseResourceLite(&MupPrefixTableLock
);
1654 /* Reroute & complete :-) */
1655 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1660 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1664 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1665 ExReleaseResourceLite(&MupPrefixTableLock
);
1667 /* Return the highest failed status we had */
1668 Status
= MasterQueryContext
->LatestStatus
;
1671 /* In finally, complete the IRP for real! */
1672 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1673 IoCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1675 MasterQueryContext
->Irp
= NULL
;
1676 MupFreeMasterQueryContext(MasterQueryContext
);
1683 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1688 ULONG LatestPos
, Pos
;
1689 PWSTR AcceptedPrefix
;
1690 PMUP_MQC MasterQueryContext
;
1691 NTSTATUS Status
, TableStatus
;
1692 PQUERY_PATH_CONTEXT QueryContext
;
1693 PQUERY_PATH_RESPONSE QueryResponse
;
1695 /* Get all the data from our query to the provider */
1696 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1697 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1698 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1699 Status
= Irp
->IoStatus
.Status
;
1701 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1703 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1704 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1706 /* If the driver returned a success, and an acceptance length */
1707 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1709 Prefix
= MasterQueryContext
->Prefix
;
1711 /* Check if we already found a provider from a previous iteration */
1712 if (MasterQueryContext
->LatestProvider
!= NULL
)
1714 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1715 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1717 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1721 /* Otherwise, if the prefix was in the prefix table, just drop it:
1722 * we have a provider which supersedes the accepted prefix, so leave
1723 * room for the new prefix/provider
1725 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1726 if (Prefix
->InTable
)
1728 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1729 RemoveEntryList(&Prefix
->PrefixListEntry
);
1730 Prefix
->InTable
= FALSE
;
1732 ExReleaseResourceLite(&MupPrefixTableLock
);
1734 Prefix
->KeepExtraRef
= FALSE
;
1736 /* Release data associated with the current prefix, if any
1737 * We'll renew them with the new accepted prefix
1739 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1741 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1742 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1743 Prefix
->AcceptedPrefix
.Length
= 0;
1744 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1745 Prefix
->ExternalAlloc
= FALSE
;
1748 /* If there was also a provider, drop it, the new one
1751 if (Prefix
->UncProvider
!= NULL
)
1753 MupDereferenceUncProvider(Prefix
->UncProvider
);
1754 Prefix
->UncProvider
= NULL
;
1758 /* Now, set our information about the provider that accepted the prefix */
1759 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1760 MasterQueryContext
->LatestStatus
= Status
;
1762 if (MasterQueryContext
->FileObject
->FsContext2
!= (PVOID
)DFS_DOWNLEVEL_OPEN_CONTEXT
)
1764 /* Allocate a buffer for the prefix */
1765 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1766 if (AcceptedPrefix
== NULL
)
1768 Prefix
->InTable
= FALSE
;
1772 /* Set it up to the accepted length */
1773 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1774 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1775 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1776 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1777 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1778 Prefix
->ExternalAlloc
= TRUE
;
1780 /* Insert the accepted prefix in the table of known prefixes */
1781 DPRINT("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1782 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1783 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1785 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1786 Prefix
->InTable
= TRUE
;
1787 Prefix
->KeepExtraRef
= TRUE
;
1791 Prefix
->InTable
= FALSE
;
1793 ExReleaseResourceLite(&MupPrefixTableLock
);
1799 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1801 /* We failed and didn't find any provider over the latest iterations */
1802 if (MasterQueryContext
->LatestProvider
== NULL
)
1804 /* If we had a success though (broken provider?) set our failed status */
1805 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1807 MasterQueryContext
->LatestStatus
= Status
;
1811 TableStatus
= MupOrderedErrorList
[0];
1814 /* Otherwise, time to compare statuses, between the latest failed
1815 * and the current failure.
1816 * We have an order table of failed status: the deeper you go in the
1817 * table, the more the error is critical.
1818 * Our goal is to return the most critical status that was returned by
1819 * any of the providers
1822 /* Look for latest status position */
1823 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1826 TableStatus
= MupOrderedErrorList
[LatestPos
];
1829 /* If at pos 0, the new status is likely more critical */
1832 MasterQueryContext
->LatestStatus
= Status
;
1836 /* Otherwise, find position of the new status in the table */
1840 if (Status
== MupOrderedErrorList
[Pos
])
1847 while (Pos
< LatestPos
);
1849 /* If it has a higher position (more critical), return it */
1850 if (Pos
>= LatestPos
)
1852 MasterQueryContext
->LatestStatus
= Status
;
1860 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1861 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1864 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1865 MupDereferenceMasterQueryContext(MasterQueryContext
);
1867 return STATUS_MORE_PROCESSING_REQUIRED
;
1871 CreateRedirectedFile(PIRP Irp
,
1872 PFILE_OBJECT FileObject
,
1873 PIO_SECURITY_CONTEXT SecurityContext
)
1882 PMUP_UNC UncProvider
;
1883 PIO_STACK_LOCATION Stack
;
1884 LARGE_INTEGER CurrentTime
;
1885 PMUP_MQC MasterQueryContext
;
1886 PQUERY_PATH_CONTEXT QueryContext
;
1887 PQUERY_PATH_REQUEST QueryPathRequest
;
1888 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1889 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1891 /* We cannot open a file without a name */
1892 if (FileObject
->FileName
.Length
== 0)
1894 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1895 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1897 return STATUS_INVALID_DEVICE_REQUEST
;
1900 DPRINT("Request for opening: %wZ\n", &FileObject
->FileName
);
1903 BreakOnFirst
= TRUE
;
1904 Status
= STATUS_BAD_NETWORK_PATH
;
1906 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1907 /* First, try to see if that's a prefix we already know */
1908 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1909 if (TableEntry
!= NULL
)
1911 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1913 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1915 /* If so, check whether the prefix is still valid */
1916 KeQuerySystemTime(&CurrentTime
);
1917 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1919 /* It is: so, update its validity period and reroute file opening */
1920 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1921 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1922 ExReleaseResourceLite(&MupPrefixTableLock
);
1924 if (Status
== STATUS_REPARSE
)
1926 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1929 Irp
->IoStatus
.Status
= Status
;
1930 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1935 /* When here, we found a matching prefix, but expired, remove it from the table
1936 * We'll redo a full search
1938 if (Prefix
->InTable
)
1940 MupRemoveKnownPrefixEntry(Prefix
);
1943 ExReleaseResourceLite(&MupPrefixTableLock
);
1945 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1946 /* First of all, start looking for a mailslot */
1947 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
1949 Name
= &FileObject
->FileName
.Buffer
[1];
1950 Len
= FileObject
->FileName
.Length
;
1952 /* Skip the remote destination name */
1955 Len
-= sizeof(WCHAR
);
1963 } while (Cur
!= L
'\\');
1964 Len
-= sizeof(WCHAR
);
1966 /* If we still have room for "Mailslot" to fit */
1967 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
1969 /* Get the len in terms of chars count */
1970 Len
/= sizeof(WCHAR
);
1971 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
1973 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
1976 /* It's indeed a mailslot opening! */
1977 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
1979 /* Broadcast open */
1980 Status
= BroadcastOpen(Irp
);
1981 if (Status
== STATUS_REPARSE
)
1983 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1986 Irp
->IoStatus
.Status
= Status
;
1987 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1994 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
1995 if (!MupEnableDfs
|| FileObject
->FsContext2
== (PVOID
)DFS_DOWNLEVEL_OPEN_CONTEXT
)
1997 /* We won't complete immediately */
1998 IoMarkIrpPending(Irp
);
2000 /* Allocate a new prefix for our search */
2001 Prefix
= MupAllocatePrefixEntry(0);
2004 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2005 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2007 return STATUS_PENDING
;
2010 /* Allocate a context for our search */
2011 MasterQueryContext
= MupAllocateMasterQueryContext();
2012 if (MasterQueryContext
== NULL
)
2014 MupFreeNode(Prefix
);
2016 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2017 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2019 return STATUS_PENDING
;
2022 MasterQueryContext
->Irp
= Irp
;
2023 MasterQueryContext
->FileObject
= FileObject
;
2024 MasterQueryContext
->LatestProvider
= NULL
;
2025 MasterQueryContext
->Prefix
= Prefix
;
2026 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2027 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2028 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2029 ++Prefix
->NodeReferences
;
2030 ExReleaseResourceLite(&MupGlobalLock
);
2034 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2037 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2038 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2040 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2042 ++UncProvider
->NodeReferences
;
2045 ExReleaseResourceLite(&MupGlobalLock
);
2048 /* We will obviously only query registered providers */
2049 if (UncProvider
->Registered
)
2051 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2052 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2053 if (QueryPathRequest
== NULL
)
2055 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2058 /* Allocate a context for IRP completion routine
2059 * In case a prefix matches the path, the reroute will happen
2060 * in the completion routine, when we have return from the provider
2062 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2063 if (QueryContext
== NULL
)
2065 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2066 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2069 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2070 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2071 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2072 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2073 QueryPathRequest
->SecurityContext
= SecurityContext
;
2074 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2076 /* Build our IRP for the query */
2077 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2079 IRP_MJ_DEVICE_CONTROL
,
2080 IOCTL_REDIR_QUERY_PATH
,
2082 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2084 sizeof(QUERY_PATH_RESPONSE
),
2085 QueryPathCompletionRoutine
);
2086 if (QueryIrp
== NULL
)
2088 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2089 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2090 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2093 QueryIrp
->RequestorMode
= KernelMode
;
2094 QueryContext
->UncProvider
= UncProvider
;
2095 QueryContext
->Irp
= QueryIrp
;
2097 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2098 ++UncProvider
->NodeReferences
;
2099 ++MasterQueryContext
->NodeReferences
;
2100 ExReleaseResourceLite(&MupGlobalLock
);
2102 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2103 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2104 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2106 /* Query the provider !*/
2107 DPRINT("Requesting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2108 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2109 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2112 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2115 /* We're done with that provider */
2116 MupDereferenceUncProvider(UncProvider
);
2119 /* If query went fine on the first request, just break and leave */
2120 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2125 BreakOnFirst
= FALSE
;
2130 if (_SEH2_AbnormalTermination())
2132 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2137 MupDereferenceUncProvider(UncProvider
);
2142 ExReleaseResourceLite(&MupGlobalLock
);
2145 MupDereferenceMasterQueryContext(MasterQueryContext
);
2147 Status
= STATUS_PENDING
;
2154 Status
= STATUS_NOT_IMPLEMENTED
;
2161 OpenMupFileSystem(PMUP_VCB Vcb
,
2162 PFILE_OBJECT FileObject
,
2163 ACCESS_MASK DesiredAccess
,
2168 DPRINT1("Opening MUP\n");
2170 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2173 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2174 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2175 if (NT_SUCCESS(Status
))
2177 ++Vcb
->NodeReferences
;
2178 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2179 Status
= STATUS_SUCCESS
;
2184 ExReleaseResourceLite(&MupVcbLock
);
2193 MupCreate(PDEVICE_OBJECT DeviceObject
,
2197 PIO_STACK_LOCATION Stack
;
2198 PFILE_OBJECT FileObject
, RelatedFileObject
;
2200 FsRtlEnterFileSystem();
2204 /* If DFS is enabled, check if that's for DFS and is so relay */
2205 if (MupEnableDfs
&& (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
))
2207 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2211 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2212 FileObject
= Stack
->FileObject
;
2213 RelatedFileObject
= FileObject
->RelatedFileObject
;
2215 /* 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 */
2216 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2218 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2220 /* Otherwise, it's just a volume open */
2223 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2225 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2226 Stack
->Parameters
.Create
.ShareAccess
);
2228 Irp
->IoStatus
.Information
= FILE_OPENED
;
2229 Irp
->IoStatus
.Status
= Status
;
2230 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2236 Status
= _SEH2_GetExceptionCode();
2238 Irp
->IoStatus
.Status
= Status
;
2239 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2243 FsRtlExitFileSystem();
2249 MupCloseUncProvider(PMUP_UNC UncProvider
)
2251 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2253 /* If the node was still valid, reregister the UNC provider */
2254 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2256 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2257 UncProvider
->Registered
= FALSE
;
2258 ExReleaseResourceLite(&MupGlobalLock
);
2260 if (UncProvider
->FileObject
!= NULL
)
2262 ZwClose(UncProvider
->DeviceHandle
);
2263 ObDereferenceObject(UncProvider
->FileObject
);
2268 ExReleaseResourceLite(&MupGlobalLock
);
2274 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2281 PIO_STACK_LOCATION Stack
;
2283 /* If DFS is enabled, check if that's for DFS and is so relay */
2286 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2288 return DfsFsdCleanup(DeviceObject
, Irp
);
2292 FsRtlEnterFileSystem();
2296 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2297 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2301 /* If we got a VCB, clean it up */
2302 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2304 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2305 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2307 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2309 /* If Ccb is not null, then, it's a UNC provider node */
2312 /* Close it, and dereference */
2313 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2314 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2315 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2317 ExReleaseResourceLite(&MupGlobalLock
);
2320 Status
= STATUS_SUCCESS
;
2324 /* If the node wasn't already cleaned, do it */
2325 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2327 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2328 Status
= STATUS_SUCCESS
;
2332 Status
= STATUS_INVALID_HANDLE
;
2335 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2336 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2338 MupDereferenceFcb(Fcb
);
2342 Status
= STATUS_INVALID_HANDLE
;
2344 Irp
->IoStatus
.Status
= Status
;
2345 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2352 Status
= _SEH2_GetExceptionCode();
2356 FsRtlExitFileSystem();
2362 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2365 PFILE_OBJECT FileObject
)
2367 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2369 /* Remove FCB, UNC from FO */
2370 MupSetFileObject(FileObject
, NULL
, NULL
);
2371 MupDereferenceVcb(Vcb
);
2373 ExReleaseResourceLite(&MupGlobalLock
);
2375 return STATUS_SUCCESS
;
2379 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2382 PFILE_OBJECT FileObject
)
2384 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2386 /* Remove FCB, CCB from FO */
2387 MupSetFileObject(FileObject
, NULL
, NULL
);
2388 MupDereferenceFcb(Fcb
);
2390 ExReleaseResourceLite(&MupGlobalLock
);
2392 return STATUS_SUCCESS
;
2397 MupClose(PDEVICE_OBJECT DeviceObject
,
2403 PIO_STACK_LOCATION Stack
;
2405 /* If DFS is enabled, check if that's for DFS and is so relay */
2408 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2410 return DfsFsdClose(DeviceObject
, Irp
);
2414 FsRtlEnterFileSystem();
2418 /* Get our internal structures from FO */
2419 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2420 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2423 Status
= STATUS_INVALID_HANDLE
;
2425 Irp
->IoStatus
.Status
= Status
;
2426 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2431 /* If we got the VCB, that's a volume close */
2432 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2434 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2436 /* Otherwise close the FCB */
2437 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2439 MupDereferenceFcb(Fcb
);
2440 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2444 Status
= STATUS_INVALID_HANDLE
;
2446 Irp
->IoStatus
.Status
= Status
;
2447 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2452 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2453 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2455 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2457 Status
= _SEH2_GetExceptionCode();
2461 FsRtlExitFileSystem();
2468 MupUnload(PDRIVER_OBJECT DriverObject
)
2470 IoDeleteDevice(mupDeviceObject
);
2474 DfsUnload(DriverObject
);
2477 MupUninitializeData();
2481 * FUNCTION: Called by the system to initialize the driver
2483 * DriverObject = object describing this driver
2484 * RegistryPath = path to our configuration entries
2485 * RETURNS: Success or failure
2490 DriverEntry(PDRIVER_OBJECT DriverObject
,
2491 PUNICODE_STRING RegistryPath
)
2494 UNICODE_STRING MupString
;
2495 PDEVICE_OBJECT DeviceObject
;
2497 /* Only initialize global state of the driver
2498 * Other inits will happen when required
2500 MupInitializeData();
2502 /* Check if DFS is disabled */
2503 MupEnableDfs
= MuppIsDfsEnabled();
2504 /* If it's not disabled but when cannot init, disable it */
2505 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2507 MupEnableDfs
= FALSE
;
2510 /* Create the MUP device */
2511 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2512 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2513 if (!NT_SUCCESS(Status
))
2517 DfsUnload(DriverObject
);
2520 MupUninitializeData();
2526 DriverObject
->DriverUnload
= MupUnload
;
2527 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2528 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2529 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2530 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2531 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2532 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2533 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2535 /* And finish init */
2536 mupDeviceObject
= DeviceObject
;
2537 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2539 return STATUS_SUCCESS
;