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 ****************************************************************/
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 explicitely 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
)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 DfsVolumePassThrough(PDEVICE_OBJECT DeviceObject
,
764 return STATUS_NOT_IMPLEMENTED
;
769 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject
,
777 BOOLEAN CcbLockAcquired
;
778 PMUP_MIC MasterIoContext
;
779 PIO_STACK_LOCATION Stack
;
781 /* If DFS is enabled, check if that's for DFS and is so relay */
782 if (MupEnableDfs
&& DeviceObject
->DeviceType
== FILE_DEVICE_DFS
)
784 return DfsVolumePassThrough(DeviceObject
, Irp
);
787 Stack
= IoGetCurrentIrpStackLocation(Irp
);
789 FsRtlEnterFileSystem();
791 /* Write request is only possible for a mailslot, we need a FCB */
792 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
793 if (Fcb
== NULL
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
795 FsRtlExitFileSystem();
796 Status
= STATUS_INVALID_DEVICE_REQUEST
;
800 /* Allocate a context */
801 MasterIoContext
= MupAllocateMasterIoContext();
802 if (MasterIoContext
== NULL
)
804 FsRtlExitFileSystem();
805 Status
= STATUS_INSUFFICIENT_RESOURCES
;
809 /* Mark the IRP pending and init the context */
810 IoMarkIrpPending(Irp
);
811 MasterIoContext
->Irp
= Irp
;
812 /* Init with a failure to catch if we ever succeed */
813 MasterIoContext
->LastSuccess
= STATUS_UNSUCCESSFUL
;
814 /* Init with the worth failure possible */
815 MasterIoContext
->LastFailed
= STATUS_BAD_NETWORK_PATH
;
816 MasterIoContext
->Fcb
= Fcb
;
820 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
821 CcbLockAcquired
= TRUE
;
823 /* For all the CCB (ie, the mailslots) we have */
824 for (Entry
= Fcb
->CcbList
.Flink
;
825 Entry
!= &Fcb
->CcbList
;
826 Entry
= Entry
->Flink
)
828 FcbListCcb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
829 ExReleaseResourceLite(&MupCcbListLock
);
830 CcbLockAcquired
= FALSE
;
832 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
833 ++FcbListCcb
->NodeReferences
;
834 ExReleaseResourceLite(&MupGlobalLock
);
836 /* Forward the write request */
837 BuildAndSubmitIrp(Irp
, FcbListCcb
, MasterIoContext
);
838 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
839 CcbLockAcquired
= TRUE
;
842 ExReleaseResourceLite(&MupCcbListLock
);
843 CcbLockAcquired
= FALSE
;
845 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
849 ExReleaseResourceLite(&MupCcbListLock
);
855 MupDereferenceMasterIoContext(MasterIoContext
, NULL
);
856 FsRtlExitFileSystem();
858 return STATUS_PENDING
;
862 Irp
->IoStatus
.Status
= Status
;
863 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
868 AddUnregisteredProvider(PCWSTR DeviceName
,
871 PMUP_UNC UncProvider
;
872 ULONG StrLen
, NameLen
;
874 /* Just allocate the node */
875 NameLen
= wcslen(DeviceName
);
876 StrLen
= NameLen
* sizeof(WCHAR
);
877 UncProvider
= MupAllocateUncProvider(StrLen
);
878 if (UncProvider
== NULL
)
884 UncProvider
->DeviceName
.MaximumLength
= StrLen
;
885 UncProvider
->DeviceName
.Length
= StrLen
;
886 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
887 UncProvider
->ProviderOrder
= ProviderOrder
;
888 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, DeviceName
, StrLen
);
890 /* And add it to the global list
891 * We're using tail here so that when called from registry init,
892 * the providers with highest priority will be in the head of
895 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
896 InsertTailList(&MupProviderList
, &UncProvider
->ProviderListEntry
);
897 ExReleaseResourceLite(&MupGlobalLock
);
903 InitializeProvider(PCWSTR ProviderName
,
908 UNICODE_STRING Key
, Value
;
909 PKEY_VALUE_FULL_INFORMATION Info
;
910 OBJECT_ATTRIBUTES ObjectAttributes
;
911 ULONG NameLen
, StrLen
, ResultLength
;
913 /* Get the information about the provider from registry */
914 NameLen
= wcslen(ProviderName
);
915 StrLen
= NameLen
* sizeof(WCHAR
) + sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L
"\\NetworkProvider");
916 Key
.Buffer
= ExAllocatePoolWithTag(PagedPool
, StrLen
, TAG_MUP
);
917 if (Key
.Buffer
== NULL
)
922 RtlMoveMemory(Key
.Buffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
923 Key
.MaximumLength
= StrLen
;
924 Key
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL
);
925 RtlAppendUnicodeToString(&Key
, ProviderName
);
926 RtlAppendUnicodeToString(&Key
, L
"\\NetworkProvider");
928 InitializeObjectAttributes(&ObjectAttributes
,
930 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
933 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
934 ExFreePoolWithTag(Key
.Buffer
, TAG_MUP
);
935 if (!NT_SUCCESS(Status
))
940 RtlInitUnicodeString(&Value
, L
"DeviceName");
941 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
942 if (Status
== STATUS_BUFFER_TOO_SMALL
)
944 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
951 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
956 /* And create the provider
957 * It will remain unregistered until FsRTL receives a registration request and forwards
960 if (NT_SUCCESS(Status
))
962 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
967 ExFreePoolWithTag(Info
, TAG_MUP
);
972 MupGetProviderInformation(VOID
)
977 PWSTR Providers
, Coma
;
978 PKEY_VALUE_FULL_INFORMATION Info
;
979 ULONG ResultLength
, ProviderCount
;
980 OBJECT_ATTRIBUTES ObjectAttributes
;
981 UNICODE_STRING NetworkProvider
, ProviderOrder
;
983 /* Open the registry to get the order of the providers */
984 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
985 InitializeObjectAttributes(&ObjectAttributes
,
987 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
990 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
991 if (!NT_SUCCESS(Status
))
996 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
997 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
998 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1000 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1007 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1012 if (NT_SUCCESS(Status
))
1014 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1018 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1019 * The order is just the order of the list
1020 * First has highest priority (0) and then, get lower and lower priority
1021 * The highest number is the lowest priority
1025 Coma
= wcschr(Providers
, L
',');
1028 *Coma
= UNICODE_NULL
;
1035 InitializeProvider(Providers
, ProviderCount
);
1038 Providers
= Coma
+ 1;
1044 ExFreePoolWithTag(Info
, TAG_MUP
);
1049 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1052 PMUP_UNC UncProvider
;
1054 /* Browse the list of all the providers nodes we have */
1055 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1056 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1058 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1060 /* If one matches the device and is not registered, that's ours! */
1061 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1063 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1068 if (Entry
== &MupProviderList
)
1072 ExReleaseResourceLite(&MupGlobalLock
);
1078 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1087 PIO_STACK_LOCATION Stack
;
1088 IO_STATUS_BLOCK IoStatusBlock
;
1089 PMUP_UNC UncProvider
, ListEntry
;
1090 OBJECT_ATTRIBUTES ObjectAttributes
;
1091 UNICODE_STRING RedirectorDeviceName
;
1092 OBJECT_HANDLE_INFORMATION HandleInfo
;
1093 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1095 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1098 /* Check whether providers order was already initialized */
1099 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1100 if (MupOrderInitialized
)
1102 ExReleaseResourceLite(&MupGlobalLock
);
1106 /* They weren't, so do it */
1107 MupOrderInitialized
= TRUE
;
1108 ExReleaseResourceLite(&MupGlobalLock
);
1109 MupGetProviderInformation();
1112 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1114 /* This can only happen with a volume open */
1115 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1117 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1118 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1120 return STATUS_INVALID_HANDLE
;
1123 /* Get the registration information */
1124 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1127 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1128 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1129 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1131 /* Have we got already a node for it? (Like from previous init) */
1132 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1133 if (UncProvider
== NULL
)
1135 /* If we don't, allocate a new one */
1137 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1138 if (UncProvider
== NULL
)
1140 Status
= STATUS_INVALID_USER_BUFFER
;
1145 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1146 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1147 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1149 /* As it wasn't in registry for order, give the lowest priority possible */
1150 UncProvider
->ProviderOrder
= MAXLONG
;
1151 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1154 /* Continue registration */
1155 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1156 ++UncProvider
->NodeReferences
;
1158 /* Open a handle to the device */
1159 InitializeObjectAttributes(&ObjectAttributes
,
1160 &UncProvider
->DeviceName
,
1161 OBJ_CASE_INSENSITIVE
,
1164 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1168 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1169 FILE_DIRECTORY_FILE
);
1170 if (NT_SUCCESS(Status
))
1172 Status
= IoStatusBlock
.Status
;
1175 /* And return the provider (as CCB) */
1176 if (NT_SUCCESS(Status
))
1178 Stack
->FileObject
->FsContext2
= UncProvider
;
1179 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1180 if (!NT_SUCCESS(Status
))
1182 NtClose(UncProvider
->DeviceHandle
);
1186 if (!NT_SUCCESS(Status
))
1188 MupDereferenceUncProvider(UncProvider
);
1192 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1194 /* Now, insert the provider in our global list
1195 * They are sorted by order
1197 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1201 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1203 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1205 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1211 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1213 UncProvider
->Registered
= TRUE
;
1214 ExReleaseResourceLite(&MupGlobalLock
);
1215 Status
= STATUS_SUCCESS
;
1217 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1222 if (_abnormal_termination())
1224 Status
= STATUS_INVALID_USER_BUFFER
;
1227 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1229 Irp
->IoStatus
.Status
= Status
;
1230 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1238 DfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject
,
1241 return STATUS_NOT_IMPLEMENTED
;
1246 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1250 PIO_STACK_LOCATION Stack
;
1252 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1256 /* MUP only understands a single FSCTL code: registering UNC provider */
1257 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1259 /* It obviously has to come from a driver/kernelmode thread */
1260 if (Irp
->RequestorMode
== UserMode
)
1262 Status
= STATUS_ACCESS_DENIED
;
1264 Irp
->IoStatus
.Status
= Status
;
1265 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1270 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1274 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1277 Status
= STATUS_INVALID_PARAMETER
;
1279 Irp
->IoStatus
.Status
= Status
;
1280 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1285 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1290 Status
= _SEH2_GetExceptionCode();
1298 MupSetFileObject(PFILE_OBJECT FileObject
,
1302 FileObject
->FsContext
= Fcb
;
1303 FileObject
->FsContext2
= Ccb
;
1307 MupRerouteOpen(PFILE_OBJECT FileObject
,
1308 PMUP_UNC UncProvider
)
1313 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1315 /* Get the full path name (device name first, and requested file name appended) */
1316 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1317 if (TotalLength
> MAXUSHORT
)
1319 return STATUS_NAME_TOO_LONG
;
1322 /* Allocate a buffer big enough */
1323 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1324 if (FullPath
== NULL
)
1326 return STATUS_INSUFFICIENT_RESOURCES
;
1329 /* Create the full path */
1330 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1331 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1333 /* And redo the path in the file oject */
1334 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1335 FileObject
->FileName
.Buffer
= FullPath
;
1336 FileObject
->FileName
.MaximumLength
= TotalLength
;
1337 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1339 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1340 return STATUS_REPARSE
;
1344 BroadcastOpen(PIRP Irp
)
1350 PMUP_UNC UncProvider
;
1351 UNICODE_STRING FullPath
;
1352 PFILE_OBJECT FileObject
;
1353 PIO_STACK_LOCATION Stack
;
1354 NTSTATUS Status
, LastFailed
;
1355 ULONG TotalLength
, LastOrder
;
1356 IO_STATUS_BLOCK IoStatusBlock
;
1357 OBJECT_ATTRIBUTES ObjectAttributes
;
1358 OBJECT_HANDLE_INFORMATION HandleInfo
;
1359 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1361 Fcb
= MupCreateFcb();
1364 return STATUS_INSUFFICIENT_RESOURCES
;
1367 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1368 FileObject
= Stack
->FileObject
;
1371 CcbInitialized
= FALSE
;
1372 LastFailed
= STATUS_NO_SUCH_FILE
;
1373 LastOrder
= (ULONG
)-1;
1377 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1380 /* Associate our FCB with the FO */
1381 MupSetFileObject(FileObject
, Fcb
, NULL
);
1382 Fcb
->FileObject
= FileObject
;
1384 /* Now, broadcast the open to any UNC provider that supports mailslots */
1385 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1387 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1388 ++UncProvider
->NodeReferences
;
1391 ExReleaseResourceLite(&MupGlobalLock
);
1394 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1395 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1397 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1398 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1399 if (FullPath
.Buffer
== NULL
)
1401 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1404 FullPath
.Length
= TotalLength
;
1405 FullPath
.MaximumLength
= TotalLength
;
1406 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1407 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1408 FileObject
->FileName
.Buffer
,
1409 FileObject
->FileName
.Length
);
1411 /* And just forward the creation request */
1412 InitializeObjectAttributes(&ObjectAttributes
,
1414 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1417 Status
= IoCreateFile(&Handle
,
1418 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1422 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1423 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1425 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1430 IO_NO_PARAMETER_CHECKING
);
1432 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1434 /* If opening succeed */
1435 if (NT_SUCCESS(Status
))
1437 Status
= IoStatusBlock
.Status
;
1440 Ccb
= MupCreateCcb();
1443 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1446 /* And associated a FO to it */
1447 if (NT_SUCCESS(Status
))
1449 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1454 /* If we failed, remember the last failed status of the higher priority provider */
1455 if (!NT_SUCCESS(Status
))
1457 if (UncProvider
->ProviderOrder
<= LastOrder
)
1459 LastOrder
= UncProvider
->ProviderOrder
;
1460 LastFailed
= Status
;
1463 /* Otherwise, properly attach our CCB to the mailslot */
1466 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1469 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1471 ++Fcb
->NodeReferences
;
1472 ExReleaseResourceLite(&MupGlobalLock
);
1474 CcbInitialized
= TRUE
;
1476 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1480 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1482 MupDereferenceUncProvider(UncProvider
);
1486 ExReleaseResourceLite(&MupGlobalLock
);
1489 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1491 Status
= _SEH2_GetExceptionCode();
1495 /* If we at least opened one mailslot, return success */
1496 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1500 MupDereferenceUncProvider(UncProvider
);
1505 ExReleaseResourceLite(&MupGlobalLock
);
1508 /* In case of failure, don't leak CCB */
1509 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1518 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1520 ULONG MajorFunction
,
1523 ULONG InputBufferSize
,
1525 ULONG OutputBufferSize
,
1526 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1529 PIO_STACK_LOCATION Stack
;
1530 PDEVICE_OBJECT DeviceObject
;
1532 if (InputBuffer
== NULL
)
1537 /* Get the device object */
1538 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1539 /* Allocate the IRP (with one more location for us */
1540 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1546 /* Skip our location */
1547 IoSetNextIrpStackLocation(Irp
);
1549 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1550 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1551 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1553 /* Setup the stack */
1554 Stack
= IoGetNextIrpStackLocation(Irp
);
1555 Stack
->MajorFunction
= MajorFunction
;
1556 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1557 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1558 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1559 Stack
->MinorFunction
= 0;
1560 Stack
->FileObject
= FileObject
;
1561 Stack
->DeviceObject
= DeviceObject
;
1563 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1565 case METHOD_BUFFERED
:
1566 /* If it's buffered, just pass the buffers we got */
1567 Irp
->MdlAddress
= NULL
;
1568 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1569 Irp
->UserBuffer
= OutputBuffer
;
1570 Irp
->Flags
= IRP_BUFFERED_IO
;
1572 if (OutputBuffer
!= NULL
)
1574 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1578 case METHOD_IN_DIRECT
:
1579 case METHOD_OUT_DIRECT
:
1580 /* Otherwise, allocate an MDL */
1581 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1587 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1588 Irp
->Flags
= IRP_BUFFERED_IO
;
1589 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1592 case METHOD_NEITHER
:
1593 /* Or pass the buffers */
1594 Irp
->UserBuffer
= OutputBuffer
;
1595 Irp
->MdlAddress
= NULL
;
1596 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1597 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1605 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1607 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1608 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1612 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1616 BOOLEAN KeepExtraRef
;
1618 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1619 --MasterQueryContext
->NodeReferences
;
1620 References
= MasterQueryContext
->NodeReferences
;
1621 ExReleaseResourceLite(&MupGlobalLock
);
1623 if (References
!= 0)
1625 DPRINT("Still having refs (%ld)\n", References
);
1626 return STATUS_PENDING
;
1629 /* We HAVE an IRP to complete. It cannot be NULL
1630 * Please, help preserving kittens, don't provide NULL IRPs.
1632 if (MasterQueryContext
->Irp
== NULL
)
1634 KeBugCheck(FILE_SYSTEM
);
1637 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1638 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1639 ExReleaseResourceLite(&MupGlobalLock
);
1641 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1642 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1643 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1645 /* We found a provider? */
1646 if (MasterQueryContext
->LatestProvider
!= NULL
)
1648 /* With a successful status? */
1649 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1651 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1654 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1657 ExReleaseResourceLite(&MupPrefixTableLock
);
1658 /* Reroute & complete :-) */
1659 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1664 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1668 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1669 ExReleaseResourceLite(&MupPrefixTableLock
);
1671 /* Return the highest failed status we had */
1672 Status
= MasterQueryContext
->LatestStatus
;
1675 /* In finally, complete the IRP for real! */
1676 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1677 IofCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1679 MasterQueryContext
->Irp
= NULL
;
1680 MupFreeMasterQueryContext(MasterQueryContext
);
1687 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1692 ULONG LatestPos
, Pos
;
1693 PWSTR AcceptedPrefix
;
1694 PMUP_MQC MasterQueryContext
;
1695 NTSTATUS Status
, TableStatus
;
1696 PQUERY_PATH_CONTEXT QueryContext
;
1697 PQUERY_PATH_RESPONSE QueryResponse
;
1699 /* Get all the data from our query to the provider */
1700 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1701 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1702 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1703 Status
= Irp
->IoStatus
.Status
;
1705 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1707 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1708 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1710 /* If the driver returned a success, and an acceptance length */
1711 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1713 Prefix
= MasterQueryContext
->Prefix
;
1715 /* Check if we already found a provider from a previous iteration */
1716 if (MasterQueryContext
->LatestProvider
!= NULL
)
1718 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1719 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1721 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1725 /* Otherwise, if the prefix was in the prefix table, just drop it:
1726 * we have a provider which superseeds the accepted prefix, so leave
1727 * room for the new prefix/provider
1729 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1730 if (Prefix
->InTable
)
1732 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1733 RemoveEntryList(&Prefix
->PrefixListEntry
);
1734 Prefix
->InTable
= FALSE
;
1736 ExReleaseResourceLite(&MupPrefixTableLock
);
1738 Prefix
->KeepExtraRef
= FALSE
;
1740 /* Release data associated with the current prefix, if any
1741 * We'll renew them with the new accepted prefix
1743 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1745 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1746 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1747 Prefix
->AcceptedPrefix
.Length
= 0;
1748 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1749 Prefix
->ExternalAlloc
= FALSE
;
1752 /* If there was also a provider, drop it, the new one
1755 if (Prefix
->UncProvider
!= NULL
)
1757 MupDereferenceUncProvider(Prefix
->UncProvider
);
1758 Prefix
->UncProvider
= NULL
;
1762 /* Now, set our information about the provider that accepted the prefix */
1763 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1764 MasterQueryContext
->LatestStatus
= Status
;
1766 if (MasterQueryContext
->FileObject
->FsContext2
!= DFS_MAGIC_CCB
)
1768 /* Allocate a buffer for the prefix */
1769 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1770 if (AcceptedPrefix
== NULL
)
1772 Prefix
->InTable
= FALSE
;
1776 /* Set it up to the accepted length */
1777 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1778 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1779 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1780 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1781 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1782 Prefix
->ExternalAlloc
= TRUE
;
1784 /* Insert the accepted prefix in the table of known prefixes */
1785 DPRINT1("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1786 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1787 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1789 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1790 Prefix
->InTable
= TRUE
;
1791 Prefix
->KeepExtraRef
= TRUE
;
1795 Prefix
->InTable
= FALSE
;
1797 ExReleaseResourceLite(&MupPrefixTableLock
);
1803 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1805 /* We failed and didn't find any provider over the latest iterations */
1806 if (MasterQueryContext
->LatestProvider
== NULL
)
1808 /* If we had a success though (broken provider?) set our failed status */
1809 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1811 MasterQueryContext
->LatestStatus
= Status
;
1815 TableStatus
= MupOrderedErrorList
[0];
1818 /* Otherwise, time to compare statuteses, between the latest failed
1819 * and the current failure.
1820 * We have an order table of failed status: the deeper you go in the
1821 * table, the more the error is critical.
1822 * Our goal is to return the most critical status that was returned by
1823 * any of the providers
1826 /* Look for latest status position */
1827 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1830 TableStatus
= MupOrderedErrorList
[LatestPos
];
1833 /* If at pos 0, the new status is likely more critical */
1836 MasterQueryContext
->LatestStatus
= Status
;
1840 /* Otherwise, find position of the new status in the table */
1844 if (Status
== MupOrderedErrorList
[Pos
])
1851 while (Pos
< LatestPos
);
1853 /* If it has a higher position (more critical), return it */
1854 if (Pos
>= LatestPos
)
1856 MasterQueryContext
->LatestStatus
= Status
;
1864 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1865 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1868 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1869 MupDereferenceMasterQueryContext(MasterQueryContext
);
1871 return STATUS_MORE_PROCESSING_REQUIRED
;
1875 DfsFsdCreate(PDEVICE_OBJECT DeviceObject
,
1879 return STATUS_NOT_IMPLEMENTED
;
1883 CreateRedirectedFile(PIRP Irp
,
1884 PFILE_OBJECT FileObject
,
1885 PIO_SECURITY_CONTEXT SecurityContext
)
1894 PMUP_UNC UncProvider
;
1895 PIO_STACK_LOCATION Stack
;
1896 LARGE_INTEGER CurrentTime
;
1897 PMUP_MQC MasterQueryContext
;
1898 PQUERY_PATH_CONTEXT QueryContext
;
1899 PQUERY_PATH_REQUEST QueryPathRequest
;
1900 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1901 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1903 /* We cannot open a file without a name */
1904 if (FileObject
->FileName
.Length
== 0)
1906 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1907 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1909 return STATUS_INVALID_DEVICE_REQUEST
;
1912 DPRINT1("Request for opening: %wZ\n", &FileObject
->FileName
);
1915 BreakOnFirst
= TRUE
;
1916 Status
= STATUS_BAD_NETWORK_PATH
;
1918 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1919 /* First, try to see if that's a prefix we already know */
1920 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1921 if (TableEntry
!= NULL
)
1923 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1925 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1927 /* If so, check whether the prefix is still valid */
1928 KeQuerySystemTime(&CurrentTime
);
1929 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1931 /* It is: so, update its validity period and reroute file opening */
1932 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1933 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1934 ExReleaseResourceLite(&MupPrefixTableLock
);
1936 if (Status
== STATUS_REPARSE
)
1938 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1941 Irp
->IoStatus
.Status
= Status
;
1942 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1947 /* When here, we found a matching prefix, but expired, remove it from the table
1948 * We'll redo a full search
1950 if (Prefix
->InTable
)
1952 MupRemoveKnownPrefixEntry(Prefix
);
1955 ExReleaseResourceLite(&MupPrefixTableLock
);
1957 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1958 /* First of all, start looking for a mailslot */
1959 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
1961 Name
= &FileObject
->FileName
.Buffer
[1];
1962 Len
= FileObject
->FileName
.Length
;
1964 /* Skip the remote destination name */
1967 Len
-= sizeof(WCHAR
);
1975 } while (Cur
!= L
'\\');
1976 Len
-= sizeof(WCHAR
);
1978 /* If we still have room for "Mailslot" to fit */
1979 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
1981 /* Get the len in terms of chars count */
1982 Len
/= sizeof(WCHAR
);
1983 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
1985 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
1988 /* It's indeed a mailslot opening! */
1989 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
1991 /* Broadcast open */
1992 Status
= BroadcastOpen(Irp
);
1993 if (Status
== STATUS_REPARSE
)
1995 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1998 Irp
->IoStatus
.Status
= Status
;
1999 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2006 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
2007 if (!MupEnableDfs
|| FileObject
->FsContext2
== DFS_MAGIC_CCB
)
2009 /* We won't complete immediately */
2010 IoMarkIrpPending(Irp
);
2012 /* Allocate a new prefix for our search */
2013 Prefix
= MupAllocatePrefixEntry(0);
2016 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2017 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2019 return STATUS_PENDING
;
2022 /* Allocate a context for our search */
2023 MasterQueryContext
= MupAllocateMasterQueryContext();
2024 if (MasterQueryContext
== NULL
)
2026 MupFreeNode(Prefix
);
2028 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2029 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2031 return STATUS_PENDING
;
2034 MasterQueryContext
->Irp
= Irp
;
2035 MasterQueryContext
->FileObject
= FileObject
;
2036 MasterQueryContext
->LatestProvider
= NULL
;
2037 MasterQueryContext
->Prefix
= Prefix
;
2038 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2039 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2040 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2041 ++Prefix
->NodeReferences
;
2042 ExReleaseResourceLite(&MupGlobalLock
);
2046 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2049 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2050 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2052 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2054 ++UncProvider
->NodeReferences
;
2057 ExReleaseResourceLite(&MupGlobalLock
);
2060 /* We will obviously only query registered providers */
2061 if (UncProvider
->Registered
)
2063 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2064 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2065 if (QueryPathRequest
== NULL
)
2067 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2070 /* Allocate a context for IRP completion routine
2071 * In case a prefix matches the path, the reroute will happen
2072 * in the completion routine, when we have return from the provider
2074 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2075 if (QueryContext
== NULL
)
2077 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2078 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2081 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2082 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2083 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2084 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2085 QueryPathRequest
->SecurityContext
= SecurityContext
;
2086 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2088 /* Build our IRP for the query */
2089 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2091 IRP_MJ_DEVICE_CONTROL
,
2092 IOCTL_REDIR_QUERY_PATH
,
2094 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2096 sizeof(QUERY_PATH_RESPONSE
),
2097 QueryPathCompletionRoutine
);
2098 if (QueryIrp
== NULL
)
2100 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2101 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2102 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2105 QueryIrp
->RequestorMode
= KernelMode
;
2106 QueryContext
->UncProvider
= UncProvider
;
2107 QueryContext
->Irp
= QueryIrp
;
2109 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2110 ++UncProvider
->NodeReferences
;
2111 ++MasterQueryContext
->NodeReferences
;
2112 ExReleaseResourceLite(&MupGlobalLock
);
2114 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2115 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2116 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2118 /* Query the provider !*/
2119 DPRINT1("Requeting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2120 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2121 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2124 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2127 /* We're done with that provider */
2128 MupDereferenceUncProvider(UncProvider
);
2131 /* If query went fine on the first request, just break and leave */
2132 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2137 BreakOnFirst
= FALSE
;
2142 if (_abnormal_termination())
2144 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2149 MupDereferenceUncProvider(UncProvider
);
2154 ExReleaseResourceLite(&MupGlobalLock
);
2157 MupDereferenceMasterQueryContext(MasterQueryContext
);
2159 Status
= STATUS_PENDING
;
2166 Status
= STATUS_NOT_IMPLEMENTED
;
2173 OpenMupFileSystem(PMUP_VCB Vcb
,
2174 PFILE_OBJECT FileObject
,
2175 ACCESS_MASK DesiredAccess
,
2180 DPRINT1("Opening MUP\n");
2182 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2185 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2186 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2187 if (NT_SUCCESS(Status
))
2189 ++Vcb
->NodeReferences
;
2190 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2191 Status
= STATUS_SUCCESS
;
2196 ExReleaseResourceLite(&MupVcbLock
);
2205 MupCreate(PDEVICE_OBJECT DeviceObject
,
2209 PIO_STACK_LOCATION Stack
;
2210 PFILE_OBJECT FileObject
, RelatedFileObject
;
2212 FsRtlEnterFileSystem();
2216 /* If DFS is enabled, check if that's for DFS and is so relay */
2217 if (MupEnableDfs
&& (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
))
2219 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2223 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2224 FileObject
= Stack
->FileObject
;
2225 RelatedFileObject
= FileObject
->RelatedFileObject
;
2227 /* 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 */
2228 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2230 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2232 /* Otherwise, it's just a volume open */
2235 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2237 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2238 Stack
->Parameters
.Create
.ShareAccess
);
2240 Irp
->IoStatus
.Information
= FILE_OPENED
;
2241 Irp
->IoStatus
.Status
= Status
;
2242 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2246 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2248 Status
= _SEH2_GetExceptionCode();
2250 Irp
->IoStatus
.Status
= Status
;
2251 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2255 FsRtlExitFileSystem();
2261 MupCloseUncProvider(PMUP_UNC UncProvider
)
2263 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2265 /* If the node was still valid, reregister the UNC provider */
2266 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2268 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2269 UncProvider
->Registered
= FALSE
;
2270 ExReleaseResourceLite(&MupGlobalLock
);
2272 if (UncProvider
->FileObject
!= NULL
)
2274 ZwClose(UncProvider
->DeviceHandle
);
2275 ObDereferenceObject(UncProvider
->FileObject
);
2280 ExReleaseResourceLite(&MupGlobalLock
);
2285 DfsFsdCleanup(PDEVICE_OBJECT DeviceObject
,
2289 return STATUS_NOT_IMPLEMENTED
;
2294 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2301 PIO_STACK_LOCATION Stack
;
2303 /* If DFS is enabled, check if that's for DFS and is so relay */
2306 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2308 return DfsFsdCleanup(DeviceObject
, Irp
);
2312 FsRtlEnterFileSystem();
2316 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2317 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2321 /* If we got a VCB, clean it up */
2322 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2324 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2325 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2327 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2329 /* If Ccb is not null, then, it's a UNC provider node */
2332 /* Close it, and dereference */
2333 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2334 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2335 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2337 ExReleaseResourceLite(&MupGlobalLock
);
2340 Status
= STATUS_SUCCESS
;
2344 /* If the node wasn't already cleaned, do it */
2345 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2347 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2348 Status
= STATUS_SUCCESS
;
2352 Status
= STATUS_INVALID_HANDLE
;
2355 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2356 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2358 MupDereferenceFcb(Fcb
);
2362 Status
= STATUS_INVALID_HANDLE
;
2364 Irp
->IoStatus
.Status
= Status
;
2365 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2372 Status
= _SEH2_GetExceptionCode();
2376 FsRtlExitFileSystem();
2382 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2385 PFILE_OBJECT FileObject
)
2387 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2389 /* Remove FCB, UNC from FO */
2390 MupSetFileObject(FileObject
, NULL
, NULL
);
2391 MupDereferenceVcb(Vcb
);
2393 ExReleaseResourceLite(&MupGlobalLock
);
2395 return STATUS_SUCCESS
;
2399 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2402 PFILE_OBJECT FileObject
)
2404 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2406 /* Remove FCB, CCB from FO */
2407 MupSetFileObject(FileObject
, NULL
, NULL
);
2408 MupDereferenceFcb(Fcb
);
2410 ExReleaseResourceLite(&MupGlobalLock
);
2412 return STATUS_SUCCESS
;
2416 DfsFsdClose(PDEVICE_OBJECT DeviceObject
,
2420 return STATUS_NOT_IMPLEMENTED
;
2425 MupClose(PDEVICE_OBJECT DeviceObject
,
2431 PIO_STACK_LOCATION Stack
;
2433 /* If DFS is enabled, check if that's for DFS and is so relay */
2436 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2438 return DfsFsdClose(DeviceObject
, Irp
);
2442 FsRtlEnterFileSystem();
2446 /* Get our internal structures from FO */
2447 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2448 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2451 Status
= STATUS_INVALID_HANDLE
;
2453 Irp
->IoStatus
.Status
= Status
;
2454 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2459 /* If we got the VCB, that's a volume close */
2460 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2462 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2464 /* Otherwise close the FCB */
2465 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2467 MupDereferenceFcb(Fcb
);
2468 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2472 Status
= STATUS_INVALID_HANDLE
;
2474 Irp
->IoStatus
.Status
= Status
;
2475 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2480 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2481 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2485 Status
= _SEH2_GetExceptionCode();
2489 FsRtlExitFileSystem();
2495 DfsUnload(PDRIVER_OBJECT DriverObject
)
2502 MupUnload(PDRIVER_OBJECT DriverObject
)
2504 IoDeleteDevice(mupDeviceObject
);
2508 DfsUnload(DriverObject
);
2511 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
2536 DriverEntry(PDRIVER_OBJECT DriverObject
,
2537 PUNICODE_STRING RegistryPath
)
2540 UNICODE_STRING MupString
;
2541 PDEVICE_OBJECT DeviceObject
;
2543 /* Only initialize global state of the driver
2544 * Other inits will happen when required
2546 MupInitializeData();
2548 /* Check if DFS is disabled */
2549 MupEnableDfs
= MuppIsDfsEnabled();
2550 /* If it's not disabled but when cannot init, disable it */
2551 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2553 MupEnableDfs
= FALSE
;
2556 /* Create the MUP device */
2557 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2558 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2559 if (!NT_SUCCESS(Status
))
2563 DfsUnload(DriverObject
);
2566 MupUninitializeData();
2572 DriverObject
->DriverUnload
= MupUnload
;
2573 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2574 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2575 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2576 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2577 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2578 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2579 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2581 /* And finish init */
2582 mupDeviceObject
= DeviceObject
;
2583 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2585 return STATUS_SUCCESS
;